summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2008-07-12 05:00:28 +0000
committerpeter <peter@FreeBSD.org>2008-07-12 05:00:28 +0000
commitba8f85b49c38af7bc2a9acdef5dcde2de008d25e (patch)
treeceac31a567976fd5866cb5791b059781f6e045de /lib
parent0f328cea2580ffb8f9e363be671a517787111472 (diff)
downloadFreeBSD-src-ba8f85b49c38af7bc2a9acdef5dcde2de008d25e.zip
FreeBSD-src-ba8f85b49c38af7bc2a9acdef5dcde2de008d25e.tar.gz
Flatten bind9 vendor work area
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.in29
-rw-r--r--lib/bind/Makefile.in133
-rw-r--r--lib/bind/README4
-rw-r--r--lib/bind/aclocal.m42
-rw-r--r--lib/bind/api3
-rw-r--r--lib/bind/bsd/Makefile.in39
-rw-r--r--lib/bind/bsd/daemon.c81
-rw-r--r--lib/bind/bsd/ftruncate.c64
-rw-r--r--lib/bind/bsd/gettimeofday.c64
-rw-r--r--lib/bind/bsd/mktemp.c156
-rw-r--r--lib/bind/bsd/putenv.c27
-rw-r--r--lib/bind/bsd/readv.c39
-rw-r--r--lib/bind/bsd/setenv.c151
-rw-r--r--lib/bind/bsd/setitimer.c29
-rw-r--r--lib/bind/bsd/strcasecmp.c124
-rw-r--r--lib/bind/bsd/strdup.c20
-rw-r--r--lib/bind/bsd/strerror.c92
-rw-r--r--lib/bind/bsd/strpbrk.c70
-rw-r--r--lib/bind/bsd/strsep.c88
-rw-r--r--lib/bind/bsd/strtoul.c119
-rw-r--r--lib/bind/bsd/utimes.c40
-rw-r--r--lib/bind/bsd/writev.c89
-rw-r--r--lib/bind/config.h.in61
-rwxr-xr-xlib/bind/configure33825
-rw-r--r--lib/bind/configure.in2683
-rw-r--r--lib/bind/dst/Makefile.in32
-rw-r--r--lib/bind/dst/dst_api.c1048
-rw-r--r--lib/bind/dst/dst_internal.h155
-rw-r--r--lib/bind/dst/hmac_link.c489
-rw-r--r--lib/bind/dst/md5.h108
-rw-r--r--lib/bind/dst/md5_dgst.c374
-rw-r--r--lib/bind/dst/md5_locl.h193
-rw-r--r--lib/bind/dst/support.c342
-rw-r--r--lib/bind/include/Makefile.in47
-rw-r--r--lib/bind/include/arpa/inet.h126
-rw-r--r--lib/bind/include/arpa/nameser.h574
-rw-r--r--lib/bind/include/arpa/nameser_compat.h232
-rw-r--r--lib/bind/include/fd_setsize.h10
-rw-r--r--lib/bind/include/hesiod.h39
-rw-r--r--lib/bind/include/irp.h107
-rw-r--r--lib/bind/include/irs.h348
-rw-r--r--lib/bind/include/isc/assertions.h122
-rw-r--r--lib/bind/include/isc/ctl.h112
-rw-r--r--lib/bind/include/isc/dst.h168
-rw-r--r--lib/bind/include/isc/eventlib.h204
-rw-r--r--lib/bind/include/isc/heap.h49
-rw-r--r--lib/bind/include/isc/irpmarshall.h112
-rw-r--r--lib/bind/include/isc/list.h117
-rw-r--r--lib/bind/include/isc/logging.h113
-rw-r--r--lib/bind/include/isc/memcluster.h50
-rw-r--r--lib/bind/include/isc/misc.h43
-rw-r--r--lib/bind/include/isc/tree.h59
-rw-r--r--lib/bind/include/netdb.h582
-rw-r--r--lib/bind/include/netgroup.h26
-rw-r--r--lib/bind/include/res_update.h69
-rw-r--r--lib/bind/include/resolv.h505
-rw-r--r--lib/bind/include/resolv_mt.h47
-rw-r--r--lib/bind/inet/Makefile.in35
-rw-r--r--lib/bind/inet/inet_addr.c208
-rw-r--r--lib/bind/inet/inet_cidr_ntop.c263
-rw-r--r--lib/bind/inet/inet_cidr_pton.c277
-rw-r--r--lib/bind/inet/inet_data.c46
-rw-r--r--lib/bind/inet/inet_lnaof.c65
-rw-r--r--lib/bind/inet/inet_makeaddr.c68
-rw-r--r--lib/bind/inet/inet_net_ntop.c279
-rw-r--r--lib/bind/inet/inet_net_pton.c407
-rw-r--r--lib/bind/inet/inet_neta.c89
-rw-r--r--lib/bind/inet/inet_netof.c64
-rw-r--r--lib/bind/inet/inet_network.c106
-rw-r--r--lib/bind/inet/inet_ntoa.c64
-rw-r--r--lib/bind/inet/inet_ntop.c207
-rw-r--r--lib/bind/inet/inet_pton.c223
-rw-r--r--lib/bind/inet/nsap_addr.c111
-rw-r--r--lib/bind/irs/Makefile.in70
-rw-r--r--lib/bind/irs/dns.c154
-rw-r--r--lib/bind/irs/dns_gr.c294
-rw-r--r--lib/bind/irs/dns_ho.c1142
-rw-r--r--lib/bind/irs/dns_nw.c591
-rw-r--r--lib/bind/irs/dns_p.h52
-rw-r--r--lib/bind/irs/dns_pr.c268
-rw-r--r--lib/bind/irs/dns_pw.c232
-rw-r--r--lib/bind/irs/dns_sv.c300
-rw-r--r--lib/bind/irs/gai_strerror.c105
-rw-r--r--lib/bind/irs/gen.c433
-rw-r--r--lib/bind/irs/gen_gr.c493
-rw-r--r--lib/bind/irs/gen_ho.c391
-rw-r--r--lib/bind/irs/gen_ng.c174
-rw-r--r--lib/bind/irs/gen_nw.c264
-rw-r--r--lib/bind/irs/gen_p.h113
-rw-r--r--lib/bind/irs/gen_pr.c228
-rw-r--r--lib/bind/irs/gen_pw.c234
-rw-r--r--lib/bind/irs/gen_sv.c229
-rw-r--r--lib/bind/irs/getaddrinfo.c1253
-rw-r--r--lib/bind/irs/getgrent.c224
-rw-r--r--lib/bind/irs/getgrent_r.c230
-rw-r--r--lib/bind/irs/gethostent.c1070
-rw-r--r--lib/bind/irs/gethostent_r.c275
-rw-r--r--lib/bind/irs/getnameinfo.c334
-rw-r--r--lib/bind/irs/getnetent.c345
-rw-r--r--lib/bind/irs/getnetent_r.c234
-rw-r--r--lib/bind/irs/getnetgrent.c158
-rw-r--r--lib/bind/irs/getnetgrent_r.c178
-rw-r--r--lib/bind/irs/getprotoent.c176
-rw-r--r--lib/bind/irs/getprotoent_r.c223
-rw-r--r--lib/bind/irs/getpwent.c201
-rw-r--r--lib/bind/irs/getpwent_r.c276
-rw-r--r--lib/bind/irs/getservent.c179
-rw-r--r--lib/bind/irs/getservent_r.c242
-rw-r--r--lib/bind/irs/hesiod.c505
-rw-r--r--lib/bind/irs/hesiod_p.h48
-rw-r--r--lib/bind/irs/irp.c582
-rw-r--r--lib/bind/irs/irp_gr.c357
-rw-r--r--lib/bind/irs/irp_ho.c405
-rw-r--r--lib/bind/irs/irp_ng.c253
-rw-r--r--lib/bind/irs/irp_nw.c348
-rw-r--r--lib/bind/irs/irp_p.h60
-rw-r--r--lib/bind/irs/irp_pr.c327
-rw-r--r--lib/bind/irs/irp_pw.c340
-rw-r--r--lib/bind/irs/irp_sv.c346
-rw-r--r--lib/bind/irs/irpmarshall.c2301
-rw-r--r--lib/bind/irs/irs_data.c246
-rw-r--r--lib/bind/irs/irs_data.h63
-rw-r--r--lib/bind/irs/irs_p.h51
-rw-r--r--lib/bind/irs/lcl.c142
-rw-r--r--lib/bind/irs/lcl_gr.c354
-rw-r--r--lib/bind/irs/lcl_ho.c578
-rw-r--r--lib/bind/irs/lcl_ng.c446
-rw-r--r--lib/bind/irs/lcl_nw.c373
-rw-r--r--lib/bind/irs/lcl_p.h51
-rw-r--r--lib/bind/irs/lcl_pr.c294
-rw-r--r--lib/bind/irs/lcl_pw.c309
-rw-r--r--lib/bind/irs/lcl_sv.c432
-rw-r--r--lib/bind/irs/nis.c156
-rw-r--r--lib/bind/irs/nis_gr.c354
-rw-r--r--lib/bind/irs/nis_ho.c535
-rw-r--r--lib/bind/irs/nis_ng.c304
-rw-r--r--lib/bind/irs/nis_nw.c385
-rw-r--r--lib/bind/irs/nis_p.h47
-rw-r--r--lib/bind/irs/nis_pr.c302
-rw-r--r--lib/bind/irs/nis_pw.c288
-rw-r--r--lib/bind/irs/nis_sv.c310
-rw-r--r--lib/bind/irs/nul_ng.c127
-rw-r--r--lib/bind/irs/pathnames.h52
-rw-r--r--lib/bind/irs/util.c109
-rw-r--r--lib/bind/isc/Makefile.in35
-rw-r--r--lib/bind/isc/assertions.c93
-rw-r--r--lib/bind/isc/assertions.mdoc138
-rw-r--r--lib/bind/isc/base64.c322
-rw-r--r--lib/bind/isc/bitncmp.c68
-rw-r--r--lib/bind/isc/bitncmp.mdoc82
-rw-r--r--lib/bind/isc/ctl_clnt.c617
-rw-r--r--lib/bind/isc/ctl_p.c188
-rw-r--r--lib/bind/isc/ctl_p.h28
-rw-r--r--lib/bind/isc/ctl_srvr.c784
-rw-r--r--lib/bind/isc/ev_connects.c369
-rw-r--r--lib/bind/isc/ev_files.c277
-rw-r--r--lib/bind/isc/ev_streams.c308
-rw-r--r--lib/bind/isc/ev_timers.c499
-rw-r--r--lib/bind/isc/ev_waits.c247
-rw-r--r--lib/bind/isc/eventlib.c933
-rw-r--r--lib/bind/isc/eventlib.mdoc918
-rw-r--r--lib/bind/isc/eventlib_p.h281
-rw-r--r--lib/bind/isc/heap.c236
-rw-r--r--lib/bind/isc/heap.mdoc378
-rw-r--r--lib/bind/isc/hex.c119
-rw-r--r--lib/bind/isc/logging.c722
-rw-r--r--lib/bind/isc/logging.mdoc1056
-rw-r--r--lib/bind/isc/logging_p.h61
-rw-r--r--lib/bind/isc/memcluster.c588
-rw-r--r--lib/bind/isc/memcluster.mdoc376
-rw-r--r--lib/bind/isc/movefile.c37
-rw-r--r--lib/bind/isc/tree.c534
-rw-r--r--lib/bind/isc/tree.mdoc154
-rw-r--r--lib/bind/make/includes.in44
-rw-r--r--lib/bind/make/mkdep.in147
-rw-r--r--lib/bind/make/rules.in177
-rwxr-xr-xlib/bind/mkinstalldirs40
-rw-r--r--lib/bind/nameser/Makefile.in31
-rw-r--r--lib/bind/nameser/ns_date.c129
-rw-r--r--lib/bind/nameser/ns_name.c973
-rw-r--r--lib/bind/nameser/ns_netint.c58
-rw-r--r--lib/bind/nameser/ns_parse.c211
-rw-r--r--lib/bind/nameser/ns_print.c897
-rw-r--r--lib/bind/nameser/ns_samedomain.c207
-rw-r--r--lib/bind/nameser/ns_sign.c387
-rw-r--r--lib/bind/nameser/ns_ttl.c162
-rw-r--r--lib/bind/nameser/ns_verify.c484
-rw-r--r--lib/bind/port/Makefile.in14
-rw-r--r--lib/bind/port/freebsd/Makefile.in14
-rw-r--r--lib/bind/port/freebsd/include/Makefile.in34
-rw-r--r--lib/bind/port/freebsd/include/sys/bitypes.h37
-rw-r--r--lib/bind/port_after.h.in415
-rw-r--r--lib/bind/port_before.h.in162
-rw-r--r--lib/bind/resolv/Makefile.in34
-rw-r--r--lib/bind/resolv/herror.c129
-rw-r--r--lib/bind/resolv/mtctxres.c129
-rw-r--r--lib/bind/resolv/res_comp.c265
-rw-r--r--lib/bind/resolv/res_data.c297
-rw-r--r--lib/bind/resolv/res_debug.c1165
-rw-r--r--lib/bind/resolv/res_debug.h35
-rw-r--r--lib/bind/resolv/res_findzonecut.c722
-rw-r--r--lib/bind/resolv/res_init.c801
-rw-r--r--lib/bind/resolv/res_mkquery.c257
-rw-r--r--lib/bind/resolv/res_mkupdate.c1162
-rw-r--r--lib/bind/resolv/res_mkupdate.h25
-rw-r--r--lib/bind/resolv/res_private.h22
-rw-r--r--lib/bind/resolv/res_query.c432
-rw-r--r--lib/bind/resolv/res_send.c1094
-rw-r--r--lib/bind/resolv/res_sendsigned.c170
-rw-r--r--lib/bind/resolv/res_update.c213
-rw-r--r--lib/bind9/Makefile.in84
-rw-r--r--lib/bind9/api3
-rw-r--r--lib/bind9/check.c2043
-rw-r--r--lib/bind9/getaddresses.c231
-rw-r--r--lib/bind9/include/Makefile.in25
-rw-r--r--lib/bind9/include/bind9/Makefile.in42
-rw-r--r--lib/bind9/include/bind9/check.h57
-rw-r--r--lib/bind9/include/bind9/getaddresses.h61
-rw-r--r--lib/bind9/include/bind9/version.h28
-rw-r--r--lib/bind9/version.c28
-rw-r--r--lib/dns/Makefile.in171
-rw-r--r--lib/dns/acache.c1778
-rw-r--r--lib/dns/acl.c452
-rw-r--r--lib/dns/adb.c3610
-rw-r--r--lib/dns/api3
-rw-r--r--lib/dns/byaddr.c316
-rw-r--r--lib/dns/cache.c1154
-rw-r--r--lib/dns/callbacks.c113
-rw-r--r--lib/dns/compress.c341
-rw-r--r--lib/dns/db.c821
-rw-r--r--lib/dns/dbiterator.c143
-rw-r--r--lib/dns/dbtable.c291
-rw-r--r--lib/dns/diff.c554
-rw-r--r--lib/dns/dispatch.c2674
-rw-r--r--lib/dns/dlz.c510
-rw-r--r--lib/dns/dnssec.c865
-rw-r--r--lib/dns/ds.c104
-rw-r--r--lib/dns/dst_api.c1221
-rw-r--r--lib/dns/dst_internal.h142
-rw-r--r--lib/dns/dst_lib.c67
-rw-r--r--lib/dns/dst_openssl.h34
-rw-r--r--lib/dns/dst_parse.c493
-rw-r--r--lib/dns/dst_parse.h118
-rw-r--r--lib/dns/dst_result.c88
-rw-r--r--lib/dns/forward.c199
-rw-r--r--lib/dns/gen-unix.h97
-rw-r--r--lib/dns/gen.c884
-rw-r--r--lib/dns/gssapi_link.c222
-rw-r--r--lib/dns/gssapictx.c264
-rw-r--r--lib/dns/hmac_link.c1668
-rw-r--r--lib/dns/include/Makefile.in25
-rw-r--r--lib/dns/include/dns/Makefile.in54
-rw-r--r--lib/dns/include/dns/acache.h445
-rw-r--r--lib/dns/include/dns/acl.h222
-rw-r--r--lib/dns/include/dns/adb.h635
-rw-r--r--lib/dns/include/dns/bit.h39
-rw-r--r--lib/dns/include/dns/byaddr.h171
-rw-r--r--lib/dns/include/dns/cache.h253
-rw-r--r--lib/dns/include/dns/callbacks.h87
-rw-r--r--lib/dns/include/dns/cert.h69
-rw-r--r--lib/dns/include/dns/compress.h269
-rw-r--r--lib/dns/include/dns/db.h1299
-rw-r--r--lib/dns/include/dns/dbiterator.h297
-rw-r--r--lib/dns/include/dns/dbtable.h165
-rw-r--r--lib/dns/include/dns/diff.h280
-rw-r--r--lib/dns/include/dns/dispatch.h453
-rw-r--r--lib/dns/include/dns/dlz.h290
-rw-r--r--lib/dns/include/dns/dnssec.h183
-rw-r--r--lib/dns/include/dns/ds.h63
-rw-r--r--lib/dns/include/dns/events.h75
-rw-r--r--lib/dns/include/dns/fixedname.h86
-rw-r--r--lib/dns/include/dns/forward.h118
-rw-r--r--lib/dns/include/dns/journal.h276
-rw-r--r--lib/dns/include/dns/keyflags.h54
-rw-r--r--lib/dns/include/dns/keytable.h255
-rw-r--r--lib/dns/include/dns/keyvalues.h98
-rw-r--r--lib/dns/include/dns/lib.h45
-rw-r--r--lib/dns/include/dns/log.h106
-rw-r--r--lib/dns/include/dns/lookup.h137
-rw-r--r--lib/dns/include/dns/master.h277
-rw-r--r--lib/dns/include/dns/masterdump.h334
-rw-r--r--lib/dns/include/dns/message.h1339
-rw-r--r--lib/dns/include/dns/name.h1296
-rw-r--r--lib/dns/include/dns/ncache.h159
-rw-r--r--lib/dns/include/dns/nsec.h69
-rw-r--r--lib/dns/include/dns/opcode.h51
-rw-r--r--lib/dns/include/dns/order.h99
-rw-r--r--lib/dns/include/dns/peer.h212
-rw-r--r--lib/dns/include/dns/portlist.h101
-rw-r--r--lib/dns/include/dns/rbt.h916
-rw-r--r--lib/dns/include/dns/rcode.h98
-rw-r--r--lib/dns/include/dns/rdata.h701
-rw-r--r--lib/dns/include/dns/rdataclass.h81
-rw-r--r--lib/dns/include/dns/rdatalist.h103
-rw-r--r--lib/dns/include/dns/rdataset.h597
-rw-r--r--lib/dns/include/dns/rdatasetiter.h170
-rw-r--r--lib/dns/include/dns/rdataslab.h163
-rw-r--r--lib/dns/include/dns/rdatatype.h83
-rw-r--r--lib/dns/include/dns/request.h374
-rw-r--r--lib/dns/include/dns/resolver.h479
-rw-r--r--lib/dns/include/dns/result.h190
-rw-r--r--lib/dns/include/dns/rootns.h45
-rw-r--r--lib/dns/include/dns/sdb.h209
-rw-r--r--lib/dns/include/dns/sdlz.h266
-rw-r--r--lib/dns/include/dns/secalg.h71
-rw-r--r--lib/dns/include/dns/secproto.h71
-rw-r--r--lib/dns/include/dns/soa.h81
-rw-r--r--lib/dns/include/dns/ssu.h165
-rw-r--r--lib/dns/include/dns/stats.h61
-rw-r--r--lib/dns/include/dns/tcpmsg.h147
-rw-r--r--lib/dns/include/dns/time.h72
-rw-r--r--lib/dns/include/dns/timer.h52
-rw-r--r--lib/dns/include/dns/tkey.h198
-rw-r--r--lib/dns/include/dns/tsig.h254
-rw-r--r--lib/dns/include/dns/ttl.h78
-rw-r--r--lib/dns/include/dns/types.h328
-rw-r--r--lib/dns/include/dns/validator.h247
-rw-r--r--lib/dns/include/dns/version.h28
-rw-r--r--lib/dns/include/dns/view.h804
-rw-r--r--lib/dns/include/dns/xfrin.h111
-rw-r--r--lib/dns/include/dns/zone.h1586
-rw-r--r--lib/dns/include/dns/zonekey.h42
-rw-r--r--lib/dns/include/dns/zt.h183
-rw-r--r--lib/dns/include/dst/Makefile.in37
-rw-r--r--lib/dns/include/dst/dst.h620
-rw-r--r--lib/dns/include/dst/gssapi.h58
-rw-r--r--lib/dns/include/dst/lib.h41
-rw-r--r--lib/dns/include/dst/result.h70
-rw-r--r--lib/dns/journal.c2182
-rw-r--r--lib/dns/key.c147
-rw-r--r--lib/dns/keytable.c395
-rw-r--r--lib/dns/lib.c65
-rw-r--r--lib/dns/log.c97
-rw-r--r--lib/dns/lookup.c497
-rw-r--r--lib/dns/master.c2833
-rw-r--r--lib/dns/masterdump.c1738
-rw-r--r--lib/dns/message.c3265
-rw-r--r--lib/dns/name.c2406
-rw-r--r--lib/dns/ncache.c559
-rw-r--r--lib/dns/nsec.c220
-rw-r--r--lib/dns/openssl_link.c261
-rw-r--r--lib/dns/openssldh_link.c626
-rw-r--r--lib/dns/openssldsa_link.c462
-rw-r--r--lib/dns/opensslrsa_link.c629
-rw-r--r--lib/dns/order.c167
-rw-r--r--lib/dns/peer.c685
-rw-r--r--lib/dns/portlist.c266
-rw-r--r--lib/dns/rbt.c2544
-rw-r--r--lib/dns/rbtdb.c6760
-rw-r--r--lib/dns/rbtdb.h44
-rw-r--r--lib/dns/rbtdb64.c23
-rw-r--r--lib/dns/rbtdb64.h45
-rw-r--r--lib/dns/rcode.c474
-rw-r--r--lib/dns/rdata.c1746
-rw-r--r--lib/dns/rdata/any_255/tsig_250.c597
-rw-r--r--lib/dns/rdata/any_255/tsig_250.h38
-rw-r--r--lib/dns/rdata/ch_3/a_1.c316
-rw-r--r--lib/dns/rdata/ch_3/a_1.h34
-rw-r--r--lib/dns/rdata/generic/afsdb_18.c309
-rw-r--r--lib/dns/rdata/generic/afsdb_18.h34
-rw-r--r--lib/dns/rdata/generic/cert_37.c280
-rw-r--r--lib/dns/rdata/generic/cert_37.h34
-rw-r--r--lib/dns/rdata/generic/cname_5.c232
-rw-r--r--lib/dns/rdata/generic/cname_5.h29
-rw-r--r--lib/dns/rdata/generic/dlv_32769.c321
-rw-r--r--lib/dns/rdata/generic/dlv_32769.h33
-rw-r--r--lib/dns/rdata/generic/dname_39.c233
-rw-r--r--lib/dns/rdata/generic/dname_39.h32
-rw-r--r--lib/dns/rdata/generic/dnskey_48.c312
-rw-r--r--lib/dns/rdata/generic/dnskey_48.h37
-rw-r--r--lib/dns/rdata/generic/ds_43.c321
-rw-r--r--lib/dns/rdata/generic/ds_43.h35
-rw-r--r--lib/dns/rdata/generic/gpos_27.c252
-rw-r--r--lib/dns/rdata/generic/gpos_27.h37
-rw-r--r--lib/dns/rdata/generic/hinfo_13.c224
-rw-r--r--lib/dns/rdata/generic/hinfo_13.h32
-rw-r--r--lib/dns/rdata/generic/ipseckey_45.c462
-rw-r--r--lib/dns/rdata/generic/ipseckey_45.h35
-rw-r--r--lib/dns/rdata/generic/isdn_20.c234
-rw-r--r--lib/dns/rdata/generic/isdn_20.h35
-rw-r--r--lib/dns/rdata/generic/key_25.c312
-rw-r--r--lib/dns/rdata/generic/key_25.h37
-rw-r--r--lib/dns/rdata/generic/loc_29.c794
-rw-r--r--lib/dns/rdata/generic/loc_29.h43
-rw-r--r--lib/dns/rdata/generic/mb_7.c234
-rw-r--r--lib/dns/rdata/generic/mb_7.h30
-rw-r--r--lib/dns/rdata/generic/md_3.c236
-rw-r--r--lib/dns/rdata/generic/md_3.h31
-rw-r--r--lib/dns/rdata/generic/mf_4.c235
-rw-r--r--lib/dns/rdata/generic/mf_4.h30
-rw-r--r--lib/dns/rdata/generic/mg_8.c230
-rw-r--r--lib/dns/rdata/generic/mg_8.h30
-rw-r--r--lib/dns/rdata/generic/minfo_14.c324
-rw-r--r--lib/dns/rdata/generic/minfo_14.h31
-rw-r--r--lib/dns/rdata/generic/mr_9.c231
-rw-r--r--lib/dns/rdata/generic/mr_9.h30
-rw-r--r--lib/dns/rdata/generic/mx_15.c319
-rw-r--r--lib/dns/rdata/generic/mx_15.h31
-rw-r--r--lib/dns/rdata/generic/ns_2.c251
-rw-r--r--lib/dns/rdata/generic/ns_2.h31
-rw-r--r--lib/dns/rdata/generic/nsec_47.c366
-rw-r--r--lib/dns/rdata/generic/nsec_47.h34
-rw-r--r--lib/dns/rdata/generic/null_10.c192
-rw-r--r--lib/dns/rdata/generic/null_10.h32
-rw-r--r--lib/dns/rdata/generic/nxt_30.c329
-rw-r--r--lib/dns/rdata/generic/nxt_30.h34
-rw-r--r--lib/dns/rdata/generic/opt_41.c280
-rw-r--r--lib/dns/rdata/generic/opt_41.h55
-rw-r--r--lib/dns/rdata/generic/proforma.c173
-rw-r--r--lib/dns/rdata/generic/proforma.h30
-rw-r--r--lib/dns/rdata/generic/ptr_12.c291
-rw-r--r--lib/dns/rdata/generic/ptr_12.h30
-rw-r--r--lib/dns/rdata/generic/rp_17.c314
-rw-r--r--lib/dns/rdata/generic/rp_17.h34
-rw-r--r--lib/dns/rdata/generic/rrsig_46.c551
-rw-r--r--lib/dns/rdata/generic/rrsig_46.h41
-rw-r--r--lib/dns/rdata/generic/rt_21.c311
-rw-r--r--lib/dns/rdata/generic/rt_21.h33
-rw-r--r--lib/dns/rdata/generic/sig_24.c578
-rw-r--r--lib/dns/rdata/generic/sig_24.h42
-rw-r--r--lib/dns/rdata/generic/soa_6.c443
-rw-r--r--lib/dns/rdata/generic/soa_6.h37
-rw-r--r--lib/dns/rdata/generic/spf_99.c238
-rw-r--r--lib/dns/rdata/generic/spf_99.h51
-rw-r--r--lib/dns/rdata/generic/sshfp_44.c262
-rw-r--r--lib/dns/rdata/generic/sshfp_44.h35
-rw-r--r--lib/dns/rdata/generic/tkey_249.c555
-rw-r--r--lib/dns/rdata/generic/tkey_249.h41
-rw-r--r--lib/dns/rdata/generic/txt_16.c238
-rw-r--r--lib/dns/rdata/generic/txt_16.h52
-rw-r--r--lib/dns/rdata/generic/unspec_103.c189
-rw-r--r--lib/dns/rdata/generic/unspec_103.h31
-rw-r--r--lib/dns/rdata/generic/x25_19.c219
-rw-r--r--lib/dns/rdata/generic/x25_19.h33
-rw-r--r--lib/dns/rdata/hs_4/a_1.c232
-rw-r--r--lib/dns/rdata/hs_4/a_1.h29
-rw-r--r--lib/dns/rdata/in_1/a6_38.c461
-rw-r--r--lib/dns/rdata/in_1/a6_38.h34
-rw-r--r--lib/dns/rdata/in_1/a_1.c236
-rw-r--r--lib/dns/rdata/in_1/a_1.h29
-rw-r--r--lib/dns/rdata/in_1/aaaa_28.c233
-rw-r--r--lib/dns/rdata/in_1/aaaa_28.h31
-rw-r--r--lib/dns/rdata/in_1/apl_42.c402
-rw-r--r--lib/dns/rdata/in_1/apl_42.h56
-rw-r--r--lib/dns/rdata/in_1/kx_36.c288
-rw-r--r--lib/dns/rdata/in_1/kx_36.h33
-rw-r--r--lib/dns/rdata/in_1/naptr_35.c578
-rw-r--r--lib/dns/rdata/in_1/naptr_35.h40
-rw-r--r--lib/dns/rdata/in_1/nsap-ptr_23.c245
-rw-r--r--lib/dns/rdata/in_1/nsap-ptr_23.h32
-rw-r--r--lib/dns/rdata/in_1/nsap_22.c255
-rw-r--r--lib/dns/rdata/in_1/nsap_22.h33
-rw-r--r--lib/dns/rdata/in_1/px_26.c374
-rw-r--r--lib/dns/rdata/in_1/px_26.h34
-rw-r--r--lib/dns/rdata/in_1/srv_33.c373
-rw-r--r--lib/dns/rdata/in_1/srv_33.h37
-rw-r--r--lib/dns/rdata/in_1/wks_11.c349
-rw-r--r--lib/dns/rdata/in_1/wks_11.h32
-rw-r--r--lib/dns/rdata/rdatastructpre.h42
-rw-r--r--lib/dns/rdata/rdatastructsuf.h22
-rw-r--r--lib/dns/rdatalist.c229
-rw-r--r--lib/dns/rdatalist_p.h57
-rw-r--r--lib/dns/rdataset.c709
-rw-r--r--lib/dns/rdatasetiter.c80
-rw-r--r--lib/dns/rdataslab.c1045
-rw-r--r--lib/dns/request.c1461
-rw-r--r--lib/dns/resolver.c7181
-rw-r--r--lib/dns/result.c276
-rw-r--r--lib/dns/rootns.c514
-rw-r--r--lib/dns/sdb.c1538
-rw-r--r--lib/dns/sdlz.c1786
-rw-r--r--lib/dns/soa.c111
-rw-r--r--lib/dns/ssu.c366
-rw-r--r--lib/dns/stats.c57
-rw-r--r--lib/dns/tcpmsg.c243
-rw-r--r--lib/dns/time.c174
-rw-r--r--lib/dns/timer.c60
-rw-r--r--lib/dns/tkey.c1242
-rw-r--r--lib/dns/tsig.c1464
-rw-r--r--lib/dns/ttl.c216
-rw-r--r--lib/dns/validator.c3078
-rw-r--r--lib/dns/version.c28
-rw-r--r--lib/dns/view.c1367
-rw-r--r--lib/dns/xfrin.c1470
-rw-r--r--lib/dns/zone.c8043
-rw-r--r--lib/dns/zonekey.c55
-rw-r--r--lib/dns/zt.c410
-rw-r--r--lib/isc/Makefile.in112
-rw-r--r--lib/isc/alpha/Makefile.in24
-rw-r--r--lib/isc/alpha/include/Makefile.in24
-rw-r--r--lib/isc/alpha/include/isc/Makefile.in36
-rw-r--r--lib/isc/alpha/include/isc/atomic.h170
-rw-r--r--lib/isc/api3
-rw-r--r--lib/isc/arm/include/isc/atomic.h81
-rw-r--r--lib/isc/assertions.c96
-rw-r--r--lib/isc/base64.c250
-rw-r--r--lib/isc/bitstring.c127
-rw-r--r--lib/isc/buffer.c413
-rw-r--r--lib/isc/bufferlist.c64
-rw-r--r--lib/isc/commandline.c222
-rw-r--r--lib/isc/entropy.c1263
-rw-r--r--lib/isc/error.c106
-rw-r--r--lib/isc/event.c88
-rw-r--r--lib/isc/fsaccess.c102
-rw-r--r--lib/isc/hash.c390
-rw-r--r--lib/isc/heap.c256
-rw-r--r--lib/isc/hex.c201
-rw-r--r--lib/isc/hmacmd5.c118
-rw-r--r--lib/isc/hmacsha.c438
-rw-r--r--lib/isc/ia64/Makefile.in24
-rw-r--r--lib/isc/ia64/include/Makefile.in24
-rw-r--r--lib/isc/ia64/include/isc/Makefile.in36
-rw-r--r--lib/isc/ia64/include/isc/atomic.h88
-rw-r--r--lib/isc/include/Makefile.in25
-rw-r--r--lib/isc/include/isc/Makefile.in57
-rw-r--r--lib/isc/include/isc/app.h212
-rw-r--r--lib/isc/include/isc/assertions.h123
-rw-r--r--lib/isc/include/isc/base64.h99
-rw-r--r--lib/isc/include/isc/bitstring.h157
-rw-r--r--lib/isc/include/isc/boolean.h31
-rw-r--r--lib/isc/include/isc/buffer.h811
-rw-r--r--lib/isc/include/isc/bufferlist.h86
-rw-r--r--lib/isc/include/isc/commandline.h50
-rw-r--r--lib/isc/include/isc/entropy.h307
-rw-r--r--lib/isc/include/isc/error.h62
-rw-r--r--lib/isc/include/isc/event.h121
-rw-r--r--lib/isc/include/isc/eventclass.h53
-rw-r--r--lib/isc/include/isc/file.h256
-rw-r--r--lib/isc/include/isc/formatcheck.h40
-rw-r--r--lib/isc/include/isc/fsaccess.h177
-rw-r--r--lib/isc/include/isc/hash.h185
-rw-r--r--lib/isc/include/isc/heap.h170
-rw-r--r--lib/isc/include/isc/hex.h98
-rw-r--r--lib/isc/include/isc/hmacmd5.h63
-rw-r--r--lib/isc/include/isc/hmacsha.h156
-rw-r--r--lib/isc/include/isc/interfaceiter.h133
-rw-r--r--lib/isc/include/isc/ipv6.h148
-rw-r--r--lib/isc/include/isc/lang.h33
-rw-r--r--lib/isc/include/isc/lex.h431
-rw-r--r--lib/isc/include/isc/lfsr.h130
-rw-r--r--lib/isc/include/isc/lib.h41
-rw-r--r--lib/isc/include/isc/list.h184
-rw-r--r--lib/isc/include/isc/log.h913
-rw-r--r--lib/isc/include/isc/magic.h41
-rw-r--r--lib/isc/include/isc/md5.h73
-rw-r--r--lib/isc/include/isc/mem.h543
-rw-r--r--lib/isc/include/isc/msgcat.h131
-rw-r--r--lib/isc/include/isc/msgs.h191
-rw-r--r--lib/isc/include/isc/mutexblock.h71
-rw-r--r--lib/isc/include/isc/netaddr.h175
-rw-r--r--lib/isc/include/isc/netscope.h43
-rw-r--r--lib/isc/include/isc/ondestroy.h116
-rw-r--r--lib/isc/include/isc/os.h38
-rw-r--r--lib/isc/include/isc/parseint.h64
-rw-r--r--lib/isc/include/isc/platform.h.in306
-rw-r--r--lib/isc/include/isc/print.h87
-rw-r--r--lib/isc/include/isc/quota.h119
-rw-r--r--lib/isc/include/isc/random.h62
-rw-r--r--lib/isc/include/isc/ratelimiter.h134
-rw-r--r--lib/isc/include/isc/refcount.h233
-rw-r--r--lib/isc/include/isc/region.h99
-rw-r--r--lib/isc/include/isc/resource.h87
-rw-r--r--lib/isc/include/isc/result.h104
-rw-r--r--lib/isc/include/isc/resultclass.h50
-rw-r--r--lib/isc/include/isc/rwlock.h135
-rw-r--r--lib/isc/include/isc/serial.h75
-rw-r--r--lib/isc/include/isc/sha1.h59
-rw-r--r--lib/isc/include/isc/sha2.h132
-rw-r--r--lib/isc/include/isc/sockaddr.h240
-rw-r--r--lib/isc/include/isc/socket.h752
-rw-r--r--lib/isc/include/isc/stdio.h77
-rw-r--r--lib/isc/include/isc/stdlib.h40
-rw-r--r--lib/isc/include/isc/string.h231
-rw-r--r--lib/isc/include/isc/symtab.h131
-rw-r--r--lib/isc/include/isc/task.h616
-rw-r--r--lib/isc/include/isc/taskpool.h105
-rw-r--r--lib/isc/include/isc/timer.h342
-rw-r--r--lib/isc/include/isc/types.h103
-rw-r--r--lib/isc/include/isc/util.h233
-rw-r--r--lib/isc/include/isc/version.h28
-rw-r--r--lib/isc/inet_aton.c196
-rw-r--r--lib/isc/inet_ntop.c198
-rw-r--r--lib/isc/inet_pton.c214
-rw-r--r--lib/isc/lex.c963
-rw-r--r--lib/isc/lfsr.c161
-rw-r--r--lib/isc/lib.c79
-rw-r--r--lib/isc/log.c1761
-rw-r--r--lib/isc/md5.c251
-rw-r--r--lib/isc/mem.c1955
-rw-r--r--lib/isc/mips/Makefile.in24
-rw-r--r--lib/isc/mips/include/Makefile.in24
-rw-r--r--lib/isc/mips/include/isc/Makefile.in36
-rw-r--r--lib/isc/mips/include/isc/atomic.h98
-rw-r--r--lib/isc/mutexblock.c59
-rw-r--r--lib/isc/netaddr.c436
-rw-r--r--lib/isc/netscope.c76
-rw-r--r--lib/isc/nls/Makefile.in37
-rw-r--r--lib/isc/nls/msgcat.c131
-rw-r--r--lib/isc/noatomic/Makefile.in24
-rw-r--r--lib/isc/noatomic/include/Makefile.in24
-rw-r--r--lib/isc/noatomic/include/isc/Makefile.in36
-rw-r--r--lib/isc/noatomic/include/isc/atomic.h24
-rw-r--r--lib/isc/nothreads/Makefile.in38
-rw-r--r--lib/isc/nothreads/condition.c24
-rw-r--r--lib/isc/nothreads/include/Makefile.in25
-rw-r--r--lib/isc/nothreads/include/isc/Makefile.in37
-rw-r--r--lib/isc/nothreads/include/isc/condition.h59
-rw-r--r--lib/isc/nothreads/include/isc/mutex.h39
-rw-r--r--lib/isc/nothreads/include/isc/once.h32
-rw-r--r--lib/isc/nothreads/include/isc/thread.h35
-rw-r--r--lib/isc/nothreads/mutex.c25
-rw-r--r--lib/isc/nothreads/thread.c28
-rw-r--r--lib/isc/ondestroy.c85
-rw-r--r--lib/isc/parseint.c72
-rw-r--r--lib/isc/powerpc/Makefile.in24
-rw-r--r--lib/isc/powerpc/include/Makefile.in24
-rw-r--r--lib/isc/powerpc/include/isc/Makefile.in36
-rw-r--r--lib/isc/powerpc/include/isc/atomic.h160
-rw-r--r--lib/isc/print.c559
-rw-r--r--lib/isc/pthreads/Makefile.in38
-rw-r--r--lib/isc/pthreads/condition.c74
-rw-r--r--lib/isc/pthreads/include/Makefile.in25
-rw-r--r--lib/isc/pthreads/include/isc/Makefile.in37
-rw-r--r--lib/isc/pthreads/include/isc/condition.h65
-rw-r--r--lib/isc/pthreads/include/isc/mutex.h145
-rw-r--r--lib/isc/pthreads/include/isc/once.h50
-rw-r--r--lib/isc/pthreads/include/isc/thread.h60
-rw-r--r--lib/isc/pthreads/mutex.c270
-rw-r--r--lib/isc/pthreads/thread.c76
-rw-r--r--lib/isc/quota.c101
-rw-r--r--lib/isc/random.c104
-rw-r--r--lib/isc/ratelimiter.c328
-rw-r--r--lib/isc/refcount.c37
-rw-r--r--lib/isc/region.c45
-rw-r--r--lib/isc/result.c212
-rw-r--r--lib/isc/rwlock.c808
-rw-r--r--lib/isc/serial.c59
-rw-r--r--lib/isc/sha1.c315
-rw-r--r--lib/isc/sha2.c1234
-rw-r--r--lib/isc/sockaddr.c503
-rw-r--r--lib/isc/sparc64/Makefile.in24
-rw-r--r--lib/isc/sparc64/include/Makefile.in24
-rw-r--r--lib/isc/sparc64/include/isc/Makefile.in36
-rw-r--r--lib/isc/sparc64/include/isc/atomic.h127
-rw-r--r--lib/isc/string.c270
-rw-r--r--lib/isc/strtoul.c129
-rw-r--r--lib/isc/symtab.c252
-rw-r--r--lib/isc/task.c1298
-rw-r--r--lib/isc/task_p.h31
-rw-r--r--lib/isc/taskpool.c95
-rw-r--r--lib/isc/timer.c930
-rw-r--r--lib/isc/timer_p.h31
-rw-r--r--lib/isc/unix/Makefile.in51
-rw-r--r--lib/isc/unix/app.c683
-rw-r--r--lib/isc/unix/dir.c247
-rw-r--r--lib/isc/unix/entropy.c594
-rw-r--r--lib/isc/unix/errno2result.c123
-rw-r--r--lib/isc/unix/errno2result.h39
-rw-r--r--lib/isc/unix/file.c437
-rw-r--r--lib/isc/unix/fsaccess.c93
-rw-r--r--lib/isc/unix/ifiter_getifaddrs.c185
-rw-r--r--lib/isc/unix/ifiter_ioctl.c1029
-rw-r--r--lib/isc/unix/ifiter_sysctl.c302
-rw-r--r--lib/isc/unix/include/Makefile.in25
-rw-r--r--lib/isc/unix/include/isc/Makefile.in38
-rw-r--r--lib/isc/unix/include/isc/dir.h94
-rw-r--r--lib/isc/unix/include/isc/int.h55
-rw-r--r--lib/isc/unix/include/isc/keyboard.h52
-rw-r--r--lib/isc/unix/include/isc/net.h348
-rw-r--r--lib/isc/unix/include/isc/netdb.h57
-rw-r--r--lib/isc/unix/include/isc/offset.h45
-rw-r--r--lib/isc/unix/include/isc/stat.h52
-rw-r--r--lib/isc/unix/include/isc/stdtime.h60
-rw-r--r--lib/isc/unix/include/isc/strerror.h45
-rw-r--r--lib/isc/unix/include/isc/syslog.h47
-rw-r--r--lib/isc/unix/include/isc/time.h304
-rw-r--r--lib/isc/unix/interfaceiter.c222
-rw-r--r--lib/isc/unix/ipv6.c27
-rw-r--r--lib/isc/unix/keyboard.c126
-rw-r--r--lib/isc/unix/net.c367
-rw-r--r--lib/isc/unix/os.c94
-rw-r--r--lib/isc/unix/resource.c204
-rw-r--r--lib/isc/unix/socket.c3836
-rw-r--r--lib/isc/unix/socket_p.h35
-rw-r--r--lib/isc/unix/stdio.c117
-rw-r--r--lib/isc/unix/stdtime.c86
-rw-r--r--lib/isc/unix/strerror.c74
-rw-r--r--lib/isc/unix/syslog.c84
-rw-r--r--lib/isc/unix/time.c414
-rw-r--r--lib/isc/version.c28
-rw-r--r--lib/isc/x86_32/Makefile.in24
-rw-r--r--lib/isc/x86_32/include/Makefile.in24
-rw-r--r--lib/isc/x86_32/include/isc/Makefile.in36
-rw-r--r--lib/isc/x86_32/include/isc/atomic.h158
-rw-r--r--lib/isc/x86_64/Makefile.in24
-rw-r--r--lib/isc/x86_64/include/Makefile.in24
-rw-r--r--lib/isc/x86_64/include/isc/Makefile.in36
-rw-r--r--lib/isc/x86_64/include/isc/atomic.h103
-rw-r--r--lib/isccc/Makefile.in86
-rw-r--r--lib/isccc/alist.c299
-rw-r--r--lib/isccc/api3
-rw-r--r--lib/isccc/base64.c65
-rw-r--r--lib/isccc/cc.c818
-rw-r--r--lib/isccc/ccmsg.c222
-rw-r--r--lib/isccc/include/Makefile.in25
-rw-r--r--lib/isccc/include/isccc/Makefile.in42
-rw-r--r--lib/isccc/include/isccc/alist.h74
-rw-r--r--lib/isccc/include/isccc/base64.h72
-rw-r--r--lib/isccc/include/isccc/cc.h109
-rw-r--r--lib/isccc/include/isccc/ccmsg.h135
-rw-r--r--lib/isccc/include/isccc/events.h37
-rw-r--r--lib/isccc/include/isccc/lib.h42
-rw-r--r--lib/isccc/include/isccc/result.h60
-rw-r--r--lib/isccc/include/isccc/sexpr.h111
-rw-r--r--lib/isccc/include/isccc/symtab.h122
-rw-r--r--lib/isccc/include/isccc/symtype.h31
-rw-r--r--lib/isccc/include/isccc/types.h46
-rw-r--r--lib/isccc/include/isccc/util.h212
-rw-r--r--lib/isccc/include/isccc/version.h28
-rw-r--r--lib/isccc/lib.c65
-rw-r--r--lib/isccc/result.c72
-rw-r--r--lib/isccc/sexpr.c312
-rw-r--r--lib/isccc/symtab.c280
-rw-r--r--lib/isccc/version.c28
-rw-r--r--lib/isccfg/Makefile.in83
-rw-r--r--lib/isccfg/aclconf.c256
-rw-r--r--lib/isccfg/api3
-rw-r--r--lib/isccfg/include/Makefile.in25
-rw-r--r--lib/isccfg/include/isccfg/Makefile.in42
-rw-r--r--lib/isccfg/include/isccfg/aclconf.h73
-rw-r--r--lib/isccfg/include/isccfg/cfg.h417
-rw-r--r--lib/isccfg/include/isccfg/grammar.h452
-rw-r--r--lib/isccfg/include/isccfg/log.h55
-rw-r--r--lib/isccfg/include/isccfg/namedconf.h45
-rw-r--r--lib/isccfg/include/isccfg/version.h28
-rw-r--r--lib/isccfg/log.c52
-rw-r--r--lib/isccfg/namedconf.c2049
-rw-r--r--lib/isccfg/parser.c2382
-rw-r--r--lib/isccfg/version.c29
-rw-r--r--lib/lwres/Makefile.in84
-rw-r--r--lib/lwres/api3
-rw-r--r--lib/lwres/assert_p.h35
-rw-r--r--lib/lwres/context.c482
-rw-r--r--lib/lwres/context_p.h65
-rw-r--r--lib/lwres/gai_strerror.c83
-rw-r--r--lib/lwres/getaddrinfo.c808
-rw-r--r--lib/lwres/gethost.c362
-rw-r--r--lib/lwres/getipnode.c1148
-rw-r--r--lib/lwres/getnameinfo.c346
-rw-r--r--lib/lwres/getrrset.c288
-rw-r--r--lib/lwres/herror.c122
-rw-r--r--lib/lwres/include/Makefile.in25
-rw-r--r--lib/lwres/include/lwres/Makefile.in46
-rw-r--r--lib/lwres/include/lwres/context.h129
-rw-r--r--lib/lwres/include/lwres/int.h34
-rw-r--r--lib/lwres/include/lwres/ipv6.h124
-rw-r--r--lib/lwres/include/lwres/lang.h33
-rw-r--r--lib/lwres/include/lwres/list.h121
-rw-r--r--lib/lwres/include/lwres/lwbuffer.h406
-rw-r--r--lib/lwres/include/lwres/lwpacket.h159
-rw-r--r--lib/lwres/include/lwres/lwres.h579
-rw-r--r--lib/lwres/include/lwres/netdb.h.in520
-rw-r--r--lib/lwres/include/lwres/platform.h.in120
-rw-r--r--lib/lwres/include/lwres/result.h42
-rw-r--r--lib/lwres/include/lwres/stdlib.h40
-rw-r--r--lib/lwres/include/lwres/version.h28
-rw-r--r--lib/lwres/lwbuffer.c361
-rw-r--r--lib/lwres/lwconfig.c725
-rw-r--r--lib/lwres/lwinetaton.c205
-rw-r--r--lib/lwres/lwinetntop.c197
-rw-r--r--lib/lwres/lwinetpton.c209
-rw-r--r--lib/lwres/lwpacket.c129
-rw-r--r--lib/lwres/lwres_gabn.c505
-rw-r--r--lib/lwres/lwres_gnba.c415
-rw-r--r--lib/lwres/lwres_grbn.c426
-rw-r--r--lib/lwres/lwres_noop.c342
-rw-r--r--lib/lwres/lwresutil.c576
-rw-r--r--lib/lwres/man/Makefile.in232
-rw-r--r--lib/lwres/man/lwres.3165
-rw-r--r--lib/lwres/man/lwres.docbook266
-rw-r--r--lib/lwres/man/lwres.html218
-rw-r--r--lib/lwres/man/lwres_buffer.3233
-rw-r--r--lib/lwres/man/lwres_buffer.docbook394
-rw-r--r--lib/lwres/man/lwres_buffer.html455
-rw-r--r--lib/lwres/man/lwres_config.3106
-rw-r--r--lib/lwres/man/lwres_config.docbook173
-rw-r--r--lib/lwres/man/lwres_config.html156
-rw-r--r--lib/lwres/man/lwres_context.3170
-rw-r--r--lib/lwres/man/lwres_context.docbook262
-rw-r--r--lib/lwres/man/lwres_context.html295
-rw-r--r--lib/lwres/man/lwres_gabn.3195
-rw-r--r--lib/lwres/man/lwres_gabn.docbook260
-rw-r--r--lib/lwres/man/lwres_gabn.html324
-rw-r--r--lib/lwres/man/lwres_gai_strerror.3129
-rw-r--r--lib/lwres/man/lwres_gai_strerror.docbook200
-rw-r--r--lib/lwres/man/lwres_gai_strerror.html124
-rw-r--r--lib/lwres/man/lwres_getaddrinfo.3246
-rw-r--r--lib/lwres/man/lwres_getaddrinfo.docbook387
-rw-r--r--lib/lwres/man/lwres_getaddrinfo.html322
-rw-r--r--lib/lwres/man/lwres_gethostent.3315
-rw-r--r--lib/lwres/man/lwres_gethostent.docbook439
-rw-r--r--lib/lwres/man/lwres_gethostent.html466
-rw-r--r--lib/lwres/man/lwres_getipnode.3206
-rw-r--r--lib/lwres/man/lwres_getipnode.docbook331
-rw-r--r--lib/lwres/man/lwres_getipnode.html279
-rw-r--r--lib/lwres/man/lwres_getnameinfo.3117
-rw-r--r--lib/lwres/man/lwres_getnameinfo.docbook205
-rw-r--r--lib/lwres/man/lwres_getnameinfo.html176
-rw-r--r--lib/lwres/man/lwres_getrrsetbyname.3164
-rw-r--r--lib/lwres/man/lwres_getrrsetbyname.docbook223
-rw-r--r--lib/lwres/man/lwres_getrrsetbyname.html192
-rw-r--r--lib/lwres/man/lwres_gnba.3183
-rw-r--r--lib/lwres/man/lwres_gnba.docbook261
-rw-r--r--lib/lwres/man/lwres_gnba.html316
-rw-r--r--lib/lwres/man/lwres_hstrerror.399
-rw-r--r--lib/lwres/man/lwres_hstrerror.docbook152
-rw-r--r--lib/lwres/man/lwres_hstrerror.html104
-rw-r--r--lib/lwres/man/lwres_inetntop.377
-rw-r--r--lib/lwres/man/lwres_inetntop.docbook120
-rw-r--r--lib/lwres/man/lwres_inetntop.html103
-rw-r--r--lib/lwres/man/lwres_noop.3183
-rw-r--r--lib/lwres/man/lwres_noop.docbook255
-rw-r--r--lib/lwres/man/lwres_noop.html317
-rw-r--r--lib/lwres/man/lwres_packet.3170
-rw-r--r--lib/lwres/man/lwres_packet.docbook291
-rw-r--r--lib/lwres/man/lwres_packet.html235
-rw-r--r--lib/lwres/man/lwres_resutil.3170
-rw-r--r--lib/lwres/man/lwres_resutil.docbook238
-rw-r--r--lib/lwres/man/lwres_resutil.html258
-rw-r--r--lib/lwres/print.c560
-rw-r--r--lib/lwres/print_p.h86
-rw-r--r--lib/lwres/strtoul.c135
-rw-r--r--lib/lwres/unix/Makefile.in25
-rw-r--r--lib/lwres/unix/include/Makefile.in25
-rw-r--r--lib/lwres/unix/include/lwres/Makefile.in34
-rw-r--r--lib/lwres/unix/include/lwres/net.h135
-rw-r--r--lib/lwres/version.c28
837 files changed, 292145 insertions, 0 deletions
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644
index 0000000..e8be294
--- /dev/null
+++ b/lib/Makefile.in
@@ -0,0 +1,29 @@
+# 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.19 2004/03/05 05:05:00 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+# Note: the order of SUBDIRS is important.
+# Attempt to disable parallel processing.
+.NOTPARALLEL:
+.NO_PARALLEL:
+SUBDIRS = isc isccc dns isccfg bind9 lwres tests
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/Makefile.in b/lib/bind/Makefile.in
new file mode 100644
index 0000000..fd9a16f
--- /dev/null
+++ b/lib/bind/Makefile.in
@@ -0,0 +1,133 @@
+# Copyright (C) 2004-2006 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: Makefile.in,v 1.22.18.7 2006/06/24 00:25:39 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+
+@LIBBIND_API@
+
+LIBS = @LIBS@
+
+DAEMON_OBJS=bsd/daemon.@O@
+STRSEP_OBJS=bsd/strsep.@O@
+
+BSDOBJS= @DAEMON_OBJS@ @STRSEP_OBJS@ bsd/ftruncate.@O@ bsd/gettimeofday.@O@ \
+ bsd/mktemp.@O@ bsd/putenv.@O@ bsd/readv.@O@ bsd/setenv.@O@ \
+ bsd/setitimer.@O@ bsd/strcasecmp.@O@ bsd/strdup.@O@ \
+ bsd/strerror.@O@ bsd/strpbrk.@O@ bsd/strtoul.@O@ bsd/utimes.@O@ \
+ bsd/writev.@O@
+
+DSTOBJS= dst/dst_api.@O@ dst/hmac_link.@O@ dst/md5_dgst.@O@ dst/support.@O@
+
+INETOBJS= inet/inet_addr.@O@ inet/inet_cidr_ntop.@O@ inet/inet_cidr_pton.@O@ \
+ inet/inet_data.@O@ inet/inet_lnaof.@O@ inet/inet_makeaddr.@O@ \
+ inet/inet_net_ntop.@O@ inet/inet_net_pton.@O@ inet/inet_neta.@O@ \
+ inet/inet_netof.@O@ inet/inet_network.@O@ inet/inet_ntoa.@O@ \
+ inet/inet_ntop.@O@ inet/inet_pton.@O@ inet/nsap_addr.@O@
+
+WANT_IRS_THREADS_OBJS= irs/gethostent_r.@O@ irs/getnetent_r.@O@ \
+ irs/getnetgrent_r.@O@ irs/getprotoent_r.@O@ irs/getservent_r.@O@
+
+WANT_IRS_NISGR_OBJS= irs/nis_gr.@O@
+WANT_IRS_GR_OBJS= irs/dns_gr.@O@ irs/irp_gr.@O@ irs/lcl_gr.@O@ irs/gen_gr.@O@ \
+ irs/getgrent.@O@ @WANT_IRS_NISGR_OBJS@ @WANT_IRS_THREADSGR_OBJS@
+
+WANT_IRS_THREADSPW_OBJS=irs/getpwent_r.@O@
+WANT_IRS_NISPW_OBJS= irs/nis_pw.@O@
+WANT_IRS_DBPW_OBJS=irs/irp_pw.@O@ irs/lcl_pw.@O@
+WANT_IRS_PW_OBJS= irs/dns_pw.@O@ irs/gen_pw.@O@ irs/getpwent.@O@ \
+ @WANT_IRS_DBPW_OBJS@ @WANT_IRS_NISPW_OBJS@ @WANT_IRS_THREADSPW_OBJS@
+
+WANT_IRS_NIS_OBJS= irs/nis_ho.@O@ irs/nis_ng.@O@ irs/nis_nw.@O@ \
+ irs/nis_pr.@O@ irs/nis_sv.@O@
+
+IRSOBJS= @WANT_IRS_GR_OBJS@ @WANT_IRS_NIS_OBJS@ @WANT_IRS_THREADS_OBJS@ \
+ @WANT_IRS_PW_OBJS@ \
+ irs/dns.@O@ irs/dns_ho.@O@ irs/dns_nw.@O@ irs/dns_pr.@O@ \
+ irs/dns_sv.@O@ irs/gai_strerror.@O@ irs/gen.@O@ irs/gen_ho.@O@ \
+ irs/gen_ng.@O@ irs/gen_nw.@O@ irs/gen_pr.@O@ irs/gen_sv.@O@ \
+ irs/getaddrinfo.@O@ irs/gethostent.@O@ irs/getnameinfo.@O@ \
+ irs/getnetent.@O@ irs/getnetgrent.@O@ \
+ irs/getprotoent.@O@ irs/getservent.@O@ irs/hesiod.@O@ \
+ irs/irp.@O@ irs/irp_ho.@O@ irs/irp_ng.@O@ irs/irp_nw.@O@ \
+ irs/irp_pr.@O@ irs/irp_sv.@O@ irs/irpmarshall.@O@ irs/irs_data.@O@ \
+ irs/lcl.@O@ irs/lcl_ho.@O@ irs/lcl_ng.@O@ irs/lcl_nw.@O@ \
+ irs/lcl_pr.@O@ irs/lcl_sv.@O@ irs/nis.@O@ irs/nul_ng.@O@ irs/util.@O@
+
+WANT_IRS_THREADSGR_OBJS=irs/getgrent_r.@O@
+
+ISCOBJS= isc/assertions.@O@ isc/base64.@O@ isc/bitncmp.@O@ isc/ctl_clnt.@O@ \
+ isc/ctl_p.@O@ isc/ctl_srvr.@O@ isc/ev_connects.@O@ isc/ev_files.@O@ \
+ isc/ev_streams.@O@ isc/ev_timers.@O@ isc/ev_waits.@O@ \
+ isc/eventlib.@O@ isc/heap.@O@ isc/hex.@O@ isc/logging.@O@ \
+ isc/memcluster.@O@ isc/movefile.@O@ isc/tree.@O@
+
+NAMESEROBJS= nameser/ns_date.@O@ nameser/ns_name.@O@ nameser/ns_netint.@O@ \
+ nameser/ns_parse.@O@ nameser/ns_print.@O@ nameser/ns_samedomain.@O@ \
+ nameser/ns_sign.@O@ nameser/ns_ttl.@O@ nameser/ns_verify.@O@
+
+RESOLVOBJS= resolv/herror.@O@ resolv/mtctxres.@O@ resolv/res_comp.@O@ \
+ resolv/res_data.@O@ resolv/res_debug.@O@ resolv/res_findzonecut.@O@ \
+ resolv/res_init.@O@ resolv/res_mkquery.@O@ resolv/res_mkupdate.@O@ \
+ resolv/res_query.@O@ resolv/res_send.@O@ resolv/res_sendsigned.@O@ \
+ resolv/res_update.@O@
+
+SUBDIRS = bsd dst include inet irs isc nameser resolv @PORT_INCLUDE@
+
+TARGETS= timestamp
+OBJS= ${BSDOBJS} ${DSTOBJS} ${INETOBJS} ${IRSOBJS} ${ISCOBJS} \
+ ${NAMESEROBJS} ${RESOLVOBJS}
+
+@BIND9_MAKE_RULES@
+
+# Attempt to disable parallel processing.
+.NOTPARALLEL:
+.NO_PARALLEL:
+
+libbind.@SA@: ${OBJS}
+ ${AR} ${ARFLAGS} $@ ${OBJS}
+ ${RANLIB} $@
+
+libbind.la: ${OBJS}
+ ${LIBTOOL_MODE_LINK} \
+ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libbind.la -rpath ${libdir} \
+ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ ${OBJS} ${LIBS}
+
+timestamp: libbind.@A@
+ touch timestamp
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+
+install:: timestamp installdirs
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libbind.@A@ ${DESTDIR}${libdir}
+
+clean distclean::
+ rm -f libbind.@SA@ libbind.la
+
+distclean::
+ rm -f make/rules make/includes make/mkdep
+
+distclean::
+ rm -f config.cache config.h config.log config.status libtool
+ rm -f port_before.h port_after.h configure.lineno
+ rm -f port/Makefile @PORT_DIR@/Makefile
+
+man:
diff --git a/lib/bind/README b/lib/bind/README
new file mode 100644
index 0000000..b89cff7
--- /dev/null
+++ b/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/lib/bind/aclocal.m4 b/lib/bind/aclocal.m4
new file mode 100644
index 0000000..110ed87
--- /dev/null
+++ b/lib/bind/aclocal.m4
@@ -0,0 +1,2 @@
+sinclude(../../libtool.m4)dnl
+
diff --git a/lib/bind/api b/lib/bind/api
new file mode 100644
index 0000000..a87852a
--- /dev/null
+++ b/lib/bind/api
@@ -0,0 +1,3 @@
+LIBINTERFACE = 4
+LIBREVISION = 10
+LIBAGE = 0
diff --git a/lib/bind/bsd/Makefile.in b/lib/bind/bsd/Makefile.in
new file mode 100644
index 0000000..cf70c10
--- /dev/null
+++ b/lib/bind/bsd/Makefile.in
@@ -0,0 +1,39 @@
+# 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: Makefile.in,v 1.7 2004/03/05 05:05:07 marka Exp $
+
+srcdir= @srcdir@
+VPATH = @srcdir@
+
+DAEMON_OBJS=daemon.@O@
+STRSEP_OBJS=strsep.@O@
+
+OBJS= @DAEMON_OBJS@ @STRSEP_OBJS@ ftruncate.@O@ gettimeofday.@O@ \
+ mktemp.@O@ putenv.@O@ \
+ readv.@O@ setenv.@O@ setitimer.@O@ strcasecmp.@O@ strdup.@O@ \
+ strerror.@O@ strpbrk.@O@ strtoul.@O@ utimes.@O@ \
+ writev.@O@
+
+SRCS= daemon.c ftruncate.c gettimeofday.c mktemp.c putenv.c \
+ readv.c setenv.c setitimer.c strcasecmp.c strdup.c \
+ strerror.c strpbrk.c strsep.c strtoul.c utimes.c \
+ writev.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I${srcdir}/../include
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/bsd/daemon.c b/lib/bind/bsd/daemon.c
new file mode 100644
index 0000000..a7d2ded
--- /dev/null
+++ b/lib/bind/bsd/daemon.c
@@ -0,0 +1,81 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)daemon.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: daemon.c,v 1.1.352.1 2005/04/27 05:00:42 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "port_before.h"
+
+#include <fcntl.h>
+#include <paths.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+#ifndef NEED_DAEMON
+int __bind_daemon__;
+#else
+
+int
+daemon(int nochdir, int noclose) {
+ int fd;
+
+ switch (fork()) {
+ case -1:
+ return (-1);
+ case 0:
+ break;
+ default:
+ _exit(0);
+ }
+
+ if (setsid() == -1)
+ return (-1);
+
+ if (!nochdir)
+ (void)chdir("/");
+
+ if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ (void)dup2(fd, STDIN_FILENO);
+ (void)dup2(fd, STDOUT_FILENO);
+ (void)dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ (void)close (fd);
+ }
+ return (0);
+}
+#endif
+
+/*! \file */
diff --git a/lib/bind/bsd/ftruncate.c b/lib/bind/bsd/ftruncate.c
new file mode 100644
index 0000000..b222c8b
--- /dev/null
+++ b/lib/bind/bsd/ftruncate.c
@@ -0,0 +1,64 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: ftruncate.c,v 1.1.352.3 2005/06/22 22:05:45 marka Exp $";
+#endif
+
+/*! \file
+ * \brief
+ * ftruncate - set file size, BSD Style
+ *
+ * shortens or enlarges the file as neeeded
+ * uses some undocumented locking call. It is known to work on SCO unix,
+ * other vendors should try.
+ * The #error directive prevents unsupported OSes
+ */
+
+#include "port_before.h"
+
+#if defined(M_UNIX)
+#define OWN_FTRUNCATE
+#include <stdio.h>
+#ifdef _XOPEN_SOURCE
+#undef _XOPEN_SOURCE
+#endif
+#ifdef _POSIX_SOURCE
+#undef _POSIX_SOURCE
+#endif
+
+#include <fcntl.h>
+
+#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/lib/bind/bsd/gettimeofday.c b/lib/bind/bsd/gettimeofday.c
new file mode 100644
index 0000000..0c88e00
--- /dev/null
+++ b/lib/bind/bsd/gettimeofday.c
@@ -0,0 +1,64 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: gettimeofday.c,v 1.3.332.1 2005/04/27 05:00:43 sra Exp $";
+#endif
+
+#include "port_before.h"
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/time.h>
+#include "port_after.h"
+
+#if !defined(NEED_GETTIMEOFDAY)
+/*%
+ * gettimeofday() occasionally returns invalid tv_usec on some platforms.
+ */
+#define MILLION 1000000
+#undef gettimeofday
+
+int
+isc__gettimeofday(struct timeval *tp, struct timezone *tzp) {
+ int res;
+
+ res = gettimeofday(tp, tzp);
+ if (res < 0)
+ return (res);
+ if (tp == NULL)
+ return (res);
+ if (tp->tv_usec < 0) {
+ do {
+ tp->tv_usec += MILLION;
+ tp->tv_sec--;
+ } while (tp->tv_usec < 0);
+ goto log;
+ } else if (tp->tv_usec > MILLION) {
+ do {
+ tp->tv_usec -= MILLION;
+ tp->tv_sec++;
+ } while (tp->tv_usec > MILLION);
+ goto log;
+ }
+ return (res);
+ log:
+ syslog(LOG_ERR, "gettimeofday: tv_usec out of range\n");
+ return (res);
+}
+#else
+int
+gettimeofday(struct timeval *tvp, struct _TIMEZONE *tzp) {
+ time_t clock, time(time_t *);
+
+ if (time(&clock) == (time_t) -1)
+ return (-1);
+ if (tvp) {
+ tvp->tv_sec = clock;
+ tvp->tv_usec = 0;
+ }
+ if (tzp) {
+ tzp->tz_minuteswest = 0;
+ tzp->tz_dsttime = 0;
+ }
+ return (0);
+}
+#endif /*NEED_GETTIMEOFDAY*/
+
+/*! \file */
diff --git a/lib/bind/bsd/mktemp.c b/lib/bind/bsd/mktemp.c
new file mode 100644
index 0000000..f201c2d
--- /dev/null
+++ b/lib/bind/bsd/mktemp.c
@@ -0,0 +1,156 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: mktemp.c,v 1.1.352.1 2005/04/27 05:00:43 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "port_after.h"
+
+#if (!defined(NEED_MKTEMP)) && (!defined(NEED_MKSTEMP))
+int __mktemp_unneeded__;
+#else
+
+static int gettemp(char *path, int *doopen);
+
+#ifdef NEED_MKSTEMP
+mkstemp(char *path) {
+ int fd;
+
+ return (gettemp(path, &fd) ? fd : -1);
+}
+#endif
+
+#ifdef NEED_MKTEMP
+char *
+mktemp(char *path) {
+ return(gettemp(path, (int *)NULL) ? path : (char *)NULL);
+}
+#endif
+
+static int
+gettemp(char *path, int *doopen) {
+ char *start, *trv;
+ struct stat sbuf;
+ u_int pid;
+
+ pid = getpid();
+ for (trv = path; *trv; ++trv); /*%< extra X's get set to 0's */
+ while (*--trv == 'X') {
+ *trv = (pid % 10) + '0';
+ pid /= 10;
+ }
+
+ /*
+ * check the target directory; if you have six X's and it
+ * doesn't exist this runs for a *very* long time.
+ */
+ for (start = trv + 1;; --trv) {
+ if (trv <= path)
+ break;
+ if (*trv == '/') {
+ *trv = '\0';
+ if (stat(path, &sbuf))
+ return(0);
+ if (!S_ISDIR(sbuf.st_mode)) {
+ errno = ENOTDIR;
+ return(0);
+ }
+ *trv = '/';
+ break;
+ }
+ }
+
+ for (;;) {
+ if (doopen) {
+ if ((*doopen =
+ open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
+ return(1);
+ if (errno != EEXIST)
+ return(0);
+ }
+ else if (stat(path, &sbuf))
+ return(errno == ENOENT ? 1 : 0);
+
+ /* tricky little algorithm for backward compatibility */
+ for (trv = start;;) {
+ if (!*trv)
+ return(0);
+ if (*trv == 'z')
+ *trv++ = 'a';
+ else {
+ if (isdigit(*trv))
+ *trv = 'a';
+ else
+ ++*trv;
+ break;
+ }
+ }
+ }
+ /*NOTREACHED*/
+}
+
+#endif /*NEED_MKTEMP*/
+
+/*! \file */
diff --git a/lib/bind/bsd/putenv.c b/lib/bind/bsd/putenv.c
new file mode 100644
index 0000000..dca02c10
--- /dev/null
+++ b/lib/bind/bsd/putenv.c
@@ -0,0 +1,27 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: putenv.c,v 1.1.352.1 2005/04/27 05:00:43 sra Exp $";
+#endif
+
+#include "port_before.h"
+#include "port_after.h"
+
+/*%
+ * To give a little credit to Sun, SGI,
+ * and many vendors in the SysV world.
+ */
+
+#if !defined(NEED_PUTENV)
+int __bindcompat_putenv;
+#else
+int
+putenv(char *str) {
+ char *tmp;
+
+ for (tmp = str; *tmp && (*tmp != '='); tmp++)
+ ;
+
+ return (setenv(str, tmp, 1));
+}
+#endif
+
+/*! \file */
diff --git a/lib/bind/bsd/readv.c b/lib/bind/bsd/readv.c
new file mode 100644
index 0000000..eb13bcc
--- /dev/null
+++ b/lib/bind/bsd/readv.c
@@ -0,0 +1,39 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: readv.c,v 1.1.352.1 2005/04/27 05:00:43 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include "port_after.h"
+
+#ifndef NEED_READV
+int __bindcompat_readv;
+#else
+
+int
+__readv(fd, vp, vpcount)
+ int fd;
+ const struct iovec *vp;
+ int vpcount;
+{
+ int count = 0;
+
+ while (vpcount-- > 0) {
+ int bytes = read(fd, vp->iov_base, vp->iov_len);
+
+ if (bytes < 0)
+ return (-1);
+ count += bytes;
+ if (bytes != vp->iov_len)
+ break;
+ vp++;
+ }
+ return (count);
+}
+#endif /* NEED_READV */
+/*! \file */
diff --git a/lib/bind/bsd/setenv.c b/lib/bind/bsd/setenv.c
new file mode 100644
index 0000000..ce2f063
--- /dev/null
+++ b/lib/bind/bsd/setenv.c
@@ -0,0 +1,151 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)setenv.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: setenv.c,v 1.1.352.1 2005/04/27 05:00:44 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "port_before.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#if !defined(NEED_SETENV)
+int __bindcompat_setenv;
+#else
+
+extern char **environ;
+
+static char *findenv(const char *name, int *offset);
+
+/*%
+ * setenv --
+ * Set the value of the environmental variable "name" to be
+ * "value". If rewrite is set, replace any current value.
+ */
+setenv(const char *name, const char *value, int rewrite) {
+ extern char **environ;
+ static int alloced; /*%< if allocated space before */
+ char *c;
+ int l_value, offset;
+
+ if (*value == '=') /*%< no `=' in value */
+ ++value;
+ l_value = strlen(value);
+ if ((c = findenv(name, &offset))) { /*%< find if already exists */
+ if (!rewrite)
+ return (0);
+ if (strlen(c) >= l_value) { /*%< old larger; copy over */
+ while (*c++ = *value++);
+ return (0);
+ }
+ } else { /*%< create new slot */
+ int cnt;
+ char **p;
+
+ for (p = environ, cnt = 0; *p; ++p, ++cnt);
+ if (alloced) { /*%< just increase size */
+ environ = (char **)realloc((char *)environ,
+ (size_t)(sizeof(char *) * (cnt + 2)));
+ if (!environ)
+ return (-1);
+ }
+ else { /*%< get new space */
+ alloced = 1; /*%< copy old entries into it */
+ p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
+ if (!p)
+ return (-1);
+ memcpy(p, environ, cnt * sizeof(char *));
+ environ = p;
+ }
+ environ[cnt + 1] = NULL;
+ offset = cnt;
+ }
+ for (c = (char *)name; *c && *c != '='; ++c); /*%< no `=' in name */
+ if (!(environ[offset] = /*%< name + `=' + value */
+ malloc((size_t)((int)(c - name) + l_value + 2))))
+ return (-1);
+ for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
+ for (*c++ = '='; *c++ = *value++;);
+ return (0);
+}
+
+/*%
+ * unsetenv(name) --
+ * Delete environmental variable "name".
+ */
+void
+unsetenv(const char *name) {
+ char **p;
+ int offset;
+
+ while (findenv(name, &offset)) /*%< if set multiple times */
+ for (p = &environ[offset];; ++p)
+ if (!(*p = *(p + 1)))
+ break;
+}
+
+/*%
+ * findenv --
+ * Returns pointer to value associated with name, if any, else NULL.
+ * Sets offset to be the offset of the name/value combination in the
+ * environmental array, for use by setenv(3) and unsetenv(3).
+ * Explicitly removes '=' in argument name.
+ *
+ * This routine *should* be a static; don't use it.
+ */
+static char *
+findenv(const char *name, int *offset) {
+ const char *np;
+ char **p, *c;
+ int len;
+
+ if (name == NULL || environ == NULL)
+ return (NULL);
+ for (np = name; *np && *np != '='; ++np)
+ continue;
+ len = np - name;
+ for (p = environ; (c = *p) != NULL; ++p)
+ if (strncmp(c, name, len) == 0 && c[len] == '=') {
+ *offset = p - environ;
+ return (c + len + 1);
+ }
+ return (NULL);
+}
+#endif
+
+/*! \file */
diff --git a/lib/bind/bsd/setitimer.c b/lib/bind/bsd/setitimer.c
new file mode 100644
index 0000000..2d5a4e4
--- /dev/null
+++ b/lib/bind/bsd/setitimer.c
@@ -0,0 +1,29 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: setitimer.c,v 1.1.352.1 2005/04/27 05:00:44 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/time.h>
+
+#include "port_after.h"
+
+/*%
+ * Setitimer emulation routine.
+ */
+#ifndef NEED_SETITIMER
+int __bindcompat_setitimer;
+#else
+
+int
+__setitimer(int which, const struct itimerval *value,
+ struct itimerval *ovalue)
+{
+ if (alarm(value->it_value.tv_sec) >= 0)
+ return (0);
+ else
+ return (-1);
+}
+#endif
+
+/*! \file */
diff --git a/lib/bind/bsd/strcasecmp.c b/lib/bind/bsd/strcasecmp.c
new file mode 100644
index 0000000..fd76837
--- /dev/null
+++ b/lib/bind/bsd/strcasecmp.c
@@ -0,0 +1,124 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strcasecmp.c,v 1.1.352.1 2005/04/27 05:00:45 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+#include <string.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRCASECMP
+int __strcasecmp_unneeded__;
+#else
+
+/*%
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison. The mappings are
+ * based upon ascii character sequences.
+ */
+static const u_char charmap[] = {
+ 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
+ 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
+ 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
+ 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
+ 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
+ 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
+ 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
+ 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
+ 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
+ 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
+ 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
+ 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
+ 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
+ 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
+ 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
+ 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
+ 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
+ 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
+ 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
+ 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
+ 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
+ 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
+ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
+ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
+ 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
+ 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
+ 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
+ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
+ 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
+ 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
+ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
+ 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
+};
+
+int
+strcasecmp(const char *s1, const char *s2) {
+ const u_char *cm = charmap,
+ *us1 = (const u_char *)s1,
+ *us2 = (const u_char *)s2;
+
+ while (cm[*us1] == cm[*us2++])
+ if (*us1++ == '\0')
+ return (0);
+ return (cm[*us1] - cm[*--us2]);
+}
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n) {
+ if (n != 0) {
+ const u_char *cm = charmap,
+ *us1 = (const u_char *)s1,
+ *us2 = (const u_char *)s2;
+
+ do {
+ if (cm[*us1] != cm[*us2++])
+ return (cm[*us1] - cm[*--us2]);
+ if (*us1++ == '\0')
+ break;
+ } while (--n != 0);
+ }
+ return (0);
+}
+
+#endif /*NEED_STRCASECMP*/
+
+/*! \file */
diff --git a/lib/bind/bsd/strdup.c b/lib/bind/bsd/strdup.c
new file mode 100644
index 0000000..a8d31e9
--- /dev/null
+++ b/lib/bind/bsd/strdup.c
@@ -0,0 +1,20 @@
+#include "port_before.h"
+
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRDUP
+int __bind_strdup_unneeded;
+#else
+char *
+strdup(const char *src) {
+ char *dst = malloc(strlen(src) + 1);
+
+ if (dst)
+ strcpy(dst, src);
+ return (dst);
+}
+#endif
+
+/*! \file */
diff --git a/lib/bind/bsd/strerror.c b/lib/bind/bsd/strerror.c
new file mode 100644
index 0000000..5743398
--- /dev/null
+++ b/lib/bind/bsd/strerror.c
@@ -0,0 +1,92 @@
+#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.4.332.1 2005/04/27 05:00:46 sra 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 <sys/param.h>
+#include <sys/types.h>
+
+#include <string.h>
+
+#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*/
+
+/*! \file */
diff --git a/lib/bind/bsd/strpbrk.c b/lib/bind/bsd/strpbrk.c
new file mode 100644
index 0000000..4502572
--- /dev/null
+++ b/lib/bind/bsd/strpbrk.c
@@ -0,0 +1,70 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strpbrk.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strpbrk.c,v 1.1.352.1 2005/04/27 05:00:46 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/cdefs.h>
+
+#include <string.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRPBRK
+int __strpbrk_unneeded__;
+#else
+
+/*%
+ * Find the first occurrence in s1 of a character in s2 (excluding NUL).
+ */
+char *
+strpbrk(const char *s1, const char *s2) {
+ const char *scanp;
+ int c, sc;
+
+ while ((c = *s1++) != 0) {
+ for (scanp = s2; (sc = *scanp++) != 0;)
+ if (sc == c)
+ return ((char *)(s1 - 1));
+ }
+ return (NULL);
+}
+
+#endif /*NEED_STRPBRK*/
+
+/*! \file */
diff --git a/lib/bind/bsd/strsep.c b/lib/bind/bsd/strsep.c
new file mode 100644
index 0000000..1214f80
--- /dev/null
+++ b/lib/bind/bsd/strsep.c
@@ -0,0 +1,88 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "strsep.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strsep.c,v 1.1.352.1 2005/04/27 05:00:47 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "port_before.h"
+#include <sys/cdefs.h>
+#include <string.h>
+#include <stdio.h>
+#include "port_after.h"
+
+#ifndef NEED_STRSEP
+int __strsep_unneeded__;
+#else
+
+/*%
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim) {
+ char *s;
+ const char *spanp;
+ int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
+
+#endif /*NEED_STRSEP*/
+
+/*! \file */
diff --git a/lib/bind/bsd/strtoul.c b/lib/bind/bsd/strtoul.c
new file mode 100644
index 0000000..f419227
--- /dev/null
+++ b/lib/bind/bsd/strtoul.c
@@ -0,0 +1,119 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strtoul.c,v 1.2.164.1 2005/04/27 05:00:47 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#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*/
+
+/*! \file */
diff --git a/lib/bind/bsd/utimes.c b/lib/bind/bsd/utimes.c
new file mode 100644
index 0000000..2f65cff
--- /dev/null
+++ b/lib/bind/bsd/utimes.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <utime.h>
+
+#include "port_after.h"
+
+#ifndef NEED_UTIMES
+int __bind_utimes_unneeded;
+#else
+
+int
+__utimes(char *filename, struct timeval *tvp) {
+ struct utimbuf utb;
+
+ utb.actime = (time_t)tvp[0].tv_sec;
+ utb.modtime = (time_t)tvp[1].tv_sec;
+ return (utime(filename, &utb));
+}
+
+#endif /* NEED_UTIMES */
+/*! \file */
diff --git a/lib/bind/bsd/writev.c b/lib/bind/bsd/writev.c
new file mode 100644
index 0000000..0e81c26
--- /dev/null
+++ b/lib/bind/bsd/writev.c
@@ -0,0 +1,89 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: writev.c,v 1.2.164.1 2005/04/27 05:00:47 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include "port_after.h"
+
+#ifndef NEED_WRITEV
+int __bindcompat_writev;
+#else
+
+#ifdef _CRAY
+#define OWN_WRITEV
+int
+__writev(int fd, struct iovec *iov, int iovlen)
+{
+ struct stat statbuf;
+
+ if (fstat(fd, &statbuf) < 0)
+ return (-1);
+
+ /*
+ * Allow for atomic writes to network.
+ */
+ if (statbuf.st_mode & S_IFSOCK) {
+ struct msghdr mesg;
+
+ memset(&mesg, 0, sizeof(mesg));
+ mesg.msg_name = 0;
+ mesg.msg_namelen = 0;
+ mesg.msg_iov = iov;
+ mesg.msg_iovlen = iovlen;
+ mesg.msg_accrights = 0;
+ mesg.msg_accrightslen = 0;
+ return (sendmsg(fd, &mesg, 0));
+ } else {
+ struct iovec *tv;
+ int i, rcode = 0, count = 0;
+
+ for (i = 0, tv = iov; i <= iovlen; tv++) {
+ rcode = write(fd, tv->iov_base, tv->iov_len);
+
+ if (rcode < 0)
+ break;
+
+ count += rcode;
+ }
+
+ if (count == 0)
+ return (rcode);
+ else
+ return (count);
+ }
+}
+
+#else /*_CRAY*/
+
+int
+__writev(fd, vp, vpcount)
+ int fd;
+ const struct iovec *vp;
+ int vpcount;
+{
+ int count = 0;
+
+ while (vpcount-- > 0) {
+ int written = write(fd, vp->iov_base, vp->iov_len);
+
+ if (written < 0)
+ return (-1);
+ count += written;
+ if (written != vp->iov_len)
+ break;
+ vp++;
+ }
+ return (count);
+}
+
+#endif /*_CRAY*/
+
+#endif /*NEED_WRITEV*/
+
+/*! \file */
diff --git a/lib/bind/config.h.in b/lib/bind/config.h.in
new file mode 100644
index 0000000..69ea285
--- /dev/null
+++ b/lib/bind/config.h.in
@@ -0,0 +1,61 @@
+#undef _SOCKADDR_LEN
+#undef HAVE_FCNTL_H
+#undef HAVE_PATHS_H
+#undef HAVE_INTTYPES_H
+#undef HAVE_STROPTS_H
+#undef HAVE_SYS_TIMERS_H
+#undef HAVE_SYS_SELECT_H
+#undef SYS_CDEFS_H
+#undef _POSIX_PTHREAD_SEMANTICS
+#undef POSIX_GETPWUID_R
+#undef POSIX_GETPWNAM_R
+#undef POSIX_GETGRGID_R
+#undef POSIX_GETGRNAM_R
+#undef HAVE_MEMMOVE
+#undef HAVE_MEMCHR
+
+#undef NEED_SETGROUPENT
+#undef NEED_GETGROUPLIST
+
+/* define if prototype for getgrnam_r() is required */
+#undef NEED_GETGRNAM_R
+#undef NEED_GETGRGID_R
+#undef NEED_GETGRENT_R
+#undef NEED_SETGRENT_R
+#undef NEED_ENDGRENT_R
+
+#undef NEED_INNETGR_R
+#undef NEED_SETNETGRENT_R
+#undef NEED_ENDNETGRENT_R
+
+#undef NEED_GETPWNAM_R
+#undef NEED_GETPWUID_R
+#undef NEED_SETPWENT_R
+#undef NEED_SETPASSENT_R
+#undef NEED_SETPWENT_R
+#undef NEED_GETPWENT_R
+#undef NEED_ENDPWENT_R
+
+#undef NEED_SETPASSENT
+
+#undef HAS_PW_CLASS
+
+#undef ssize_t
+#undef uintptr_t
+
+/* Shut up warnings about sputaux in stdio.h on BSD/OS pre-4.1 */
+#undef SHUTUP_SPUTAUX
+#ifdef SHUTUP_SPUTAUX
+struct __sFILE;
+extern __inline int __sputaux(int _c, struct __sFILE *_p);
+#endif
+#undef BROKEN_IN6ADDR_INIT_MACROS
+#undef HAVE_STRLCAT
+/* Shut up warnings about missing braces */
+#undef SHUTUP_MUTEX_INITIALIZER
+#ifdef SHUTUP_MUTEX_INITIALIZER
+#define LIBBIND_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
+#else
+#define LIBBIND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#endif
+
diff --git a/lib/bind/configure b/lib/bind/configure
new file mode 100755
index 0000000..403c09e
--- /dev/null
+++ b/lib/bind/configure
@@ -0,0 +1,33825 @@
+#! /bin/sh
+# From configure.in Revision: 1.90.18.33 .
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$ECHO in
+X*--fallback-echo)
+ # Remove one level of quotation (which was required for Make).
+ ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','`
+ ;;
+esac
+
+echo=${ECHO-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.
+ exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$ECHO"; then
+if test "X${echo_test_string+set}" != Xset; then
+# find a string as large as possible, as long as the shell can cope with it
+ for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
+ # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+ if (echo_test_string="`eval $cmd`") 2>/dev/null &&
+ echo_test_string="`eval $cmd`" &&
+ (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+ then
+ break
+ fi
+ done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ :
+else
+ # The Solaris, AIX, and Digital Unix default echo programs unquote
+ # backslashes. This makes it impossible to quote backslashes using
+ # echo "$something" | sed 's/\\/\\\\/g'
+ #
+ # So, first we look for a working echo in the user's PATH.
+
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for dir in $PATH /usr/ucb; do
+ IFS="$lt_save_ifs"
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+ test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$dir/echo"
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ if test "X$echo" = Xecho; then
+ # We didn't find a better echo, so look for alternatives.
+ if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # This shell has a builtin print -r that does the trick.
+ echo='print -r'
+ elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+ test "X$CONFIG_SHELL" != X/bin/ksh; then
+ # If we have ksh, try running configure again with it.
+ ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+ export ORIGINAL_CONFIG_SHELL
+ CONFIG_SHELL=/bin/ksh
+ export CONFIG_SHELL
+ exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"}
+ else
+ # Try using printf.
+ echo='printf %s\n'
+ if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # Cool, printf works
+ :
+ elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+ export CONFIG_SHELL
+ SHELL="$CONFIG_SHELL"
+ export SHELL
+ echo="$CONFIG_SHELL $0 --fallback-echo"
+ elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$CONFIG_SHELL $0 --fallback-echo"
+ else
+ # maybe with a smaller string...
+ prev=:
+
+ for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
+ if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+ then
+ break
+ fi
+ prev="$cmd"
+ done
+
+ if test "$prev" != 'sed 50q "$0"'; then
+ echo_test_string=`eval $prev`
+ export echo_test_string
+ exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"}
+ else
+ # Oops. We lost completely, so just stick with echo.
+ echo=echo
+ fi
+ fi
+ fi
+ fi
+fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+ECHO=$echo
+if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then
+ ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo"
+fi
+
+
+
+
+tagnames=${tagnames+${tagnames},}CXX
+
+tagnames=${tagnames+${tagnames},}F77
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="resolv/herror.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os SET_MAKE RANLIB ac_ct_RANLIB INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA STD_CINCLUDES STD_CDEFINES STD_CWARNINGS CCOPT AR ARFLAGS LN ETAGS PERL CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP ISC_PLATFORM_NEEDSYSSELECTH WANT_IRS_GR WANT_IRS_GR_OBJS WANT_IRS_PW WANT_IRS_PW_OBJS WANT_IRS_NIS WANT_IRS_NIS_OBJS WANT_IRS_NISGR_OBJS WANT_IRS_NISPW_OBJS WANT_IRS_DBPW_OBJS ALWAYS_DEFINES DO_PTHREADS WANT_IRS_THREADSGR_OBJS WANT_IRS_THREADSPW_OBJS WANT_IRS_THREADS_OBJS WANT_THREADS_OBJS USE_IFNAMELINKID ISC_THREAD_DIR DAEMON_OBJS NEED_DAEMON STRSEP_OBJS NEED_STRSEP NEED_STRERROR MKDEPCC MKDEPCFLAGS MKDEPPROG IRIX_DNSSEC_WARNINGS_HACK purify_path PURIFY LN_S ECHO ac_ct_AR STRIP ac_ct_STRIP CXX CXXFLAGS ac_ct_CXX CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL O A SA LIBTOOL_MKDEP_SED LIBTOOL_MODE_COMPILE LIBTOOL_MODE_INSTALL LIBTOOL_MODE_LINK HAS_INET6_STRUCTS ISC_PLATFORM_NEEDNETINETIN6H ISC_PLATFORM_NEEDNETINET6IN6H HAS_IN_ADDR6 NEED_IN6ADDR_ANY ISC_PLATFORM_HAVEIN6PKTINFO ISC_PLATFORM_FIXIN6ISADDR ISC_IPV6_H ISC_IPV6_O ISC_ISCIPV6_O ISC_IPV6_C HAVE_SIN6_SCOPE_ID HAVE_SOCKADDR_STORAGE ISC_PLATFORM_NEEDNTOP ISC_PLATFORM_NEEDPTON ISC_PLATFORM_NEEDATON HAVE_SA_LEN HAVE_MINIMUM_IFREQ BSD_COMP SOLARIS_BITTYPES USE_FIONBIO_IOCTL PORT_NONBLOCK PORT_DIR USE_POLL HAVE_MD5 SOLARIS2 PORT_INCLUDE ISC_PLATFORM_MSGHDRFLAVOR ISC_PLATFORM_NEEDPORTT ISC_PLATFORM_NEEDTIMESPEC ISC_LWRES_ENDHOSTENTINT ISC_LWRES_SETNETENTINT ISC_LWRES_ENDNETENTINT ISC_LWRES_GETHOSTBYADDRVOID ISC_LWRES_NEEDHERRNO ISC_LWRES_GETIPNODEPROTO ISC_LWRES_GETADDRINFOPROTO ISC_LWRES_GETNAMEINFOPROTO NEED_PSELECT NEED_GETTIMEOFDAY HAVE_STRNDUP ISC_PLATFORM_NEEDSTRSEP ISC_PLATFORM_NEEDVSNPRINTF ISC_EXTRA_OBJS ISC_EXTRA_SRCS USE_SYSERROR_LIST ISC_PLATFORM_QUADFORMAT ISC_SOCKLEN_T GETGROUPLIST_ARGS NET_R_ARGS NET_R_BAD NET_R_COPY NET_R_COPY_ARGS NET_R_OK NET_R_SETANSWER NET_R_RETURN GETNETBYADDR_ADDR_T NETENT_DATA NET_R_ENT_ARGS NET_R_SET_RESULT NET_R_SET_RETURN NET_R_END_RESULT NET_R_END_RETURN GROUP_R_ARGS GROUP_R_BAD GROUP_R_OK GROUP_R_RETURN GROUP_R_END_RESULT GROUP_R_END_RETURN GROUP_R_ENT_ARGS GROUP_R_SET_RESULT GROUP_R_SET_RETURN HOST_R_ARGS HOST_R_BAD HOST_R_COPY HOST_R_COPY_ARGS HOST_R_ERRNO HOST_R_OK HOST_R_RETURN HOST_R_SETANSWER HOSTENT_DATA HOST_R_END_RESULT HOST_R_END_RETURN HOST_R_ENT_ARGS HOST_R_SET_RESULT HOST_R_SET_RETURN SETPWENT_VOID SETGRENT_VOID NGR_R_ARGS NGR_R_BAD NGR_R_COPY NGR_R_COPY_ARGS NGR_R_OK NGR_R_RETURN NGR_R_PRIVATE NGR_R_END_RESULT NGR_R_END_RETURN NGR_R_ENT_ARGS NGR_R_SET_RESULT NGR_R_SET_RETURN PROTO_R_ARGS PROTO_R_BAD PROTO_R_COPY PROTO_R_COPY_ARGS PROTO_R_OK PROTO_R_SETANSWER PROTO_R_RETURN PROTOENT_DATA PROTO_R_END_RESULT PROTO_R_END_RETURN PROTO_R_ENT_ARGS PROTO_R_ENT_UNUSED PROTO_R_SET_RESULT PROTO_R_SET_RETURN PASS_R_ARGS PASS_R_BAD PASS_R_COPY PASS_R_COPY_ARGS PASS_R_OK PASS_R_RETURN PASS_R_END_RESULT PASS_R_END_RETURN PASS_R_ENT_ARGS PASS_R_SET_RESULT PASS_R_SET_RETURN SERV_R_ARGS SERV_R_BAD SERV_R_COPY SERV_R_COPY_ARGS SERV_R_OK SERV_R_SETANSWER SERV_R_RETURN SERVENT_DATA SERV_R_END_RESULT SERV_R_END_RETURN SERV_R_ENT_ARGS SERV_R_ENT_UNUSED SERV_R_SET_RESULT SERV_R_SET_RETURN SETNETGRENT_ARGS INNETGR_ARGS BIND9_TOP_BUILDDIR BIND9_VERSION LIBOBJS LTLIBOBJS'
+ac_subst_files='BIND9_INCLUDES BIND9_MAKE_RULES LIBBIND_API'
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+ac_env_CXX_set=${CXX+set}
+ac_env_CXX_value=$CXX
+ac_cv_env_CXX_set=${CXX+set}
+ac_cv_env_CXX_value=$CXX
+ac_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_env_CXXFLAGS_value=$CXXFLAGS
+ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_cv_env_CXXFLAGS_value=$CXXFLAGS
+ac_env_CXXCPP_set=${CXXCPP+set}
+ac_env_CXXCPP_value=$CXXCPP
+ac_cv_env_CXXCPP_set=${CXXCPP+set}
+ac_cv_env_CXXCPP_value=$CXXCPP
+ac_env_F77_set=${F77+set}
+ac_env_F77_value=$F77
+ac_cv_env_F77_set=${F77+set}
+ac_cv_env_F77_value=$F77
+ac_env_FFLAGS_set=${FFLAGS+set}
+ac_env_FFLAGS_value=$FFLAGS
+ac_cv_env_FFLAGS_set=${FFLAGS+set}
+ac_cv_env_FFLAGS_value=$FFLAGS
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-threads enable multithreading
+ --enable-shared[=PKGS]
+ build shared libraries [default=yes]
+ --enable-static[=PKGS]
+ build static libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+ --enable-ipv6 use IPv6 default=autodetect
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-irs-gr Build ....
+ --with-irs-pw Build ....
+ --with-irs-nis Build ....
+ --with-randomdev=PATH Specify path for random device
+ --with-ptl2 on NetBSD, use the ptl2 thread library (experimental)
+ --with-purify=PATH use Rational purify
+ --with-libtool use GNU libtool (following indented options supported)
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-pic try to use only PIC/non-PIC objects [default=use
+ both]
+ --with-tags[=TAGS]
+ include additional configurations [automatic]
+ --with-kame=PATH use Kame IPv6 default path /usr/local/v6
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+ CXX C++ compiler command
+ CXXFLAGS C++ compiler flags
+ CXXCPP C++ preprocessor
+ F77 Fortran 77 compiler command
+ FFLAGS Fortran 77 compiler flags
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ac_config_headers="$ac_config_headers config.h"
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+
+
+
+
+
+# Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $AR in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_AR="$AR" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ ;;
+esac
+fi
+AR=$ac_cv_path_AR
+
+if test -n "$AR"; then
+ echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ARFLAGS="cruv"
+
+
+
+# The POSIX ln(1) program. Non-POSIX systems may substitute
+# "copy" or something.
+LN=ln
+
+
+case "$AR" in
+ "")
+ { { echo "$as_me:$LINENO: error:
+ar program not found. Please fix your PATH to include the directory in
+which ar resides, or set AR in the environment with the full path to ar.
+" >&5
+echo "$as_me: error:
+ar program not found. Please fix your PATH to include the directory in
+which ar resides, or set AR in the environment with the full path to ar.
+" >&2;}
+ { (exit 1); exit 1; }; }
+
+ ;;
+esac
+
+#
+# Etags.
+#
+for ac_prog in etags emacs-etags
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_ETAGS+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $ETAGS in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ETAGS="$ETAGS" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ETAGS="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ ;;
+esac
+fi
+ETAGS=$ac_cv_path_ETAGS
+
+if test -n "$ETAGS"; then
+ echo "$as_me:$LINENO: result: $ETAGS" >&5
+echo "${ECHO_T}$ETAGS" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ETAGS" && break
+done
+
+
+#
+# Some systems, e.g. RH7, have the Exuberant Ctags etags instead of
+# GNU emacs etags, and it requires the -L flag.
+#
+if test "X$ETAGS" != "X"; then
+ echo "$as_me:$LINENO: checking for Exuberant Ctags etags" >&5
+echo $ECHO_N "checking for Exuberant Ctags etags... $ECHO_C" >&6
+ if $ETAGS --version 2>&1 | grep 'Exuberant Ctags' >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ETAGS="$ETAGS -L"
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+fi
+
+
+#
+# Perl is optional; it is used only by some of the system test scripts.
+#
+for ac_prog in perl5 perl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_PERL+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PERL in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ ;;
+esac
+fi
+PERL=$ac_cv_path_PERL
+
+if test -n "$PERL"; then
+ echo "$as_me:$LINENO: result: $PERL" >&5
+echo "${ECHO_T}$PERL" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$PERL" && break
+done
+
+
+
+#
+# isc/list.h and others clash with the rest of BIND 9
+#
+case "$includedir" in
+ '${prefix}/include')
+ includedir='${prefix}/bind/include'
+ ;;
+esac
+case "$libdir" in
+ '${prefix}/lib')
+ libdir='${prefix}/bind/lib'
+ ;;
+esac
+
+#
+# Make sure INSTALL uses an absolute path, else it will be wrong in all
+# Makefiles, since they use make/rules.in and INSTALL will be adjusted by
+# configure based on the location of the file where it is substituted.
+# Since in BIND9 INSTALL is only substituted into make/rules.in, an immediate
+# subdirectory of install-sh, This relative path will be wrong for all
+# directories more than one level down from install-sh.
+#
+case "$INSTALL" in
+ /*)
+ ;;
+ *)
+ #
+ # Not all systems have dirname.
+ #
+
+ ac_dir="`echo $INSTALL | sed 's%/[^/]*$%%'`"
+
+
+ ac_prog="`echo $INSTALL | sed 's%.*/%%'`"
+ test "$ac_dir" = "$ac_prog" && ac_dir=.
+ test -d "$ac_dir" && ac_dir="`(cd \"$ac_dir\" && pwd)`"
+ INSTALL="$ac_dir/$ac_prog"
+ ;;
+esac
+
+#
+# On these hosts, we really want to use cc, not gcc, even if it is
+# found. The gcc that these systems have will not correctly handle
+# pthreads.
+#
+# However, if the user sets $CC to be something, let that override
+# our change.
+#
+if test "X$CC" = "X" ; then
+ case "$host" in
+ *-dec-osf*)
+ CC="cc"
+ ;;
+ *-solaris*)
+ # Use Sun's cc if it is available, but watch
+ # out for /usr/ucb/cc; it will never be the right
+ # compiler to use.
+ #
+ # If setting CC here fails, the AC_PROG_CC done
+ # below might still find gcc.
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ case "$ac_dir" in
+ /usr/ucb)
+ # exclude
+ ;;
+ *)
+ if test -f "$ac_dir/cc"; then
+ CC="$ac_dir/cc"
+ break
+ fi
+ ;;
+ esac
+ done
+ IFS="$ac_save_ifs"
+ ;;
+ *-hp-hpux*)
+ CC="cc"
+ ;;
+ mips-sgi-irix*)
+ CC="cc"
+ ;;
+ esac
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
+ break;;
+ * )
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std1 is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std1. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+
+
+
+
+
+for ac_header in fcntl.h db.h paths.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/timers.h stropts.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists. ##
+## ------------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset x;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *ccp;
+ char **p;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ ccp = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++ccp;
+ p = (char**) ccp;
+ ccp = (char const *const *) p;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ }
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_const=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_inline=$ac_kw; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((size_t *) 0)
+ return 0;
+if (sizeof (size_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_size_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_size_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+if test $ac_cv_type_size_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for ssize_t" >&5
+echo $ECHO_N "checking for ssize_t... $ECHO_C" >&6
+if test "${ac_cv_type_ssize_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((ssize_t *) 0)
+ return 0;
+if (sizeof (ssize_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_ssize_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_ssize_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_ssize_t" >&5
+echo "${ECHO_T}$ac_cv_type_ssize_t" >&6
+if test $ac_cv_type_ssize_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define ssize_t signed
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for uintptr_t" >&5
+echo $ECHO_N "checking for uintptr_t... $ECHO_C" >&6
+if test "${ac_cv_type_uintptr_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((uintptr_t *) 0)
+ return 0;
+if (sizeof (uintptr_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_uintptr_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_uintptr_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_uintptr_t" >&5
+echo "${ECHO_T}$ac_cv_type_uintptr_t" >&6
+if test $ac_cv_type_uintptr_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uintptr_t unsigned long
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6
+if test "${ac_cv_header_time+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_time=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_time=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6
+if test $ac_cv_header_time = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+#
+# check if we need to #include sys/select.h explicitly
+#
+case $ac_cv_header_unistd_h in
+yes)
+echo "$as_me:$LINENO: checking if unistd.h defines fd_set" >&5
+echo $ECHO_N "checking if unistd.h defines fd_set... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <unistd.h>
+int
+main ()
+{
+fd_set read_set; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_PLATFORM_NEEDSYSSELECTH="#undef ISC_PLATFORM_NEEDSYSSELECTH"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ case ac_cv_header_sys_select_h in
+ yes)
+ ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+ ;;
+ no)
+ { { echo "$as_me:$LINENO: error: need either working unistd.h or sys/select.h" >&5
+echo "$as_me: error: need either working unistd.h or sys/select.h" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ esac
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ ;;
+no)
+ case ac_cv_header_sys_select_h in
+ yes)
+ ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+ ;;
+ no)
+ { { echo "$as_me:$LINENO: error: need either unistd.h or sys/select.h" >&5
+echo "$as_me: error: need either unistd.h or sys/select.h" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ esac
+ ;;
+esac
+
+
+#
+# Find the machine's endian flavor.
+#
+echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6
+if test "${ac_cv_c_bigendian+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_bigendian=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+# It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+ # try to guess the endianness by grepping values into an object file
+ ac_cv_c_bigendian=unknown
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+ ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+int
+main ()
+{
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6
+case $ac_cv_c_bigendian in
+ yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define WORDS_BIGENDIAN 1
+_ACEOF
+ ;;
+ no)
+ ;;
+ *)
+ { { echo "$as_me:$LINENO: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&5
+echo "$as_me: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}
+ { (exit 1); exit 1; }; } ;;
+esac
+
+
+
+# Check whether --with-irs-gr or --without-irs-gr was given.
+if test "${with_irs_gr+set}" = set; then
+ withval="$with_irs_gr"
+ want_irs_gr="$withval"
+else
+ want_irs_gr="no"
+fi;
+case "$want_irs_gr" in
+yes) WANT_IRS_GR="#define WANT_IRS_GR 1"
+ WANT_IRS_GR_OBJS="\${WANT_IRS_GR_OBJS}"
+ ;;
+*) WANT_IRS_GR="#undef WANT_IRS_GR" WANT_IRS_GR_OBJS="";;
+esac
+
+
+
+
+# Check whether --with-irs-pw or --without-irs-pw was given.
+if test "${with_irs_pw+set}" = set; then
+ withval="$with_irs_pw"
+ want_irs_pw="$withval"
+else
+ want_irs_pw="no"
+fi;
+case "$want_irs_pw" in
+yes) WANT_IRS_PW="#define WANT_IRS_PW 1"
+ WANT_IRS_PW_OBJS="\${WANT_IRS_PW_OBJS}";;
+*) WANT_IRS_PW="#undef WANT_IRS_PW" WANT_IRS_PW_OBJS="";;
+esac
+
+
+
+
+# Check whether --with-irs-nis or --without-irs-nis was given.
+if test "${with_irs_nis+set}" = set; then
+ withval="$with_irs_nis"
+ want_irs_nis="$withval"
+else
+ want_irs_nis="no"
+fi;
+case "$want_irs_nis" in
+yes)
+ WANT_IRS_NIS="#define WANT_IRS_NIS 1"
+ WANT_IRS_NIS_OBJS="\${WANT_IRS_NIS_OBJS}"
+ case "$want_irs_gr" in
+ yes)
+ WANT_IRS_NISGR_OBJS="\${WANT_IRS_NISGR_OBJS}";;
+ *)
+ WANT_IRS_NISGR_OBJS="";;
+ esac
+ case "$want_irs_pw" in
+ yes)
+ WANT_IRS_NISPW_OBJS="\${WANT_IRS_NISPW_OBJS}";;
+ *)
+ WANT_IRS_NISPW_OBJS="";;
+ esac
+ ;;
+*)
+ WANT_IRS_NIS="#undef WANT_IRS_NIS"
+ WANT_IRS_NIS_OBJS=""
+ WANT_IRS_NISGR_OBJS=""
+ WANT_IRS_NISPW_OBJS="";;
+esac
+
+
+
+
+if test "$cross_compiling" = yes; then
+ WANT_IRS_DBPW_OBJS=""
+
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#ifdef HAVE_DB_H
+int have_db_h = 1;
+#else
+int have_db_h = 0;
+#endif
+main() { return(!have_db_h); }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ WANT_IRS_DBPW_OBJS="\${WANT_IRS_DBPW_OBJS}"
+
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+WANT_IRS_DBPW_OBJS=""
+
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+#
+# was --with-randomdev specified?
+#
+echo "$as_me:$LINENO: checking for random device" >&5
+echo $ECHO_N "checking for random device... $ECHO_C" >&6
+
+# Check whether --with-randomdev or --without-randomdev was given.
+if test "${with_randomdev+set}" = set; then
+ withval="$with_randomdev"
+ use_randomdev="$withval"
+else
+ use_randomdev="unspec"
+fi;
+
+case "$use_randomdev" in
+ unspec)
+ case "$host" in
+ *-openbsd*)
+ devrandom=/dev/srandom
+ ;;
+ *)
+ devrandom=/dev/random
+ ;;
+ esac
+ echo "$as_me:$LINENO: result: $devrandom" >&5
+echo "${ECHO_T}$devrandom" >&6
+ as_ac_File=`echo "ac_cv_file_$devrandom" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $devrandom" >&5
+echo $ECHO_N "checking for $devrandom... $ECHO_C" >&6
+if eval "test \"\${$as_ac_File+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ test "$cross_compiling" = yes &&
+ { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+ { (exit 1); exit 1; }; }
+if test -r "$devrandom"; then
+ eval "$as_ac_File=yes"
+else
+ eval "$as_ac_File=no"
+fi
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_File'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_File'}'`" >&6
+if test `eval echo '${'$as_ac_File'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define PATH_RANDOMDEV "$devrandom"
+_ACEOF
+
+fi
+
+ ;;
+ yes)
+ { { echo "$as_me:$LINENO: error: --with-randomdev must specify a path" >&5
+echo "$as_me: error: --with-randomdev must specify a path" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ *)
+ cat >>confdefs.h <<_ACEOF
+#define PATH_RANDOMDEV "$use_randomdev"
+_ACEOF
+
+ echo "$as_me:$LINENO: result: using \"$use_randomdev\"" >&5
+echo "${ECHO_T}using \"$use_randomdev\"" >&6
+ ;;
+esac
+
+#
+# Begin pthreads checking.
+#
+# First, decide whether to use multithreading or not.
+#
+# Enable multithreading by default on systems where it is known
+# to work well, and where debugging of multithreaded programs
+# is supported.
+#
+
+echo "$as_me:$LINENO: checking whether to build with thread support" >&5
+echo $ECHO_N "checking whether to build with thread support... $ECHO_C" >&6
+
+case $host in
+*-dec-osf*)
+ use_threads=true ;;
+*-solaris2.[0-6])
+ # Thread signals are broken on Solaris 2.6; they are sometimes
+ # delivered to the wrong thread.
+ use_threads=false ;;
+*-solaris*)
+ use_threads=true ;;
+*-ibm-aix*)
+ use_threads=true ;;
+*-hp-hpux10*)
+ use_threads=false ;;
+*-hp-hpux11*)
+ use_threads=true ;;
+*-sgi-irix*)
+ use_threads=true ;;
+*-sco-sysv*uw*|*-*-sysv*UnixWare*)
+ # UnixWare
+ use_threads=false ;;
+*-*-sysv*OpenUNIX*)
+ # UnixWare
+ use_threads=true ;;
+*-netbsd*)
+ if test -r /usr/lib/libpthread.so ; then
+ use_threads=true
+ else
+ # Socket I/O optimizations introduced in 9.2 expose a
+ # bug in unproven-pthreads; see PR #12650
+ use_threads=false
+ fi
+ ;;
+*-openbsd*)
+ # OpenBSD users have reported that named dumps core on
+ # startup when built with threads.
+ use_threads=false ;;
+*-freebsd*)
+ use_threads=false ;;
+*-bsdi234*)
+ # Thread signals do not work reliably on some versions of BSD/OS.
+ use_threads=false ;;
+*-bsdi5*)
+ use_threads=true ;;
+*-linux*)
+ # Threads are disabled on Linux by default because most
+ # Linux kernels produce unusable core dumps from multithreaded
+ # programs, and because of limitations in setuid().
+ use_threads=false ;;
+*)
+ use_threads=false ;;
+esac
+
+# Check whether --enable-threads or --disable-threads was given.
+if test "${enable_threads+set}" = set; then
+ enableval="$enable_threads"
+
+fi;
+case "$enable_threads" in
+ yes)
+ use_threads=true
+ ;;
+ no)
+ use_threads=false
+ ;;
+ '')
+ # Use system-dependent default
+ ;;
+ *)
+ { { echo "$as_me:$LINENO: error: --enable-threads takes yes or no" >&5
+echo "$as_me: error: --enable-threads takes yes or no" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+esac
+
+if $use_threads
+then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if $use_threads
+then
+ #
+ # Search for / configure pthreads in a system-dependent fashion.
+ #
+ case "$host" in
+ *-netbsd*)
+ # NetBSD has multiple pthreads implementations. The
+ # recommended one to use is "unproven-pthreads". The
+ # older "mit-pthreads" may also work on some NetBSD
+ # versions. The PTL2 thread library does not
+ # currently work with bind9, but can be chosen with
+ # the --with-ptl2 option for those who wish to
+ # experiment with it.
+ CC="gcc"
+ echo "$as_me:$LINENO: checking which NetBSD thread library to use" >&5
+echo $ECHO_N "checking which NetBSD thread library to use... $ECHO_C" >&6
+
+
+# Check whether --with-ptl2 or --without-ptl2 was given.
+if test "${with_ptl2+set}" = set; then
+ withval="$with_ptl2"
+ use_ptl2="$withval"
+else
+ use_ptl2="no"
+fi;
+
+ : ${LOCALBASE:=/usr/pkg}
+
+ if test "X$use_ptl2" = "Xyes"
+ then
+ echo "$as_me:$LINENO: result: PTL2" >&5
+echo "${ECHO_T}PTL2" >&6
+ { echo "$as_me:$LINENO: WARNING: linking with PTL2 is highly experimental and not expected to work" >&5
+echo "$as_me: WARNING: linking with PTL2 is highly experimental and not expected to work" >&2;}
+ CC=ptlgcc
+ else
+ if test -r /usr/lib/libpthread.so
+ then
+ echo "$as_me:$LINENO: result: native" >&5
+echo "${ECHO_T}native" >&6
+ LIBS="-lpthread $LIBS"
+ else
+ if test ! -d $LOCALBASE/pthreads
+ then
+ echo "$as_me:$LINENO: result: none" >&5
+echo "${ECHO_T}none" >&6
+ { { echo "$as_me:$LINENO: error: \"could not find thread libraries\"" >&5
+echo "$as_me: error: \"could not find thread libraries\"" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ if $use_threads
+ then
+ echo "$as_me:$LINENO: result: mit-pthreads/unproven-pthreads" >&5
+echo "${ECHO_T}mit-pthreads/unproven-pthreads" >&6
+ pkg="$LOCALBASE/pthreads"
+ lib1="-L$pkg/lib -Wl,-R$pkg/lib"
+ lib2="-lpthread -lm -lgcc -lpthread"
+ LIBS="$lib1 $lib2 $LIBS"
+ CPPFLAGS="$CPPFLAGS -I$pkg/include"
+ STD_CINCLUDES="$STD_CINCLUDES -I$pkg/include"
+ fi
+ fi
+ fi
+ ;;
+ *-freebsd*)
+ # We don't want to set -lpthread as that break
+ # the ability to choose threads library at final
+ # link time and is not valid for all architectures.
+
+ PTHREAD=
+ if test "X$GCC" = "Xyes"; then
+ saved_cc="$CC"
+ CC="$CC -pthread"
+ echo "$as_me:$LINENO: checking for gcc -pthread support" >&5
+echo $ECHO_N "checking for gcc -pthread support... $ECHO_C" >&6;
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <pthread.h>
+int
+main ()
+{
+printf("%x\n", pthread_create);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ PTHREAD="yes"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CC="$saved_cc"
+ fi
+ if test "X$PTHREAD" != "Xyes"; then
+
+echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5
+echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_create ();
+int
+main ()
+{
+pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread_pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6
+if test $ac_cv_lib_pthread_pthread_create = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+ LIBS="-lpthread $LIBS"
+
+else
+
+echo "$as_me:$LINENO: checking for thread_create in -lthr" >&5
+echo $ECHO_N "checking for thread_create in -lthr... $ECHO_C" >&6
+if test "${ac_cv_lib_thr_thread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lthr $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char thread_create ();
+int
+main ()
+{
+thread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_thr_thread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_thr_thread_create=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_thr_thread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_thr_thread_create" >&6
+if test $ac_cv_lib_thr_thread_create = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTHR 1
+_ACEOF
+
+ LIBS="-lthr $LIBS"
+
+else
+
+echo "$as_me:$LINENO: checking for pthread_create in -lc_r" >&5
+echo $ECHO_N "checking for pthread_create in -lc_r... $ECHO_C" >&6
+if test "${ac_cv_lib_c_r_pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc_r $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_create ();
+int
+main ()
+{
+pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_r_pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_c_r_pthread_create=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_r_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_c_r_pthread_create" >&6
+if test $ac_cv_lib_c_r_pthread_create = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBC_R 1
+_ACEOF
+
+ LIBS="-lc_r $LIBS"
+
+else
+
+echo "$as_me:$LINENO: checking for pthread_create in -lc" >&5
+echo $ECHO_N "checking for pthread_create in -lc... $ECHO_C" >&6
+if test "${ac_cv_lib_c_pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_create ();
+int
+main ()
+{
+pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_c_pthread_create=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_c_pthread_create" >&6
+if test $ac_cv_lib_c_pthread_create = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBC 1
+_ACEOF
+
+ LIBS="-lc $LIBS"
+
+else
+ { { echo "$as_me:$LINENO: error: \"could not find thread libraries\"" >&5
+echo "$as_me: error: \"could not find thread libraries\"" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+fi
+
+fi
+
+fi
+
+ fi
+ ;;
+ *)
+
+echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5
+echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_create ();
+int
+main ()
+{
+pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread_pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6
+if test $ac_cv_lib_pthread_pthread_create = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+ LIBS="-lpthread $LIBS"
+
+else
+
+echo "$as_me:$LINENO: checking for __pthread_create in -lpthread" >&5
+echo $ECHO_N "checking for __pthread_create in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread___pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __pthread_create ();
+int
+main ()
+{
+__pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread___pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread___pthread_create=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread___pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread___pthread_create" >&6
+if test $ac_cv_lib_pthread___pthread_create = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+ LIBS="-lpthread $LIBS"
+
+else
+
+echo "$as_me:$LINENO: checking for __pthread_create_system in -lpthread" >&5
+echo $ECHO_N "checking for __pthread_create_system in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread___pthread_create_system+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __pthread_create_system ();
+int
+main ()
+{
+__pthread_create_system ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread___pthread_create_system=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread___pthread_create_system=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread___pthread_create_system" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread___pthread_create_system" >&6
+if test $ac_cv_lib_pthread___pthread_create_system = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+ LIBS="-lpthread $LIBS"
+
+else
+
+echo "$as_me:$LINENO: checking for pthread_create in -lc_r" >&5
+echo $ECHO_N "checking for pthread_create in -lc_r... $ECHO_C" >&6
+if test "${ac_cv_lib_c_r_pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc_r $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_create ();
+int
+main ()
+{
+pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_r_pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_c_r_pthread_create=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_r_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_c_r_pthread_create" >&6
+if test $ac_cv_lib_c_r_pthread_create = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBC_R 1
+_ACEOF
+
+ LIBS="-lc_r $LIBS"
+
+else
+
+echo "$as_me:$LINENO: checking for pthread_create in -lc" >&5
+echo $ECHO_N "checking for pthread_create in -lc... $ECHO_C" >&6
+if test "${ac_cv_lib_c_pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_create ();
+int
+main ()
+{
+pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_c_pthread_create=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_c_pthread_create" >&6
+if test $ac_cv_lib_c_pthread_create = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBC 1
+_ACEOF
+
+ LIBS="-lc $LIBS"
+
+else
+ { { echo "$as_me:$LINENO: error: \"could not find thread libraries\"" >&5
+echo "$as_me: error: \"could not find thread libraries\"" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+fi
+
+fi
+
+fi
+
+fi
+
+ ;;
+ esac
+fi
+
+if $use_threads
+then
+ if test "X$GCC" = "Xyes"; then
+ case "$host" in
+ *-freebsd*)
+ CC="$CC -pthread"
+ CCOPT="$CCOPT -pthread"
+ STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+ ;;
+ *-openbsd*)
+ CC="$CC -pthread"
+ CCOPT="$CCOPT -pthread"
+ ;;
+ *-solaris*)
+ LIBS="$LIBS -lthread"
+ ;;
+ *-ibm-aix*)
+ STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+ ;;
+ esac
+ else
+ case $host in
+ *-dec-osf*)
+ CC="$CC -pthread"
+ CCOPT="$CCOPT -pthread"
+ ;;
+ *-solaris*)
+ CC="$CC -mt"
+ CCOPT="$CCOPT -mt"
+ ;;
+ *-ibm-aix*)
+ STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+ ;;
+ *-UnixWare*)
+ CC="$CC -Kthread"
+ CCOPT="$CCOPT -Kthread"
+ ;;
+ esac
+ fi
+ cat >>confdefs.h <<\_ACEOF
+#define _REENTRANT 1
+_ACEOF
+
+ ALWAYS_DEFINES="-D_REENTRANT"
+ DO_PTHREADS="#define DO_PTHREADS 1"
+ WANT_IRS_THREADSGR_OBJS="\${WANT_IRS_THREADSGR_OBJS}"
+ WANT_IRS_THREADSPW_OBJS="\${WANT_IRS_THREADSPW_OBJS}"
+ case $host in
+ ia64-hp-hpux11.*)
+ WANT_IRS_THREADS_OBJS="";;
+ *)
+ WANT_IRS_THREADS_OBJS="\${WANT_IRS_THREADS_OBJS}";;
+ esac
+ WANT_THREADS_OBJS="\${WANT_THREADS_OBJS}"
+ thread_dir=pthreads
+
+ #
+ # We'd like to use sigwait() too
+ #
+ echo "$as_me:$LINENO: checking for sigwait" >&5
+echo $ECHO_N "checking for sigwait... $ECHO_C" >&6
+if test "${ac_cv_func_sigwait+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define sigwait to an innocuous variant, in case <limits.h> declares sigwait.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define sigwait innocuous_sigwait
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char sigwait (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef sigwait
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sigwait ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_sigwait) || defined (__stub___sigwait)
+choke me
+#else
+char (*f) () = sigwait;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != sigwait;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_sigwait=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_sigwait=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_sigwait" >&5
+echo "${ECHO_T}$ac_cv_func_sigwait" >&6
+if test $ac_cv_func_sigwait = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIGWAIT 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: checking for sigwait in -lc" >&5
+echo $ECHO_N "checking for sigwait in -lc... $ECHO_C" >&6
+if test "${ac_cv_lib_c_sigwait+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sigwait ();
+int
+main ()
+{
+sigwait ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_sigwait=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_c_sigwait=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_sigwait" >&5
+echo "${ECHO_T}$ac_cv_lib_c_sigwait" >&6
+if test $ac_cv_lib_c_sigwait = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIGWAIT 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: checking for sigwait in -lpthread" >&5
+echo $ECHO_N "checking for sigwait in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread_sigwait+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sigwait ();
+int
+main ()
+{
+sigwait ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread_sigwait=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread_sigwait=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_sigwait" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread_sigwait" >&6
+if test $ac_cv_lib_pthread_sigwait = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIGWAIT 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: checking for _Psigwait in -lpthread" >&5
+echo $ECHO_N "checking for _Psigwait in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread__Psigwait+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char _Psigwait ();
+int
+main ()
+{
+_Psigwait ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread__Psigwait=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread__Psigwait=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread__Psigwait" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread__Psigwait" >&6
+if test $ac_cv_lib_pthread__Psigwait = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIGWAIT 1
+_ACEOF
+
+fi
+
+fi
+
+fi
+
+fi
+
+
+ echo "$as_me:$LINENO: checking for pthread_attr_getstacksize" >&5
+echo $ECHO_N "checking for pthread_attr_getstacksize... $ECHO_C" >&6
+if test "${ac_cv_func_pthread_attr_getstacksize+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define pthread_attr_getstacksize to an innocuous variant, in case <limits.h> declares pthread_attr_getstacksize.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define pthread_attr_getstacksize innocuous_pthread_attr_getstacksize
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char pthread_attr_getstacksize (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef pthread_attr_getstacksize
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_attr_getstacksize ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_pthread_attr_getstacksize) || defined (__stub___pthread_attr_getstacksize)
+choke me
+#else
+char (*f) () = pthread_attr_getstacksize;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != pthread_attr_getstacksize;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_pthread_attr_getstacksize=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_pthread_attr_getstacksize=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_pthread_attr_getstacksize" >&5
+echo "${ECHO_T}$ac_cv_func_pthread_attr_getstacksize" >&6
+if test $ac_cv_func_pthread_attr_getstacksize = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_PTHREAD_ATTR_GETSTACKSIZE 1
+_ACEOF
+
+fi
+
+
+ #
+ # Additional OS-specific issues related to pthreads and sigwait.
+ #
+ case "$host" in
+ #
+ # One more place to look for sigwait.
+ #
+ *-freebsd*)
+ echo "$as_me:$LINENO: checking for sigwait in -lc_r" >&5
+echo $ECHO_N "checking for sigwait in -lc_r... $ECHO_C" >&6
+if test "${ac_cv_lib_c_r_sigwait+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc_r $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sigwait ();
+int
+main ()
+{
+sigwait ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_r_sigwait=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_c_r_sigwait=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_r_sigwait" >&5
+echo "${ECHO_T}$ac_cv_lib_c_r_sigwait" >&6
+if test $ac_cv_lib_c_r_sigwait = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIGWAIT 1
+_ACEOF
+
+fi
+
+ ;;
+ #
+ # BSDI 3.0 through 4.0.1 needs pthread_init() to be
+ # called before certain pthreads calls. This is deprecated
+ # in BSD/OS 4.1.
+ #
+ *-bsdi3.*|*-bsdi4.0*)
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_PTHREAD_INIT 1
+_ACEOF
+
+ ;;
+ #
+ # LinuxThreads requires some changes to the way we
+ # deal with signals.
+ #
+ *-linux*)
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_LINUXTHREADS 1
+_ACEOF
+
+ ;;
+ #
+ # Ensure the right sigwait() semantics on Solaris and make
+ # sure we call pthread_setconcurrency.
+ #
+ *-solaris*)
+ cat >>confdefs.h <<\_ACEOF
+#define _POSIX_PTHREAD_SEMANTICS 1
+_ACEOF
+
+ echo "$as_me:$LINENO: checking for pthread_setconcurrency" >&5
+echo $ECHO_N "checking for pthread_setconcurrency... $ECHO_C" >&6
+if test "${ac_cv_func_pthread_setconcurrency+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define pthread_setconcurrency to an innocuous variant, in case <limits.h> declares pthread_setconcurrency.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define pthread_setconcurrency innocuous_pthread_setconcurrency
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char pthread_setconcurrency (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef pthread_setconcurrency
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_setconcurrency ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_pthread_setconcurrency) || defined (__stub___pthread_setconcurrency)
+choke me
+#else
+char (*f) () = pthread_setconcurrency;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != pthread_setconcurrency;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_pthread_setconcurrency=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_pthread_setconcurrency=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_pthread_setconcurrency" >&5
+echo "${ECHO_T}$ac_cv_func_pthread_setconcurrency" >&6
+if test $ac_cv_func_pthread_setconcurrency = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define CALL_PTHREAD_SETCONCURRENCY 1
+_ACEOF
+
+fi
+
+ cat >>confdefs.h <<\_ACEOF
+#define POSIX_GETPWUID_R 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define POSIX_GETPWNAM_R 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define POSIX_GETGRGID_R 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define POSIX_GETGRNAM_R 1
+_ACEOF
+
+ ;;
+ *hpux11*)
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_ENDNETGRENT_R 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define _PTHREADS_DRAFT4 1
+_ACEOF
+
+ ;;
+ #
+ # UnixWare does things its own way.
+ #
+ *-UnixWare*)
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_UNIXWARE_SIGWAIT 1
+_ACEOF
+
+ ;;
+ esac
+
+ #
+ # Look for sysconf to allow detection of the number of processors.
+ #
+ echo "$as_me:$LINENO: checking for sysconf" >&5
+echo $ECHO_N "checking for sysconf... $ECHO_C" >&6
+if test "${ac_cv_func_sysconf+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define sysconf to an innocuous variant, in case <limits.h> declares sysconf.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define sysconf innocuous_sysconf
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char sysconf (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef sysconf
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sysconf ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_sysconf) || defined (__stub___sysconf)
+choke me
+#else
+char (*f) () = sysconf;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != sysconf;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_sysconf=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_sysconf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_sysconf" >&5
+echo "${ECHO_T}$ac_cv_func_sysconf" >&6
+if test $ac_cv_func_sysconf = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SYSCONF 1
+_ACEOF
+
+fi
+
+
+else
+ ALWAYS_DEFINES=""
+ DO_PTHREADS="#undef DO_PTHREADS"
+ WANT_IRS_THREADSGR_OBJS=""
+ WANT_IRS_THREADSPW_OBJS=""
+ WANT_IRS_THREADS_OBJS=""
+ WANT_THREADS_OBJS=""
+ thread_dir=nothreads
+fi
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for strlcat" >&5
+echo $ECHO_N "checking for strlcat... $ECHO_C" >&6
+if test "${ac_cv_func_strlcat+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define strlcat to an innocuous variant, in case <limits.h> declares strlcat.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define strlcat innocuous_strlcat
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char strlcat (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef strlcat
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strlcat ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_strlcat) || defined (__stub___strlcat)
+choke me
+#else
+char (*f) () = strlcat;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != strlcat;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_strlcat=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_strlcat=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_strlcat" >&5
+echo "${ECHO_T}$ac_cv_func_strlcat" >&6
+if test $ac_cv_func_strlcat = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRLCAT 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for memmove" >&5
+echo $ECHO_N "checking for memmove... $ECHO_C" >&6
+if test "${ac_cv_func_memmove+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define memmove to an innocuous variant, in case <limits.h> declares memmove.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define memmove innocuous_memmove
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char memmove (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef memmove
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char memmove ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_memmove) || defined (__stub___memmove)
+choke me
+#else
+char (*f) () = memmove;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != memmove;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_memmove=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_memmove=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_memmove" >&5
+echo "${ECHO_T}$ac_cv_func_memmove" >&6
+if test $ac_cv_func_memmove = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_MEMMOVE 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for memchr" >&5
+echo $ECHO_N "checking for memchr... $ECHO_C" >&6
+if test "${ac_cv_func_memchr+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define memchr to an innocuous variant, in case <limits.h> declares memchr.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define memchr innocuous_memchr
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char memchr (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef memchr
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char memchr ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_memchr) || defined (__stub___memchr)
+choke me
+#else
+char (*f) () = memchr;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != memchr;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_memchr=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_memchr=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_memchr" >&5
+echo "${ECHO_T}$ac_cv_func_memchr" >&6
+if test $ac_cv_func_memchr = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_MEMCHR 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for if_nametoindex" >&5
+echo $ECHO_N "checking for if_nametoindex... $ECHO_C" >&6
+if test "${ac_cv_func_if_nametoindex+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define if_nametoindex to an innocuous variant, in case <limits.h> declares if_nametoindex.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define if_nametoindex innocuous_if_nametoindex
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char if_nametoindex (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef if_nametoindex
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char if_nametoindex ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_if_nametoindex) || defined (__stub___if_nametoindex)
+choke me
+#else
+char (*f) () = if_nametoindex;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != if_nametoindex;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_if_nametoindex=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_if_nametoindex=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_if_nametoindex" >&5
+echo "${ECHO_T}$ac_cv_func_if_nametoindex" >&6
+if test $ac_cv_func_if_nametoindex = yes; then
+ USE_IFNAMELINKID="#define USE_IFNAMELINKID 1"
+else
+ USE_IFNAMELINKID="#undef USE_IFNAMELINKID"
+fi
+
+
+
+ISC_THREAD_DIR=$thread_dir
+
+
+echo "$as_me:$LINENO: checking for daemon" >&5
+echo $ECHO_N "checking for daemon... $ECHO_C" >&6
+if test "${ac_cv_func_daemon+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define daemon to an innocuous variant, in case <limits.h> declares daemon.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define daemon innocuous_daemon
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char daemon (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef daemon
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char daemon ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_daemon) || defined (__stub___daemon)
+choke me
+#else
+char (*f) () = daemon;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != daemon;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_daemon=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_daemon=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_daemon" >&5
+echo "${ECHO_T}$ac_cv_func_daemon" >&6
+if test $ac_cv_func_daemon = yes; then
+ DAEMON_OBJS="" NEED_DAEMON="#undef NEED_DAEMON"
+
+else
+ DAEMON_OBJS="\${DAEMON_OBJS}" NEED_DAEMON="#define NEED_DAEMON 1"
+
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking for strsep" >&5
+echo $ECHO_N "checking for strsep... $ECHO_C" >&6
+if test "${ac_cv_func_strsep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define strsep to an innocuous variant, in case <limits.h> declares strsep.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define strsep innocuous_strsep
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char strsep (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef strsep
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strsep ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_strsep) || defined (__stub___strsep)
+choke me
+#else
+char (*f) () = strsep;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != strsep;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_strsep=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_strsep=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_strsep" >&5
+echo "${ECHO_T}$ac_cv_func_strsep" >&6
+if test $ac_cv_func_strsep = yes; then
+ STRSEP_OBJS="" NEED_STRSEP="#undef NEED_STRSEP"
+
+else
+ STRSEP_OBJS="\${STRSEP_OBJS}" NEED_STRSEP="#define NEED_STRSEP 1"
+
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking for strerror" >&5
+echo $ECHO_N "checking for strerror... $ECHO_C" >&6
+if test "${ac_cv_func_strerror+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define strerror to an innocuous variant, in case <limits.h> declares strerror.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define strerror innocuous_strerror
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char strerror (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef strerror
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strerror ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_strerror) || defined (__stub___strerror)
+choke me
+#else
+char (*f) () = strerror;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != strerror;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_strerror=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_strerror=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_strerror" >&5
+echo "${ECHO_T}$ac_cv_func_strerror" >&6
+if test $ac_cv_func_strerror = yes; then
+ NEED_STRERROR="#undef NEED_STRERROR"
+else
+ NEED_STRERROR="#define NEED_STRERROR 1"
+fi
+
+
+
+#
+# flockfile is usually provided by pthreads, but we may want to use it
+# even if compiled with --disable-threads.
+#
+echo "$as_me:$LINENO: checking for flockfile" >&5
+echo $ECHO_N "checking for flockfile... $ECHO_C" >&6
+if test "${ac_cv_func_flockfile+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define flockfile to an innocuous variant, in case <limits.h> declares flockfile.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define flockfile innocuous_flockfile
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char flockfile (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef flockfile
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char flockfile ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_flockfile) || defined (__stub___flockfile)
+choke me
+#else
+char (*f) () = flockfile;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != flockfile;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_flockfile=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_flockfile=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_flockfile" >&5
+echo "${ECHO_T}$ac_cv_func_flockfile" >&6
+if test $ac_cv_func_flockfile = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_FLOCKFILE 1
+_ACEOF
+
+fi
+
+
+#
+# Indicate what the final decision was regarding threads.
+#
+echo "$as_me:$LINENO: checking whether to build with threads" >&5
+echo $ECHO_N "checking whether to build with threads... $ECHO_C" >&6
+if $use_threads; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+#
+# End of pthreads stuff.
+#
+
+#
+# Additional compiler settings.
+#
+MKDEPCC="$CC"
+MKDEPCFLAGS="-M"
+IRIX_DNSSEC_WARNINGS_HACK=""
+
+if test "X$GCC" = "Xyes"; then
+ echo "$as_me:$LINENO: checking if \"$CC\" supports -fno-strict-aliasing" >&5
+echo $ECHO_N "checking if \"$CC\" supports -fno-strict-aliasing... $ECHO_C" >&6
+ SAVE_CFLAGS=$CFLAGS
+ CFLAGS=-fno-strict-aliasing
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ FNOSTRICTALIASING=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+FNOSTRICTALIASING=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$SAVE_CFLAGS
+ if test "$FNOSTRICTALIASING" = "yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ STD_CWARNINGS="$STD_CWARNINGS -W -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wformat -Wpointer-arith -fno-strict-aliasing"
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ STD_CWARNINGS="$STD_CWARNINGS -W -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wformat -Wpointer-arith"
+ fi
+else
+ case $host in
+ *-dec-osf*)
+ CC="$CC -std"
+ CCOPT="$CCOPT -std"
+ MKDEPCC="$CC"
+ ;;
+ *-hp-hpux*)
+ CC="$CC -Ae -z"
+ # The version of the C compiler that constantly warns about
+ # 'const' as well as alignment issues is unfortunately not
+ # able to be discerned via the version of the operating
+ # system, nor does cc have a version flag.
+ case "`$CC +W 123 2>&1`" in
+ *Unknown?option*)
+ STD_CWARNINGS="+w1"
+ ;;
+ *)
+ # Turn off the pointlessly noisy warnings.
+ STD_CWARNINGS="+w1 +W 474,530,2193,2236"
+ ;;
+ esac
+ CCOPT="$CCOPT -Ae -z"
+ LIBS="-Wl,+vnocompatwarnings $LIBS"
+MKDEPPROG='cc -Ae -E -Wp,-M >/dev/null 2>&1 | awk '"'"'BEGIN {colon=0; rec="";} { for (i = 0 ; i < NF; i++) { if (colon && a$i) continue; if ($i == "\\") continue; if (!colon) { rec = $i continue; } if ($i == ":") { rec = rec " :" colon = 1 continue; } if (length(rec $i) > 76) { print rec " \\"; rec = "\t" $i; a$i = 1; } else { rec = rec " " $i a$i = 1; } } } END {print rec}'"'"' >>$TMP'
+ MKDEPPROG='cc -Ae -E -Wp,-M >/dev/null 2>>$TMP'
+ ;;
+ *-sgi-irix*)
+ STD_CWARNINGS="-fullwarn -woff 1209"
+ #
+ # Silence more than 250 instances of
+ # "prototyped function redeclared without prototype"
+ # and 11 instances of
+ # "variable ... was set but never used"
+ # from lib/dns/sec/openssl.
+ #
+ IRIX_DNSSEC_WARNINGS_HACK="-woff 1692,1552"
+ ;;
+ *-solaris*)
+ MKDEPCFLAGS="-xM"
+ ;;
+ *-UnixWare*)
+ CC="$CC -w"
+ ;;
+ esac
+fi
+
+#
+# _GNU_SOURCE is needed to access the fd_bits field of struct fd_set, which
+# is supposed to be opaque.
+#
+case $host in
+ *linux*)
+ STD_CDEFINES="$STD_CDEFINES -D_GNU_SOURCE"
+ ;;
+esac
+
+
+
+
+
+
+#
+# NLS
+#
+echo "$as_me:$LINENO: checking for catgets" >&5
+echo $ECHO_N "checking for catgets... $ECHO_C" >&6
+if test "${ac_cv_func_catgets+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define catgets to an innocuous variant, in case <limits.h> declares catgets.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define catgets innocuous_catgets
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char catgets (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef catgets
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char catgets ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_catgets) || defined (__stub___catgets)
+choke me
+#else
+char (*f) () = catgets;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != catgets;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_catgets=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_catgets=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_catgets" >&5
+echo "${ECHO_T}$ac_cv_func_catgets" >&6
+if test $ac_cv_func_catgets = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_CATGETS 1
+_ACEOF
+
+fi
+
+
+#
+# -lxnet buys us one big porting headache... standards, gotta love 'em.
+#
+# AC_CHECK_LIB(xnet, socket, ,
+# AC_CHECK_LIB(socket, socket)
+# AC_CHECK_LIB(nsl, inet_ntoa)
+# )
+#
+# Use this for now, instead:
+#
+case "$host" in
+ mips-sgi-irix*)
+ ;;
+ ia64-hp-hpux11.*)
+
+echo "$as_me:$LINENO: checking for socket in -lsocket" >&5
+echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6
+if test "${ac_cv_lib_socket_socket+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket ();
+int
+main ()
+{
+socket ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_socket_socket=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_socket_socket=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6
+if test $ac_cv_lib_socket_socket = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for inet_ntoa in -lnsl" >&5
+echo $ECHO_N "checking for inet_ntoa in -lnsl... $ECHO_C" >&6
+if test "${ac_cv_lib_nsl_inet_ntoa+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inet_ntoa ();
+int
+main ()
+{
+inet_ntoa ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_nsl_inet_ntoa=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_nsl_inet_ntoa=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_inet_ntoa" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_inet_ntoa" >&6
+if test $ac_cv_lib_nsl_inet_ntoa = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+ ;;
+ *)
+
+echo "$as_me:$LINENO: checking for gethostbyname_r in -ld4r" >&5
+echo $ECHO_N "checking for gethostbyname_r in -ld4r... $ECHO_C" >&6
+if test "${ac_cv_lib_d4r_gethostbyname_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ld4r $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname_r ();
+int
+main ()
+{
+gethostbyname_r ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_d4r_gethostbyname_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_d4r_gethostbyname_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_d4r_gethostbyname_r" >&5
+echo "${ECHO_T}$ac_cv_lib_d4r_gethostbyname_r" >&6
+if test $ac_cv_lib_d4r_gethostbyname_r = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBD4R 1
+_ACEOF
+
+ LIBS="-ld4r $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for socket in -lsocket" >&5
+echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6
+if test "${ac_cv_lib_socket_socket+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket ();
+int
+main ()
+{
+socket ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_socket_socket=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_socket_socket=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6
+if test $ac_cv_lib_socket_socket = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for inet_ntoa in -lnsl" >&5
+echo $ECHO_N "checking for inet_ntoa in -lnsl... $ECHO_C" >&6
+if test "${ac_cv_lib_nsl_inet_ntoa+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inet_ntoa ();
+int
+main ()
+{
+inet_ntoa ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_nsl_inet_ntoa=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_nsl_inet_ntoa=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_inet_ntoa" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_inet_ntoa" >&6
+if test $ac_cv_lib_nsl_inet_ntoa = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+ ;;
+esac
+
+#
+# Purify support
+#
+echo "$as_me:$LINENO: checking whether to use purify" >&5
+echo $ECHO_N "checking whether to use purify... $ECHO_C" >&6
+
+# Check whether --with-purify or --without-purify was given.
+if test "${with_purify+set}" = set; then
+ withval="$with_purify"
+ use_purify="$withval"
+else
+ use_purify="no"
+fi;
+
+case "$use_purify" in
+ no)
+ ;;
+ yes)
+ # Extract the first word of "purify", so it can be a program name with args.
+set dummy purify; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_purify_path+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $purify_path in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_purify_path="$purify_path" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_purify_path="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_purify_path" && ac_cv_path_purify_path="purify"
+ ;;
+esac
+fi
+purify_path=$ac_cv_path_purify_path
+
+if test -n "$purify_path"; then
+ echo "$as_me:$LINENO: result: $purify_path" >&5
+echo "${ECHO_T}$purify_path" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ ;;
+ *)
+ purify_path="$use_purify"
+ ;;
+esac
+
+case "$use_purify" in
+ no)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ PURIFY=""
+ ;;
+ *)
+ if test -f $purify_path || test $purify_path = purify; then
+ echo "$as_me:$LINENO: result: $purify_path" >&5
+echo "${ECHO_T}$purify_path" >&6
+ PURIFYFLAGS="`echo $PURIFYOPTIONS`"
+ PURIFY="$purify_path $PURIFYFLAGS"
+ else
+ { { echo "$as_me:$LINENO: error: $purify_path not found.
+
+Please choose the proper path with the following command:
+
+ configure --with-purify=PATH
+" >&5
+echo "$as_me: error: $purify_path not found.
+
+Please choose the proper path with the following command:
+
+ configure --with-purify=PATH
+" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ ;;
+esac
+
+
+
+#
+# GNU libtool support
+#
+
+# Check whether --with-libtool or --without-libtool was given.
+if test "${with_libtool+set}" = set; then
+ withval="$with_libtool"
+ use_libtool="$withval"
+else
+ use_libtool="no"
+fi;
+
+case $use_libtool in
+ yes)
+ # Check whether --enable-shared or --disable-shared was given.
+if test "${enable_shared+set}" = set; then
+ enableval="$enable_shared"
+ p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_shared=yes
+fi;
+
+# Check whether --enable-static or --disable-static was given.
+if test "${enable_static+set}" = set; then
+ enableval="$enable_static"
+ p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_static=yes
+fi;
+
+# Check whether --enable-fast-install or --disable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then
+ enableval="$enable_fast_install"
+ p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi;
+
+echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5
+echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6
+if test "${lt_cv_path_SED+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && break
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+
+fi
+
+SED=$lt_cv_path_SED
+echo "$as_me:$LINENO: result: $SED" >&5
+echo "${ECHO_T}$SED" >&6
+
+
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+ withval="$with_gnu_ld"
+ test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi;
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ echo "$as_me:$LINENO: checking for GNU ld" >&5
+echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6
+else
+ echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6
+fi
+if test "${lt_cv_path_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some GNU ld's only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
+if test "${lt_cv_prog_gnu_ld+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5
+echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6
+if test "${lt_cv_ld_reload_flag+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5
+echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$CC -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5
+echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6
+if test "${lt_cv_path_NM+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/${ac_tool_prefix}nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi
+fi
+echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5
+echo "${ECHO_T}$lt_cv_path_NM" >&6
+NM="$lt_cv_path_NM"
+
+echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6
+fi
+
+echo "$as_me:$LINENO: checking how to recognise dependent libraries" >&5
+echo $ECHO_N "checking how to recognise dependent libraries... $ECHO_C" >&6
+if test "${lt_cv_deplibs_check_method+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix4* | aix5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[45]*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump'.
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | kfreebsd*-gnu)
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case "$host_cpu" in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+nto-qnx*)
+ lt_cv_deplibs_check_method=unknown
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sco3.2v5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5
+echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Check whether --enable-libtool-lock or --disable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then
+ enableval="$enable_libtool_lock"
+
+fi;
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '#line 8389 "configure"' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case "`/usr/bin/file conftest.o`" in
+ *32-bit*)
+ case $host in
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5
+echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6
+if test "${lt_cv_cc_needs_belf+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ lt_cv_cc_needs_belf=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+lt_cv_cc_needs_belf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5
+echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+
+esac
+
+need_locks="$enable_libtool_lock"
+
+
+
+for ac_header in dlfcn.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists. ##
+## ------------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+ echo "$as_me:$LINENO: result: $CXX" >&5
+echo "${ECHO_T}$CXX" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CXX" && break
+ done
+fi
+if test -z "$CXX"; then
+ ac_ct_CXX=$CXX
+ for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CXX"; then
+ ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CXX="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
+echo "${ECHO_T}$ac_ct_CXX" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CXX" && break
+done
+test -n "$ac_ct_CXX" || ac_ct_CXX="g++"
+
+ CXX=$ac_ct_CXX
+fi
+
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C++ compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6
+GXX=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+CXXFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
+echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cxx_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cxx_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cxx_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6
+if test "$ac_test_CXXFLAGS" = set; then
+ CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+fi
+for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5
+echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6
+if test -z "$CXXCPP"; then
+ if test "${ac_cv_prog_CXXCPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CXXCPP needs to be expanded
+ for CXXCPP in "$CXX -E" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+ CXXCPP=$ac_cv_prog_CXXCPP
+else
+ ac_cv_prog_CXXCPP=$CXXCPP
+fi
+echo "$as_me:$LINENO: result: $CXXCPP" >&5
+echo "${ECHO_T}$CXXCPP" >&6
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+fi
+
+
+ac_ext=f
+ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
+ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_f77_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_F77+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$F77"; then
+ ac_cv_prog_F77="$F77" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_F77="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+F77=$ac_cv_prog_F77
+if test -n "$F77"; then
+ echo "$as_me:$LINENO: result: $F77" >&5
+echo "${ECHO_T}$F77" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$F77" && break
+ done
+fi
+if test -z "$F77"; then
+ ac_ct_F77=$F77
+ for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_F77+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_F77"; then
+ ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_F77="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_F77=$ac_cv_prog_ac_ct_F77
+if test -n "$ac_ct_F77"; then
+ echo "$as_me:$LINENO: result: $ac_ct_F77" >&5
+echo "${ECHO_T}$ac_ct_F77" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_F77" && break
+done
+
+ F77=$ac_ct_F77
+fi
+
+
+# Provide some information about the compiler.
+echo "$as_me:9386:" \
+ "checking for Fortran 77 compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+rm -f a.out
+
+# If we don't use `.F' as extension, the preprocessor is not run on the
+# input file. (Note that this only needs to work for GNU compilers.)
+ac_save_ext=$ac_ext
+ac_ext=F
+echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6
+if test "${ac_cv_f77_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+ program main
+#ifndef __GNUC__
+ choke me
+#endif
+
+ end
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_f77_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_f77_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6
+ac_ext=$ac_save_ext
+ac_test_FFLAGS=${FFLAGS+set}
+ac_save_FFLAGS=$FFLAGS
+FFLAGS=
+echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5
+echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_f77_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ FFLAGS=-g
+cat >conftest.$ac_ext <<_ACEOF
+ program main
+
+ end
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_f77_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_f77_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_f77_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5
+echo "${ECHO_T}$ac_cv_prog_f77_g" >&6
+if test "$ac_test_FFLAGS" = set; then
+ FFLAGS=$ac_save_FFLAGS
+elif test $ac_cv_prog_f77_g = yes; then
+ if test "x$ac_cv_f77_compiler_gnu" = xyes; then
+ FFLAGS="-g -O2"
+ else
+ FFLAGS="-g"
+ fi
+else
+ if test "x$ac_cv_f77_compiler_gnu" = xyes; then
+ FFLAGS="-O2"
+ else
+ FFLAGS=
+ fi
+fi
+
+G77=`test $ac_compiler_gnu = yes && echo yes`
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+
+# find the maximum length of command line arguments
+echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5
+echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* )
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for *BSD
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ ;;
+
+ *)
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ while (test "X"`$SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \
+ = "XX$teststring") >/dev/null 2>&1 &&
+ new_result=`expr "X$teststring" : ".*" 2>&1` &&
+ lt_cv_sys_max_cmd_len=$new_result &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on massive
+ # amounts of additional arguments before passing them to the linker.
+ # It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ ;;
+ esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5
+echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6
+else
+ echo "$as_me:$LINENO: result: none" >&5
+echo "${ECHO_T}none" >&6
+fi
+
+
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5
+echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6
+if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Transform the above into a raw symbol and a C symbol.
+symxfrm='\1 \2\3 \3'
+
+# Transform an extracted symbol line into a proper C declaration
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*) # Its linker distinguishes data from code symbols
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDEGRST]'
+ fi
+ lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+ lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+ ;;
+linux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDGIRSTW]'
+ lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+ lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris* | sysv5*)
+ symcode='[BDRT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Write the raw and C identifiers.
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5
+ (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if grep ' nm_test_var$' "$nlist" >/dev/null; then
+ if grep ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+
+ cat <<EOF >> conftest.$ac_ext
+#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[] =
+{
+EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+ cat <<\EOF >> conftest.$ac_ext
+ {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -f conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ echo "$as_me:$LINENO: result: failed" >&5
+echo "${ECHO_T}failed" >&6
+else
+ echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+fi
+
+echo "$as_me:$LINENO: checking for objdir" >&5
+echo $ECHO_N "checking for objdir... $ECHO_C" >&6
+if test "${lt_cv_objdir+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5
+echo "${ECHO_T}$lt_cv_objdir" >&6
+objdir=$lt_cv_objdir
+
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e s/^X//'
+sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Constants:
+rm="rm -f"
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except M$VC,
+# which needs '.lib').
+libext=a
+ltmain="$ac_aux_dir/ltmain.sh"
+ofile="$default_ofile"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_AR" && ac_cv_prog_ac_ct_AR="false"
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+echo "${ECHO_T}$ac_ct_AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ AR=$ac_ct_AR
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ STRIP=$ac_ct_STRIP
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$NM" && NM=nm
+test -z "$SED" && SED=sed
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$ac_objext" && ac_objext=o
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
+ ;;
+ *)
+ old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5
+echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/${ac_tool_prefix}file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+echo "${ECHO_T}$MAGIC_CMD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ echo "$as_me:$LINENO: checking for file" >&5
+echo $ECHO_N "checking for file... $ECHO_C" >&6
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+echo "${ECHO_T}$MAGIC_CMD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+enable_dlopen=no
+enable_win32_dll=no
+
+# Check whether --enable-libtool-lock or --disable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then
+ enableval="$enable_libtool_lock"
+
+fi;
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+
+# Check whether --with-pic or --without-pic was given.
+if test "${with_pic+set}" = set; then
+ withval="$with_pic"
+ pic_mode="$withval"
+else
+ pic_mode=default
+fi;
+test -z "$pic_mode" && pic_mode=default
+
+# Use C for the default configuration in the libtool script
+tagname=
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}\n'
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+#
+# Check for any special shared library compilation flags.
+#
+lt_prog_cc_shlib=
+if test "$GCC" = no; then
+ case $host_os in
+ sco3.2v5*)
+ lt_prog_cc_shlib='-belf'
+ ;;
+ esac
+fi
+if test -n "$lt_prog_cc_shlib"; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&5
+echo "$as_me: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&2;}
+ if echo "$old_CC $old_CFLAGS " | grep "[ ]$lt_prog_cc_shlib[ ]" >/dev/null; then :
+ else
+ { echo "$as_me:$LINENO: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&5
+echo "$as_me: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&2;}
+ lt_cv_prog_cc_can_build_shared=no
+ fi
+fi
+
+
+#
+# Check to make sure the static flag actually works.
+#
+echo "$as_me:$LINENO: checking if $compiler static flag $lt_prog_compiler_static works" >&5
+echo $ECHO_N "checking if $compiler static flag $lt_prog_compiler_static works... $ECHO_C" >&6
+if test "${lt_prog_compiler_static_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_prog_compiler_static"
+ printf "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ else
+ lt_prog_compiler_static_works=yes
+ fi
+ fi
+ $rm conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5
+echo "${ECHO_T}$lt_prog_compiler_static_works" >&6
+
+if test x"$lt_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin'
+
+
+echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:10447: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:10451: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+
+ beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case "$cc_basename" in
+ xlc*)
+ lt_prog_compiler_pic='-qnocommon'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ esac
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ linux*)
+ case $CC in
+ icc* | ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ esac
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ sco3.2v5*)
+ lt_prog_compiler_pic='-Kpic'
+ lt_prog_compiler_static='-dn'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:10690: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:10694: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_prog_compiler_pic_works=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works" >&6
+
+if test x"$lt_prog_compiler_pic_works" = xyes; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+case "$host_os" in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:10750: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:10754: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s out/conftest.err; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w .
+ $rm conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+ $rm out/* && rmdir out
+ cd ..
+ rmdir conftest
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+ if test "$hard_links" = no; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+ runpath_var=
+ allow_undefined_flag=
+ enable_shared_with_static_runtimes=no
+ archive_cmds=
+ archive_expsym_cmds=
+ old_archive_From_new_cmds=
+ old_archive_from_expsyms_cmds=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ thread_safe_flag_spec=
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld=
+ hardcode_libdir_separator=
+ hardcode_direct=no
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ link_all_deplibs=unknown
+ hardcode_automatic=no
+ module_cmds=
+ module_expsym_cmds=
+ always_export_symbols=no
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can't use
+ # them.
+ ld_shlibs=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris* | sysv5*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds="$tmp_archive_cmds"
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ archive_expsym_cmds="$tmp_archive_cmds"
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = yes; then
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes && test -z "$link_static_flag"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.012|aix4.012.*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct=yes
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bernotok'
+ allow_undefined_flag=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols=yes
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec=' '
+ archive_cmds_need_lc=yes
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs=no
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_From_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ darwin* | rhapsody*)
+ case "$host_os" in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ whole_archive_flag_spec=''
+ link_all_deplibs=yes
+ if test "$GCC" = yes ; then
+ output_verbose_link_cmd='echo'
+ archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ case "$cc_basename" in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ archive_cmds='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+ module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+ fi
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | kfreebsd*-gnu)
+ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ hpux10* | hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ *)
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*)
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld='+b $libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ ia64*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ *)
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_ld='-rpath $libdir'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ link_all_deplibs=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ openbsd*)
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ hardcode_libdir_separator=:
+ ;;
+
+ sco3.2v5*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='${wl}-Bexport'
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z text'
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+ else
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4.2uw2*)
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=no
+ hardcode_runpath_var=yes
+ runpath_var=LD_RUN_PATH
+ ;;
+
+ sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
+ no_undefined_flag='${wl}-z ${wl}text'
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv5*)
+ no_undefined_flag=' -z text'
+ # $CC -shared without GNU ld will not create a library from C++
+ # object files and a static libstdc++, better avoid it by now
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ hardcode_libdir_flag_spec=
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $ld_shlibs" >&5
+echo "${ECHO_T}$ld_shlibs" >&6
+test "$ld_shlibs" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+ $rm conftest*
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+ (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ then
+ archive_cmds_need_lc=no
+ else
+ archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $rm conftest*
+ echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5
+echo "${ECHO_T}$archive_cmds_need_lc" >&6
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $rm \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+ # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+ if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+ else
+ sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+ fi
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+kfreebsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+freebsd*)
+ objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.01* | freebsdelf3.01*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ *) # from 3.2 on
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case "$host_cpu" in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+knetbsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+nto-qnx*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+sco3.2v5*)
+ version_type=osf
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" || \
+ test -n "$runpath_var" || \
+ test "X$hardcode_automatic" = "Xyes" ; then
+
+ # We can hardcode non-existant directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action" >&5
+echo "${ECHO_T}$hardcode_action" >&6
+
+if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+ ;;
+ *)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ esac
+fi
+
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ echo "$as_me:$LINENO: checking for shl_load" >&5
+echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
+if test "${ac_cv_func_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shl_load (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+char (*f) () = shl_load;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != shl_load;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+echo "${ECHO_T}$ac_cv_func_shl_load" >&6
+if test $ac_cv_func_shl_load = yes; then
+ lt_cv_dlopen="shl_load"
+else
+ echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
+else
+ echo "$as_me:$LINENO: checking for dlopen" >&5
+echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
+if test "${ac_cv_func_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char dlopen (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+char (*f) () = dlopen;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != dlopen;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+echo "${ECHO_T}$ac_cv_func_dlopen" >&6
+if test $ac_cv_func_dlopen = yes; then
+ lt_cv_dlopen="dlopen"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_svld_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_svld_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
+if test $ac_cv_lib_svld_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dld_link ();
+int
+main ()
+{
+dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_dld_link=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_dld_link=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
+if test $ac_cv_lib_dld_dld_link = yes; then
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 12935 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self" >&6
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ LDFLAGS="$LDFLAGS $link_static_flag"
+ echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 13033 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+# Report which libraries types will actually be built
+echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $can_build_shared" >&5
+echo "${ECHO_T}$can_build_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+aix4* | aix5*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+esac
+echo "$as_me:$LINENO: result: $enable_shared" >&5
+echo "${ECHO_T}$enable_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+echo "$as_me:$LINENO: result: $enable_static" >&5
+echo "${ECHO_T}$enable_static" >&6
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ compiler \
+ CC \
+ LD \
+ lt_prog_compiler_wl \
+ lt_prog_compiler_pic \
+ lt_prog_compiler_static \
+ lt_prog_compiler_no_builtin_flag \
+ export_dynamic_flag_spec \
+ thread_safe_flag_spec \
+ whole_archive_flag_spec \
+ enable_shared_with_static_runtimes \
+ old_archive_cmds \
+ old_archive_from_new_cmds \
+ predep_objects \
+ postdep_objects \
+ predeps \
+ postdeps \
+ compiler_lib_search_path \
+ archive_cmds \
+ archive_expsym_cmds \
+ postinstall_cmds \
+ postuninstall_cmds \
+ old_archive_from_expsyms_cmds \
+ allow_undefined_flag \
+ no_undefined_flag \
+ export_symbols_cmds \
+ hardcode_libdir_flag_spec \
+ hardcode_libdir_flag_spec_ld \
+ hardcode_libdir_separator \
+ hardcode_automatic \
+ module_cmds \
+ module_expsym_cmds \
+ lt_cv_prog_compiler_c_o \
+ exclude_expsyms \
+ include_expsyms; do
+
+ case $var in
+ old_archive_cmds | \
+ old_archive_from_new_cmds | \
+ archive_cmds | \
+ archive_expsym_cmds | \
+ module_cmds | \
+ module_expsym_cmds | \
+ old_archive_from_expsyms_cmds | \
+ export_symbols_cmds | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\$0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+cfgfile="${ofile}T"
+ trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+ $rm -f "$cfgfile"
+ { echo "$as_me:$LINENO: creating $ofile" >&5
+echo "$as_me: creating $ofile" >&6;}
+
+ cat <<__EOF__ >> "$cfgfile"
+#! $SHELL
+
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 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.
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="$SED -e s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# The names of the tagged configurations supported by this script.
+available_tags=
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# ### END LIBTOOL CONFIG
+
+__EOF__
+
+
+ case $host_os in
+ aix3*)
+ cat <<\EOF >> "$cfgfile"
+
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+EOF
+ ;;
+ esac
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" || \
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+# Check whether --with-tags or --without-tags was given.
+if test "${with_tags+set}" = set; then
+ withval="$with_tags"
+ tagnames="$withval"
+fi;
+
+if test -f "$ltmain" && test -n "$tagnames"; then
+ if test ! -f "${ofile}"; then
+ { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not exist" >&5
+echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;}
+ fi
+
+ if test -z "$LTCC"; then
+ eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+ if test -z "$LTCC"; then
+ { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not look like a libtool script" >&5
+echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;}
+ else
+ { echo "$as_me:$LINENO: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5
+echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;}
+ fi
+ fi
+
+ # Extract list of available tagged configurations in $ofile.
+ # Note that this assumes the entire list is on one line.
+ available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
+
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for tagname in $tagnames; do
+ IFS="$lt_save_ifs"
+ # Check whether tagname contains only valid characters
+ case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in
+ "") ;;
+ *) { { echo "$as_me:$LINENO: error: invalid tag name: $tagname" >&5
+echo "$as_me: error: invalid tag name: $tagname" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ esac
+
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+ then
+ { { echo "$as_me:$LINENO: error: tag name \"$tagname\" already exists" >&5
+echo "$as_me: error: tag name \"$tagname\" already exists" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ # Update the list of available tags.
+ if test -n "$tagname"; then
+ echo appending configuration tag \"$tagname\" to $ofile
+
+ case $tagname in
+ CXX)
+ if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+
+archive_cmds_need_lc_CXX=no
+allow_undefined_flag_CXX=
+always_export_symbols_CXX=no
+archive_expsym_cmds_CXX=
+export_dynamic_flag_spec_CXX=
+hardcode_direct_CXX=no
+hardcode_libdir_flag_spec_CXX=
+hardcode_libdir_flag_spec_ld_CXX=
+hardcode_libdir_separator_CXX=
+hardcode_minus_L_CXX=no
+hardcode_automatic_CXX=no
+module_cmds_CXX=
+module_expsym_cmds_CXX=
+link_all_deplibs_CXX=unknown
+old_archive_cmds_CXX=$old_archive_cmds
+no_undefined_flag_CXX=
+whole_archive_flag_spec_CXX=
+enable_shared_with_static_runtimes_CXX=no
+
+# Dependencies to place before and after the object being linked:
+predep_objects_CXX=
+postdep_objects_CXX=
+predeps_CXX=
+postdeps_CXX=
+compiler_lib_search_path_CXX=
+
+# Source file extension for C++ test sources.
+ac_ext=cc
+
+# Object file extension for compiled C++ test sources.
+objext=o
+objext_CXX=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(int, char *) { return(0); }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_LD=$LD
+lt_save_GCC=$GCC
+GCC=$GXX
+lt_save_with_gnu_ld=$with_gnu_ld
+lt_save_path_LD=$lt_cv_path_LD
+if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+else
+ unset lt_cv_prog_gnu_ld
+fi
+if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+else
+ unset lt_cv_path_LD
+fi
+test -z "${LDCXX+set}" || LD=$LDCXX
+CC=${CXX-"c++"}
+compiler=$CC
+compiler_CXX=$CC
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+# We don't want -fno-exception wen compiling C++ code, so set the
+# no_builtin_flag separately
+if test "$GXX" = yes; then
+ lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+else
+ lt_prog_compiler_no_builtin_flag_CXX=
+fi
+
+if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+ withval="$with_gnu_ld"
+ test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi;
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ echo "$as_me:$LINENO: checking for GNU ld" >&5
+echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6
+else
+ echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6
+fi
+if test "${lt_cv_path_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some GNU ld's only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
+if test "${lt_cv_prog_gnu_ld+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+ grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_CXX=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+fi
+
+# PORTME: fill in a description of your system's C++ link characteristics
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+ld_shlibs_CXX=yes
+case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds_CXX=''
+ hardcode_direct_CXX=yes
+ hardcode_libdir_separator_CXX=':'
+ link_all_deplibs_CXX=yes
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.012|aix4.012.*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct_CXX=yes
+ else
+ # We have old collect2
+ hardcode_direct_CXX=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L_CXX=yes
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ hardcode_libdir_separator_CXX=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols_CXX=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag_CXX='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag_CXX="-z nodefs"
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag_CXX=' ${wl}-bernotok'
+ allow_undefined_flag_CXX=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols_CXX=yes
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec_CXX=' '
+ archive_cmds_need_lc_CXX=yes
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ allow_undefined_flag_CXX=unsupported
+ always_export_symbols_CXX=no
+ enable_shared_with_static_runtimes_CXX=yes
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ darwin* | rhapsody*)
+ case "$host_os" in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag_CXX='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag_CXX='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ archive_cmds_need_lc_CXX=no
+ hardcode_direct_CXX=no
+ hardcode_automatic_CXX=yes
+ hardcode_shlibpath_var_CXX=unsupported
+ whole_archive_flag_spec_CXX=''
+ link_all_deplibs_CXX=yes
+
+ if test "$GXX" = yes ; then
+ lt_int_apple_cc_single_mod=no
+ output_verbose_link_cmd='echo'
+ if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then
+ lt_int_apple_cc_single_mod=yes
+ fi
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ else
+ archive_cmds_CXX='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ fi
+ module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ case "$cc_basename" in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ archive_cmds_CXX='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+ module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ fi
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ ghcx)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+ freebsd12*)
+ # C++ shared libraries reported to be fairly broken before switch to ELF
+ ld_shlibs_CXX=no
+ ;;
+ freebsd-elf*)
+ archive_cmds_need_lc_CXX=no
+ ;;
+ freebsd* | kfreebsd*-gnu)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ ld_shlibs_CXX=yes
+ ;;
+ gnu*)
+ ;;
+ hpux9*)
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ hardcode_direct_CXX=yes
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aCC)
+ archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ case "$host_cpu" in
+ hppa*64*)
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld_CXX='+b $libdir'
+ hardcode_libdir_separator_CXX=:
+ ;;
+ ia64*)
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ ;;
+ *)
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ ;;
+ esac
+ fi
+ case "$host_cpu" in
+ hppa*64*)
+ hardcode_direct_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ ;;
+ ia64*)
+ hardcode_direct_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ *)
+ hardcode_direct_CXX=yes
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aCC)
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case "$host_cpu" in
+ ia64*|hppa*64*)
+ archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC)
+ # SGI C++
+ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ else
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+ fi
+ fi
+ link_all_deplibs_CXX=yes
+ ;;
+ esac
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ ;;
+ linux*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+ hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc)
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ archive_cmds_need_lc_CXX=no
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ cxx)
+ # Compaq C++
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ esac
+ ;;
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ m88k*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ hardcode_direct_CXX=yes
+ hardcode_shlibpath_var_CXX=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ ld_shlibs_CXX=no
+ ;;
+ openbsd*)
+ hardcode_direct_CXX=yes
+ hardcode_shlibpath_var_CXX=no
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd='echo'
+ ;;
+ osf3*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ cxx)
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+ osf4* | osf5*)
+ case $cc_basename in
+ KCC)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ old_archive_cmds_CXX='$CC -o $oldlib $oldobjs'
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ cxx)
+ allow_undefined_flag_CXX=' -expect_unresolved \*'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~
+ $rm $lib.exp'
+
+ hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+ psos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ sco*)
+ archive_cmds_need_lc_CXX=no
+ case $cc_basename in
+ CC)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ lcc)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ no_undefined_flag_CXX=' -zdefs'
+ archive_cmds_CXX='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ hardcode_shlibpath_var_CXX=no
+ case $host_os in
+ solaris2.0-5 | solaris2.0-5.*) ;;
+ *)
+ # The C++ compiler is used as linker so we must use $wl
+ # flag to pass the commands to the underlying system
+ # linker.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ link_all_deplibs_CXX=yes
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[LR]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx)
+ # Green Hills C++ Compiler
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ no_undefined_flag_CXX=' ${wl}-z ${wl}defs'
+ if $CC --version | grep -v '^2\.7' > /dev/null; then
+ archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+ fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir'
+ fi
+ ;;
+ esac
+ ;;
+ sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
+ archive_cmds_need_lc_CXX=no
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5
+echo "${ECHO_T}$ld_shlibs_CXX" >&6
+test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+GCC_CXX="$GXX"
+LD_CXX="$LD"
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+
+cat > conftest.$ac_ext <<EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+EOF
+
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ # The `*' in the case matches for architectures that use `case' in
+ # $output_verbose_cmd can trigger glob expansion during the loop
+ # eval without this substitution.
+ output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`"
+
+ for p in `eval $output_verbose_link_cmd`; do
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" \
+ || test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$compiler_lib_search_path_CXX"; then
+ compiler_lib_search_path_CXX="${prev}${p}"
+ else
+ compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$postdeps_CXX"; then
+ postdeps_CXX="${prev}${p}"
+ else
+ postdeps_CXX="${postdeps_CXX} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$predep_objects_CXX"; then
+ predep_objects_CXX="$p"
+ else
+ predep_objects_CXX="$predep_objects_CXX $p"
+ fi
+ else
+ if test -z "$postdep_objects_CXX"; then
+ postdep_objects_CXX="$p"
+ else
+ postdep_objects_CXX="$postdep_objects_CXX $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling CXX test program"
+fi
+
+$rm -f confest.$objext
+
+case " $postdeps_CXX " in
+*" -lc "*) archive_cmds_need_lc_CXX=no ;;
+esac
+
+lt_prog_compiler_wl_CXX=
+lt_prog_compiler_pic_CXX=
+lt_prog_compiler_static_CXX=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_CXX='-Bstatic'
+ fi
+ ;;
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | os2* | pw32*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic_CXX='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ lt_prog_compiler_pic_CXX=
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic_CXX=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ esac
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix4* | aix5*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_CXX='-Bstatic'
+ else
+ lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68)
+ # Green Hills C++ Compiler
+ # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case "$cc_basename" in
+ xlc*)
+ lt_prog_compiler_pic_CXX='-qnocommon'
+ lt_prog_compiler_wl_CXX='-Wl,'
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++)
+ lt_prog_compiler_pic_CXX='-KPIC'
+ ;;
+ ghcx)
+ # Green Hills C++ Compiler
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | kfreebsd*-gnu)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+ if test "$host_cpu" != ia64; then
+ lt_prog_compiler_pic_CXX='+Z'
+ fi
+ ;;
+ aCC)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux*)
+ case $cc_basename in
+ KCC)
+ # KAI C++ Compiler
+ lt_prog_compiler_wl_CXX='--backend -Wl,'
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ icpc)
+ # Intel C++
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-static'
+ ;;
+ cxx)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_static_CXX='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx)
+ lt_prog_compiler_pic_CXX='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd*)
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC)
+ lt_prog_compiler_wl_CXX='--backend -Wl,'
+ ;;
+ RCC)
+ # Rational C++ 2.4.1
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ cxx)
+ # Digital/Compaq C++
+ lt_prog_compiler_wl_CXX='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_static_CXX='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ sco*)
+ case $cc_basename in
+ CC)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ lt_prog_compiler_wl_CXX='-Qoption ld '
+ ;;
+ gcx)
+ # Green Hills C++ Compiler
+ lt_prog_compiler_pic_CXX='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC)
+ # Sun C++ 4.x
+ lt_prog_compiler_pic_CXX='-pic'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ lcc)
+ # Lucid
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC)
+ # NonStop-UX NCC 3.20
+ lt_prog_compiler_pic_CXX='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ unixware*)
+ ;;
+ vxworks*)
+ ;;
+ *)
+ lt_prog_compiler_can_build_shared_CXX=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_CXX" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_CXX"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_pic_works_CXX=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:15230: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:15234: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_prog_compiler_pic_works_CXX=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_CXX" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works_CXX" >&6
+
+if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then
+ case $lt_prog_compiler_pic_CXX in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
+ esac
+else
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_can_build_shared_CXX=no
+fi
+
+fi
+case "$host_os" in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic_CXX=
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC"
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o_CXX=no
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:15290: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:15294: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s out/conftest.err; then
+ lt_cv_prog_compiler_c_o_CXX=yes
+ fi
+ fi
+ chmod u+w .
+ $rm conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+ $rm out/* && rmdir out
+ cd ..
+ rmdir conftest
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o_CXX" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+ if test "$hard_links" = no; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ case $host_os in
+ aix4* | aix5*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ export_symbols_cmds_CXX="$ltdll_cmds"
+ ;;
+ cygwin* | mingw*)
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ *)
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+
+echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5
+echo "${ECHO_T}$ld_shlibs_CXX" >&6
+test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_CXX" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc_CXX=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds_CXX in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+ $rm conftest*
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl_CXX
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
+ allow_undefined_flag_CXX=
+ if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+ (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ then
+ archive_cmds_need_lc_CXX=no
+ else
+ archive_cmds_need_lc_CXX=yes
+ fi
+ allow_undefined_flag_CXX=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $rm conftest*
+ echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5
+echo "${ECHO_T}$archive_cmds_need_lc_CXX" >&6
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $rm \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+ # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+ if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+ else
+ sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+ fi
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+kfreebsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+freebsd*)
+ objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.01* | freebsdelf3.01*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ *) # from 3.2 on
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case "$host_cpu" in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+knetbsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+nto-qnx*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+sco3.2v5*)
+ version_type=osf
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action_CXX=
+if test -n "$hardcode_libdir_flag_spec_CXX" || \
+ test -n "$runpath_var_CXX" || \
+ test "X$hardcode_automatic_CXX" = "Xyes" ; then
+
+ # We can hardcode non-existant directories.
+ if test "$hardcode_direct_CXX" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no &&
+ test "$hardcode_minus_L_CXX" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action_CXX=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action_CXX=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action_CXX=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5
+echo "${ECHO_T}$hardcode_action_CXX" >&6
+
+if test "$hardcode_action_CXX" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+ ;;
+ *)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ esac
+fi
+
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ echo "$as_me:$LINENO: checking for shl_load" >&5
+echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
+if test "${ac_cv_func_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shl_load (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+char (*f) () = shl_load;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != shl_load;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+echo "${ECHO_T}$ac_cv_func_shl_load" >&6
+if test $ac_cv_func_shl_load = yes; then
+ lt_cv_dlopen="shl_load"
+else
+ echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
+else
+ echo "$as_me:$LINENO: checking for dlopen" >&5
+echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
+if test "${ac_cv_func_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char dlopen (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+char (*f) () = dlopen;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != dlopen;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+echo "${ECHO_T}$ac_cv_func_dlopen" >&6
+if test $ac_cv_func_dlopen = yes; then
+ lt_cv_dlopen="dlopen"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_svld_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_svld_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
+if test $ac_cv_lib_svld_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dld_link ();
+int
+main ()
+{
+dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_dld_link=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_dld_link=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
+if test $ac_cv_lib_dld_dld_link = yes; then
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 16651 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self" >&6
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ LDFLAGS="$LDFLAGS $link_static_flag"
+ echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 16749 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ compiler_CXX \
+ CC_CXX \
+ LD_CXX \
+ lt_prog_compiler_wl_CXX \
+ lt_prog_compiler_pic_CXX \
+ lt_prog_compiler_static_CXX \
+ lt_prog_compiler_no_builtin_flag_CXX \
+ export_dynamic_flag_spec_CXX \
+ thread_safe_flag_spec_CXX \
+ whole_archive_flag_spec_CXX \
+ enable_shared_with_static_runtimes_CXX \
+ old_archive_cmds_CXX \
+ old_archive_from_new_cmds_CXX \
+ predep_objects_CXX \
+ postdep_objects_CXX \
+ predeps_CXX \
+ postdeps_CXX \
+ compiler_lib_search_path_CXX \
+ archive_cmds_CXX \
+ archive_expsym_cmds_CXX \
+ postinstall_cmds_CXX \
+ postuninstall_cmds_CXX \
+ old_archive_from_expsyms_cmds_CXX \
+ allow_undefined_flag_CXX \
+ no_undefined_flag_CXX \
+ export_symbols_cmds_CXX \
+ hardcode_libdir_flag_spec_CXX \
+ hardcode_libdir_flag_spec_ld_CXX \
+ hardcode_libdir_separator_CXX \
+ hardcode_automatic_CXX \
+ module_cmds_CXX \
+ module_expsym_cmds_CXX \
+ lt_cv_prog_compiler_c_o_CXX \
+ exclude_expsyms_CXX \
+ include_expsyms_CXX; do
+
+ case $var in
+ old_archive_cmds_CXX | \
+ old_archive_from_new_cmds_CXX | \
+ archive_cmds_CXX | \
+ archive_expsym_cmds_CXX | \
+ module_cmds_CXX | \
+ module_expsym_cmds_CXX | \
+ old_archive_from_expsyms_cmds_CXX | \
+ export_symbols_cmds_CXX | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\$0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+cfgfile="$ofile"
+
+ cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_CXX
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_CXX
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_CXX
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_CXX
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_CXX
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_CXX
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_CXX
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_CXX
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_CXX
+archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_CXX
+module_expsym_cmds=$lt_module_expsym_cmds_CXX
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_CXX
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_CXX
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_CXX
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_CXX
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_CXX
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_CXX
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_CXX
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_CXX
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_CXX
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_CXX
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_CXX
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_CXX"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_CXX
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_CXX
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_CXX
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_CXX
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC=$lt_save_CC
+LDCXX=$LD
+LD=$lt_save_LD
+GCC=$lt_save_GCC
+with_gnu_ldcxx=$with_gnu_ld
+with_gnu_ld=$lt_save_with_gnu_ld
+lt_cv_path_LDCXX=$lt_cv_path_LD
+lt_cv_path_LD=$lt_save_path_LD
+lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+
+ else
+ tagname=""
+ fi
+ ;;
+
+ F77)
+ if test -n "$F77" && test "X$F77" != "Xno"; then
+
+ac_ext=f
+ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
+ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_f77_compiler_gnu
+
+
+archive_cmds_need_lc_F77=no
+allow_undefined_flag_F77=
+always_export_symbols_F77=no
+archive_expsym_cmds_F77=
+export_dynamic_flag_spec_F77=
+hardcode_direct_F77=no
+hardcode_libdir_flag_spec_F77=
+hardcode_libdir_flag_spec_ld_F77=
+hardcode_libdir_separator_F77=
+hardcode_minus_L_F77=no
+hardcode_automatic_F77=no
+module_cmds_F77=
+module_expsym_cmds_F77=
+link_all_deplibs_F77=unknown
+old_archive_cmds_F77=$old_archive_cmds
+no_undefined_flag_F77=
+whole_archive_flag_spec_F77=
+enable_shared_with_static_runtimes_F77=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+objext_F77=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code=" subroutine t\n return\n end\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code=" program t\n end\n"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${F77-"f77"}
+compiler=$CC
+compiler_F77=$CC
+cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+
+echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $can_build_shared" >&5
+echo "${ECHO_T}$can_build_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+aix4* | aix5*)
+ test "$enable_shared" = yes && enable_static=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $enable_shared" >&5
+echo "${ECHO_T}$enable_shared" >&6
+
+echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+echo "$as_me:$LINENO: result: $enable_static" >&5
+echo "${ECHO_T}$enable_static" >&6
+
+test "$ld_shlibs_F77" = no && can_build_shared=no
+
+GCC_F77="$G77"
+LD_F77="$LD"
+
+lt_prog_compiler_wl_F77=
+lt_prog_compiler_pic_F77=
+lt_prog_compiler_static_F77=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl_F77='-Wl,'
+ lt_prog_compiler_static_F77='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_F77='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4'
+ ;;
+
+ beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_F77='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic_F77='-fno-common'
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared_F77=no
+ enable_shared=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic_F77=-Kconform_pic
+ fi
+ ;;
+
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_F77='-fPIC'
+ ;;
+ esac
+ ;;
+
+ *)
+ lt_prog_compiler_pic_F77='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_F77='-Bstatic'
+ else
+ lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case "$cc_basename" in
+ xlc*)
+ lt_prog_compiler_pic_F77='-qnocommon'
+ lt_prog_compiler_wl_F77='-Wl,'
+ ;;
+ esac
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_F77='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_F77='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static_F77='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static_F77='-non_shared'
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic_F77='-KPIC'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
+
+ linux*)
+ case $CC in
+ icc* | ecc*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ lt_prog_compiler_pic_F77='-KPIC'
+ lt_prog_compiler_static_F77='-static'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static_F77='-non_shared'
+ ;;
+ esac
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static_F77='-non_shared'
+ ;;
+
+ sco3.2v5*)
+ lt_prog_compiler_pic_F77='-Kpic'
+ lt_prog_compiler_static_F77='-dn'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ lt_prog_compiler_pic_F77='-KPIC'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl_F77='-Qoption ld '
+ lt_prog_compiler_pic_F77='-PIC'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ lt_prog_compiler_pic_F77='-KPIC'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic_F77='-Kconform_pic'
+ lt_prog_compiler_static_F77='-Bstatic'
+ fi
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic_F77='-pic'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared_F77=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_F77" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_F77" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_F77"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works_F77+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_pic_works_F77=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic_F77"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:17586: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:17590: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_prog_compiler_pic_works_F77=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_F77" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works_F77" >&6
+
+if test x"$lt_prog_compiler_pic_works_F77" = xyes; then
+ case $lt_prog_compiler_pic_F77 in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;;
+ esac
+else
+ lt_prog_compiler_pic_F77=
+ lt_prog_compiler_can_build_shared_F77=no
+fi
+
+fi
+case "$host_os" in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic_F77=
+ ;;
+ *)
+ lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77"
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o_F77=no
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:17646: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:17650: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s out/conftest.err; then
+ lt_cv_prog_compiler_c_o_F77=yes
+ fi
+ fi
+ chmod u+w .
+ $rm conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+ $rm out/* && rmdir out
+ cd ..
+ rmdir conftest
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_F77" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o_F77" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+ if test "$hard_links" = no; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+ runpath_var=
+ allow_undefined_flag_F77=
+ enable_shared_with_static_runtimes_F77=no
+ archive_cmds_F77=
+ archive_expsym_cmds_F77=
+ old_archive_From_new_cmds_F77=
+ old_archive_from_expsyms_cmds_F77=
+ export_dynamic_flag_spec_F77=
+ whole_archive_flag_spec_F77=
+ thread_safe_flag_spec_F77=
+ hardcode_libdir_flag_spec_F77=
+ hardcode_libdir_flag_spec_ld_F77=
+ hardcode_libdir_separator_F77=
+ hardcode_direct_F77=no
+ hardcode_minus_L_F77=no
+ hardcode_shlibpath_var_F77=unsupported
+ link_all_deplibs_F77=unknown
+ hardcode_automatic_F77=no
+ module_cmds_F77=
+ module_expsym_cmds_F77=
+ always_export_symbols_F77=no
+ export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms_F77=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms_F77="_GLOBAL_OFFSET_TABLE_"
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs_F77=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs_F77=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_minus_L_F77=yes
+
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can't use
+ # them.
+ ld_shlibs_F77=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag_F77=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs_F77=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ allow_undefined_flag_F77=unsupported
+ always_export_symbols_F77=no
+ enable_shared_with_static_runtimes_F77=yes
+ export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris* | sysv5*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs_F77=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_F77=no
+ fi
+ ;;
+
+ sunos4*)
+ archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds_F77="$tmp_archive_cmds"
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ archive_expsym_cmds_F77="$tmp_archive_cmds"
+ fi
+ else
+ ld_shlibs_F77=no
+ fi
+ ;;
+
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_F77=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs_F77" = yes; then
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_F77='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_F77=
+ fi
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag_F77=unsupported
+ always_export_symbols_F77=yes
+ archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L_F77=yes
+ if test "$GCC" = yes && test -z "$link_static_flag"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct_F77=unsupported
+ fi
+ ;;
+
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds_F77=''
+ hardcode_direct_F77=yes
+ hardcode_libdir_separator_F77=':'
+ link_all_deplibs_F77=yes
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.012|aix4.012.*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct_F77=yes
+ else
+ # We have old collect2
+ hardcode_direct_F77=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L_F77=yes
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_libdir_separator_F77=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols_F77=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag_F77='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+ program main
+
+ end
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_f77_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag_F77="-z nodefs"
+ archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+ program main
+
+ end
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_f77_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag_F77=' ${wl}-bernotok'
+ allow_undefined_flag_F77=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols_F77=yes
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec_F77=' '
+ archive_cmds_need_lc_F77=yes
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_minus_L_F77=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs_F77=no
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec_F77=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec_F77=' '
+ allow_undefined_flag_F77=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_From_new_cmds_F77='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds_F77='lib /OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes_F77=yes
+ ;;
+
+ darwin* | rhapsody*)
+ case "$host_os" in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag_F77='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag_F77='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ archive_cmds_need_lc_F77=no
+ hardcode_direct_F77=no
+ hardcode_automatic_F77=yes
+ hardcode_shlibpath_var_F77=unsupported
+ whole_archive_flag_spec_F77=''
+ link_all_deplibs_F77=yes
+ if test "$GCC" = yes ; then
+ output_verbose_link_cmd='echo'
+ archive_cmds_F77='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ case "$cc_basename" in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ archive_cmds_F77='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+ module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ ld_shlibs_F77=no
+ ;;
+ esac
+ fi
+ ;;
+
+ dgux*)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ freebsd1*)
+ ld_shlibs_F77=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec_F77='-R$libdir'
+ hardcode_direct_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_F77=yes
+ hardcode_minus_L_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | kfreebsd*-gnu)
+ archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_F77='-R$libdir'
+ hardcode_direct_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+ hardcode_direct_F77=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_F77=yes
+ export_dynamic_flag_spec_F77='${wl}-E'
+ ;;
+
+ hpux10* | hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds_F77='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ *)
+ archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*)
+ hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld_F77='+b $libdir'
+ hardcode_libdir_separator_F77=:
+ hardcode_direct_F77=no
+ hardcode_shlibpath_var_F77=no
+ ;;
+ ia64*)
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_direct_F77=no
+ hardcode_shlibpath_var_F77=no
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_F77=yes
+ ;;
+ *)
+ hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+ hardcode_direct_F77=yes
+ export_dynamic_flag_spec_F77='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_F77=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_ld_F77='-rpath $libdir'
+ fi
+ hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+ link_all_deplibs_F77=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec_F77='-R$libdir'
+ hardcode_direct_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ newsos6)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_F77=yes
+ hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ openbsd*)
+ hardcode_direct_F77=yes
+ hardcode_shlibpath_var_F77=no
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_F77='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_F77='-R$libdir'
+ ;;
+ *)
+ archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_minus_L_F77=yes
+ allow_undefined_flag_F77=unsupported
+ archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag_F77=' -expect_unresolved \*'
+ archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag_F77=' -expect_unresolved \*'
+ archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec_F77='-rpath $libdir'
+ fi
+ hardcode_libdir_separator_F77=:
+ ;;
+
+ sco3.2v5*)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_F77=no
+ export_dynamic_flag_spec_F77='${wl}-Bexport'
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ;;
+
+ solaris*)
+ no_undefined_flag_F77=' -z text'
+ if test "$GCC" = yes; then
+ archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+ else
+ archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ fi
+ hardcode_libdir_flag_spec_F77='-R$libdir'
+ hardcode_shlibpath_var_F77=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' ;;
+ esac
+ link_all_deplibs_F77=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_direct_F77=yes
+ hardcode_minus_L_F77=yes
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_F77=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds_F77='$CC -r -o $output$reload_objs'
+ hardcode_direct_F77=no
+ ;;
+ motorola)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_F77=no
+ export_dynamic_flag_spec_F77='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_F77=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs_F77=yes
+ fi
+ ;;
+
+ sysv4.2uw2*)
+ archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_F77=yes
+ hardcode_minus_L_F77=no
+ hardcode_shlibpath_var_F77=no
+ hardcode_runpath_var=yes
+ runpath_var=LD_RUN_PATH
+ ;;
+
+ sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
+ no_undefined_flag_F77='${wl}-z ${wl}text'
+ if test "$GCC" = yes; then
+ archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_F77='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ sysv5*)
+ no_undefined_flag_F77=' -z text'
+ # $CC -shared without GNU ld will not create a library from C++
+ # object files and a static libstdc++, better avoid it by now
+ archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ hardcode_libdir_flag_spec_F77=
+ hardcode_shlibpath_var_F77=no
+ runpath_var='LD_RUN_PATH'
+ ;;
+
+ uts4*)
+ archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_F77='-L$libdir'
+ hardcode_shlibpath_var_F77=no
+ ;;
+
+ *)
+ ld_shlibs_F77=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5
+echo "${ECHO_T}$ld_shlibs_F77" >&6
+test "$ld_shlibs_F77" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_F77" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc_F77=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds_F77 in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+ $rm conftest*
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl_F77
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag_F77
+ allow_undefined_flag_F77=
+ if { (eval echo "$as_me:$LINENO: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+ (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ then
+ archive_cmds_need_lc_F77=no
+ else
+ archive_cmds_need_lc_F77=yes
+ fi
+ allow_undefined_flag_F77=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $rm conftest*
+ echo "$as_me:$LINENO: result: $archive_cmds_need_lc_F77" >&5
+echo "${ECHO_T}$archive_cmds_need_lc_F77" >&6
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $rm \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+ # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+ if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+ else
+ sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+ fi
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+kfreebsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+freebsd*)
+ objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.01* | freebsdelf3.01*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ *) # from 3.2 on
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case "$host_cpu" in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+knetbsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+nto-qnx*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+sco3.2v5*)
+ version_type=osf
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action_F77=
+if test -n "$hardcode_libdir_flag_spec_F77" || \
+ test -n "$runpath_var_F77" || \
+ test "X$hardcode_automatic_F77" = "Xyes" ; then
+
+ # We can hardcode non-existant directories.
+ if test "$hardcode_direct_F77" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no &&
+ test "$hardcode_minus_L_F77" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action_F77=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action_F77=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action_F77=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action_F77" >&5
+echo "${ECHO_T}$hardcode_action_F77" >&6
+
+if test "$hardcode_action_F77" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+ ;;
+ *)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ esac
+fi
+
+
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ compiler_F77 \
+ CC_F77 \
+ LD_F77 \
+ lt_prog_compiler_wl_F77 \
+ lt_prog_compiler_pic_F77 \
+ lt_prog_compiler_static_F77 \
+ lt_prog_compiler_no_builtin_flag_F77 \
+ export_dynamic_flag_spec_F77 \
+ thread_safe_flag_spec_F77 \
+ whole_archive_flag_spec_F77 \
+ enable_shared_with_static_runtimes_F77 \
+ old_archive_cmds_F77 \
+ old_archive_from_new_cmds_F77 \
+ predep_objects_F77 \
+ postdep_objects_F77 \
+ predeps_F77 \
+ postdeps_F77 \
+ compiler_lib_search_path_F77 \
+ archive_cmds_F77 \
+ archive_expsym_cmds_F77 \
+ postinstall_cmds_F77 \
+ postuninstall_cmds_F77 \
+ old_archive_from_expsyms_cmds_F77 \
+ allow_undefined_flag_F77 \
+ no_undefined_flag_F77 \
+ export_symbols_cmds_F77 \
+ hardcode_libdir_flag_spec_F77 \
+ hardcode_libdir_flag_spec_ld_F77 \
+ hardcode_libdir_separator_F77 \
+ hardcode_automatic_F77 \
+ module_cmds_F77 \
+ module_expsym_cmds_F77 \
+ lt_cv_prog_compiler_c_o_F77 \
+ exclude_expsyms_F77 \
+ include_expsyms_F77; do
+
+ case $var in
+ old_archive_cmds_F77 | \
+ old_archive_from_new_cmds_F77 | \
+ archive_cmds_F77 | \
+ archive_expsym_cmds_F77 | \
+ module_cmds_F77 | \
+ module_expsym_cmds_F77 | \
+ old_archive_from_expsyms_cmds_F77 | \
+ export_symbols_cmds_F77 | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\$0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+cfgfile="$ofile"
+
+ cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_F77
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_F77
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_F77
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_F77
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_F77
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_F77
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_F77
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_F77
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_F77
+archive_expsym_cmds=$lt_archive_expsym_cmds_F77
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_F77
+module_expsym_cmds=$lt_module_expsym_cmds_F77
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_F77
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_F77
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_F77
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_F77
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_F77
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_F77
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_F77
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_F77
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_F77
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_F77
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_F77
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_F77
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_F77
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_F77"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_F77
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_F77
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_F77
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_F77
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+ else
+ tagname=""
+ fi
+ ;;
+
+ GCJ)
+ if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+
+
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+objext_GCJ=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String argv) {}; }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${GCJ-"gcj"}
+compiler=$CC
+compiler_GCJ=$CC
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+archive_cmds_need_lc_GCJ=no
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+
+lt_prog_compiler_no_builtin_flag_GCJ=
+
+if test "$GCC" = yes; then
+ lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin'
+
+
+echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:19685: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:19689: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+lt_prog_compiler_wl_GCJ=
+lt_prog_compiler_pic_GCJ=
+lt_prog_compiler_static_GCJ=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ lt_prog_compiler_static_GCJ='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4'
+ ;;
+
+ beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_GCJ='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic_GCJ='-fno-common'
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared_GCJ=no
+ enable_shared=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic_GCJ=-Kconform_pic
+ fi
+ ;;
+
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_GCJ='-fPIC'
+ ;;
+ esac
+ ;;
+
+ *)
+ lt_prog_compiler_pic_GCJ='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ else
+ lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case "$cc_basename" in
+ xlc*)
+ lt_prog_compiler_pic_GCJ='-qnocommon'
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ ;;
+ esac
+ ;;
+
+ mingw* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_GCJ='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_GCJ='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static_GCJ='-non_shared'
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic_GCJ='-KPIC'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
+
+ linux*)
+ case $CC in
+ icc* | ecc*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ lt_prog_compiler_pic_GCJ='-KPIC'
+ lt_prog_compiler_static_GCJ='-static'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static_GCJ='-non_shared'
+ ;;
+ esac
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static_GCJ='-non_shared'
+ ;;
+
+ sco3.2v5*)
+ lt_prog_compiler_pic_GCJ='-Kpic'
+ lt_prog_compiler_static_GCJ='-dn'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ lt_prog_compiler_pic_GCJ='-KPIC'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl_GCJ='-Qoption ld '
+ lt_prog_compiler_pic_GCJ='-PIC'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ lt_prog_compiler_pic_GCJ='-KPIC'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic_GCJ='-Kconform_pic'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ fi
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic_GCJ='-pic'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared_GCJ=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_GCJ" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_GCJ" >&6
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_GCJ"; then
+
+echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works_GCJ+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_pic_works_GCJ=no
+ ac_outfile=conftest.$ac_objext
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic_GCJ"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:19928: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:19932: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s conftest.err; then
+ lt_prog_compiler_pic_works_GCJ=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_GCJ" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works_GCJ" >&6
+
+if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then
+ case $lt_prog_compiler_pic_GCJ in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;;
+ esac
+else
+ lt_prog_compiler_pic_GCJ=
+ lt_prog_compiler_can_build_shared_GCJ=no
+fi
+
+fi
+case "$host_os" in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic_GCJ=
+ ;;
+ *)
+ lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ"
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o_GCJ=no
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:19988: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:19992: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test ! -s out/conftest.err; then
+ lt_cv_prog_compiler_c_o_GCJ=yes
+ fi
+ fi
+ chmod u+w .
+ $rm conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+ $rm out/* && rmdir out
+ cd ..
+ rmdir conftest
+ $rm conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_GCJ" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o_GCJ" >&6
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+ if test "$hard_links" = no; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+ runpath_var=
+ allow_undefined_flag_GCJ=
+ enable_shared_with_static_runtimes_GCJ=no
+ archive_cmds_GCJ=
+ archive_expsym_cmds_GCJ=
+ old_archive_From_new_cmds_GCJ=
+ old_archive_from_expsyms_cmds_GCJ=
+ export_dynamic_flag_spec_GCJ=
+ whole_archive_flag_spec_GCJ=
+ thread_safe_flag_spec_GCJ=
+ hardcode_libdir_flag_spec_GCJ=
+ hardcode_libdir_flag_spec_ld_GCJ=
+ hardcode_libdir_separator_GCJ=
+ hardcode_direct_GCJ=no
+ hardcode_minus_L_GCJ=no
+ hardcode_shlibpath_var_GCJ=unsupported
+ link_all_deplibs_GCJ=unknown
+ hardcode_automatic_GCJ=no
+ module_cmds_GCJ=
+ module_expsym_cmds_GCJ=
+ always_export_symbols_GCJ=no
+ export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms_GCJ=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms_GCJ="_GLOBAL_OFFSET_TABLE_"
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs_GCJ=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs_GCJ=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_minus_L_GCJ=yes
+
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can't use
+ # them.
+ ld_shlibs_GCJ=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag_GCJ=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs_GCJ=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ allow_undefined_flag_GCJ=unsupported
+ always_export_symbols_GCJ=no
+ enable_shared_with_static_runtimes_GCJ=yes
+ export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris* | sysv5*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs_GCJ=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_GCJ=no
+ fi
+ ;;
+
+ sunos4*)
+ archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds_GCJ="$tmp_archive_cmds"
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ archive_expsym_cmds_GCJ="$tmp_archive_cmds"
+ fi
+ else
+ ld_shlibs_GCJ=no
+ fi
+ ;;
+
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_GCJ=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs_GCJ" = yes; then
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_GCJ='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_GCJ=
+ fi
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag_GCJ=unsupported
+ always_export_symbols_GCJ=yes
+ archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L_GCJ=yes
+ if test "$GCC" = yes && test -z "$link_static_flag"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct_GCJ=unsupported
+ fi
+ ;;
+
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds_GCJ=''
+ hardcode_direct_GCJ=yes
+ hardcode_libdir_separator_GCJ=':'
+ link_all_deplibs_GCJ=yes
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.012|aix4.012.*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct_GCJ=yes
+ else
+ # We have old collect2
+ hardcode_direct_GCJ=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L_GCJ=yes
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_libdir_separator_GCJ=
+ fi
+ esac
+ shared_flag='-shared'
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols_GCJ=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag_GCJ='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag_GCJ="-z nodefs"
+ archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`; fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag_GCJ=' ${wl}-bernotok'
+ allow_undefined_flag_GCJ=' ${wl}-berok'
+ # -bexpall does not export symbols beginning with underscore (_)
+ always_export_symbols_GCJ=yes
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec_GCJ=' '
+ archive_cmds_need_lc_GCJ=yes
+ # This is similar to how AIX traditionally builds it's shared libraries.
+ archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_minus_L_GCJ=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs_GCJ=no
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec_GCJ=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec_GCJ=' '
+ allow_undefined_flag_GCJ=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_From_new_cmds_GCJ='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds_GCJ='lib /OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes_GCJ=yes
+ ;;
+
+ darwin* | rhapsody*)
+ case "$host_os" in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag_GCJ='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag_GCJ='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ archive_cmds_need_lc_GCJ=no
+ hardcode_direct_GCJ=no
+ hardcode_automatic_GCJ=yes
+ hardcode_shlibpath_var_GCJ=unsupported
+ whole_archive_flag_spec_GCJ=''
+ link_all_deplibs_GCJ=yes
+ if test "$GCC" = yes ; then
+ output_verbose_link_cmd='echo'
+ archive_cmds_GCJ='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ case "$cc_basename" in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ archive_cmds_GCJ='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+ module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
+ archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ ld_shlibs_GCJ=no
+ ;;
+ esac
+ fi
+ ;;
+
+ dgux*)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ freebsd1*)
+ ld_shlibs_GCJ=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec_GCJ='-R$libdir'
+ hardcode_direct_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GCJ=yes
+ hardcode_minus_L_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | kfreebsd*-gnu)
+ archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_GCJ='-R$libdir'
+ hardcode_direct_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+ hardcode_direct_GCJ=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_GCJ=yes
+ export_dynamic_flag_spec_GCJ='${wl}-E'
+ ;;
+
+ hpux10* | hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case "$host_cpu" in
+ hppa*64*|ia64*)
+ archive_cmds_GCJ='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ *)
+ archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ case "$host_cpu" in
+ hppa*64*)
+ hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld_GCJ='+b $libdir'
+ hardcode_libdir_separator_GCJ=:
+ hardcode_direct_GCJ=no
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+ ia64*)
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_direct_GCJ=no
+ hardcode_shlibpath_var_GCJ=no
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_GCJ=yes
+ ;;
+ *)
+ hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+ hardcode_direct_GCJ=yes
+ export_dynamic_flag_spec_GCJ='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_GCJ=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir'
+ fi
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+ link_all_deplibs_GCJ=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec_GCJ='-R$libdir'
+ hardcode_direct_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ newsos6)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GCJ=yes
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ openbsd*)
+ hardcode_direct_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_GCJ='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_GCJ='-R$libdir'
+ ;;
+ *)
+ archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_minus_L_GCJ=yes
+ allow_undefined_flag_GCJ=unsupported
+ archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag_GCJ=' -expect_unresolved \*'
+ archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag_GCJ=' -expect_unresolved \*'
+ archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec_GCJ='-rpath $libdir'
+ fi
+ hardcode_libdir_separator_GCJ=:
+ ;;
+
+ sco3.2v5*)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_GCJ=no
+ export_dynamic_flag_spec_GCJ='${wl}-Bexport'
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ;;
+
+ solaris*)
+ no_undefined_flag_GCJ=' -z text'
+ if test "$GCC" = yes; then
+ archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+ else
+ archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ fi
+ hardcode_libdir_flag_spec_GCJ='-R$libdir'
+ hardcode_shlibpath_var_GCJ=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' ;;
+ esac
+ link_all_deplibs_GCJ=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_direct_GCJ=yes
+ hardcode_minus_L_GCJ=yes
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GCJ=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds_GCJ='$CC -r -o $output$reload_objs'
+ hardcode_direct_GCJ=no
+ ;;
+ motorola)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_GCJ=no
+ export_dynamic_flag_spec_GCJ='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_GCJ=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs_GCJ=yes
+ fi
+ ;;
+
+ sysv4.2uw2*)
+ archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GCJ=yes
+ hardcode_minus_L_GCJ=no
+ hardcode_shlibpath_var_GCJ=no
+ hardcode_runpath_var=yes
+ runpath_var=LD_RUN_PATH
+ ;;
+
+ sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
+ no_undefined_flag_GCJ='${wl}-z ${wl}text'
+ if test "$GCC" = yes; then
+ archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_GCJ='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ sysv5*)
+ no_undefined_flag_GCJ=' -z text'
+ # $CC -shared without GNU ld will not create a library from C++
+ # object files and a static libstdc++, better avoid it by now
+ archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ hardcode_libdir_flag_spec_GCJ=
+ hardcode_shlibpath_var_GCJ=no
+ runpath_var='LD_RUN_PATH'
+ ;;
+
+ uts4*)
+ archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_GCJ='-L$libdir'
+ hardcode_shlibpath_var_GCJ=no
+ ;;
+
+ *)
+ ld_shlibs_GCJ=no
+ ;;
+ esac
+ fi
+
+echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5
+echo "${ECHO_T}$ld_shlibs_GCJ" >&6
+test "$ld_shlibs_GCJ" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_GCJ" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc_GCJ=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds_GCJ in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+ $rm conftest*
+ printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl_GCJ
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ
+ allow_undefined_flag_GCJ=
+ if { (eval echo "$as_me:$LINENO: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+ (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ then
+ archive_cmds_need_lc_GCJ=no
+ else
+ archive_cmds_need_lc_GCJ=yes
+ fi
+ allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $rm conftest*
+ echo "$as_me:$LINENO: result: $archive_cmds_need_lc_GCJ" >&5
+echo "${ECHO_T}$archive_cmds_need_lc_GCJ" >&6
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $rm \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)'
+ # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+ if test "$GCC" = yes; then
+ sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+ else
+ sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+ fi
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+kfreebsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+freebsd*)
+ objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.01* | freebsdelf3.01*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ *) # from 3.2 on
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case "$host_cpu" in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+knetbsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='GNU ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+nto-qnx*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+sco3.2v5*)
+ version_type=osf
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action_GCJ=
+if test -n "$hardcode_libdir_flag_spec_GCJ" || \
+ test -n "$runpath_var_GCJ" || \
+ test "X$hardcode_automatic_GCJ" = "Xyes" ; then
+
+ # We can hardcode non-existant directories.
+ if test "$hardcode_direct_GCJ" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no &&
+ test "$hardcode_minus_L_GCJ" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action_GCJ=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action_GCJ=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action_GCJ=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action_GCJ" >&5
+echo "${ECHO_T}$hardcode_action_GCJ" >&6
+
+if test "$hardcode_action_GCJ" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+ ;;
+ *)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ esac
+fi
+
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ echo "$as_me:$LINENO: checking for shl_load" >&5
+echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
+if test "${ac_cv_func_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shl_load (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+char (*f) () = shl_load;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != shl_load;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+echo "${ECHO_T}$ac_cv_func_shl_load" >&6
+if test $ac_cv_func_shl_load = yes; then
+ lt_cv_dlopen="shl_load"
+else
+ echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
+else
+ echo "$as_me:$LINENO: checking for dlopen" >&5
+echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
+if test "${ac_cv_func_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char dlopen (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+char (*f) () = dlopen;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != dlopen;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+echo "${ECHO_T}$ac_cv_func_dlopen" >&6
+if test $ac_cv_func_dlopen = yes; then
+ lt_cv_dlopen="dlopen"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_svld_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_svld_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
+if test $ac_cv_lib_svld_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dld_link ();
+int
+main ()
+{
+dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_dld_link=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_dld_link=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
+if test $ac_cv_lib_dld_dld_link = yes; then
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 22173 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self" >&6
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ LDFLAGS="$LDFLAGS $link_static_flag"
+ echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 22271 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ compiler_GCJ \
+ CC_GCJ \
+ LD_GCJ \
+ lt_prog_compiler_wl_GCJ \
+ lt_prog_compiler_pic_GCJ \
+ lt_prog_compiler_static_GCJ \
+ lt_prog_compiler_no_builtin_flag_GCJ \
+ export_dynamic_flag_spec_GCJ \
+ thread_safe_flag_spec_GCJ \
+ whole_archive_flag_spec_GCJ \
+ enable_shared_with_static_runtimes_GCJ \
+ old_archive_cmds_GCJ \
+ old_archive_from_new_cmds_GCJ \
+ predep_objects_GCJ \
+ postdep_objects_GCJ \
+ predeps_GCJ \
+ postdeps_GCJ \
+ compiler_lib_search_path_GCJ \
+ archive_cmds_GCJ \
+ archive_expsym_cmds_GCJ \
+ postinstall_cmds_GCJ \
+ postuninstall_cmds_GCJ \
+ old_archive_from_expsyms_cmds_GCJ \
+ allow_undefined_flag_GCJ \
+ no_undefined_flag_GCJ \
+ export_symbols_cmds_GCJ \
+ hardcode_libdir_flag_spec_GCJ \
+ hardcode_libdir_flag_spec_ld_GCJ \
+ hardcode_libdir_separator_GCJ \
+ hardcode_automatic_GCJ \
+ module_cmds_GCJ \
+ module_expsym_cmds_GCJ \
+ lt_cv_prog_compiler_c_o_GCJ \
+ exclude_expsyms_GCJ \
+ include_expsyms_GCJ; do
+
+ case $var in
+ old_archive_cmds_GCJ | \
+ old_archive_from_new_cmds_GCJ | \
+ archive_cmds_GCJ | \
+ archive_expsym_cmds_GCJ | \
+ module_cmds_GCJ | \
+ module_expsym_cmds_GCJ | \
+ old_archive_from_expsyms_cmds_GCJ | \
+ export_symbols_cmds_GCJ | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\$0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+cfgfile="$ofile"
+
+ cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_GCJ
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_GCJ
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_GCJ
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_GCJ
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_GCJ
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_GCJ
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_GCJ
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_GCJ
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_GCJ
+archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_GCJ
+module_expsym_cmds=$lt_module_expsym_cmds_GCJ
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_GCJ
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_GCJ
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_GCJ
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_GCJ
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_GCJ
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_GCJ
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_GCJ
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_GCJ
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_GCJ
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_GCJ
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_GCJ
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_GCJ
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_GCJ"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_GCJ
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_GCJ
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_GCJ
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_GCJ
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+ else
+ tagname=""
+ fi
+ ;;
+
+ RC)
+
+
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+objext_RC=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${RC-"windres"}
+compiler=$CC
+compiler_RC=$CC
+lt_cv_prog_compiler_c_o_RC=yes
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ compiler_RC \
+ CC_RC \
+ LD_RC \
+ lt_prog_compiler_wl_RC \
+ lt_prog_compiler_pic_RC \
+ lt_prog_compiler_static_RC \
+ lt_prog_compiler_no_builtin_flag_RC \
+ export_dynamic_flag_spec_RC \
+ thread_safe_flag_spec_RC \
+ whole_archive_flag_spec_RC \
+ enable_shared_with_static_runtimes_RC \
+ old_archive_cmds_RC \
+ old_archive_from_new_cmds_RC \
+ predep_objects_RC \
+ postdep_objects_RC \
+ predeps_RC \
+ postdeps_RC \
+ compiler_lib_search_path_RC \
+ archive_cmds_RC \
+ archive_expsym_cmds_RC \
+ postinstall_cmds_RC \
+ postuninstall_cmds_RC \
+ old_archive_from_expsyms_cmds_RC \
+ allow_undefined_flag_RC \
+ no_undefined_flag_RC \
+ export_symbols_cmds_RC \
+ hardcode_libdir_flag_spec_RC \
+ hardcode_libdir_flag_spec_ld_RC \
+ hardcode_libdir_separator_RC \
+ hardcode_automatic_RC \
+ module_cmds_RC \
+ module_expsym_cmds_RC \
+ lt_cv_prog_compiler_c_o_RC \
+ exclude_expsyms_RC \
+ include_expsyms_RC; do
+
+ case $var in
+ old_archive_cmds_RC | \
+ old_archive_from_new_cmds_RC | \
+ archive_cmds_RC | \
+ archive_expsym_cmds_RC | \
+ module_cmds_RC | \
+ module_expsym_cmds_RC | \
+ old_archive_from_expsyms_cmds_RC | \
+ export_symbols_cmds_RC | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\$0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+cfgfile="$ofile"
+
+ cat <<__EOF__ >> "$cfgfile"
+# ### BEGIN LIBTOOL TAG CONFIG: $tagname
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_RC
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_compiler_RC
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC_RC
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD_RC
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_RC
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_RC
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC
+
+# Must we lock files when doing compilation ?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_RC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds_RC
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds_RC
+archive_expsym_cmds=$lt_archive_expsym_cmds_RC
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds_RC
+module_expsym_cmds=$lt_module_expsym_cmds_RC
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects_RC
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects_RC
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps_RC
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps_RC
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_RC
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_RC
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_RC
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_RC
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct_RC
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L_RC
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_RC
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic_RC
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_RC
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path_RC"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols_RC
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_RC
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_RC
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_RC
+
+# ### END LIBTOOL TAG CONFIG: $tagname
+
+__EOF__
+
+
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+ ;;
+
+ *)
+ { { echo "$as_me:$LINENO: error: Unsupported tag name: $tagname" >&5
+echo "$as_me: error: Unsupported tag name: $tagname" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ esac
+
+ # Append the new tag name to the list of available tags.
+ if test -n "$tagname" ; then
+ available_tags="$available_tags $tagname"
+ fi
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ # Now substitute the updated list of available tags.
+ if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+ mv "${ofile}T" "$ofile"
+ chmod +x "$ofile"
+ else
+ rm -f "${ofile}T"
+ { { echo "$as_me:$LINENO: error: unable to update list of available tagged configurations." >&5
+echo "$as_me: error: unable to update list of available tagged configurations." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+fi
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+# Prevent multiple expansion
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ O=lo
+ A=la
+ LIBTOOL_MKDEP_SED='s;\.o;\.lo;'
+ LIBTOOL_MODE_COMPILE='--mode=compile'
+ LIBTOOL_MODE_INSTALL='--mode=install'
+ LIBTOOL_MODE_LINK='--mode=link'
+ ;;
+ *)
+ O=o
+ A=a
+ LIBTOOL=
+
+ LIBTOOL_MKDEP_SED=
+ LIBTOOL_MODE_COMPILE=
+ LIBTOOL_MODE_INSTALL=
+ LIBTOOL_MODE_LINK=
+ ;;
+esac
+
+#
+# File name extension for static archive files, for those few places
+# where they are treated differently from dynamic ones.
+#
+SA=a
+
+
+
+
+
+
+
+
+
+#
+# Here begins a very long section to determine the system's networking
+# capabilities. The order of the tests is signficant.
+#
+
+#
+# IPv6
+#
+# Check whether --enable-ipv6 or --disable-ipv6 was given.
+if test "${enable_ipv6+set}" = set; then
+ enableval="$enable_ipv6"
+
+fi;
+
+case "$enable_ipv6" in
+ yes|''|autodetect)
+ cat >>confdefs.h <<\_ACEOF
+#define WANT_IPV6 1
+_ACEOF
+
+ ;;
+ no)
+ ;;
+esac
+
+#
+# We do the IPv6 compilation checking after libtool so that we can put
+# the right suffix on the files.
+#
+echo "$as_me:$LINENO: checking for IPv6 structures" >&5
+echo $ECHO_N "checking for IPv6 structures... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+int
+main ()
+{
+struct sockaddr_in6 sin6; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ found_ipv6=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ found_ipv6=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+#
+# See whether IPv6 support is provided via a Kame add-on.
+# This is done before other IPv6 linking tests to LIBS is properly set.
+#
+echo "$as_me:$LINENO: checking for Kame IPv6 support" >&5
+echo $ECHO_N "checking for Kame IPv6 support... $ECHO_C" >&6
+
+# Check whether --with-kame or --without-kame was given.
+if test "${with_kame+set}" = set; then
+ withval="$with_kame"
+ use_kame="$withval"
+else
+ use_kame="no"
+fi;
+
+case "$use_kame" in
+ no)
+ ;;
+ yes)
+ kame_path=/usr/local/v6
+ ;;
+ *)
+ kame_path="$use_kame"
+ ;;
+esac
+
+case "$use_kame" in
+ no)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ *)
+ if test -f $kame_path/lib/libinet6.a; then
+ echo "$as_me:$LINENO: result: $kame_path/lib/libinet6.a" >&5
+echo "${ECHO_T}$kame_path/lib/libinet6.a" >&6
+ LIBS="-L$kame_path/lib -linet6 $LIBS"
+ else
+ { { echo "$as_me:$LINENO: error: $kame_path/lib/libinet6.a not found.
+
+Please choose the proper path with the following command:
+
+ configure --with-kame=PATH
+" >&5
+echo "$as_me: error: $kame_path/lib/libinet6.a not found.
+
+Please choose the proper path with the following command:
+
+ configure --with-kame=PATH
+" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ ;;
+esac
+
+#
+# Whether netinet6/in6.h is needed has to be defined in isc/platform.h.
+# Including it on Kame-using platforms is very bad, though, because
+# Kame uses #error against direct inclusion. So include it on only
+# the platform that is otherwise broken without it -- BSD/OS 4.0 through 4.1.
+# This is done before the in6_pktinfo check because that's what
+# netinet6/in6.h is needed for.
+#
+
+case "$host" in
+*-bsdi4.[01]*)
+ ISC_PLATFORM_NEEDNETINET6IN6H="#define ISC_PLATFORM_NEEDNETINET6IN6H 1"
+ isc_netinet6in6_hack="#include <netinet6/in6.h>"
+ ;;
+*)
+ ISC_PLATFORM_NEEDNETINET6IN6H="#undef ISC_PLATFORM_NEEDNETINET6IN6H"
+ isc_netinet6in6_hack=""
+ ;;
+esac
+
+
+#
+# This is similar to the netinet6/in6.h issue.
+#
+case "$host" in
+*-UnixWare*)
+ ISC_PLATFORM_NEEDNETINETIN6H="#define ISC_PLATFORM_NEEDNETINETIN6H 1"
+ ISC_PLATFORM_FIXIN6ISADDR="#define ISC_PLATFORM_FIXIN6ISADDR 1"
+ isc_netinetin6_hack="#include <netinet/in6.h>"
+ ;;
+*)
+ ISC_PLATFORM_NEEDNETINETIN6H="#undef ISC_PLATFORM_NEEDNETINETIN6H"
+ ISC_PLATFORM_FIXIN6ISADDR="#undef ISC_PLATFORM_FIXIN6ISADDR"
+ isc_netinetin6_hack=""
+ ;;
+esac
+
+#
+# Now delve deeper into the suitability of the IPv6 support.
+#
+case "$found_ipv6" in
+ yes)
+ HAS_INET6_STRUCTS="#define HAS_INET6_STRUCTS 1"
+
+ echo "$as_me:$LINENO: checking for in6_addr" >&5
+echo $ECHO_N "checking for in6_addr... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+
+int
+main ()
+{
+struct in6_addr in6; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ HAS_IN_ADDR6="#undef HAS_IN_ADDR6"
+ isc_in_addr6_hack=""
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ HAS_IN_ADDR6="#define HAS_IN_ADDR6 1"
+ isc_in_addr6_hack="#define in6_addr in_addr6"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+ echo "$as_me:$LINENO: checking for in6addr_any" >&5
+echo $ECHO_N "checking for in6addr_any... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+$isc_in_addr6_hack
+
+int
+main ()
+{
+struct in6_addr in6; in6 = in6addr_any; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ NEED_IN6ADDR_ANY="#undef NEED_IN6ADDR_ANY"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ NEED_IN6ADDR_ANY="#define NEED_IN6ADDR_ANY 1"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ echo "$as_me:$LINENO: checking for sin6_scope_id in struct sockaddr_in6" >&5
+echo $ECHO_N "checking for sin6_scope_id in struct sockaddr_in6... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+
+int
+main ()
+{
+struct sockaddr_in6 xyzzy; xyzzy.sin6_scope_id = 0; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ result="#define HAVE_SIN6_SCOPE_ID 1"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ result="#undef HAVE_SIN6_SCOPE_ID"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ HAVE_SIN6_SCOPE_ID="$result"
+
+ echo "$as_me:$LINENO: checking for in6_pktinfo" >&5
+echo $ECHO_N "checking for in6_pktinfo... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+
+int
+main ()
+{
+struct in6_pktinfo xyzzy; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_PLATFORM_HAVEIN6PKTINFO="#define ISC_PLATFORM_HAVEIN6PKTINFO 1"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no -- disabling runtime ipv6 support" >&5
+echo "${ECHO_T}no -- disabling runtime ipv6 support" >&6
+ ISC_PLATFORM_HAVEIN6PKTINFO="#undef ISC_PLATFORM_HAVEIN6PKTINFO"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ ;;
+ no)
+ HAS_INET6_STRUCTS="#undef HAS_INET6_STRUCTS"
+ NEED_IN6ADDR_ANY="#undef NEED_IN6ADDR_ANY"
+ ISC_PLATFORM_HAVEIN6PKTINFO="#undef ISC_PLATFORM_HAVEIN6PKTINFO"
+ HAVE_SIN6_SCOPE_ID="#define HAVE_SIN6_SCOPE_ID 1"
+ ISC_IPV6_H="ipv6.h"
+ ISC_IPV6_O="ipv6.$O"
+ ISC_ISCIPV6_O="unix/ipv6.$O"
+ ISC_IPV6_C="ipv6.c"
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking for sockaddr_storage" >&5
+echo $ECHO_N "checking for sockaddr_storage... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+struct sockaddr_storage xyzzy; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ HAVE_SOCKADDR_STORAGE="#define HAVE_SOCKADDR_STORAGE 1"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ HAVE_SOCKADDR_STORAGE="#undef HAVE_SOCKADDR_STORAGE"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check for network functions that are often missing. We do this
+# after the libtool checking, so we can put the right suffix on
+# the files. It also needs to come after checking for a Kame add-on,
+# which provides some (all?) of the desired functions.
+#
+echo "$as_me:$LINENO: checking for inet_ntop" >&5
+echo $ECHO_N "checking for inet_ntop... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+int
+main ()
+{
+inet_ntop(0, 0, 0, 0); return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_PLATFORM_NEEDNTOP="#undef ISC_PLATFORM_NEEDNTOP"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
+ ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
+ ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+echo "$as_me:$LINENO: checking for inet_pton" >&5
+echo $ECHO_N "checking for inet_pton... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+int
+main ()
+{
+inet_pton(0, 0, 0); return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_PLATFORM_NEEDPTON="#undef ISC_PLATFORM_NEEDPTON"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_pton.$O"
+ ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_pton.c"
+ ISC_PLATFORM_NEEDPTON="#define ISC_PLATFORM_NEEDPTON 1"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+echo "$as_me:$LINENO: checking for inet_aton" >&5
+echo $ECHO_N "checking for inet_aton... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+int
+main ()
+{
+struct in_addr in; inet_aton(0, &in); return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_PLATFORM_NEEDATON="#undef ISC_PLATFORM_NEEDATON"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_aton.$O"
+ ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_aton.c"
+ ISC_PLATFORM_NEEDATON="#define ISC_PLATFORM_NEEDATON 1"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+
+
+
+
+#
+# Look for a 4.4BSD-style sa_len member in struct sockaddr.
+#
+case "$host" in
+ *-dec-osf*)
+ # Turn on 4.4BSD style sa_len support.
+ cat >>confdefs.h <<\_ACEOF
+#define _SOCKADDR_LEN 1
+_ACEOF
+
+ ;;
+esac
+
+echo "$as_me:$LINENO: checking for sa_len in struct sockaddr" >&5
+echo $ECHO_N "checking for sa_len in struct sockaddr... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int
+main ()
+{
+struct sockaddr sa; sa.sa_len = 0; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ HAVE_SA_LEN="#define HAVE_SA_LEN 1"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ HAVE_SA_LEN="#undef HAVE_SA_LEN"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+# HAVE_MINIMUM_IFREQ
+
+case "$host" in
+ *-bsdi2345*) have_minimum_ifreq=yes;;
+ *-darwin*) have_minimum_ifreq=yes;;
+ *-freebsd*) have_minimum_ifreq=yes;;
+ *-lynxos*) have_minimum_ifreq=yes;;
+ *-netbsd*) have_minimum_ifreq=yes;;
+ *-next*) have_minimum_ifreq=yes;;
+ *-openbsd*) have_minimum_ifreq=yes;;
+ *-rhapsody*) have_minimum_ifreq=yes;;
+esac
+
+case "$have_minimum_ifreq" in
+ yes)
+ HAVE_MINIMUM_IFREQ="#define HAVE_MINIMUM_IFREQ 1";;
+ no)
+ HAVE_MINIMUM_IFREQ="#undef HAVE_MINIMUM_IFREQ";;
+ *)
+ HAVE_MINIMUM_IFREQ="#undef HAVE_MINIMUM_IFREQ";;
+esac
+
+
+# PORT_DIR
+PORT_DIR=port/unknown
+SOLARIS_BITTYPES="#undef NEED_SOLARIS_BITTYPES"
+BSD_COMP="#undef BSD_COMP"
+USE_FIONBIO_IOCTL="#undef USE_FIONBIO_IOCTL"
+PORT_NONBLOCK="#define PORT_NONBLOCK O_NONBLOCK"
+HAVE_MD5="#undef HAVE_MD5"
+USE_POLL="#undef HAVE_POLL"
+SOLARIS2="#undef SOLARIS2"
+case "$host" in
+ *aix3.2*) PORT_DIR="port/aix32";;
+ *aix4*) PORT_DIR="port/aix4";;
+ *aix5*) PORT_DIR="port/aix5";;
+ *aux3*) PORT_DIR="port/aux3";;
+ *-bsdi2*) PORT_DIR="port/bsdos2";;
+ *-bsdi*) PORT_DIR="port/bsdos";;
+ *-cygwin*)
+ PORT_NONBLOCK="#define PORT_NONBLOCK O_NDELAY"
+ PORT_DIR="port/cygwin";;
+ *-darwin*) PORT_DIR="port/darwin";;
+ *-osf*) PORT_DIR="port/decunix";;
+ *-freebsd*) PORT_DIR="port/freebsd";;
+ *-hpux9*) PORT_DIR="port/hpux9";;
+ *-hpux10*) PORT_DIR="port/hpux10";;
+ *-hpux11*) PORT_DIR="port/hpux";;
+ *-irix*) PORT_DIR="port/irix";;
+ *-linux*) PORT_DIR="port/linux";;
+ *-lynxos*) PORT_DIR="port/lynxos";;
+ *-mpe*) PORT_DIR="port/mpe";;
+ *-netbsd*) PORT_DIR="port/netbsd";;
+ *-next*) PORT_DIR="port/next";;
+ *-openbsd*) PORT_DIR="port/openbsd";;
+ *-qnx*) PORT_DIR="port/qnx";;
+ *-rhapsody*) PORT_DIR="port/rhapsody";;
+ *-sunos4*)
+ PORT_NONBLOCK="#define PORT_NONBLOCK O_NDELAY"
+ PORT_DIR="port/sunos";;
+ *-solaris2.[01234])
+ BSD_COMP="#define BSD_COMP 1"
+ SOLARIS_BITTYPES="#define NEED_SOLARIS_BITTYPES 1"
+ USE_FIONBIO_IOCTL="#define USE_FIONBIO_IOCTL 1"
+ SOLARIS2="#define SOLARIS2 1"
+ PORT_DIR="port/solaris";;
+ *-solaris2.5)
+ BSD_COMP="#define BSD_COMP 1"
+ SOLARIS_BITTYPES="#define NEED_SOLARIS_BITTYPES 1"
+ SOLARIS2="#define SOLARIS2 1"
+ PORT_DIR="port/solaris";;
+ *-solaris2.[67])
+ BSD_COMP="#define BSD_COMP 1"
+ SOLARIS2="#define SOLARIS2 1"
+ PORT_DIR="port/solaris";;
+ *-solaris2*) BSD_COMP="#define BSD_COMP 1"
+ USE_POLL="#define USE_POLL 1"
+ HAVE_MD5="#define HAVE_MD5 1"
+ SOLARIS2="#define SOLARIS2 1"
+ PORT_DIR="port/solaris";;
+ *-ultrix*) PORT_DIR="port/ultrix";;
+ *-sco-sysv*uw2.0*) PORT_DIR="port/unixware20";;
+ *-sco-sysv*uw2.1.2*) PORT_DIR="port/unixware212";;
+ *-sco-sysv*uw7*) PORT_DIR="port/unixware7";;
+esac
+
+
+
+
+
+
+
+
+
+PORT_INCLUDE=${PORT_DIR}/include
+
+
+#
+# Look for a 4.4BSD or 4.3BSD struct msghdr
+#
+echo "$as_me:$LINENO: checking for struct msghdr flavor" >&5
+echo $ECHO_N "checking for struct msghdr flavor... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int
+main ()
+{
+struct msghdr msg; msg.msg_flags = 0; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: 4.4BSD" >&5
+echo "${ECHO_T}4.4BSD" >&6
+ ISC_PLATFORM_MSGHDRFLAVOR="#define ISC_NET_BSD44MSGHDR 1"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: 4.3BSD" >&5
+echo "${ECHO_T}4.3BSD" >&6
+ ISC_PLATFORM_MSGHDRFLAVOR="#define ISC_NET_BSD43MSGHDR 1"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+#
+# Look for in_port_t.
+#
+echo "$as_me:$LINENO: checking for type in_port_t" >&5
+echo $ECHO_N "checking for type in_port_t... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+int
+main ()
+{
+in_port_t port = 25; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_PLATFORM_NEEDPORTT="#undef ISC_PLATFORM_NEEDPORTT"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ISC_PLATFORM_NEEDPORTT="#define ISC_PLATFORM_NEEDPORTT 1"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+echo "$as_me:$LINENO: checking for struct timespec" >&5
+echo $ECHO_N "checking for struct timespec... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <time.h>
+int
+main ()
+{
+struct timespec ts = { 0, 0 }; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_PLATFORM_NEEDTIMESPEC="#undef ISC_PLATFORM_NEEDTIMESPEC"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ISC_PLATFORM_NEEDTIMESPEC="#define ISC_PLATFORM_NEEDTIMESPEC 1"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+#
+# Check for addrinfo
+#
+echo "$as_me:$LINENO: checking for struct addrinfo" >&5
+echo $ECHO_N "checking for struct addrinfo... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <netdb.h>
+int
+main ()
+{
+struct addrinfo a; return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_ADDRINFO 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking for int sethostent" >&5
+echo $ECHO_N "checking for int sethostent... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <netdb.h>
+int
+main ()
+{
+int i = sethostent(0); return(0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking for int endhostent" >&5
+echo $ECHO_N "checking for int endhostent... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <netdb.h>
+int
+main ()
+{
+int i = endhostent(); return(0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_LWRES_ENDHOSTENTINT="#define ISC_LWRES_ENDHOSTENTINT 1"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ISC_LWRES_ENDHOSTENTINT="#undef ISC_LWRES_ENDHOSTENTINT"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+echo "$as_me:$LINENO: checking for int setnetent" >&5
+echo $ECHO_N "checking for int setnetent... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <netdb.h>
+int
+main ()
+{
+int i = setnetent(0); return(0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_LWRES_SETNETENTINT="#define ISC_LWRES_SETNETENTINT 1"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ISC_LWRES_SETNETENTINT="#undef ISC_LWRES_SETNETENTINT"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+echo "$as_me:$LINENO: checking for int endnetent" >&5
+echo $ECHO_N "checking for int endnetent... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <netdb.h>
+int
+main ()
+{
+int i = endnetent(); return(0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_LWRES_ENDNETENTINT="#define ISC_LWRES_ENDNETENTINT 1"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ISC_LWRES_ENDNETENTINT="#undef ISC_LWRES_ENDNETENTINT"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+echo "$as_me:$LINENO: checking for gethostbyaddr(const void *, size_t, ...)" >&5
+echo $ECHO_N "checking for gethostbyaddr(const void *, size_t, ...)... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <netdb.h>
+struct hostent *gethostbyaddr(const void *, size_t, int);
+int
+main ()
+{
+return(0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_LWRES_GETHOSTBYADDRVOID="#define ISC_LWRES_GETHOSTBYADDRVOID 1"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ISC_LWRES_GETHOSTBYADDRVOID="#undef ISC_LWRES_GETHOSTBYADDRVOID"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+echo "$as_me:$LINENO: checking for h_errno in netdb.h" >&5
+echo $ECHO_N "checking for h_errno in netdb.h... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <netdb.h>
+int
+main ()
+{
+h_errno = 1; return(0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ISC_LWRES_NEEDHERRNO="#undef ISC_LWRES_NEEDHERRNO"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ISC_LWRES_NEEDHERRNO="#define ISC_LWRES_NEEDHERRNO 1"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+echo "$as_me:$LINENO: checking for getipnodebyname" >&5
+echo $ECHO_N "checking for getipnodebyname... $ECHO_C" >&6
+if test "${ac_cv_func_getipnodebyname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getipnodebyname to an innocuous variant, in case <limits.h> declares getipnodebyname.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getipnodebyname innocuous_getipnodebyname
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getipnodebyname (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getipnodebyname
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getipnodebyname ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getipnodebyname) || defined (__stub___getipnodebyname)
+choke me
+#else
+char (*f) () = getipnodebyname;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getipnodebyname;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getipnodebyname=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getipnodebyname=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getipnodebyname" >&5
+echo "${ECHO_T}$ac_cv_func_getipnodebyname" >&6
+if test $ac_cv_func_getipnodebyname = yes; then
+ ISC_LWRES_GETIPNODEPROTO="#undef ISC_LWRES_GETIPNODEPROTO"
+else
+ ISC_LWRES_GETIPNODEPROTO="#define ISC_LWRES_GETIPNODEPROTO 1"
+fi
+
+echo "$as_me:$LINENO: checking for getnameinfo" >&5
+echo $ECHO_N "checking for getnameinfo... $ECHO_C" >&6
+if test "${ac_cv_func_getnameinfo+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getnameinfo to an innocuous variant, in case <limits.h> declares getnameinfo.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getnameinfo innocuous_getnameinfo
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getnameinfo (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getnameinfo
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getnameinfo ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getnameinfo) || defined (__stub___getnameinfo)
+choke me
+#else
+char (*f) () = getnameinfo;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getnameinfo;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getnameinfo=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getnameinfo=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getnameinfo" >&5
+echo "${ECHO_T}$ac_cv_func_getnameinfo" >&6
+if test $ac_cv_func_getnameinfo = yes; then
+ ISC_LWRES_GETNAMEINFOPROTO="#undef ISC_LWRES_GETNAMEINFOPROTO"
+else
+ ISC_LWRES_GETNAMEINFOPROTO="#define ISC_LWRES_GETNAMEINFOPROTO 1"
+fi
+
+echo "$as_me:$LINENO: checking for getaddrinfo" >&5
+echo $ECHO_N "checking for getaddrinfo... $ECHO_C" >&6
+if test "${ac_cv_func_getaddrinfo+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getaddrinfo to an innocuous variant, in case <limits.h> declares getaddrinfo.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getaddrinfo innocuous_getaddrinfo
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getaddrinfo (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getaddrinfo
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getaddrinfo ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getaddrinfo) || defined (__stub___getaddrinfo)
+choke me
+#else
+char (*f) () = getaddrinfo;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getaddrinfo;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getaddrinfo=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getaddrinfo=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getaddrinfo" >&5
+echo "${ECHO_T}$ac_cv_func_getaddrinfo" >&6
+if test $ac_cv_func_getaddrinfo = yes; then
+ ISC_LWRES_GETADDRINFOPROTO="#undef ISC_LWRES_GETADDRINFOPROTO"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_GETADDRINFO 1
+_ACEOF
+
+else
+ ISC_LWRES_GETADDRINFOPROTO="#define ISC_LWRES_GETADDRINFOPROTO 1"
+fi
+
+echo "$as_me:$LINENO: checking for gai_strerror" >&5
+echo $ECHO_N "checking for gai_strerror... $ECHO_C" >&6
+if test "${ac_cv_func_gai_strerror+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define gai_strerror to an innocuous variant, in case <limits.h> declares gai_strerror.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define gai_strerror innocuous_gai_strerror
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char gai_strerror (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef gai_strerror
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gai_strerror ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_gai_strerror) || defined (__stub___gai_strerror)
+choke me
+#else
+char (*f) () = gai_strerror;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != gai_strerror;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_gai_strerror=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_gai_strerror=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_gai_strerror" >&5
+echo "${ECHO_T}$ac_cv_func_gai_strerror" >&6
+if test $ac_cv_func_gai_strerror = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_GAISTRERROR 1
+_ACEOF
+
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking for pselect" >&5
+echo $ECHO_N "checking for pselect... $ECHO_C" >&6
+if test "${ac_cv_func_pselect+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define pselect to an innocuous variant, in case <limits.h> declares pselect.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define pselect innocuous_pselect
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char pselect (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef pselect
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pselect ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_pselect) || defined (__stub___pselect)
+choke me
+#else
+char (*f) () = pselect;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != pselect;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_pselect=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_pselect=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_pselect" >&5
+echo "${ECHO_T}$ac_cv_func_pselect" >&6
+if test $ac_cv_func_pselect = yes; then
+ NEED_PSELECT="#undef NEED_PSELECT"
+else
+ NEED_PSELECT="#define NEED_PSELECT"
+fi
+
+
+echo "$as_me:$LINENO: checking for gettimeofday" >&5
+echo $ECHO_N "checking for gettimeofday... $ECHO_C" >&6
+if test "${ac_cv_func_gettimeofday+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define gettimeofday to an innocuous variant, in case <limits.h> declares gettimeofday.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define gettimeofday innocuous_gettimeofday
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char gettimeofday (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef gettimeofday
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gettimeofday ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_gettimeofday) || defined (__stub___gettimeofday)
+choke me
+#else
+char (*f) () = gettimeofday;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != gettimeofday;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_gettimeofday=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_gettimeofday=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_gettimeofday" >&5
+echo "${ECHO_T}$ac_cv_func_gettimeofday" >&6
+if test $ac_cv_func_gettimeofday = yes; then
+ NEED_GETTIMEOFDAY="#undef NEED_GETTIMEOFDAY"
+else
+ NEED_GETTIMEOFDAY="#define NEED_GETTIMEOFDAY 1"
+fi
+
+
+echo "$as_me:$LINENO: checking for strndup" >&5
+echo $ECHO_N "checking for strndup... $ECHO_C" >&6
+if test "${ac_cv_func_strndup+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define strndup to an innocuous variant, in case <limits.h> declares strndup.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define strndup innocuous_strndup
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char strndup (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef strndup
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strndup ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_strndup) || defined (__stub___strndup)
+choke me
+#else
+char (*f) () = strndup;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != strndup;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_strndup=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_strndup=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_strndup" >&5
+echo "${ECHO_T}$ac_cv_func_strndup" >&6
+if test $ac_cv_func_strndup = yes; then
+ HAVE_STRNDUP="#define HAVE_STRNDUP 1"
+else
+ HAVE_STRNDUP="#undef HAVE_STRNDUP"
+fi
+
+
+
+#
+# Look for a sysctl call to get the list of network interfaces.
+#
+echo "$as_me:$LINENO: checking for interface list sysctl" >&5
+echo $ECHO_N "checking for interface list sysctl... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#ifdef NET_RT_IFLIST
+found_rt_iflist
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "found_rt_iflist" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IFLIST_SYSCTL 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+#
+# Check for some other useful functions that are not ever-present.
+#
+echo "$as_me:$LINENO: checking for strsep" >&5
+echo $ECHO_N "checking for strsep... $ECHO_C" >&6
+if test "${ac_cv_func_strsep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define strsep to an innocuous variant, in case <limits.h> declares strsep.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define strsep innocuous_strsep
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char strsep (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef strsep
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strsep ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_strsep) || defined (__stub___strsep)
+choke me
+#else
+char (*f) () = strsep;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != strsep;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_strsep=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_strsep=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_strsep" >&5
+echo "${ECHO_T}$ac_cv_func_strsep" >&6
+if test $ac_cv_func_strsep = yes; then
+ ISC_PLATFORM_NEEDSTRSEP="#undef ISC_PLATFORM_NEEDSTRSEP"
+else
+ ISC_PLATFORM_NEEDSTRSEP="#define ISC_PLATFORM_NEEDSTRSEP 1"
+fi
+
+echo "$as_me:$LINENO: checking for vsnprintf" >&5
+echo $ECHO_N "checking for vsnprintf... $ECHO_C" >&6
+if test "${ac_cv_func_vsnprintf+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define vsnprintf to an innocuous variant, in case <limits.h> declares vsnprintf.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define vsnprintf innocuous_vsnprintf
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char vsnprintf (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef vsnprintf
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char vsnprintf ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_vsnprintf) || defined (__stub___vsnprintf)
+choke me
+#else
+char (*f) () = vsnprintf;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != vsnprintf;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_vsnprintf=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_vsnprintf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_vsnprintf" >&5
+echo "${ECHO_T}$ac_cv_func_vsnprintf" >&6
+if test $ac_cv_func_vsnprintf = yes; then
+ ISC_PLATFORM_NEEDVSNPRINTF="#undef ISC_PLATFORM_NEEDVSNPRINTF"
+else
+ ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS print.$O"
+ ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS print.c"
+ ISC_PLATFORM_NEEDVSNPRINTF="#define ISC_PLATFORM_NEEDVSNPRINTF 1"
+fi
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for strerror" >&5
+echo $ECHO_N "checking for strerror... $ECHO_C" >&6
+if test "${ac_cv_func_strerror+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define strerror to an innocuous variant, in case <limits.h> declares strerror.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define strerror innocuous_strerror
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char strerror (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef strerror
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strerror ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_strerror) || defined (__stub___strerror)
+choke me
+#else
+char (*f) () = strerror;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != strerror;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_strerror=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_strerror=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_strerror" >&5
+echo "${ECHO_T}$ac_cv_func_strerror" >&6
+if test $ac_cv_func_strerror = yes; then
+ USE_SYSERROR_LIST="#undef USE_SYSERROR_LIST"
+else
+ USE_SYSERROR_LIST="#define USE_SYSERROR_LIST 1"
+fi
+
+
+
+#
+# Determine the printf format characters to use when printing
+# values of type isc_int64_t. We make the assumption that platforms
+# where a "long long" is the same size as a "long" (e.g., Alpha/OSF1)
+# want "%ld" and everyone else can use "%lld". Win32 uses "%I64d",
+# but that's defined elsewhere since we don't use configure on Win32.
+#
+echo "$as_me:$LINENO: checking printf format modifier for 64-bit integers" >&5
+echo $ECHO_N "checking printf format modifier for 64-bit integers... $ECHO_C" >&6
+if test "$cross_compiling" = yes; then
+ echo "$as_me:$LINENO: result: default ll" >&5
+echo "${ECHO_T}default ll" >&6
+ ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "ll"'
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+main() { exit(!(sizeof(long long int) == sizeof(long int))); }
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: l" >&5
+echo "${ECHO_T}l" >&6
+ ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "l"'
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+echo "$as_me:$LINENO: result: ll" >&5
+echo "${ECHO_T}ll" >&6
+ ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "ll"'
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+#
+# Security Stuff
+#
+echo "$as_me:$LINENO: checking for chroot" >&5
+echo $ECHO_N "checking for chroot... $ECHO_C" >&6
+if test "${ac_cv_func_chroot+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define chroot to an innocuous variant, in case <limits.h> declares chroot.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define chroot innocuous_chroot
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char chroot (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef chroot
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char chroot ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_chroot) || defined (__stub___chroot)
+choke me
+#else
+char (*f) () = chroot;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != chroot;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_chroot=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_chroot=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_chroot" >&5
+echo "${ECHO_T}$ac_cv_func_chroot" >&6
+if test $ac_cv_func_chroot = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_CHROOT 1
+_ACEOF
+
+fi
+
+
+#
+# for accept, recvfrom, getpeername etc.
+#
+echo "$as_me:$LINENO: checking for socket length type" >&5
+echo $ECHO_N "checking for socket length type... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int accept(int, struct sockaddr *, socklen_t *);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ISC_SOCKLEN_T="#define ISC_SOCKLEN_T socklen_t"
+echo "$as_me:$LINENO: result: socklen_t" >&5
+echo "${ECHO_T}socklen_t" >&6
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int accept(int, struct sockaddr *, unsigned int *);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ISC_SOCKLEN_T="#define ISC_SOCKLEN_T unsigned int"
+echo "$as_me:$LINENO: result: unsigned int" >&5
+echo "${ECHO_T}unsigned int" >&6
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int accept(int, struct sockaddr *, unsigned long *);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ISC_SOCKLEN_T="#define ISC_SOCKLEN_T unsigned long"
+echo "$as_me:$LINENO: result: unsigned long" >&5
+echo "${ECHO_T}unsigned long" >&6
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int accept(int, struct sockaddr *, long *);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ISC_SOCKLEN_T="#define ISC_SOCKLEN_T long"
+echo "$as_me:$LINENO: result: long" >&5
+echo "${ECHO_T}long" >&6
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ISC_SOCKLEN_T="#define ISC_SOCKLEN_T int"
+echo "$as_me:$LINENO: result: int" >&5
+echo "${ECHO_T}int" >&6
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+echo "$as_me:$LINENO: checking for getgrouplist" >&5
+echo $ECHO_N "checking for getgrouplist... $ECHO_C" >&6
+if test "${ac_cv_func_getgrouplist+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getgrouplist to an innocuous variant, in case <limits.h> declares getgrouplist.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getgrouplist innocuous_getgrouplist
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getgrouplist (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getgrouplist
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getgrouplist ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getgrouplist) || defined (__stub___getgrouplist)
+choke me
+#else
+char (*f) () = getgrouplist;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getgrouplist;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getgrouplist=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getgrouplist=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getgrouplist" >&5
+echo "${ECHO_T}$ac_cv_func_getgrouplist" >&6
+if test $ac_cv_func_getgrouplist = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <unistd.h>
+int
+getgrouplist(const char *name, int basegid, int *groups, int *ngroups) {
+}
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, int basegid, int *groups, int *ngroups"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, gid_t basegid, gid_t *groups, int *ngroups"
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, gid_t basegid, gid_t *groups, int *ngroups"
+cat >>confdefs.h <<\_ACEOF
+#define NEED_GETGROUPLIST 1
+_ACEOF
+
+
+fi
+
+
+
+echo "$as_me:$LINENO: checking for setgroupent" >&5
+echo $ECHO_N "checking for setgroupent... $ECHO_C" >&6
+if test "${ac_cv_func_setgroupent+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define setgroupent to an innocuous variant, in case <limits.h> declares setgroupent.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define setgroupent innocuous_setgroupent
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char setgroupent (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef setgroupent
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setgroupent ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_setgroupent) || defined (__stub___setgroupent)
+choke me
+#else
+char (*f) () = setgroupent;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != setgroupent;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_setgroupent=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_setgroupent=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_setgroupent" >&5
+echo "${ECHO_T}$ac_cv_func_setgroupent" >&6
+if test $ac_cv_func_setgroupent = yes; then
+ :
+else
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_SETGROUPENT 1
+_ACEOF
+
+fi
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for getnetbyaddr_r" >&5
+echo $ECHO_N "checking for getnetbyaddr_r... $ECHO_C" >&6
+if test "${ac_cv_func_getnetbyaddr_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getnetbyaddr_r to an innocuous variant, in case <limits.h> declares getnetbyaddr_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getnetbyaddr_r innocuous_getnetbyaddr_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getnetbyaddr_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getnetbyaddr_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getnetbyaddr_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getnetbyaddr_r) || defined (__stub___getnetbyaddr_r)
+choke me
+#else
+char (*f) () = getnetbyaddr_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getnetbyaddr_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getnetbyaddr_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getnetbyaddr_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getnetbyaddr_r" >&5
+echo "${ECHO_T}$ac_cv_func_getnetbyaddr_r" >&6
+if test $ac_cv_func_getnetbyaddr_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#define _OSF_SOURCE
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+struct netent *
+getnetbyaddr_r(long net, int type, struct netent *result, char *buffer,
+int buflen) {}
+
+int
+main ()
+{
+return (0)
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NET_R_ARGS="#define NET_R_ARGS char *buf, int buflen"
+NET_R_BAD="#define NET_R_BAD NULL"
+NET_R_COPY="#define NET_R_COPY buf, buflen"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS NET_R_ARGS"
+NET_R_OK="#define NET_R_OK nptr"
+NET_R_SETANSWER="#undef NET_R_SETANSWER"
+NET_R_RETURN="#define NET_R_RETURN struct netent *"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T long"
+NETENT_DATA="#undef NETENT_DATA"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#define _OSF_SOURCE
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getnetbyaddr_r (unsigned long int, int, struct netent *,
+ char *, size_t, struct netent **, int *);
+
+int
+main ()
+{
+return (0)
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NET_R_ARGS="#define NET_R_ARGS char *buf, size_t buflen, struct netent **answerp, int *h_errnop"
+NET_R_BAD="#define NET_R_BAD ERANGE"
+NET_R_COPY="#define NET_R_COPY buf, buflen"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS char *buf, size_t buflen"
+NET_R_OK="#define NET_R_OK 0"
+NET_R_SETANSWER="#define NET_R_SETANSWER 1"
+NET_R_RETURN="#define NET_R_RETURN int"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T unsigned long int"
+NETENT_DATA="#undef NETENT_DATA"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#define _OSF_SOURCE
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int getnetbyaddr_r(int, int, struct netent *, struct netent_data *);
+
+int
+main ()
+{
+return (0)
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NET_R_ARGS="#define NET_R_ARGS struct netent_data *ndptr"
+NET_R_BAD="#define NET_R_BAD (-1)"
+NET_R_COPY="#define NET_R_COPY ndptr"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS struct netent_data *ndptr"
+NET_R_OK="#define NET_R_OK 0"
+NET_R_SETANSWER="#undef NET_R_SETANSWER"
+NET_R_RETURN="#define NET_R_RETURN int"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T int"
+NETENT_DATA="#define NETENT_DATA 1"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getnetbyaddr_r (in_addr_t, int, struct netent *, struct netent_data *);
+
+int
+main ()
+{
+return (0)
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NET_R_ARGS="#define NET_R_ARGS struct netent_data *ndptr"
+NET_R_BAD="#define NET_R_BAD (-1)"
+NET_R_COPY="#define NET_R_COPY ndptr"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS struct netent_data *ndptr"
+NET_R_OK="#define NET_R_OK 0"
+NET_R_SETANSWER="#undef NET_R_SETANSWER"
+NET_R_RETURN="#define NET_R_RETURN int"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T long"
+NETENT_DATA="#define NETENT_DATA 1"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getnetbyaddr_r (long, int, struct netent *, struct netent_data *);
+
+int
+main ()
+{
+return (0)
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NET_R_ARGS="#define NET_R_ARGS struct netent_data *ndptr"
+NET_R_BAD="#define NET_R_BAD (-1)"
+NET_R_COPY="#define NET_R_COPY ndptr"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS struct netent_data *ndptr"
+NET_R_OK="#define NET_R_OK 0"
+NET_R_SETANSWER="#undef NET_R_SETANSWER"
+NET_R_RETURN="#define NET_R_RETURN int"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T long"
+NETENT_DATA="#define NETENT_DATA 1"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getnetbyaddr_r (uint32_t, int, struct netent *,
+ char *, size_t, struct netent **, int *);
+
+int
+main ()
+{
+return (0)
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NET_R_ARGS="#define NET_R_ARGS char *buf, size_t buflen, struct netent **answerp, int *h_errnop"
+NET_R_BAD="#define NET_R_BAD ERANGE"
+NET_R_COPY="#define NET_R_COPY buf, buflen"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS char *buf, size_t buflen"
+NET_R_OK="#define NET_R_OK 0"
+NET_R_SETANSWER="#define NET_R_SETANSWER 1"
+NET_R_RETURN="#define NET_R_RETURN int"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T unsigned long int"
+NETENT_DATA="#undef NETENT_DATA"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ NET_R_ARGS="#define NET_R_ARGS char *buf, int buflen"
+NET_R_BAD="#define NET_R_BAD NULL"
+NET_R_COPY="#define NET_R_COPY buf, buflen"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS NET_R_ARGS"
+NET_R_OK="#define NET_R_OK nptr"
+NET_R_SETANSWER="#undef NET_R_SETANSWER"
+NET_R_RETURN="#define NET_R_RETURN struct netent *"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T long"
+NETENT_DATA="#undef NETENT_DATA"
+
+fi
+
+esac
+
+case "$host" in
+*dec-osf*) GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T int" ;;
+esac
+
+
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for setnetent_r" >&5
+echo $ECHO_N "checking for setnetent_r... $ECHO_C" >&6
+if test "${ac_cv_func_setnetent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define setnetent_r to an innocuous variant, in case <limits.h> declares setnetent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define setnetent_r innocuous_setnetent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char setnetent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef setnetent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setnetent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_setnetent_r) || defined (__stub___setnetent_r)
+choke me
+#else
+char (*f) () = setnetent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != setnetent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_setnetent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_setnetent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_setnetent_r" >&5
+echo "${ECHO_T}$ac_cv_func_setnetent_r" >&6
+if test $ac_cv_func_setnetent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void setnetent_r (int);
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NET_R_ENT_ARGS="#undef NET_R_ENT_ARGS /*empty*/"
+NET_R_SET_RESULT="#undef NET_R_SET_RESULT /*empty*/"
+NET_R_SET_RETURN="#define NET_R_SET_RETURN void"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int setnetent_r(int, struct netent_data *);
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NET_R_ENT_ARGS="#define NET_R_ENT_ARGS struct netent_data *ndptr"
+NET_R_SET_RESULT="#define NET_R_SET_RESULT NET_R_OK"
+NET_R_SET_RETURN="#define NET_R_SET_RETURN int"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ NET_R_ENT_ARGS="#undef NET_R_ENT_ARGS /*empty*/"
+NET_R_SET_RESULT="#undef NET_R_SET_RESULT /*empty*/"
+NET_R_SET_RETURN="#define NET_R_SET_RETURN void"
+
+fi
+
+
+
+
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for endnetent_r" >&5
+echo $ECHO_N "checking for endnetent_r... $ECHO_C" >&6
+if test "${ac_cv_func_endnetent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define endnetent_r to an innocuous variant, in case <limits.h> declares endnetent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define endnetent_r innocuous_endnetent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char endnetent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef endnetent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char endnetent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_endnetent_r) || defined (__stub___endnetent_r)
+choke me
+#else
+char (*f) () = endnetent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != endnetent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_endnetent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_endnetent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_endnetent_r" >&5
+echo "${ECHO_T}$ac_cv_func_endnetent_r" >&6
+if test $ac_cv_func_endnetent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endnetent_r (void);
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NET_R_END_RESULT="#define NET_R_END_RESULT(x) /*empty*/"
+NET_R_END_RETURN="#define NET_R_END_RETURN void"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int endnetent_r(struct netent_data *);
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NET_R_END_RESULT="#define NET_R_END_RESULT(x) return (x)"
+NET_R_END_RETURN="#define NET_R_END_RETURN int"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern void endnetent_r(struct netent_data *);
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NET_R_END_RESULT="#define NET_R_END_RESULT(x) /*empty*/"
+NET_R_END_RETURN="#define NET_R_END_RETURN void"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ NET_R_END_RESULT="#define NET_R_END_RESULT(x) /*empty*/"
+NET_R_END_RETURN="#define NET_R_END_RETURN void"
+
+fi
+
+esac
+
+
+
+echo "$as_me:$LINENO: checking for getgrnam_r" >&5
+echo $ECHO_N "checking for getgrnam_r... $ECHO_C" >&6
+if test "${ac_cv_func_getgrnam_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getgrnam_r to an innocuous variant, in case <limits.h> declares getgrnam_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getgrnam_r innocuous_getgrnam_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getgrnam_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getgrnam_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getgrnam_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getgrnam_r) || defined (__stub___getgrnam_r)
+choke me
+#else
+char (*f) () = getgrnam_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getgrnam_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getgrnam_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getgrnam_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getgrnam_r" >&5
+echo "${ECHO_T}$ac_cv_func_getgrnam_r" >&6
+if test $ac_cv_func_getgrnam_r = yes; then
+ :
+else
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_GETGRNAM_R 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for getgrgid_r" >&5
+echo $ECHO_N "checking for getgrgid_r... $ECHO_C" >&6
+if test "${ac_cv_func_getgrgid_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getgrgid_r to an innocuous variant, in case <limits.h> declares getgrgid_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getgrgid_r innocuous_getgrgid_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getgrgid_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getgrgid_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getgrgid_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getgrgid_r) || defined (__stub___getgrgid_r)
+choke me
+#else
+char (*f) () = getgrgid_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getgrgid_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getgrgid_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getgrgid_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getgrgid_r" >&5
+echo "${ECHO_T}$ac_cv_func_getgrgid_r" >&6
+if test $ac_cv_func_getgrgid_r = yes; then
+ :
+else
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_GETGRGID_R 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for getgrent_r" >&5
+echo $ECHO_N "checking for getgrent_r... $ECHO_C" >&6
+if test "${ac_cv_func_getgrent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getgrent_r to an innocuous variant, in case <limits.h> declares getgrent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getgrent_r innocuous_getgrent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getgrent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getgrent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getgrent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getgrent_r) || defined (__stub___getgrent_r)
+choke me
+#else
+char (*f) () = getgrent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getgrent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getgrent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getgrent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getgrent_r" >&5
+echo "${ECHO_T}$ac_cv_func_getgrent_r" >&6
+if test $ac_cv_func_getgrent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <grp.h>
+struct group *getgrent_r(struct group *grp, char *buffer,
+ int buflen) {}
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+GROUP_R_ARGS="#define GROUP_R_ARGS char *buf, int buflen"
+GROUP_R_BAD="#define GROUP_R_BAD NULL"
+GROUP_R_OK="#define GROUP_R_OK gptr"
+GROUP_R_RETURN="#define GROUP_R_RETURN struct group *"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ GROUP_R_ARGS="#define GROUP_R_ARGS char *buf, int buflen"
+GROUP_R_BAD="#define GROUP_R_BAD NULL"
+GROUP_R_OK="#define GROUP_R_OK gptr"
+GROUP_R_RETURN="#define GROUP_R_RETURN struct group *"
+cat >>confdefs.h <<\_ACEOF
+#define NEED_GETGRENT_R 1
+_ACEOF
+
+
+fi
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for endgrent_r" >&5
+echo $ECHO_N "checking for endgrent_r... $ECHO_C" >&6
+if test "${ac_cv_func_endgrent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define endgrent_r to an innocuous variant, in case <limits.h> declares endgrent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define endgrent_r innocuous_endgrent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char endgrent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef endgrent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char endgrent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_endgrent_r) || defined (__stub___endgrent_r)
+choke me
+#else
+char (*f) () = endgrent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != endgrent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_endgrent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_endgrent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_endgrent_r" >&5
+echo "${ECHO_T}$ac_cv_func_endgrent_r" >&6
+if test $ac_cv_func_endgrent_r = yes; then
+ :
+else
+ GROUP_R_END_RESULT="#define GROUP_R_END_RESULT(x) /*empty*/"
+GROUP_R_END_RETURN="#define GROUP_R_END_RETURN void"
+GROUP_R_ENT_ARGS="#define GROUP_R_ENT_ARGS void"
+cat >>confdefs.h <<\_ACEOF
+#define NEED_ENDGRENT_R 1
+_ACEOF
+
+
+fi
+
+
+
+
+
+echo "$as_me:$LINENO: checking for setgrent_r" >&5
+echo $ECHO_N "checking for setgrent_r... $ECHO_C" >&6
+if test "${ac_cv_func_setgrent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define setgrent_r to an innocuous variant, in case <limits.h> declares setgrent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define setgrent_r innocuous_setgrent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char setgrent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef setgrent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setgrent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_setgrent_r) || defined (__stub___setgrent_r)
+choke me
+#else
+char (*f) () = setgrent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != setgrent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_setgrent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_setgrent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_setgrent_r" >&5
+echo "${ECHO_T}$ac_cv_func_setgrent_r" >&6
+if test $ac_cv_func_setgrent_r = yes; then
+ :
+else
+ GROUP_R_SET_RESULT="#undef GROUP_R_SET_RESULT /*empty*/"
+GROUP_R_SET_RETURN="#define GROUP_R_SET_RETURN void"
+cat >>confdefs.h <<\_ACEOF
+#define NEED_SETGRENT_R 1
+_ACEOF
+
+
+fi
+
+
+
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for gethostbyname_r" >&5
+echo $ECHO_N "checking for gethostbyname_r... $ECHO_C" >&6
+if test "${ac_cv_func_gethostbyname_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define gethostbyname_r to an innocuous variant, in case <limits.h> declares gethostbyname_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define gethostbyname_r innocuous_gethostbyname_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char gethostbyname_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef gethostbyname_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_gethostbyname_r) || defined (__stub___gethostbyname_r)
+choke me
+#else
+char (*f) () = gethostbyname_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != gethostbyname_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_gethostbyname_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_gethostbyname_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname_r" >&5
+echo "${ECHO_T}$ac_cv_func_gethostbyname_r" >&6
+if test $ac_cv_func_gethostbyname_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+struct hostent *gethostbyname_r
+(const char *name, struct hostent *hp, char *buf, int len, int *h_errnop) {}
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+HOST_R_ARGS="#define HOST_R_ARGS char *buf, int buflen, int *h_errnop"
+HOST_R_BAD="#define HOST_R_BAD NULL"
+HOST_R_COPY="#define HOST_R_COPY buf, buflen"
+HOST_R_COPY_ARGS="#define HOST_R_COPY_ARGS char *buf, int buflen"
+HOST_R_ERRNO="#define HOST_R_ERRNO *h_errnop = h_errno"
+HOST_R_OK="#define HOST_R_OK hptr"
+HOST_R_RETURN="#define HOST_R_RETURN struct hostent *"
+HOST_R_SETANSWER="#undef HOST_R_SETANSWER"
+HOSTENT_DATA="#undef HOSTENT_DATA"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int gethostbyname_r(const char *name,
+ struct hostent *result,
+ struct hostent_data *hdptr);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+HOST_R_ARGS="#define HOST_R_ARGS struct hostent_data *hdptr"
+HOST_R_BAD="#define HOST_R_BAD (-1)"
+HOST_R_COPY="#define HOST_R_COPY hdptr"
+HOST_R_COPY_ARGS="#define HOST_R_COPY_ARGS HOST_R_ARGS"
+HOST_R_ERRNO="#undef HOST_R_ERRNO"
+HOST_R_OK="#define HOST_R_OK 0"
+HOST_R_RETURN="#define HOST_R_RETURN int"
+HOST_R_SETANSWER="#undef HOST_R_SETANSWER"
+HOSTENT_DATA="#define HOSTENT_DATA 1"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int gethostbyname_r (const char *,
+ struct hostent *,
+ char *, size_t,
+ struct hostent **,
+ int *);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+HOST_R_ARGS="#define HOST_R_ARGS char *buf, size_t buflen, struct hostent **answerp, int *h_errnop"
+HOST_R_BAD="#define HOST_R_BAD ERANGE"
+HOST_R_COPY="#define HOST_R_COPY buf, buflen"
+HOST_R_COPY_ARGS="#define HOST_R_COPY_ARGS char *buf, int buflen"
+HOST_R_ERRNO="#define HOST_R_ERRNO *h_errnop = h_errno"
+HOST_R_OK="#define HOST_R_OK 0"
+HOST_R_RETURN="#define HOST_R_RETURN int"
+HOST_R_SETANSWER="#define HOST_R_SETANSWER 1"
+HOSTENT_DATA="#undef HOSTENT_DATA"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ HOST_R_ARGS="#define HOST_R_ARGS char *buf, int buflen, int *h_errnop"
+HOST_R_BAD="#define HOST_R_BAD NULL"
+HOST_R_COPY="#define HOST_R_COPY buf, buflen"
+HOST_R_COPY_ARGS="#define HOST_R_COPY_ARGS char *buf, int buflen"
+HOST_R_ERRNO="#define HOST_R_ERRNO *h_errnop = h_errno"
+HOST_R_OK="#define HOST_R_OK hptr"
+HOST_R_RETURN="#define HOST_R_RETURN struct hostent *"
+HOST_R_SETANSWER="#undef HOST_R_SETANSWER"
+HOSTENT_DATA="#undef HOSTENT_DATA"
+
+fi
+
+esac
+
+
+
+
+
+
+
+
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for endhostent_r" >&5
+echo $ECHO_N "checking for endhostent_r... $ECHO_C" >&6
+if test "${ac_cv_func_endhostent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define endhostent_r to an innocuous variant, in case <limits.h> declares endhostent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define endhostent_r innocuous_endhostent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char endhostent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef endhostent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char endhostent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_endhostent_r) || defined (__stub___endhostent_r)
+choke me
+#else
+char (*f) () = endhostent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != endhostent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_endhostent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_endhostent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_endhostent_r" >&5
+echo "${ECHO_T}$ac_cv_func_endhostent_r" >&6
+if test $ac_cv_func_endhostent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int endhostent_r(struct hostent_data *buffer);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ HOST_R_END_RESULT="#define HOST_R_END_RESULT(x) return (x)"
+HOST_R_END_RETURN="#define HOST_R_END_RETURN int"
+HOST_R_ENT_ARGS="#define HOST_R_ENT_ARGS struct hostent_data *hdptr"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern void endhostent_r(struct hostent_data *ht_data);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+HOST_R_END_RESULT="#define HOST_R_END_RESULT(x)"
+HOST_R_END_RETURN="#define HOST_R_END_RETURN void"
+HOST_R_ENT_ARGS="#define HOST_R_ENT_ARGS struct hostent_data *hdptr"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern void endhostent_r(void);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+HOST_R_END_RESULT="#define HOST_R_END_RESULT(x) /*empty*/"
+HOST_R_END_RETURN="#define HOST_R_END_RETURN void"
+HOST_R_ENT_ARGS="#undef HOST_R_ENT_ARGS /*empty*/"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ HOST_R_END_RESULT="#define HOST_R_END_RESULT(x) /*empty*/"
+HOST_R_END_RETURN="#define HOST_R_END_RETURN void"
+HOST_R_ENT_ARGS="#undef HOST_R_ENT_ARGS /*empty*/"
+
+fi
+
+esac;
+
+
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for sethostent_r" >&5
+echo $ECHO_N "checking for sethostent_r... $ECHO_C" >&6
+if test "${ac_cv_func_sethostent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define sethostent_r to an innocuous variant, in case <limits.h> declares sethostent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define sethostent_r innocuous_sethostent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char sethostent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef sethostent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sethostent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_sethostent_r) || defined (__stub___sethostent_r)
+choke me
+#else
+char (*f) () = sethostent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != sethostent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_sethostent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_sethostent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_sethostent_r" >&5
+echo "${ECHO_T}$ac_cv_func_sethostent_r" >&6
+if test $ac_cv_func_sethostent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern void sethostent_r(int flag, struct hostent_data *ht_data);
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ HOST_R_SET_RESULT="#undef HOST_R_SET_RESULT /*empty*/"
+HOST_R_SET_RETURN="#define HOST_R_SET_RETURN void"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int sethostent_r(int flag, struct hostent_data *ht_data);
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ HOST_R_SET_RESULT="#define HOST_R_SET_RESULT 0"
+HOST_R_SET_RETURN="#define HOST_R_SET_RETURN int"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void sethostent_r (int);
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ HOST_R_SET_RESULT="#undef HOST_R_SET_RESULT"
+HOST_R_SET_RETURN="#define HOST_R_SET_RETURN void"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ HOST_R_SET_RESULT="#undef HOST_R_SET_RESULT"
+HOST_R_SET_RETURN="#define HOST_R_SET_RETURN void"
+
+fi
+
+esac
+
+
+
+
+echo "$as_me:$LINENO: checking struct passwd element pw_class" >&5
+echo $ECHO_N "checking struct passwd element pw_class... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <pwd.h>
+
+int
+main ()
+{
+struct passwd *pw; pw->pw_class = "";
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+cat >>confdefs.h <<\_ACEOF
+#define HAS_PW_CLASS 1
+_ACEOF
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <pwd.h>
+void
+setpwent(void) {}
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ SETPWENT_VOID="#define SETPWENT_VOID 1"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+SETPWENT_VOID="#undef SETPWENT_VOID"
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <grp.h>
+void
+setgrent(void) {}
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ SETGRENT_VOID="#define SETGRENT_VOID 1"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+SETGRENT_VOID="#undef SETGRENT_VOID"
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for getnetgrent_r" >&5
+echo $ECHO_N "checking for getnetgrent_r... $ECHO_C" >&6
+if test "${ac_cv_func_getnetgrent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getnetgrent_r to an innocuous variant, in case <limits.h> declares getnetgrent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getnetgrent_r innocuous_getnetgrent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getnetgrent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getnetgrent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getnetgrent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getnetgrent_r) || defined (__stub___getnetgrent_r)
+choke me
+#else
+char (*f) () = getnetgrent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getnetgrent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getnetgrent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getnetgrent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getnetgrent_r" >&5
+echo "${ECHO_T}$ac_cv_func_getnetgrent_r" >&6
+if test $ac_cv_func_getnetgrent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getnetgrent_r(char **m, char **u, char **d, char *b, int l) {}
+
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NGR_R_ARGS="#define NGR_R_ARGS char *buf, int buflen"
+NGR_R_BAD="#define NGR_R_BAD (0)"
+NGR_R_COPY="#define NGR_R_COPY buf, buflen"
+NGR_R_COPY_ARGS="#define NGR_R_COPY_ARGS NGR_R_ARGS"
+NGR_R_OK="#define NGR_R_OK 1"
+NGR_R_RETURN="#define NGR_R_RETURN int"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getnetgrent_r(char **m, char **u, char **d, char *b, size_t l) {}
+
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NGR_R_ARGS="#define NGR_R_ARGS char *buf, size_t buflen"
+NGR_R_BAD="#define NGR_R_BAD (0)"
+NGR_R_COPY="#define NGR_R_COPY buf, buflen"
+NGR_R_COPY_ARGS="#define NGR_R_COPY_ARGS NGR_R_ARGS"
+NGR_R_OK="#define NGR_R_OK 1"
+NGR_R_RETURN="#define NGR_R_RETURN int"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int getnetgrent_r( char **, char **, char **, void **);
+
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NGR_R_ARGS="#define NGR_R_ARGS void **buf"
+NGR_R_BAD="#define NGR_R_BAD (0)"
+NGR_R_COPY="#define NGR_R_COPY buf"
+NGR_R_COPY_ARGS="#define NGR_R_COPY_ARGS NGR_R_ARGS"
+NGR_R_OK="#define NGR_R_OK 1"
+NGR_R_RETURN="#define NGR_R_RETURN int"
+NGR_R_PRIVATE="#define NGR_R_PRIVATE 1"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ NGR_R_ARGS="#define NGR_R_ARGS char *buf, int buflen"
+NGR_R_BAD="#define NGR_R_BAD (0)"
+NGR_R_COPY="#define NGR_R_COPY buf, buflen"
+NGR_R_COPY_ARGS="#define NGR_R_COPY_ARGS NGR_R_ARGS"
+NGR_R_OK="#define NGR_R_OK 1"
+NGR_R_RETURN="#define NGR_R_RETURN int"
+
+fi
+
+esac
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for endnetgrent_r" >&5
+echo $ECHO_N "checking for endnetgrent_r... $ECHO_C" >&6
+if test "${ac_cv_func_endnetgrent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define endnetgrent_r to an innocuous variant, in case <limits.h> declares endnetgrent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define endnetgrent_r innocuous_endnetgrent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char endnetgrent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef endnetgrent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char endnetgrent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_endnetgrent_r) || defined (__stub___endnetgrent_r)
+choke me
+#else
+char (*f) () = endnetgrent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != endnetgrent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_endnetgrent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_endnetgrent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_endnetgrent_r" >&5
+echo "${ECHO_T}$ac_cv_func_endnetgrent_r" >&6
+if test $ac_cv_func_endnetgrent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endnetgrent_r(void **ptr);
+
+
+int
+main ()
+{
+return (0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+NGR_R_END_RESULT="#define NGR_R_END_RESULT(x) /* empty */"
+NGR_R_END_RETURN="#define NGR_R_END_RETURN void"
+NGR_R_ENT_ARGS="#define NGR_R_ENT_ARGS NGR_R_ARGS"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+NGR_R_END_RESULT="#define NGR_R_END_RESULT(x) return (x)"
+NGR_R_END_RETURN="#define NGR_R_END_RETURN int"
+NGR_R_ENT_ARGS="#define NGR_R_ENT_ARGS NGR_R_ARGS"
+
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ NGR_R_END_RESULT="#define NGR_R_END_RESULT(x) /*empty*/"
+NGR_R_END_RETURN="#define NGR_R_END_RETURN void"
+NGR_R_ENT_ARGS="#undef NGR_R_ENT_ARGS /*empty*/"
+cat >>confdefs.h <<\_ACEOF
+#define NEED_ENDNETGRENT_R 1
+_ACEOF
+
+
+fi
+
+
+
+
+
+echo "$as_me:$LINENO: checking for setnetgrent_r" >&5
+echo $ECHO_N "checking for setnetgrent_r... $ECHO_C" >&6
+if test "${ac_cv_func_setnetgrent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define setnetgrent_r to an innocuous variant, in case <limits.h> declares setnetgrent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define setnetgrent_r innocuous_setnetgrent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char setnetgrent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef setnetgrent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setnetgrent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_setnetgrent_r) || defined (__stub___setnetgrent_r)
+choke me
+#else
+char (*f) () = setnetgrent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != setnetgrent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_setnetgrent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_setnetgrent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_setnetgrent_r" >&5
+echo "${ECHO_T}$ac_cv_func_setnetgrent_r" >&6
+if test $ac_cv_func_setnetgrent_r = yes; then
+
+case "$host" in
+*bsdi*)
+ NGR_R_SET_RESULT="#undef NGR_R_SET_RESULT /*empty*/"
+ NGR_R_SET_RETURN="#define NGR_R_SET_RETURN void"
+ ;;
+*)
+ NGR_R_SET_RESULT="#define NGR_R_SET_RESULT NGR_R_OK"
+ NGR_R_SET_RETURN="#define NGR_R_SET_RETURN int"
+ ;;
+esac
+
+
+else
+ NGR_R_SET_RESULT="#undef NGR_R_SET_RESULT /*empty*/"
+NGR_R_SET_RETURN="#define NGR_R_SET_RETURN void"
+
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking for innetgr_r" >&5
+echo $ECHO_N "checking for innetgr_r... $ECHO_C" >&6
+if test "${ac_cv_func_innetgr_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define innetgr_r to an innocuous variant, in case <limits.h> declares innetgr_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define innetgr_r innocuous_innetgr_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char innetgr_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef innetgr_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char innetgr_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_innetgr_r) || defined (__stub___innetgr_r)
+choke me
+#else
+char (*f) () = innetgr_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != innetgr_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_innetgr_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_innetgr_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_innetgr_r" >&5
+echo "${ECHO_T}$ac_cv_func_innetgr_r" >&6
+if test $ac_cv_func_innetgr_r = yes; then
+ :
+else
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_INNETGR_R 1
+_ACEOF
+
+fi
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for getprotoent_r" >&5
+echo $ECHO_N "checking for getprotoent_r... $ECHO_C" >&6
+if test "${ac_cv_func_getprotoent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getprotoent_r to an innocuous variant, in case <limits.h> declares getprotoent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getprotoent_r innocuous_getprotoent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getprotoent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getprotoent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getprotoent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getprotoent_r) || defined (__stub___getprotoent_r)
+choke me
+#else
+char (*f) () = getprotoent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getprotoent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getprotoent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getprotoent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getprotoent_r" >&5
+echo "${ECHO_T}$ac_cv_func_getprotoent_r" >&6
+if test $ac_cv_func_getprotoent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+struct protoent *getprotoent_r(struct protoent *result,
+ char *buffer, int buflen) {}
+
+
+int
+main ()
+{
+return (0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+PROTO_R_ARGS="#define PROTO_R_ARGS char *buf, int buflen"
+PROTO_R_BAD="#define PROTO_R_BAD NULL"
+PROTO_R_COPY="#define PROTO_R_COPY buf, buflen"
+PROTO_R_COPY_ARGS="#define PROTO_R_COPY_ARGS PROTO_R_ARGS"
+PROTO_R_OK="#define PROTO_R_OK pptr"
+PROTO_R_SETANSWER="#undef PROTO_R_SETANSWER"
+PROTO_R_RETURN="#define PROTO_R_RETURN struct protoent *"
+PROTOENT_DATA="#undef PROTOENT_DATA"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getprotoent_r (struct protoent *, char *, size_t, struct protoent **);
+
+
+
+int
+main ()
+{
+return (0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+PROTO_R_ARGS="#define PROTO_R_ARGS char *buf, size_t buflen, struct protoent **answerp"
+PROTO_R_BAD="#define PROTO_R_BAD ERANGE"
+PROTO_R_COPY="#define PROTO_R_COPY buf, buflen"
+PROTO_R_COPY_ARGS="#define PROTO_R_COPY_ARGS char *buf, size_t buflen"
+PROTO_R_OK="#define PROTO_R_OK 0"
+PROTO_R_SETANSWER="#define PROTO_R_SETANSWER 1"
+PROTO_R_RETURN="#define PROTO_R_RETURN int"
+PROTOENT_DATA="#undef PROTOENT_DATA"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getprotoent_r (struct protoent *, struct protoent_data *prot_data);
+
+
+
+int
+main ()
+{
+return (0);
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+PROTO_R_ARGS="#define PROTO_R_ARGS struct protoent_data *prot_data"
+PROTO_R_BAD="#define PROTO_R_BAD (-1)"
+PROTO_R_COPY="#define PROTO_R_COPY prot_data"
+PROTO_R_COPY_ARGS="#define PROTO_R_COPY_ARGS struct protoent_data *pdptr"
+PROTO_R_OK="#define PROTO_R_OK 0"
+PROTO_R_SETANSWER="#undef PROTO_R_SETANSWER"
+PROTO_R_RETURN="#define PROTO_R_RETURN int"
+PROTOENT_DATA="#define PROTOENT_DATA 1"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ PROTO_R_ARGS="#define PROTO_R_ARGS char *buf, int buflen"
+PROTO_R_BAD="#define PROTO_R_BAD NULL"
+PROTO_R_COPY="#define PROTO_R_COPY buf, buflen"
+PROTO_R_COPY_ARGS="#define PROTO_R_COPY_ARGS PROTO_R_ARGS"
+PROTO_R_OK="#define PROTO_R_OK pptr"
+PROTO_R_SETANSWER="#undef PROTO_R_SETANSWER"
+PROTO_R_RETURN="#define PROTO_R_RETURN struct protoent *"
+PROTOENT_DATA="#undef PROTOENT_DATA"
+
+fi
+
+;;
+esac
+
+
+
+
+
+
+
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for endprotoent_r" >&5
+echo $ECHO_N "checking for endprotoent_r... $ECHO_C" >&6
+if test "${ac_cv_func_endprotoent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define endprotoent_r to an innocuous variant, in case <limits.h> declares endprotoent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define endprotoent_r innocuous_endprotoent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char endprotoent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef endprotoent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char endprotoent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_endprotoent_r) || defined (__stub___endprotoent_r)
+choke me
+#else
+char (*f) () = endprotoent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != endprotoent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_endprotoent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_endprotoent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_endprotoent_r" >&5
+echo "${ECHO_T}$ac_cv_func_endprotoent_r" >&6
+if test $ac_cv_func_endprotoent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endprotoent_r(void);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+PROTO_R_END_RESULT="#define PROTO_R_END_RESULT(x) /*empty*/"
+PROTO_R_END_RETURN="#define PROTO_R_END_RETURN void"
+PROTO_R_ENT_ARGS="#undef PROTO_R_ENT_ARGS"
+PROTO_R_ENT_UNUSED="#undef PROTO_R_ENT_UNUSED"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endprotoent_r(struct protoent_data *);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+PROTO_R_END_RESULT="#define PROTO_R_END_RESULT(x) /*empty*/"
+PROTO_R_END_RETURN="#define PROTO_R_END_RETURN void"
+PROTO_R_ENT_ARGS="#define PROTO_R_ENT_ARGS struct protoent_data *proto_data"
+PROTO_R_ENT_UNUSED="#define PROTO_R_ENT_UNUSED UNUSED(proto_data)"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int endprotoent_r(struct protoent_data *);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+PROTO_R_END_RESULT="#define PROTO_R_END_RESULT(x) return(0)"
+PROTO_R_END_RETURN="#define PROTO_R_END_RETURN int"
+PROTO_R_ENT_ARGS="#define PROTO_R_ENT_ARGS struct protoent_data *proto_data"
+PROTO_R_ENT_UNUSED="#define PROTO_R_ENT_UNUSED UNUSED(proto_data)"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ PROTO_R_END_RESULT="#define PROTO_R_END_RESULT(x) /*empty*/"
+PROTO_R_END_RETURN="#define PROTO_R_END_RETURN void"
+PROTO_R_ENT_ARGS="#undef PROTO_R_ENT_ARGS /*empty*/"
+PROTO_R_ENT_UNUSED="#undef PROTO_R_ENT_UNUSED"
+
+fi
+
+esac
+
+
+
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for setprotoent_r" >&5
+echo $ECHO_N "checking for setprotoent_r... $ECHO_C" >&6
+if test "${ac_cv_func_setprotoent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define setprotoent_r to an innocuous variant, in case <limits.h> declares setprotoent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define setprotoent_r innocuous_setprotoent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char setprotoent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef setprotoent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setprotoent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_setprotoent_r) || defined (__stub___setprotoent_r)
+choke me
+#else
+char (*f) () = setprotoent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != setprotoent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_setprotoent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_setprotoent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_setprotoent_r" >&5
+echo "${ECHO_T}$ac_cv_func_setprotoent_r" >&6
+if test $ac_cv_func_setprotoent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void setprotoent_r __P((int));
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ PROTO_R_SET_RESULT="#undef PROTO_R_SET_RESULT"
+PROTO_R_SET_RETURN="#define PROTO_R_SET_RETURN void"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int setprotoent_r (int, struct protoent_data *);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ PROTO_R_SET_RESULT="#define PROTO_R_SET_RESULT (0)"
+PROTO_R_SET_RETURN="#define PROTO_R_SET_RETURN int"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ PROTO_R_SET_RESULT="#undef PROTO_R_SET_RESULT"
+PROTO_R_SET_RETURN="#define PROTO_R_SET_RETURN void"
+
+fi
+
+esac
+
+
+
+echo "$as_me:$LINENO: checking for getpwent_r" >&5
+echo $ECHO_N "checking for getpwent_r... $ECHO_C" >&6
+if test "${ac_cv_func_getpwent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getpwent_r to an innocuous variant, in case <limits.h> declares getpwent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getpwent_r innocuous_getpwent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getpwent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getpwent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getpwent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getpwent_r) || defined (__stub___getpwent_r)
+choke me
+#else
+char (*f) () = getpwent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getpwent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getpwent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getpwent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getpwent_r" >&5
+echo "${ECHO_T}$ac_cv_func_getpwent_r" >&6
+if test $ac_cv_func_getpwent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <pwd.h>
+struct passwd *
+getpwent_r(struct passwd *pwptr, char *buf, int buflen) {}
+
+
+int
+main ()
+{
+
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ PASS_R_ARGS="#define PASS_R_ARGS char *buf, int buflen"
+PASS_R_BAD="#define PASS_R_BAD NULL"
+PASS_R_COPY="#define PASS_R_COPY buf, buflen"
+PASS_R_COPY_ARGS="#define PASS_R_COPY_ARGS PASS_R_ARGS"
+PASS_R_OK="#define PASS_R_OK pwptr"
+PASS_R_RETURN="#define PASS_R_RETURN struct passwd *"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ PASS_R_ARGS="#define PASS_R_ARGS char *buf, int buflen"
+PASS_R_BAD="#define PASS_R_BAD NULL"
+PASS_R_COPY="#define PASS_R_COPY buf, buflen"
+PASS_R_COPY_ARGS="#define PASS_R_COPY_ARGS PASS_R_ARGS"
+PASS_R_OK="#define PASS_R_OK pwptr"
+PASS_R_RETURN="#define PASS_R_RETURN struct passwd *"
+cat >>confdefs.h <<\_ACEOF
+#define NEED_GETPWENT_R 1
+_ACEOF
+
+
+fi
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for endpwent_r" >&5
+echo $ECHO_N "checking for endpwent_r... $ECHO_C" >&6
+if test "${ac_cv_func_endpwent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define endpwent_r to an innocuous variant, in case <limits.h> declares endpwent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define endpwent_r innocuous_endpwent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char endpwent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef endpwent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char endpwent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_endpwent_r) || defined (__stub___endpwent_r)
+choke me
+#else
+char (*f) () = endpwent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != endpwent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_endpwent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_endpwent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_endpwent_r" >&5
+echo "${ECHO_T}$ac_cv_func_endpwent_r" >&6
+if test $ac_cv_func_endpwent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <pwd.h>
+void endpwent_r(FILE **pwfp);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ PASS_R_END_RESULT="#define PASS_R_END_RESULT(x) /*empty*/"
+PASS_R_END_RETURN="#define PASS_R_END_RETURN void"
+PASS_R_ENT_ARGS="#define PASS_R_ENT_ARGS FILE **pwptr"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ PASS_R_END_RESULT="#define PASS_R_END_RESULT(x) /*empty*/"
+PASS_R_END_RETURN="#define PASS_R_END_RETURN void"
+PASS_R_ENT_ARGS="#undef PASS_R_ENT_ARGS"
+cat >>confdefs.h <<\_ACEOF
+#define NEED_ENDPWENT_R 1
+_ACEOF
+
+
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking for setpassent_r" >&5
+echo $ECHO_N "checking for setpassent_r... $ECHO_C" >&6
+if test "${ac_cv_func_setpassent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define setpassent_r to an innocuous variant, in case <limits.h> declares setpassent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define setpassent_r innocuous_setpassent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char setpassent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef setpassent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setpassent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_setpassent_r) || defined (__stub___setpassent_r)
+choke me
+#else
+char (*f) () = setpassent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != setpassent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_setpassent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_setpassent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_setpassent_r" >&5
+echo "${ECHO_T}$ac_cv_func_setpassent_r" >&6
+if test $ac_cv_func_setpassent_r = yes; then
+ :
+else
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_SETPASSENT_R 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for setpassent" >&5
+echo $ECHO_N "checking for setpassent... $ECHO_C" >&6
+if test "${ac_cv_func_setpassent+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define setpassent to an innocuous variant, in case <limits.h> declares setpassent.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define setpassent innocuous_setpassent
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char setpassent (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef setpassent
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setpassent ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_setpassent) || defined (__stub___setpassent)
+choke me
+#else
+char (*f) () = setpassent;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != setpassent;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_setpassent=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_setpassent=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_setpassent" >&5
+echo "${ECHO_T}$ac_cv_func_setpassent" >&6
+if test $ac_cv_func_setpassent = yes; then
+ :
+else
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_SETPASSENT 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for setpwent_r" >&5
+echo $ECHO_N "checking for setpwent_r... $ECHO_C" >&6
+if test "${ac_cv_func_setpwent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define setpwent_r to an innocuous variant, in case <limits.h> declares setpwent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define setpwent_r innocuous_setpwent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char setpwent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef setpwent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setpwent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_setpwent_r) || defined (__stub___setpwent_r)
+choke me
+#else
+char (*f) () = setpwent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != setpwent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_setpwent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_setpwent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_setpwent_r" >&5
+echo "${ECHO_T}$ac_cv_func_setpwent_r" >&6
+if test $ac_cv_func_setpwent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <pwd.h>
+void setpwent_r(FILE **pwfp);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ PASS_R_SET_RESULT="#undef PASS_R_SET_RESULT /* empty */"
+PASS_R_SET_RETURN="#define PASS_R_SET_RETURN int"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <pwd.h>
+int setpwent_r(FILE **pwfp);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ PASS_R_SET_RESULT="#define PASS_R_SET_RESULT 0"
+PASS_R_SET_RETURN="#define PASS_R_SET_RETURN int"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ PASS_R_SET_RESULT="#undef PASS_R_SET_RESULT /*empty*/"
+PASS_R_SET_RETURN="#define PASS_R_SET_RETURN void"
+cat >>confdefs.h <<\_ACEOF
+#define NEED_SETPWENT_R 1
+_ACEOF
+
+
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking for getpwnam_r" >&5
+echo $ECHO_N "checking for getpwnam_r... $ECHO_C" >&6
+if test "${ac_cv_func_getpwnam_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getpwnam_r to an innocuous variant, in case <limits.h> declares getpwnam_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getpwnam_r innocuous_getpwnam_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getpwnam_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getpwnam_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getpwnam_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getpwnam_r) || defined (__stub___getpwnam_r)
+choke me
+#else
+char (*f) () = getpwnam_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getpwnam_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getpwnam_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getpwnam_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getpwnam_r" >&5
+echo "${ECHO_T}$ac_cv_func_getpwnam_r" >&6
+if test $ac_cv_func_getpwnam_r = yes; then
+ :
+else
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_GETPWNAM_R 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for getpwuid_r" >&5
+echo $ECHO_N "checking for getpwuid_r... $ECHO_C" >&6
+if test "${ac_cv_func_getpwuid_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getpwuid_r to an innocuous variant, in case <limits.h> declares getpwuid_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getpwuid_r innocuous_getpwuid_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getpwuid_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getpwuid_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getpwuid_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getpwuid_r) || defined (__stub___getpwuid_r)
+choke me
+#else
+char (*f) () = getpwuid_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getpwuid_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getpwuid_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getpwuid_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getpwuid_r" >&5
+echo "${ECHO_T}$ac_cv_func_getpwuid_r" >&6
+if test $ac_cv_func_getpwuid_r = yes; then
+ :
+else
+ cat >>confdefs.h <<\_ACEOF
+#define NEED_GETPWUID_R 1
+_ACEOF
+
+fi
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for getservent_r" >&5
+echo $ECHO_N "checking for getservent_r... $ECHO_C" >&6
+if test "${ac_cv_func_getservent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define getservent_r to an innocuous variant, in case <limits.h> declares getservent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define getservent_r innocuous_getservent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char getservent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getservent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char getservent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getservent_r) || defined (__stub___getservent_r)
+choke me
+#else
+char (*f) () = getservent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != getservent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_getservent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_getservent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getservent_r" >&5
+echo "${ECHO_T}$ac_cv_func_getservent_r" >&6
+if test $ac_cv_func_getservent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+struct servent *
+getservent_r(struct servent *result, char *buffer, int buflen) {}
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+SERV_R_ARGS="#define SERV_R_ARGS char *buf, int buflen"
+SERV_R_BAD="#define SERV_R_BAD NULL"
+SERV_R_COPY="#define SERV_R_COPY buf, buflen"
+SERV_R_COPY_ARGS="#define SERV_R_COPY_ARGS SERV_R_ARGS"
+SERV_R_OK="#define SERV_R_OK sptr"
+SERV_R_SETANSWER="#undef SERV_R_SETANSWER"
+SERV_R_RETURN="#define SERV_R_RETURN struct servent *"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int
+getservent_r (struct servent *, char *, size_t, struct servent **);
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+SERV_R_ARGS="#define SERV_R_ARGS char *buf, size_t buflen, struct servent **answerp"
+SERV_R_BAD="#define SERV_R_BAD ERANGE"
+SERV_R_COPY="#define SERV_R_COPY buf, buflen"
+SERV_R_COPY_ARGS="#define SERV_R_COPY_ARGS char *buf, size_t buflen"
+SERV_R_OK="#define SERV_R_OK (0)"
+SERV_R_SETANSWER="#define SERV_R_SETANSWER 1"
+SERV_R_RETURN="#define SERV_R_RETURN int"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int
+getservent_r (struct servent *, struct servent_data *serv_data);
+
+int
+main ()
+{
+return (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+SERV_R_ARGS="#define SERV_R_ARGS struct servent_data *serv_data"
+SERV_R_BAD="#define SERV_R_BAD (-1)"
+SERV_R_COPY="#define SERV_R_COPY serv_data"
+SERV_R_COPY_ARGS="#define SERV_R_COPY_ARGS struct servent_data *sdptr"
+SERV_R_OK="#define SERV_R_OK (0)"
+SERV_R_SETANSWER="#undef SERV_R_SETANSWER"
+SERV_R_RETURN="#define SERV_R_RETURN int"
+SERVENT_DATA="#define SERVENT_DATA 1"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ SERV_R_ARGS="#define SERV_R_ARGS char *buf, int buflen"
+SERV_R_BAD="#define SERV_R_BAD NULL"
+SERV_R_COPY="#define SERV_R_COPY buf, buflen"
+SERV_R_COPY_ARGS="#define SERV_R_COPY_ARGS SERV_R_ARGS"
+SERV_R_OK="#define SERV_R_OK sptr"
+SERV_R_SETANSWER="#undef SERV_R_SETANSWER"
+SERV_R_RETURN="#define SERV_R_RETURN struct servent *"
+
+fi
+
+esac
+
+
+
+
+
+
+
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for endservent_r" >&5
+echo $ECHO_N "checking for endservent_r... $ECHO_C" >&6
+if test "${ac_cv_func_endservent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define endservent_r to an innocuous variant, in case <limits.h> declares endservent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define endservent_r innocuous_endservent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char endservent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef endservent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char endservent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_endservent_r) || defined (__stub___endservent_r)
+choke me
+#else
+char (*f) () = endservent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != endservent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_endservent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_endservent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_endservent_r" >&5
+echo "${ECHO_T}$ac_cv_func_endservent_r" >&6
+if test $ac_cv_func_endservent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endservent_r(void);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+SERV_R_END_RESULT="#define SERV_R_END_RESULT(x) /*empty*/"
+SERV_R_END_RETURN="#define SERV_R_END_RETURN void "
+SERV_R_ENT_ARGS="#undef SERV_R_ENT_ARGS /*empty*/"
+SERV_R_ENT_UNUSED="#undef SERV_R_ENT_UNUSED /*empty*/"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endservent_r(struct servent_data *serv_data);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+SERV_R_END_RESULT="#define SERV_R_END_RESULT(x) /*empty*/"
+SERV_R_END_RETURN="#define SERV_R_END_RETURN void "
+SERV_R_ENT_ARGS="#define SERV_R_ENT_ARGS struct servent_data *serv_data"
+SERV_R_ENT_UNUSED="#define SERV_R_ENT_UNUSED UNUSED(serv_data)"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int endservent_r(struct servent_data *serv_data);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+SERV_R_END_RESULT="#define SERV_R_END_RESULT(x) return(x)"
+SERV_R_END_RETURN="#define SERV_R_END_RETURN int "
+SERV_R_ENT_ARGS="#define SERV_R_ENT_ARGS struct servent_data *serv_data"
+SERV_R_ENT_UNUSED="#define SERV_R_ENT_UNUSED UNUSED(serv_data)"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ SERV_R_END_RESULT="#define SERV_R_END_RESULT(x) /*empty*/"
+SERV_R_END_RETURN="#define SERV_R_END_RETURN void "
+SERV_R_ENT_ARGS="#undef SERV_R_ENT_ARGS /*empty*/"
+SERV_R_ENT_UNUSED="#undef SERV_R_ENT_UNUSED /*empty*/"
+
+fi
+
+esac
+
+
+
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+echo "$as_me:$LINENO: checking for setservent_r" >&5
+echo $ECHO_N "checking for setservent_r... $ECHO_C" >&6
+if test "${ac_cv_func_setservent_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define setservent_r to an innocuous variant, in case <limits.h> declares setservent_r.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define setservent_r innocuous_setservent_r
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char setservent_r (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef setservent_r
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setservent_r ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_setservent_r) || defined (__stub___setservent_r)
+choke me
+#else
+char (*f) () = setservent_r;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != setservent_r;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_setservent_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_setservent_r=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_setservent_r" >&5
+echo "${ECHO_T}$ac_cv_func_setservent_r" >&6
+if test $ac_cv_func_setservent_r = yes; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void setservent_r(int);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+SERV_R_SET_RESULT="#undef SERV_R_SET_RESULT"
+SERV_R_SET_RETURN="#define SERV_R_SET_RETURN void"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int setservent_r(int, struct servent_data *);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+SERV_R_SET_RESULT="#define SERV_R_SET_RESULT (0)"
+SERV_R_SET_RETURN="#define SERV_R_SET_RETURN int"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+ SERV_R_SET_RESULT="#undef SERV_R_SET_RESULT"
+SERV_R_SET_RETURN="#define SERV_R_SET_RETURN void"
+
+fi
+
+esac
+
+
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <unistd.h>
+#include <netdb.h>
+int innetgr(const char *netgroup, const char *host, const char *user, const char *domain);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+INNETGR_ARGS="#undef INNETGR_ARGS"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <unistd.h>
+#include <netdb.h>
+int innetgr(char *netgroup, char *host, char *user, char *domain);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+INNETGR_ARGS="#define INNETGR_ARGS char *netgroup, char *host, char *user, char *domain"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <unistd.h>
+#include <netdb.h>
+void setnetgrent(const char *);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+SETNETGRENT_ARGS="#undef SETNETGRENT_ARGS"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <unistd.h>
+#include <netdb.h>
+void setnetgrent(char *);
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+SETNETGRENT_ARGS="#define SETNETGRENT_ARGS char *netgroup"
+
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+
+#
+# Random remaining OS-specific issues involving compiler warnings.
+# XXXDCL print messages to indicate some compensation is being done?
+#
+BROKEN_IN6ADDR_INIT_MACROS="#undef BROKEN_IN6ADDR_INIT_MACROS"
+
+case "$host" in
+ *-aix5.1.*)
+ hack_shutup_pthreadmutexinit=yes
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-aix5.[23].*)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-bsdi3.1*)
+ hack_shutup_sputaux=yes
+ ;;
+ *-bsdi4.0*)
+ hack_shutup_sigwait=yes
+ hack_shutup_sputaux=yes
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-bsdi4.1*)
+ hack_shutup_stdargcast=yes
+ ;;
+ *-hpux11.11)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-osf5.1|*-osf5.1b)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-solaris2.8)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-solaris2.9)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-solaris2.10)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+esac
+
+case "$hack_shutup_pthreadmutexinit" in
+ yes)
+ #
+ # Shut up PTHREAD_MUTEX_INITIALIZER unbraced
+ # initializer warnings.
+ #
+ cat >>confdefs.h <<\_ACEOF
+#define SHUTUP_MUTEX_INITIALIZER 1
+_ACEOF
+
+ ;;
+esac
+
+case "$hack_shutup_sigwait" in
+ yes)
+ #
+ # Shut up a -Wmissing-prototypes warning for sigwait().
+ #
+ cat >>confdefs.h <<\_ACEOF
+#define SHUTUP_SIGWAIT 1
+_ACEOF
+
+ ;;
+esac
+
+case "$hack_shutup_sputaux" in
+ yes)
+ #
+ # Shut up a -Wmissing-prototypes warning from <stdio.h>.
+ #
+ cat >>confdefs.h <<\_ACEOF
+#define SHUTUP_SPUTAUX 1
+_ACEOF
+
+ ;;
+esac
+
+case "$hack_shutup_stdargcast" in
+ yes)
+ #
+ # Shut up a -Wcast-qual warning from va_start().
+ #
+ cat >>confdefs.h <<\_ACEOF
+#define SHUTUP_STDARG_CAST 1
+_ACEOF
+
+ ;;
+esac
+
+case "$hack_shutup_in6addr_init_macros" in
+ yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_IN6ADDR_INIT_MACROS 1
+_ACEOF
+
+ ;;
+esac
+
+#
+# Substitutions
+#
+
+BIND9_TOP_BUILDDIR=`pwd`
+
+
+BIND9_INCLUDES=$BIND9_TOP_BUILDDIR/make/includes
+
+
+BIND9_MAKE_RULES=$BIND9_TOP_BUILDDIR/make/rules
+
+. $srcdir/../../version
+BIND9_VERSION="VERSION=${MAJORVER}.${MINORVER}.${PATCHVER}${RELEASETYPE}${RELEASEVER}"
+
+
+
+LIBBIND_API=$srcdir/api
+
+ ac_config_files="$ac_config_files make/rules make/mkdep make/includes Makefile bsd/Makefile dst/Makefile include/Makefile inet/Makefile irs/Makefile isc/Makefile nameser/Makefile port_after.h port_before.h resolv/Makefile port/Makefile ${PORT_DIR}/Makefile ${PORT_INCLUDE}/Makefile"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.59,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "make/rules" ) CONFIG_FILES="$CONFIG_FILES make/rules" ;;
+ "make/mkdep" ) CONFIG_FILES="$CONFIG_FILES make/mkdep" ;;
+ "make/includes" ) CONFIG_FILES="$CONFIG_FILES make/includes" ;;
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "bsd/Makefile" ) CONFIG_FILES="$CONFIG_FILES bsd/Makefile" ;;
+ "dst/Makefile" ) CONFIG_FILES="$CONFIG_FILES dst/Makefile" ;;
+ "include/Makefile" ) CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
+ "inet/Makefile" ) CONFIG_FILES="$CONFIG_FILES inet/Makefile" ;;
+ "irs/Makefile" ) CONFIG_FILES="$CONFIG_FILES irs/Makefile" ;;
+ "isc/Makefile" ) CONFIG_FILES="$CONFIG_FILES isc/Makefile" ;;
+ "nameser/Makefile" ) CONFIG_FILES="$CONFIG_FILES nameser/Makefile" ;;
+ "port_after.h" ) CONFIG_FILES="$CONFIG_FILES port_after.h" ;;
+ "port_before.h" ) CONFIG_FILES="$CONFIG_FILES port_before.h" ;;
+ "resolv/Makefile" ) CONFIG_FILES="$CONFIG_FILES resolv/Makefile" ;;
+ "port/Makefile" ) CONFIG_FILES="$CONFIG_FILES port/Makefile" ;;
+ "${PORT_DIR}/Makefile" ) CONFIG_FILES="$CONFIG_FILES ${PORT_DIR}/Makefile" ;;
+ "${PORT_INCLUDE}/Makefile" ) CONFIG_FILES="$CONFIG_FILES ${PORT_INCLUDE}/Makefile" ;;
+ "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@STD_CINCLUDES@,$STD_CINCLUDES,;t t
+s,@STD_CDEFINES@,$STD_CDEFINES,;t t
+s,@STD_CWARNINGS@,$STD_CWARNINGS,;t t
+s,@CCOPT@,$CCOPT,;t t
+s,@AR@,$AR,;t t
+s,@ARFLAGS@,$ARFLAGS,;t t
+s,@LN@,$LN,;t t
+s,@ETAGS@,$ETAGS,;t t
+s,@PERL@,$PERL,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@ISC_PLATFORM_NEEDSYSSELECTH@,$ISC_PLATFORM_NEEDSYSSELECTH,;t t
+s,@WANT_IRS_GR@,$WANT_IRS_GR,;t t
+s,@WANT_IRS_GR_OBJS@,$WANT_IRS_GR_OBJS,;t t
+s,@WANT_IRS_PW@,$WANT_IRS_PW,;t t
+s,@WANT_IRS_PW_OBJS@,$WANT_IRS_PW_OBJS,;t t
+s,@WANT_IRS_NIS@,$WANT_IRS_NIS,;t t
+s,@WANT_IRS_NIS_OBJS@,$WANT_IRS_NIS_OBJS,;t t
+s,@WANT_IRS_NISGR_OBJS@,$WANT_IRS_NISGR_OBJS,;t t
+s,@WANT_IRS_NISPW_OBJS@,$WANT_IRS_NISPW_OBJS,;t t
+s,@WANT_IRS_DBPW_OBJS@,$WANT_IRS_DBPW_OBJS,;t t
+s,@ALWAYS_DEFINES@,$ALWAYS_DEFINES,;t t
+s,@DO_PTHREADS@,$DO_PTHREADS,;t t
+s,@WANT_IRS_THREADSGR_OBJS@,$WANT_IRS_THREADSGR_OBJS,;t t
+s,@WANT_IRS_THREADSPW_OBJS@,$WANT_IRS_THREADSPW_OBJS,;t t
+s,@WANT_IRS_THREADS_OBJS@,$WANT_IRS_THREADS_OBJS,;t t
+s,@WANT_THREADS_OBJS@,$WANT_THREADS_OBJS,;t t
+s,@USE_IFNAMELINKID@,$USE_IFNAMELINKID,;t t
+s,@ISC_THREAD_DIR@,$ISC_THREAD_DIR,;t t
+s,@DAEMON_OBJS@,$DAEMON_OBJS,;t t
+s,@NEED_DAEMON@,$NEED_DAEMON,;t t
+s,@STRSEP_OBJS@,$STRSEP_OBJS,;t t
+s,@NEED_STRSEP@,$NEED_STRSEP,;t t
+s,@NEED_STRERROR@,$NEED_STRERROR,;t t
+s,@MKDEPCC@,$MKDEPCC,;t t
+s,@MKDEPCFLAGS@,$MKDEPCFLAGS,;t t
+s,@MKDEPPROG@,$MKDEPPROG,;t t
+s,@IRIX_DNSSEC_WARNINGS_HACK@,$IRIX_DNSSEC_WARNINGS_HACK,;t t
+s,@purify_path@,$purify_path,;t t
+s,@PURIFY@,$PURIFY,;t t
+s,@LN_S@,$LN_S,;t t
+s,@ECHO@,$ECHO,;t t
+s,@ac_ct_AR@,$ac_ct_AR,;t t
+s,@STRIP@,$STRIP,;t t
+s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t
+s,@CXX@,$CXX,;t t
+s,@CXXFLAGS@,$CXXFLAGS,;t t
+s,@ac_ct_CXX@,$ac_ct_CXX,;t t
+s,@CXXCPP@,$CXXCPP,;t t
+s,@F77@,$F77,;t t
+s,@FFLAGS@,$FFLAGS,;t t
+s,@ac_ct_F77@,$ac_ct_F77,;t t
+s,@LIBTOOL@,$LIBTOOL,;t t
+s,@O@,$O,;t t
+s,@A@,$A,;t t
+s,@SA@,$SA,;t t
+s,@LIBTOOL_MKDEP_SED@,$LIBTOOL_MKDEP_SED,;t t
+s,@LIBTOOL_MODE_COMPILE@,$LIBTOOL_MODE_COMPILE,;t t
+s,@LIBTOOL_MODE_INSTALL@,$LIBTOOL_MODE_INSTALL,;t t
+s,@LIBTOOL_MODE_LINK@,$LIBTOOL_MODE_LINK,;t t
+s,@HAS_INET6_STRUCTS@,$HAS_INET6_STRUCTS,;t t
+s,@ISC_PLATFORM_NEEDNETINETIN6H@,$ISC_PLATFORM_NEEDNETINETIN6H,;t t
+s,@ISC_PLATFORM_NEEDNETINET6IN6H@,$ISC_PLATFORM_NEEDNETINET6IN6H,;t t
+s,@HAS_IN_ADDR6@,$HAS_IN_ADDR6,;t t
+s,@NEED_IN6ADDR_ANY@,$NEED_IN6ADDR_ANY,;t t
+s,@ISC_PLATFORM_HAVEIN6PKTINFO@,$ISC_PLATFORM_HAVEIN6PKTINFO,;t t
+s,@ISC_PLATFORM_FIXIN6ISADDR@,$ISC_PLATFORM_FIXIN6ISADDR,;t t
+s,@ISC_IPV6_H@,$ISC_IPV6_H,;t t
+s,@ISC_IPV6_O@,$ISC_IPV6_O,;t t
+s,@ISC_ISCIPV6_O@,$ISC_ISCIPV6_O,;t t
+s,@ISC_IPV6_C@,$ISC_IPV6_C,;t t
+s,@HAVE_SIN6_SCOPE_ID@,$HAVE_SIN6_SCOPE_ID,;t t
+s,@HAVE_SOCKADDR_STORAGE@,$HAVE_SOCKADDR_STORAGE,;t t
+s,@ISC_PLATFORM_NEEDNTOP@,$ISC_PLATFORM_NEEDNTOP,;t t
+s,@ISC_PLATFORM_NEEDPTON@,$ISC_PLATFORM_NEEDPTON,;t t
+s,@ISC_PLATFORM_NEEDATON@,$ISC_PLATFORM_NEEDATON,;t t
+s,@HAVE_SA_LEN@,$HAVE_SA_LEN,;t t
+s,@HAVE_MINIMUM_IFREQ@,$HAVE_MINIMUM_IFREQ,;t t
+s,@BSD_COMP@,$BSD_COMP,;t t
+s,@SOLARIS_BITTYPES@,$SOLARIS_BITTYPES,;t t
+s,@USE_FIONBIO_IOCTL@,$USE_FIONBIO_IOCTL,;t t
+s,@PORT_NONBLOCK@,$PORT_NONBLOCK,;t t
+s,@PORT_DIR@,$PORT_DIR,;t t
+s,@USE_POLL@,$USE_POLL,;t t
+s,@HAVE_MD5@,$HAVE_MD5,;t t
+s,@SOLARIS2@,$SOLARIS2,;t t
+s,@PORT_INCLUDE@,$PORT_INCLUDE,;t t
+s,@ISC_PLATFORM_MSGHDRFLAVOR@,$ISC_PLATFORM_MSGHDRFLAVOR,;t t
+s,@ISC_PLATFORM_NEEDPORTT@,$ISC_PLATFORM_NEEDPORTT,;t t
+s,@ISC_PLATFORM_NEEDTIMESPEC@,$ISC_PLATFORM_NEEDTIMESPEC,;t t
+s,@ISC_LWRES_ENDHOSTENTINT@,$ISC_LWRES_ENDHOSTENTINT,;t t
+s,@ISC_LWRES_SETNETENTINT@,$ISC_LWRES_SETNETENTINT,;t t
+s,@ISC_LWRES_ENDNETENTINT@,$ISC_LWRES_ENDNETENTINT,;t t
+s,@ISC_LWRES_GETHOSTBYADDRVOID@,$ISC_LWRES_GETHOSTBYADDRVOID,;t t
+s,@ISC_LWRES_NEEDHERRNO@,$ISC_LWRES_NEEDHERRNO,;t t
+s,@ISC_LWRES_GETIPNODEPROTO@,$ISC_LWRES_GETIPNODEPROTO,;t t
+s,@ISC_LWRES_GETADDRINFOPROTO@,$ISC_LWRES_GETADDRINFOPROTO,;t t
+s,@ISC_LWRES_GETNAMEINFOPROTO@,$ISC_LWRES_GETNAMEINFOPROTO,;t t
+s,@NEED_PSELECT@,$NEED_PSELECT,;t t
+s,@NEED_GETTIMEOFDAY@,$NEED_GETTIMEOFDAY,;t t
+s,@HAVE_STRNDUP@,$HAVE_STRNDUP,;t t
+s,@ISC_PLATFORM_NEEDSTRSEP@,$ISC_PLATFORM_NEEDSTRSEP,;t t
+s,@ISC_PLATFORM_NEEDVSNPRINTF@,$ISC_PLATFORM_NEEDVSNPRINTF,;t t
+s,@ISC_EXTRA_OBJS@,$ISC_EXTRA_OBJS,;t t
+s,@ISC_EXTRA_SRCS@,$ISC_EXTRA_SRCS,;t t
+s,@USE_SYSERROR_LIST@,$USE_SYSERROR_LIST,;t t
+s,@ISC_PLATFORM_QUADFORMAT@,$ISC_PLATFORM_QUADFORMAT,;t t
+s,@ISC_SOCKLEN_T@,$ISC_SOCKLEN_T,;t t
+s,@GETGROUPLIST_ARGS@,$GETGROUPLIST_ARGS,;t t
+s,@NET_R_ARGS@,$NET_R_ARGS,;t t
+s,@NET_R_BAD@,$NET_R_BAD,;t t
+s,@NET_R_COPY@,$NET_R_COPY,;t t
+s,@NET_R_COPY_ARGS@,$NET_R_COPY_ARGS,;t t
+s,@NET_R_OK@,$NET_R_OK,;t t
+s,@NET_R_SETANSWER@,$NET_R_SETANSWER,;t t
+s,@NET_R_RETURN@,$NET_R_RETURN,;t t
+s,@GETNETBYADDR_ADDR_T@,$GETNETBYADDR_ADDR_T,;t t
+s,@NETENT_DATA@,$NETENT_DATA,;t t
+s,@NET_R_ENT_ARGS@,$NET_R_ENT_ARGS,;t t
+s,@NET_R_SET_RESULT@,$NET_R_SET_RESULT,;t t
+s,@NET_R_SET_RETURN@,$NET_R_SET_RETURN,;t t
+s,@NET_R_END_RESULT@,$NET_R_END_RESULT,;t t
+s,@NET_R_END_RETURN@,$NET_R_END_RETURN,;t t
+s,@GROUP_R_ARGS@,$GROUP_R_ARGS,;t t
+s,@GROUP_R_BAD@,$GROUP_R_BAD,;t t
+s,@GROUP_R_OK@,$GROUP_R_OK,;t t
+s,@GROUP_R_RETURN@,$GROUP_R_RETURN,;t t
+s,@GROUP_R_END_RESULT@,$GROUP_R_END_RESULT,;t t
+s,@GROUP_R_END_RETURN@,$GROUP_R_END_RETURN,;t t
+s,@GROUP_R_ENT_ARGS@,$GROUP_R_ENT_ARGS,;t t
+s,@GROUP_R_SET_RESULT@,$GROUP_R_SET_RESULT,;t t
+s,@GROUP_R_SET_RETURN@,$GROUP_R_SET_RETURN,;t t
+s,@HOST_R_ARGS@,$HOST_R_ARGS,;t t
+s,@HOST_R_BAD@,$HOST_R_BAD,;t t
+s,@HOST_R_COPY@,$HOST_R_COPY,;t t
+s,@HOST_R_COPY_ARGS@,$HOST_R_COPY_ARGS,;t t
+s,@HOST_R_ERRNO@,$HOST_R_ERRNO,;t t
+s,@HOST_R_OK@,$HOST_R_OK,;t t
+s,@HOST_R_RETURN@,$HOST_R_RETURN,;t t
+s,@HOST_R_SETANSWER@,$HOST_R_SETANSWER,;t t
+s,@HOSTENT_DATA@,$HOSTENT_DATA,;t t
+s,@HOST_R_END_RESULT@,$HOST_R_END_RESULT,;t t
+s,@HOST_R_END_RETURN@,$HOST_R_END_RETURN,;t t
+s,@HOST_R_ENT_ARGS@,$HOST_R_ENT_ARGS,;t t
+s,@HOST_R_SET_RESULT@,$HOST_R_SET_RESULT,;t t
+s,@HOST_R_SET_RETURN@,$HOST_R_SET_RETURN,;t t
+s,@SETPWENT_VOID@,$SETPWENT_VOID,;t t
+s,@SETGRENT_VOID@,$SETGRENT_VOID,;t t
+s,@NGR_R_ARGS@,$NGR_R_ARGS,;t t
+s,@NGR_R_BAD@,$NGR_R_BAD,;t t
+s,@NGR_R_COPY@,$NGR_R_COPY,;t t
+s,@NGR_R_COPY_ARGS@,$NGR_R_COPY_ARGS,;t t
+s,@NGR_R_OK@,$NGR_R_OK,;t t
+s,@NGR_R_RETURN@,$NGR_R_RETURN,;t t
+s,@NGR_R_PRIVATE@,$NGR_R_PRIVATE,;t t
+s,@NGR_R_END_RESULT@,$NGR_R_END_RESULT,;t t
+s,@NGR_R_END_RETURN@,$NGR_R_END_RETURN,;t t
+s,@NGR_R_ENT_ARGS@,$NGR_R_ENT_ARGS,;t t
+s,@NGR_R_SET_RESULT@,$NGR_R_SET_RESULT,;t t
+s,@NGR_R_SET_RETURN@,$NGR_R_SET_RETURN,;t t
+s,@PROTO_R_ARGS@,$PROTO_R_ARGS,;t t
+s,@PROTO_R_BAD@,$PROTO_R_BAD,;t t
+s,@PROTO_R_COPY@,$PROTO_R_COPY,;t t
+s,@PROTO_R_COPY_ARGS@,$PROTO_R_COPY_ARGS,;t t
+s,@PROTO_R_OK@,$PROTO_R_OK,;t t
+s,@PROTO_R_SETANSWER@,$PROTO_R_SETANSWER,;t t
+s,@PROTO_R_RETURN@,$PROTO_R_RETURN,;t t
+s,@PROTOENT_DATA@,$PROTOENT_DATA,;t t
+s,@PROTO_R_END_RESULT@,$PROTO_R_END_RESULT,;t t
+s,@PROTO_R_END_RETURN@,$PROTO_R_END_RETURN,;t t
+s,@PROTO_R_ENT_ARGS@,$PROTO_R_ENT_ARGS,;t t
+s,@PROTO_R_ENT_UNUSED@,$PROTO_R_ENT_UNUSED,;t t
+s,@PROTO_R_SET_RESULT@,$PROTO_R_SET_RESULT,;t t
+s,@PROTO_R_SET_RETURN@,$PROTO_R_SET_RETURN,;t t
+s,@PASS_R_ARGS@,$PASS_R_ARGS,;t t
+s,@PASS_R_BAD@,$PASS_R_BAD,;t t
+s,@PASS_R_COPY@,$PASS_R_COPY,;t t
+s,@PASS_R_COPY_ARGS@,$PASS_R_COPY_ARGS,;t t
+s,@PASS_R_OK@,$PASS_R_OK,;t t
+s,@PASS_R_RETURN@,$PASS_R_RETURN,;t t
+s,@PASS_R_END_RESULT@,$PASS_R_END_RESULT,;t t
+s,@PASS_R_END_RETURN@,$PASS_R_END_RETURN,;t t
+s,@PASS_R_ENT_ARGS@,$PASS_R_ENT_ARGS,;t t
+s,@PASS_R_SET_RESULT@,$PASS_R_SET_RESULT,;t t
+s,@PASS_R_SET_RETURN@,$PASS_R_SET_RETURN,;t t
+s,@SERV_R_ARGS@,$SERV_R_ARGS,;t t
+s,@SERV_R_BAD@,$SERV_R_BAD,;t t
+s,@SERV_R_COPY@,$SERV_R_COPY,;t t
+s,@SERV_R_COPY_ARGS@,$SERV_R_COPY_ARGS,;t t
+s,@SERV_R_OK@,$SERV_R_OK,;t t
+s,@SERV_R_SETANSWER@,$SERV_R_SETANSWER,;t t
+s,@SERV_R_RETURN@,$SERV_R_RETURN,;t t
+s,@SERVENT_DATA@,$SERVENT_DATA,;t t
+s,@SERV_R_END_RESULT@,$SERV_R_END_RESULT,;t t
+s,@SERV_R_END_RETURN@,$SERV_R_END_RETURN,;t t
+s,@SERV_R_ENT_ARGS@,$SERV_R_ENT_ARGS,;t t
+s,@SERV_R_ENT_UNUSED@,$SERV_R_ENT_UNUSED,;t t
+s,@SERV_R_SET_RESULT@,$SERV_R_SET_RESULT,;t t
+s,@SERV_R_SET_RETURN@,$SERV_R_SET_RETURN,;t t
+s,@SETNETGRENT_ARGS@,$SETNETGRENT_ARGS,;t t
+s,@INNETGR_ARGS@,$INNETGR_ARGS,;t t
+s,@BIND9_TOP_BUILDDIR@,$BIND9_TOP_BUILDDIR,;t t
+s,@BIND9_VERSION@,$BIND9_VERSION,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+/@BIND9_INCLUDES@/r $BIND9_INCLUDES
+s,@BIND9_INCLUDES@,,;t t
+/@BIND9_MAKE_RULES@/r $BIND9_MAKE_RULES
+s,@BIND9_MAKE_RULES@,,;t t
+/@LIBBIND_API@/r $LIBBIND_API
+s,@LIBBIND_API@,,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='[ ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ # Do quote $f, to prevent DOS paths from being IFS'd.
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+ # Remove the trailing spaces.
+ sed 's/[ ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h. The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status. Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless. Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo ' :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+ # Write a limited-size here document to $tmp/defines.sed.
+ echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#define' lines.
+ echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/defines.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo ' fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+ # Write a limited-size here document to $tmp/undefs.sed.
+ echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#undef'
+ echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+ rm -f conftest.undefs
+ mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ echo "/* Generated by configure. */" >$tmp/config.h
+ else
+ echo "/* $ac_file. Generated by configure. */" >$tmp/config.h
+ fi
+ cat $tmp/in >>$tmp/config.h
+ rm -f $tmp/in
+ if test x"$ac_file" != x-; then
+ if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ rm -f $ac_file
+ mv $tmp/config.h $ac_file
+ fi
+ else
+ cat $tmp/config.h
+ rm -f $tmp/config.h
+ fi
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+
+# Tell Emacs to edit this file in shell mode.
+# Local Variables:
+# mode: sh
+# End:
diff --git a/lib/bind/configure.in b/lib/bind/configure.in
new file mode 100644
index 0000000..82bea78
--- /dev/null
+++ b/lib/bind/configure.in
@@ -0,0 +1,2683 @@
+# Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2001, 2003 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+AC_REVISION($Revision: 1.90.18.34 $)
+
+AC_INIT(resolv/herror.c)
+AC_PREREQ(2.13)
+
+AC_CONFIG_HEADER(config.h)
+
+AC_CANONICAL_HOST
+
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+
+AC_SUBST(STD_CINCLUDES)
+AC_SUBST(STD_CDEFINES)
+AC_SUBST(STD_CWARNINGS)
+AC_SUBST(CCOPT)
+
+AC_PATH_PROG(AR, ar)
+ARFLAGS="cruv"
+AC_SUBST(AR)
+AC_SUBST(ARFLAGS)
+
+# The POSIX ln(1) program. Non-POSIX systems may substitute
+# "copy" or something.
+LN=ln
+AC_SUBST(LN)
+
+case "$AR" in
+ "")
+ AC_MSG_ERROR([
+ar program not found. Please fix your PATH to include the directory in
+which ar resides, or set AR in the environment with the full path to ar.
+])
+
+ ;;
+esac
+
+#
+# Etags.
+#
+AC_PATH_PROGS(ETAGS, etags emacs-etags)
+
+#
+# Some systems, e.g. RH7, have the Exuberant Ctags etags instead of
+# GNU emacs etags, and it requires the -L flag.
+#
+if test "X$ETAGS" != "X"; then
+ AC_MSG_CHECKING(for Exuberant Ctags etags)
+ if $ETAGS --version 2>&1 | grep 'Exuberant Ctags' >/dev/null 2>&1; then
+ AC_MSG_RESULT(yes)
+ ETAGS="$ETAGS -L"
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+AC_SUBST(ETAGS)
+
+#
+# Perl is optional; it is used only by some of the system test scripts.
+#
+AC_PATH_PROGS(PERL, perl5 perl)
+AC_SUBST(PERL)
+
+#
+# isc/list.h and others clash with the rest of BIND 9
+#
+case "$includedir" in
+ '${prefix}/include')
+ includedir='${prefix}/bind/include'
+ ;;
+esac
+case "$libdir" in
+ '${prefix}/lib')
+ libdir='${prefix}/bind/lib'
+ ;;
+esac
+
+#
+# Make sure INSTALL uses an absolute path, else it will be wrong in all
+# Makefiles, since they use make/rules.in and INSTALL will be adjusted by
+# configure based on the location of the file where it is substituted.
+# Since in BIND9 INSTALL is only substituted into make/rules.in, an immediate
+# subdirectory of install-sh, This relative path will be wrong for all
+# directories more than one level down from install-sh.
+#
+case "$INSTALL" in
+ /*)
+ ;;
+ *)
+ #
+ # Not all systems have dirname.
+ #
+ changequote({, })
+ ac_dir="`echo $INSTALL | sed 's%/[^/]*$%%'`"
+ changequote([, ])
+
+ ac_prog="`echo $INSTALL | sed 's%.*/%%'`"
+ test "$ac_dir" = "$ac_prog" && ac_dir=.
+ test -d "$ac_dir" && ac_dir="`(cd \"$ac_dir\" && pwd)`"
+ INSTALL="$ac_dir/$ac_prog"
+ ;;
+esac
+
+#
+# On these hosts, we really want to use cc, not gcc, even if it is
+# found. The gcc that these systems have will not correctly handle
+# pthreads.
+#
+# However, if the user sets $CC to be something, let that override
+# our change.
+#
+if test "X$CC" = "X" ; then
+ case "$host" in
+ *-dec-osf*)
+ CC="cc"
+ ;;
+ *-solaris*)
+ # Use Sun's cc if it is available, but watch
+ # out for /usr/ucb/cc; it will never be the right
+ # compiler to use.
+ #
+ # If setting CC here fails, the AC_PROG_CC done
+ # below might still find gcc.
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ case "$ac_dir" in
+ /usr/ucb)
+ # exclude
+ ;;
+ *)
+ if test -f "$ac_dir/cc"; then
+ CC="$ac_dir/cc"
+ break
+ fi
+ ;;
+ esac
+ done
+ IFS="$ac_save_ifs"
+ ;;
+ *-hp-hpux*)
+ CC="cc"
+ ;;
+ mips-sgi-irix*)
+ CC="cc"
+ ;;
+ esac
+fi
+
+
+AC_PROG_CC
+
+AC_HEADER_STDC
+
+
+AC_CHECK_HEADERS(fcntl.h db.h paths.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/timers.h stropts.h)
+
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_SIZE_T
+AC_CHECK_TYPE(ssize_t,signed)
+AC_CHECK_TYPE(uintptr_t,unsigned long)
+AC_HEADER_TIME
+#
+# check if we need to #include sys/select.h explicitly
+#
+case $ac_cv_header_unistd_h in
+yes)
+AC_MSG_CHECKING(if unistd.h defines fd_set)
+AC_TRY_COMPILE([
+#include <unistd.h>],
+[fd_set read_set; return (0);],
+ [AC_MSG_RESULT(yes)
+ ISC_PLATFORM_NEEDSYSSELECTH="#undef ISC_PLATFORM_NEEDSYSSELECTH"
+ ],
+ [AC_MSG_RESULT(no)
+ case ac_cv_header_sys_select_h in
+ yes)
+ ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+ ;;
+ no)
+ AC_MSG_ERROR([need either working unistd.h or sys/select.h])
+ ;;
+ esac
+ ])
+ ;;
+no)
+ case ac_cv_header_sys_select_h in
+ yes)
+ ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+ ;;
+ no)
+ AC_MSG_ERROR([need either unistd.h or sys/select.h])
+ ;;
+ esac
+ ;;
+esac
+AC_SUBST(ISC_PLATFORM_NEEDSYSSELECTH)
+
+#
+# Find the machine's endian flavor.
+#
+AC_C_BIGENDIAN
+
+AC_ARG_WITH(irs-gr,[ --with-irs-gr Build ....],
+want_irs_gr="$withval", want_irs_gr="no")
+case "$want_irs_gr" in
+yes) WANT_IRS_GR="#define WANT_IRS_GR 1"
+ WANT_IRS_GR_OBJS="\${WANT_IRS_GR_OBJS}"
+ ;;
+*) WANT_IRS_GR="#undef WANT_IRS_GR" WANT_IRS_GR_OBJS="";;
+esac
+AC_SUBST(WANT_IRS_GR)
+AC_SUBST(WANT_IRS_GR_OBJS)
+
+AC_ARG_WITH(irs-pw,[ --with-irs-pw Build ....],
+want_irs_pw="$withval", want_irs_pw="no")
+case "$want_irs_pw" in
+yes) WANT_IRS_PW="#define WANT_IRS_PW 1"
+ WANT_IRS_PW_OBJS="\${WANT_IRS_PW_OBJS}";;
+*) WANT_IRS_PW="#undef WANT_IRS_PW" WANT_IRS_PW_OBJS="";;
+esac
+AC_SUBST(WANT_IRS_PW)
+AC_SUBST(WANT_IRS_PW_OBJS)
+
+AC_ARG_WITH(irs-nis,[ --with-irs-nis Build ....],
+want_irs_nis="$withval", want_irs_nis="no")
+case "$want_irs_nis" in
+yes)
+ WANT_IRS_NIS="#define WANT_IRS_NIS 1"
+ WANT_IRS_NIS_OBJS="\${WANT_IRS_NIS_OBJS}"
+ case "$want_irs_gr" in
+ yes)
+ WANT_IRS_NISGR_OBJS="\${WANT_IRS_NISGR_OBJS}";;
+ *)
+ WANT_IRS_NISGR_OBJS="";;
+ esac
+ case "$want_irs_pw" in
+ yes)
+ WANT_IRS_NISPW_OBJS="\${WANT_IRS_NISPW_OBJS}";;
+ *)
+ WANT_IRS_NISPW_OBJS="";;
+ esac
+ ;;
+*)
+ WANT_IRS_NIS="#undef WANT_IRS_NIS"
+ WANT_IRS_NIS_OBJS=""
+ WANT_IRS_NISGR_OBJS=""
+ WANT_IRS_NISPW_OBJS="";;
+esac
+AC_SUBST(WANT_IRS_NIS)
+AC_SUBST(WANT_IRS_NIS_OBJS)
+AC_SUBST(WANT_IRS_NISGR_OBJS)
+AC_SUBST(WANT_IRS_NISPW_OBJS)
+AC_TRY_RUN([
+#ifdef HAVE_DB_H
+int have_db_h = 1;
+#else
+int have_db_h = 0;
+#endif
+main() { return(!have_db_h); }
+],
+WANT_IRS_DBPW_OBJS="\${WANT_IRS_DBPW_OBJS}"
+,
+WANT_IRS_DBPW_OBJS=""
+,
+WANT_IRS_DBPW_OBJS=""
+)
+AC_SUBST(WANT_IRS_DBPW_OBJS)
+
+#
+# was --with-randomdev specified?
+#
+AC_MSG_CHECKING(for random device)
+AC_ARG_WITH(randomdev,
+[ --with-randomdev=PATH Specify path for random device],
+ use_randomdev="$withval", use_randomdev="unspec")
+
+case "$use_randomdev" in
+ unspec)
+ case "$host" in
+ *-openbsd*)
+ devrandom=/dev/srandom
+ ;;
+ *)
+ devrandom=/dev/random
+ ;;
+ esac
+ AC_MSG_RESULT($devrandom)
+ AC_CHECK_FILE($devrandom,
+ AC_DEFINE_UNQUOTED(PATH_RANDOMDEV,
+ "$devrandom"),)
+ ;;
+ yes)
+ AC_MSG_ERROR([--with-randomdev must specify a path])
+ ;;
+ *)
+ AC_DEFINE_UNQUOTED(PATH_RANDOMDEV, "$use_randomdev")
+ AC_MSG_RESULT(using "$use_randomdev")
+ ;;
+esac
+
+sinclude(../../config.threads.in)dnl
+
+if $use_threads
+then
+ if test "X$GCC" = "Xyes"; then
+ case "$host" in
+ *-freebsd*)
+ CC="$CC -pthread"
+ CCOPT="$CCOPT -pthread"
+ STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+ ;;
+ *-openbsd*)
+ CC="$CC -pthread"
+ CCOPT="$CCOPT -pthread"
+ ;;
+ *-solaris*)
+ LIBS="$LIBS -lthread"
+ ;;
+ *-ibm-aix*)
+ STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+ ;;
+ esac
+ else
+ case $host in
+ *-dec-osf*)
+ CC="$CC -pthread"
+ CCOPT="$CCOPT -pthread"
+ ;;
+ *-solaris*)
+ CC="$CC -mt"
+ CCOPT="$CCOPT -mt"
+ ;;
+ *-ibm-aix*)
+ STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+ ;;
+ *-UnixWare*)
+ CC="$CC -Kthread"
+ CCOPT="$CCOPT -Kthread"
+ ;;
+ esac
+ fi
+ AC_DEFINE(_REENTRANT)
+ ALWAYS_DEFINES="-D_REENTRANT"
+ DO_PTHREADS="#define DO_PTHREADS 1"
+ WANT_IRS_THREADSGR_OBJS="\${WANT_IRS_THREADSGR_OBJS}"
+ WANT_IRS_THREADSPW_OBJS="\${WANT_IRS_THREADSPW_OBJS}"
+ case $host in
+ ia64-hp-hpux11.*)
+ WANT_IRS_THREADS_OBJS="";;
+ *)
+ WANT_IRS_THREADS_OBJS="\${WANT_IRS_THREADS_OBJS}";;
+ esac
+ WANT_THREADS_OBJS="\${WANT_THREADS_OBJS}"
+ thread_dir=pthreads
+
+ #
+ # We'd like to use sigwait() too
+ #
+ AC_CHECK_FUNC(sigwait,
+ AC_DEFINE(HAVE_SIGWAIT),
+ AC_CHECK_LIB(c, sigwait,
+ AC_DEFINE(HAVE_SIGWAIT),
+ AC_CHECK_LIB(pthread, sigwait,
+ AC_DEFINE(HAVE_SIGWAIT),
+ AC_CHECK_LIB(pthread, _Psigwait,
+ AC_DEFINE(HAVE_SIGWAIT),))))
+
+ AC_CHECK_FUNC(pthread_attr_getstacksize,
+ AC_DEFINE(HAVE_PTHREAD_ATTR_GETSTACKSIZE),)
+
+ #
+ # Additional OS-specific issues related to pthreads and sigwait.
+ #
+ case "$host" in
+ #
+ # One more place to look for sigwait.
+ #
+ *-freebsd*)
+ AC_CHECK_LIB(c_r, sigwait, AC_DEFINE(HAVE_SIGWAIT),)
+ ;;
+ #
+ # BSDI 3.0 through 4.0.1 needs pthread_init() to be
+ # called before certain pthreads calls. This is deprecated
+ # in BSD/OS 4.1.
+ #
+ *-bsdi3.*|*-bsdi4.0*)
+ AC_DEFINE(NEED_PTHREAD_INIT)
+ ;;
+ #
+ # LinuxThreads requires some changes to the way we
+ # deal with signals.
+ #
+ *-linux*)
+ AC_DEFINE(HAVE_LINUXTHREADS)
+ ;;
+ #
+ # Ensure the right sigwait() semantics on Solaris and make
+ # sure we call pthread_setconcurrency.
+ #
+ *-solaris*)
+ AC_DEFINE(_POSIX_PTHREAD_SEMANTICS)
+ AC_CHECK_FUNC(pthread_setconcurrency,
+ AC_DEFINE(CALL_PTHREAD_SETCONCURRENCY))
+ AC_DEFINE(POSIX_GETPWUID_R)
+ AC_DEFINE(POSIX_GETPWNAM_R)
+ AC_DEFINE(POSIX_GETGRGID_R)
+ AC_DEFINE(POSIX_GETGRNAM_R)
+ ;;
+ *hpux11*)
+ AC_DEFINE(NEED_ENDNETGRENT_R)
+ AC_DEFINE(_PTHREADS_DRAFT4)
+ ;;
+ #
+ # UnixWare does things its own way.
+ #
+ *-UnixWare*)
+ AC_DEFINE(HAVE_UNIXWARE_SIGWAIT)
+ ;;
+ esac
+
+ #
+ # Look for sysconf to allow detection of the number of processors.
+ #
+ AC_CHECK_FUNC(sysconf, AC_DEFINE(HAVE_SYSCONF),)
+
+else
+ ALWAYS_DEFINES=""
+ DO_PTHREADS="#undef DO_PTHREADS"
+ WANT_IRS_THREADSGR_OBJS=""
+ WANT_IRS_THREADSPW_OBJS=""
+ WANT_IRS_THREADS_OBJS=""
+ WANT_THREADS_OBJS=""
+ thread_dir=nothreads
+fi
+
+AC_SUBST(ALWAYS_DEFINES)
+AC_SUBST(DO_PTHREADS)
+AC_SUBST(WANT_IRS_THREADSGR_OBJS)
+AC_SUBST(WANT_IRS_THREADSPW_OBJS)
+AC_SUBST(WANT_IRS_THREADS_OBJS)
+AC_SUBST(WANT_THREADS_OBJS)
+
+AC_CHECK_FUNC(strlcat, AC_DEFINE(HAVE_STRLCAT))
+AC_CHECK_FUNC(memmove, AC_DEFINE(HAVE_MEMMOVE))
+AC_CHECK_FUNC(memchr, AC_DEFINE(HAVE_MEMCHR))
+
+AC_CHECK_FUNC(if_nametoindex,
+ [USE_IFNAMELINKID="#define USE_IFNAMELINKID 1"],
+ [USE_IFNAMELINKID="#undef USE_IFNAMELINKID"])
+AC_SUBST(USE_IFNAMELINKID)
+
+ISC_THREAD_DIR=$thread_dir
+AC_SUBST(ISC_THREAD_DIR)
+
+AC_CHECK_FUNC(daemon,
+[DAEMON_OBJS="" NEED_DAEMON="#undef NEED_DAEMON"]
+,
+[DAEMON_OBJS="\${DAEMON_OBJS}" NEED_DAEMON="#define NEED_DAEMON 1"]
+)
+AC_SUBST(DAEMON_OBJS)
+AC_SUBST(NEED_DAEMON)
+
+AC_CHECK_FUNC(strsep,
+[STRSEP_OBJS="" NEED_STRSEP="#undef NEED_STRSEP"]
+,
+[STRSEP_OBJS="\${STRSEP_OBJS}" NEED_STRSEP="#define NEED_STRSEP 1"]
+)
+AC_SUBST(STRSEP_OBJS)
+AC_SUBST(NEED_STRSEP)
+
+AC_CHECK_FUNC(strerror, [NEED_STRERROR="#undef NEED_STRERROR"],
+[NEED_STRERROR="#define NEED_STRERROR 1"])
+AC_SUBST(NEED_STRERROR)
+
+#
+# flockfile is usually provided by pthreads, but we may want to use it
+# even if compiled with --disable-threads.
+#
+AC_CHECK_FUNC(flockfile, AC_DEFINE(HAVE_FLOCKFILE),)
+
+#
+# Indicate what the final decision was regarding threads.
+#
+AC_MSG_CHECKING(whether to build with threads)
+if $use_threads; then
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+fi
+
+#
+# End of pthreads stuff.
+#
+
+#
+# Additional compiler settings.
+#
+MKDEPCC="$CC"
+MKDEPCFLAGS="-M"
+IRIX_DNSSEC_WARNINGS_HACK=""
+
+if test "X$GCC" = "Xyes"; then
+ AC_MSG_CHECKING(if "$CC" supports -fno-strict-aliasing)
+ SAVE_CFLAGS=$CFLAGS
+ CFLAGS=-fno-strict-aliasing
+ AC_TRY_COMPILE(,, [FNOSTRICTALIASING=yes],[FNOSTRICTALIASING=no])
+ CFLAGS=$SAVE_CFLAGS
+ if test "$FNOSTRICTALIASING" = "yes"; then
+ AC_MSG_RESULT(yes)
+ STD_CWARNINGS="$STD_CWARNINGS -W -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wformat -Wpointer-arith -fno-strict-aliasing"
+ else
+ AC_MSG_RESULT(no)
+ STD_CWARNINGS="$STD_CWARNINGS -W -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wformat -Wpointer-arith"
+ fi
+else
+ case $host in
+ *-dec-osf*)
+ CC="$CC -std"
+ CCOPT="$CCOPT -std"
+ MKDEPCC="$CC"
+ ;;
+ *-hp-hpux*)
+ CC="$CC -Ae -z"
+ # The version of the C compiler that constantly warns about
+ # 'const' as well as alignment issues is unfortunately not
+ # able to be discerned via the version of the operating
+ # system, nor does cc have a version flag.
+ case "`$CC +W 123 2>&1`" in
+ *Unknown?option*)
+ STD_CWARNINGS="+w1"
+ ;;
+ *)
+ # Turn off the pointlessly noisy warnings.
+ STD_CWARNINGS="+w1 +W 474,530,2193,2236"
+ ;;
+ esac
+ CCOPT="$CCOPT -Ae -z"
+ LIBS="-Wl,+vnocompatwarnings $LIBS"
+MKDEPPROG='cc -Ae -E -Wp,-M >/dev/null 2>&1 | awk '"'"'BEGIN {colon=0; rec="";} { for (i = 0 ; i < NF; i++) { if (colon && a[$i]) continue; if ($i == "\\") continue; if (!colon) { rec = $i continue; } if ($i == ":") { rec = rec " :" colon = 1 continue; } if (length(rec $i) > 76) { print rec " \\"; rec = "\t" $i; a[$i] = 1; } else { rec = rec " " $i a[$i] = 1; } } } END {print rec}'"'"' >>$TMP'
+ MKDEPPROG='cc -Ae -E -Wp,-M >/dev/null 2>>$TMP'
+ ;;
+ *-sgi-irix*)
+ STD_CWARNINGS="-fullwarn -woff 1209"
+ #
+ # Silence more than 250 instances of
+ # "prototyped function redeclared without prototype"
+ # and 11 instances of
+ # "variable ... was set but never used"
+ # from lib/dns/sec/openssl.
+ #
+ IRIX_DNSSEC_WARNINGS_HACK="-woff 1692,1552"
+ ;;
+ *-solaris*)
+ MKDEPCFLAGS="-xM"
+ ;;
+ *-UnixWare*)
+ CC="$CC -w"
+ ;;
+ esac
+fi
+
+#
+# _GNU_SOURCE is needed to access the fd_bits field of struct fd_set, which
+# is supposed to be opaque.
+#
+case $host in
+ *linux*)
+ STD_CDEFINES="$STD_CDEFINES -D_GNU_SOURCE"
+ ;;
+esac
+
+AC_SUBST(MKDEPCC)
+AC_SUBST(MKDEPCFLAGS)
+AC_SUBST(MKDEPPROG)
+AC_SUBST(IRIX_DNSSEC_WARNINGS_HACK)
+
+#
+# NLS
+#
+AC_CHECK_FUNC(catgets, AC_DEFINE(HAVE_CATGETS),)
+
+#
+# -lxnet buys us one big porting headache... standards, gotta love 'em.
+#
+# AC_CHECK_LIB(xnet, socket, ,
+# AC_CHECK_LIB(socket, socket)
+# AC_CHECK_LIB(nsl, inet_ntoa)
+# )
+#
+# Use this for now, instead:
+#
+case "$host" in
+ mips-sgi-irix*)
+ ;;
+ ia64-hp-hpux11.*)
+ AC_CHECK_LIB(socket, socket)
+ AC_CHECK_LIB(nsl, inet_ntoa)
+ ;;
+ *)
+ AC_CHECK_LIB(d4r, gethostbyname_r)
+ AC_CHECK_LIB(socket, socket)
+ AC_CHECK_LIB(nsl, inet_ntoa)
+ ;;
+esac
+
+#
+# Purify support
+#
+AC_MSG_CHECKING(whether to use purify)
+AC_ARG_WITH(purify,
+ [ --with-purify[=PATH] use Rational purify],
+ use_purify="$withval", use_purify="no")
+
+case "$use_purify" in
+ no)
+ ;;
+ yes)
+ AC_PATH_PROG(purify_path, purify, purify)
+ ;;
+ *)
+ purify_path="$use_purify"
+ ;;
+esac
+
+case "$use_purify" in
+ no)
+ AC_MSG_RESULT(no)
+ PURIFY=""
+ ;;
+ *)
+ if test -f $purify_path || test $purify_path = purify; then
+ AC_MSG_RESULT($purify_path)
+ PURIFYFLAGS="`echo $PURIFYOPTIONS`"
+ PURIFY="$purify_path $PURIFYFLAGS"
+ else
+ AC_MSG_ERROR([$purify_path not found.
+
+Please choose the proper path with the following command:
+
+ configure --with-purify=PATH
+])
+ fi
+ ;;
+esac
+
+AC_SUBST(PURIFY)
+
+#
+# GNU libtool support
+#
+AC_ARG_WITH(libtool,
+ [ --with-libtool use GNU libtool (following indented options supported)],
+ use_libtool="$withval", use_libtool="no")
+
+case $use_libtool in
+ yes)
+ AM_PROG_LIBTOOL
+ O=lo
+ A=la
+ LIBTOOL_MKDEP_SED='s;\.o;\.lo;'
+ LIBTOOL_MODE_COMPILE='--mode=compile'
+ LIBTOOL_MODE_INSTALL='--mode=install'
+ LIBTOOL_MODE_LINK='--mode=link'
+ ;;
+ *)
+ O=o
+ A=a
+ LIBTOOL=
+ AC_SUBST(LIBTOOL)
+ LIBTOOL_MKDEP_SED=
+ LIBTOOL_MODE_COMPILE=
+ LIBTOOL_MODE_INSTALL=
+ LIBTOOL_MODE_LINK=
+ ;;
+esac
+
+#
+# File name extension for static archive files, for those few places
+# where they are treated differently from dynamic ones.
+#
+SA=a
+
+AC_SUBST(O)
+AC_SUBST(A)
+AC_SUBST(SA)
+AC_SUBST(LIBTOOL_MKDEP_SED)
+AC_SUBST(LIBTOOL_MODE_COMPILE)
+AC_SUBST(LIBTOOL_MODE_INSTALL)
+AC_SUBST(LIBTOOL_MODE_LINK)
+
+#
+# Here begins a very long section to determine the system's networking
+# capabilities. The order of the tests is signficant.
+#
+
+#
+# IPv6
+#
+AC_ARG_ENABLE(ipv6,
+ [ --enable-ipv6 use IPv6 [default=autodetect]])
+
+case "$enable_ipv6" in
+ yes|''|autodetect)
+ AC_DEFINE(WANT_IPV6)
+ ;;
+ no)
+ ;;
+esac
+
+#
+# We do the IPv6 compilation checking after libtool so that we can put
+# the right suffix on the files.
+#
+AC_MSG_CHECKING(for IPv6 structures)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>],
+[struct sockaddr_in6 sin6; return (0);],
+ [AC_MSG_RESULT(yes)
+ found_ipv6=yes],
+ [AC_MSG_RESULT(no)
+ found_ipv6=no])
+
+#
+# See whether IPv6 support is provided via a Kame add-on.
+# This is done before other IPv6 linking tests to LIBS is properly set.
+#
+AC_MSG_CHECKING(for Kame IPv6 support)
+AC_ARG_WITH(kame,
+ [ --with-kame[=PATH] use Kame IPv6 [default path /usr/local/v6]],
+ use_kame="$withval", use_kame="no")
+
+case "$use_kame" in
+ no)
+ ;;
+ yes)
+ kame_path=/usr/local/v6
+ ;;
+ *)
+ kame_path="$use_kame"
+ ;;
+esac
+
+case "$use_kame" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ if test -f $kame_path/lib/libinet6.a; then
+ AC_MSG_RESULT($kame_path/lib/libinet6.a)
+ LIBS="-L$kame_path/lib -linet6 $LIBS"
+ else
+ AC_MSG_ERROR([$kame_path/lib/libinet6.a not found.
+
+Please choose the proper path with the following command:
+
+ configure --with-kame=PATH
+])
+ fi
+ ;;
+esac
+
+#
+# Whether netinet6/in6.h is needed has to be defined in isc/platform.h.
+# Including it on Kame-using platforms is very bad, though, because
+# Kame uses #error against direct inclusion. So include it on only
+# the platform that is otherwise broken without it -- BSD/OS 4.0 through 4.1.
+# This is done before the in6_pktinfo check because that's what
+# netinet6/in6.h is needed for.
+#
+changequote({, })
+case "$host" in
+*-bsdi4.[01]*)
+ ISC_PLATFORM_NEEDNETINET6IN6H="#define ISC_PLATFORM_NEEDNETINET6IN6H 1"
+ isc_netinet6in6_hack="#include <netinet6/in6.h>"
+ ;;
+*)
+ ISC_PLATFORM_NEEDNETINET6IN6H="#undef ISC_PLATFORM_NEEDNETINET6IN6H"
+ isc_netinet6in6_hack=""
+ ;;
+esac
+changequote([, ])
+
+#
+# This is similar to the netinet6/in6.h issue.
+#
+case "$host" in
+*-UnixWare*)
+ ISC_PLATFORM_NEEDNETINETIN6H="#define ISC_PLATFORM_NEEDNETINETIN6H 1"
+ ISC_PLATFORM_FIXIN6ISADDR="#define ISC_PLATFORM_FIXIN6ISADDR 1"
+ isc_netinetin6_hack="#include <netinet/in6.h>"
+ ;;
+*)
+ ISC_PLATFORM_NEEDNETINETIN6H="#undef ISC_PLATFORM_NEEDNETINETIN6H"
+ ISC_PLATFORM_FIXIN6ISADDR="#undef ISC_PLATFORM_FIXIN6ISADDR"
+ isc_netinetin6_hack=""
+ ;;
+esac
+
+#
+# Now delve deeper into the suitability of the IPv6 support.
+#
+case "$found_ipv6" in
+ yes)
+ HAS_INET6_STRUCTS="#define HAS_INET6_STRUCTS 1"
+
+ AC_MSG_CHECKING(for in6_addr)
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+],
+[struct in6_addr in6; return (0);],
+ [AC_MSG_RESULT(yes)
+ HAS_IN_ADDR6="#undef HAS_IN_ADDR6"
+ isc_in_addr6_hack=""],
+ [AC_MSG_RESULT(no)
+ HAS_IN_ADDR6="#define HAS_IN_ADDR6 1"
+ isc_in_addr6_hack="#define in6_addr in_addr6"])
+
+ AC_MSG_CHECKING(for in6addr_any)
+ AC_TRY_LINK([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+$isc_in_addr6_hack
+],
+ [struct in6_addr in6; in6 = in6addr_any; return (0);],
+ [AC_MSG_RESULT(yes)
+ NEED_IN6ADDR_ANY="#undef NEED_IN6ADDR_ANY"],
+ [AC_MSG_RESULT(no)
+ NEED_IN6ADDR_ANY="#define NEED_IN6ADDR_ANY 1"])
+
+ AC_MSG_CHECKING(for sin6_scope_id in struct sockaddr_in6)
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+],
+ [struct sockaddr_in6 xyzzy; xyzzy.sin6_scope_id = 0; return (0);],
+ [AC_MSG_RESULT(yes)
+ result="#define HAVE_SIN6_SCOPE_ID 1"],
+ [AC_MSG_RESULT(no)
+ result="#undef HAVE_SIN6_SCOPE_ID"])
+ HAVE_SIN6_SCOPE_ID="$result"
+
+ AC_MSG_CHECKING(for in6_pktinfo)
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+],
+ [struct in6_pktinfo xyzzy; return (0);],
+ [AC_MSG_RESULT(yes)
+ ISC_PLATFORM_HAVEIN6PKTINFO="#define ISC_PLATFORM_HAVEIN6PKTINFO 1"],
+ [AC_MSG_RESULT(no -- disabling runtime ipv6 support)
+ ISC_PLATFORM_HAVEIN6PKTINFO="#undef ISC_PLATFORM_HAVEIN6PKTINFO"])
+ ;;
+ no)
+ HAS_INET6_STRUCTS="#undef HAS_INET6_STRUCTS"
+ NEED_IN6ADDR_ANY="#undef NEED_IN6ADDR_ANY"
+ ISC_PLATFORM_HAVEIN6PKTINFO="#undef ISC_PLATFORM_HAVEIN6PKTINFO"
+ HAVE_SIN6_SCOPE_ID="#define HAVE_SIN6_SCOPE_ID 1"
+ ISC_IPV6_H="ipv6.h"
+ ISC_IPV6_O="ipv6.$O"
+ ISC_ISCIPV6_O="unix/ipv6.$O"
+ ISC_IPV6_C="ipv6.c"
+ ;;
+esac
+
+AC_MSG_CHECKING(for sockaddr_storage)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+],
+[struct sockaddr_storage xyzzy; return (0);],
+ [AC_MSG_RESULT(yes)
+ HAVE_SOCKADDR_STORAGE="#define HAVE_SOCKADDR_STORAGE 1"],
+ [AC_MSG_RESULT(no)
+ HAVE_SOCKADDR_STORAGE="#undef HAVE_SOCKADDR_STORAGE"])
+
+AC_SUBST(HAS_INET6_STRUCTS)
+AC_SUBST(ISC_PLATFORM_NEEDNETINETIN6H)
+AC_SUBST(ISC_PLATFORM_NEEDNETINET6IN6H)
+AC_SUBST(HAS_IN_ADDR6)
+AC_SUBST(NEED_IN6ADDR_ANY)
+AC_SUBST(ISC_PLATFORM_HAVEIN6PKTINFO)
+AC_SUBST(ISC_PLATFORM_FIXIN6ISADDR)
+AC_SUBST(ISC_IPV6_H)
+AC_SUBST(ISC_IPV6_O)
+AC_SUBST(ISC_ISCIPV6_O)
+AC_SUBST(ISC_IPV6_C)
+AC_SUBST(HAVE_SIN6_SCOPE_ID)
+AC_SUBST(HAVE_SOCKADDR_STORAGE)
+
+#
+# Check for network functions that are often missing. We do this
+# after the libtool checking, so we can put the right suffix on
+# the files. It also needs to come after checking for a Kame add-on,
+# which provides some (all?) of the desired functions.
+#
+AC_MSG_CHECKING([for inet_ntop])
+AC_TRY_LINK([
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>],
+ [inet_ntop(0, 0, 0, 0); return (0);],
+ [AC_MSG_RESULT(yes)
+ ISC_PLATFORM_NEEDNTOP="#undef ISC_PLATFORM_NEEDNTOP"],
+
+ [AC_MSG_RESULT(no)
+ ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
+ ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
+ ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"])
+AC_MSG_CHECKING([for inet_pton])
+AC_TRY_LINK([
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>],
+ [inet_pton(0, 0, 0); return (0);],
+ [AC_MSG_RESULT(yes)
+ ISC_PLATFORM_NEEDPTON="#undef ISC_PLATFORM_NEEDPTON"],
+
+ [AC_MSG_RESULT(no)
+ ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_pton.$O"
+ ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_pton.c"
+ ISC_PLATFORM_NEEDPTON="#define ISC_PLATFORM_NEEDPTON 1"])
+AC_MSG_CHECKING([for inet_aton])
+AC_TRY_LINK([
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>],
+ [struct in_addr in; inet_aton(0, &in); return (0);],
+ [AC_MSG_RESULT(yes)
+ ISC_PLATFORM_NEEDATON="#undef ISC_PLATFORM_NEEDATON"],
+
+ [AC_MSG_RESULT(no)
+ ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_aton.$O"
+ ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_aton.c"
+ ISC_PLATFORM_NEEDATON="#define ISC_PLATFORM_NEEDATON 1"])
+
+AC_SUBST(ISC_PLATFORM_NEEDNTOP)
+AC_SUBST(ISC_PLATFORM_NEEDPTON)
+AC_SUBST(ISC_PLATFORM_NEEDATON)
+
+#
+# Look for a 4.4BSD-style sa_len member in struct sockaddr.
+#
+case "$host" in
+ *-dec-osf*)
+ # Turn on 4.4BSD style sa_len support.
+ AC_DEFINE(_SOCKADDR_LEN)
+ ;;
+esac
+
+AC_MSG_CHECKING(for sa_len in struct sockaddr)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>],
+[struct sockaddr sa; sa.sa_len = 0; return (0);],
+ [AC_MSG_RESULT(yes)
+ HAVE_SA_LEN="#define HAVE_SA_LEN 1"],
+ [AC_MSG_RESULT(no)
+ HAVE_SA_LEN="#undef HAVE_SA_LEN"])
+AC_SUBST(HAVE_SA_LEN)
+
+# HAVE_MINIMUM_IFREQ
+
+case "$host" in
+ *-bsdi[2345]*) have_minimum_ifreq=yes;;
+ *-darwin*) have_minimum_ifreq=yes;;
+ *-freebsd*) have_minimum_ifreq=yes;;
+ *-lynxos*) have_minimum_ifreq=yes;;
+ *-netbsd*) have_minimum_ifreq=yes;;
+ *-next*) have_minimum_ifreq=yes;;
+ *-openbsd*) have_minimum_ifreq=yes;;
+ *-rhapsody*) have_minimum_ifreq=yes;;
+esac
+
+case "$have_minimum_ifreq" in
+ yes)
+ HAVE_MINIMUM_IFREQ="#define HAVE_MINIMUM_IFREQ 1";;
+ no)
+ HAVE_MINIMUM_IFREQ="#undef HAVE_MINIMUM_IFREQ";;
+ *)
+ HAVE_MINIMUM_IFREQ="#undef HAVE_MINIMUM_IFREQ";;
+esac
+AC_SUBST(HAVE_MINIMUM_IFREQ)
+
+# PORT_DIR
+PORT_DIR=port/unknown
+SOLARIS_BITTYPES="#undef NEED_SOLARIS_BITTYPES"
+BSD_COMP="#undef BSD_COMP"
+USE_FIONBIO_IOCTL="#undef USE_FIONBIO_IOCTL"
+PORT_NONBLOCK="#define PORT_NONBLOCK O_NONBLOCK"
+HAVE_MD5="#undef HAVE_MD5"
+USE_POLL="#undef HAVE_POLL"
+SOLARIS2="#undef SOLARIS2"
+case "$host" in
+ *aix3.2*) PORT_DIR="port/aix32";;
+ *aix4*) PORT_DIR="port/aix4";;
+ *aix5*) PORT_DIR="port/aix5";;
+ *aux3*) PORT_DIR="port/aux3";;
+ *-bsdi2*) PORT_DIR="port/bsdos2";;
+ *-bsdi*) PORT_DIR="port/bsdos";;
+ *-cygwin*)
+ PORT_NONBLOCK="#define PORT_NONBLOCK O_NDELAY"
+ PORT_DIR="port/cygwin";;
+ *-darwin*) PORT_DIR="port/darwin";;
+ *-osf*) PORT_DIR="port/decunix";;
+ *-freebsd*) PORT_DIR="port/freebsd";;
+ *-hpux9*) PORT_DIR="port/hpux9";;
+ *-hpux10*) PORT_DIR="port/hpux10";;
+ *-hpux11*) PORT_DIR="port/hpux";;
+ *-irix*) PORT_DIR="port/irix";;
+ *-linux*) PORT_DIR="port/linux";;
+ *-lynxos*) PORT_DIR="port/lynxos";;
+ *-mpe*) PORT_DIR="port/mpe";;
+ *-netbsd*) PORT_DIR="port/netbsd";;
+ *-next*) PORT_DIR="port/next";;
+ *-openbsd*) PORT_DIR="port/openbsd";;
+ *-qnx*) PORT_DIR="port/qnx";;
+ *-rhapsody*) PORT_DIR="port/rhapsody";;
+ *-sunos4*)
+ PORT_NONBLOCK="#define PORT_NONBLOCK O_NDELAY"
+ PORT_DIR="port/sunos";;
+ *-solaris2.[[01234]])
+ BSD_COMP="#define BSD_COMP 1"
+ SOLARIS_BITTYPES="#define NEED_SOLARIS_BITTYPES 1"
+ USE_FIONBIO_IOCTL="#define USE_FIONBIO_IOCTL 1"
+ SOLARIS2="#define SOLARIS2 1"
+ PORT_DIR="port/solaris";;
+ *-solaris2.5)
+ BSD_COMP="#define BSD_COMP 1"
+ SOLARIS_BITTYPES="#define NEED_SOLARIS_BITTYPES 1"
+ SOLARIS2="#define SOLARIS2 1"
+ PORT_DIR="port/solaris";;
+ *-solaris2.[[67]])
+ BSD_COMP="#define BSD_COMP 1"
+ SOLARIS2="#define SOLARIS2 1"
+ PORT_DIR="port/solaris";;
+ *-solaris2*) BSD_COMP="#define BSD_COMP 1"
+ USE_POLL="#define USE_POLL 1"
+ HAVE_MD5="#define HAVE_MD5 1"
+ SOLARIS2="#define SOLARIS2 1"
+ PORT_DIR="port/solaris";;
+ *-ultrix*) PORT_DIR="port/ultrix";;
+ *-sco-sysv*uw2.0*) PORT_DIR="port/unixware20";;
+ *-sco-sysv*uw2.1.2*) PORT_DIR="port/unixware212";;
+ *-sco-sysv*uw7*) PORT_DIR="port/unixware7";;
+esac
+
+AC_SUBST(BSD_COMP)
+AC_SUBST(SOLARIS_BITTYPES)
+AC_SUBST(USE_FIONBIO_IOCTL)
+AC_SUBST(PORT_NONBLOCK)
+AC_SUBST(PORT_DIR)
+AC_SUBST(USE_POLL)
+AC_SUBST(HAVE_MD5)
+AC_SUBST(SOLARIS2)
+PORT_INCLUDE=${PORT_DIR}/include
+AC_SUBST(PORT_INCLUDE)
+
+#
+# Look for a 4.4BSD or 4.3BSD struct msghdr
+#
+AC_MSG_CHECKING(for struct msghdr flavor)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>],
+[struct msghdr msg; msg.msg_flags = 0; return (0);],
+ [AC_MSG_RESULT(4.4BSD)
+ ISC_PLATFORM_MSGHDRFLAVOR="#define ISC_NET_BSD44MSGHDR 1"],
+ [AC_MSG_RESULT(4.3BSD)
+ ISC_PLATFORM_MSGHDRFLAVOR="#define ISC_NET_BSD43MSGHDR 1"])
+AC_SUBST(ISC_PLATFORM_MSGHDRFLAVOR)
+
+#
+# Look for in_port_t.
+#
+AC_MSG_CHECKING(for type in_port_t)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <netinet/in.h>],
+[in_port_t port = 25; return (0);],
+ [AC_MSG_RESULT(yes)
+ ISC_PLATFORM_NEEDPORTT="#undef ISC_PLATFORM_NEEDPORTT"],
+ [AC_MSG_RESULT(no)
+ ISC_PLATFORM_NEEDPORTT="#define ISC_PLATFORM_NEEDPORTT 1"])
+AC_SUBST(ISC_PLATFORM_NEEDPORTT)
+
+AC_MSG_CHECKING(for struct timespec)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <time.h>],
+[struct timespec ts = { 0, 0 }; return (0);],
+ [AC_MSG_RESULT(yes)
+ ISC_PLATFORM_NEEDTIMESPEC="#undef ISC_PLATFORM_NEEDTIMESPEC"],
+ [AC_MSG_RESULT(no)
+ ISC_PLATFORM_NEEDTIMESPEC="#define ISC_PLATFORM_NEEDTIMESPEC 1"])
+AC_SUBST(ISC_PLATFORM_NEEDTIMESPEC)
+
+#
+# Check for addrinfo
+#
+AC_MSG_CHECKING(for struct addrinfo)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[struct addrinfo a; return (0);],
+ [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_ADDRINFO)],
+ [AC_MSG_RESULT(no)])
+
+AC_MSG_CHECKING(for int sethostent)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[int i = sethostent(0); return(0);],
+ [AC_MSG_RESULT(yes)],
+ [AC_MSG_RESULT(no)])
+
+AC_MSG_CHECKING(for int endhostent)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[int i = endhostent(); return(0);],
+ [AC_MSG_RESULT(yes)
+ ISC_LWRES_ENDHOSTENTINT="#define ISC_LWRES_ENDHOSTENTINT 1"],
+ [AC_MSG_RESULT(no)
+ ISC_LWRES_ENDHOSTENTINT="#undef ISC_LWRES_ENDHOSTENTINT"])
+AC_SUBST(ISC_LWRES_ENDHOSTENTINT)
+
+AC_MSG_CHECKING(for int setnetent)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[int i = setnetent(0); return(0);],
+ [AC_MSG_RESULT(yes)
+ ISC_LWRES_SETNETENTINT="#define ISC_LWRES_SETNETENTINT 1"],
+ [AC_MSG_RESULT(no)
+ ISC_LWRES_SETNETENTINT="#undef ISC_LWRES_SETNETENTINT"])
+AC_SUBST(ISC_LWRES_SETNETENTINT)
+
+AC_MSG_CHECKING(for int endnetent)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[int i = endnetent(); return(0);],
+ [AC_MSG_RESULT(yes)
+ ISC_LWRES_ENDNETENTINT="#define ISC_LWRES_ENDNETENTINT 1"],
+ [AC_MSG_RESULT(no)
+ ISC_LWRES_ENDNETENTINT="#undef ISC_LWRES_ENDNETENTINT"])
+AC_SUBST(ISC_LWRES_ENDNETENTINT)
+
+AC_MSG_CHECKING(for gethostbyaddr(const void *, size_t, ...))
+AC_TRY_COMPILE([
+#include <netdb.h>
+struct hostent *gethostbyaddr(const void *, size_t, int);],
+[return(0);],
+ [AC_MSG_RESULT(yes)
+ ISC_LWRES_GETHOSTBYADDRVOID="#define ISC_LWRES_GETHOSTBYADDRVOID 1"],
+ [AC_MSG_RESULT(no)
+ ISC_LWRES_GETHOSTBYADDRVOID="#undef ISC_LWRES_GETHOSTBYADDRVOID"])
+AC_SUBST(ISC_LWRES_GETHOSTBYADDRVOID)
+
+AC_MSG_CHECKING(for h_errno in netdb.h)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[h_errno = 1; return(0);],
+ [AC_MSG_RESULT(yes)
+ ISC_LWRES_NEEDHERRNO="#undef ISC_LWRES_NEEDHERRNO"],
+ [AC_MSG_RESULT(no)
+ ISC_LWRES_NEEDHERRNO="#define ISC_LWRES_NEEDHERRNO 1"])
+AC_SUBST(ISC_LWRES_NEEDHERRNO)
+
+AC_CHECK_FUNC(getipnodebyname,
+ [ISC_LWRES_GETIPNODEPROTO="#undef ISC_LWRES_GETIPNODEPROTO"],
+ [ISC_LWRES_GETIPNODEPROTO="#define ISC_LWRES_GETIPNODEPROTO 1"])
+AC_CHECK_FUNC(getnameinfo,
+ [ISC_LWRES_GETNAMEINFOPROTO="#undef ISC_LWRES_GETNAMEINFOPROTO"],
+ [ISC_LWRES_GETNAMEINFOPROTO="#define ISC_LWRES_GETNAMEINFOPROTO 1"])
+AC_CHECK_FUNC(getaddrinfo,
+ [ISC_LWRES_GETADDRINFOPROTO="#undef ISC_LWRES_GETADDRINFOPROTO"
+ AC_DEFINE(HAVE_GETADDRINFO)],
+ [ISC_LWRES_GETADDRINFOPROTO="#define ISC_LWRES_GETADDRINFOPROTO 1"])
+AC_CHECK_FUNC(gai_strerror, AC_DEFINE(HAVE_GAISTRERROR))
+AC_SUBST(ISC_LWRES_GETIPNODEPROTO)
+AC_SUBST(ISC_LWRES_GETADDRINFOPROTO)
+AC_SUBST(ISC_LWRES_GETNAMEINFOPROTO)
+AC_CHECK_FUNC(pselect,
+ [NEED_PSELECT="#undef NEED_PSELECT"],
+ [NEED_PSELECT="#define NEED_PSELECT"])
+AC_SUBST(NEED_PSELECT)
+AC_CHECK_FUNC(gettimeofday,
+ [NEED_GETTIMEOFDAY="#undef NEED_GETTIMEOFDAY"],
+ [NEED_GETTIMEOFDAY="#define NEED_GETTIMEOFDAY 1"])
+AC_SUBST(NEED_GETTIMEOFDAY)
+AC_CHECK_FUNC(strndup,
+ [HAVE_STRNDUP="#define HAVE_STRNDUP 1"],
+ [HAVE_STRNDUP="#undef HAVE_STRNDUP"])
+AC_SUBST(HAVE_STRNDUP)
+
+#
+# Look for a sysctl call to get the list of network interfaces.
+#
+AC_MSG_CHECKING(for interface list sysctl)
+AC_EGREP_CPP(found_rt_iflist, [
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#ifdef NET_RT_IFLIST
+found_rt_iflist
+#endif
+],
+ [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_IFLIST_SYSCTL)],
+ [AC_MSG_RESULT(no)])
+
+#
+# Check for some other useful functions that are not ever-present.
+#
+AC_CHECK_FUNC(strsep,
+ [ISC_PLATFORM_NEEDSTRSEP="#undef ISC_PLATFORM_NEEDSTRSEP"],
+ [ISC_PLATFORM_NEEDSTRSEP="#define ISC_PLATFORM_NEEDSTRSEP 1"])
+AC_CHECK_FUNC(vsnprintf,
+ [ISC_PLATFORM_NEEDVSNPRINTF="#undef ISC_PLATFORM_NEEDVSNPRINTF"],
+ [ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS print.$O"
+ ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS print.c"
+ ISC_PLATFORM_NEEDVSNPRINTF="#define ISC_PLATFORM_NEEDVSNPRINTF 1"])
+AC_SUBST(ISC_PLATFORM_NEEDSTRSEP)
+AC_SUBST(ISC_PLATFORM_NEEDVSNPRINTF)
+
+AC_SUBST(ISC_EXTRA_OBJS)
+AC_SUBST(ISC_EXTRA_SRCS)
+AC_CHECK_FUNC(strerror,
+ [USE_SYSERROR_LIST="#undef USE_SYSERROR_LIST"],
+ [USE_SYSERROR_LIST="#define USE_SYSERROR_LIST 1"])
+AC_SUBST(USE_SYSERROR_LIST)
+
+#
+# Determine the printf format characters to use when printing
+# values of type isc_int64_t. We make the assumption that platforms
+# where a "long long" is the same size as a "long" (e.g., Alpha/OSF1)
+# want "%ld" and everyone else can use "%lld". Win32 uses "%I64d",
+# but that's defined elsewhere since we don't use configure on Win32.
+#
+AC_MSG_CHECKING(printf format modifier for 64-bit integers)
+AC_TRY_RUN([main() { exit(!(sizeof(long long int) == sizeof(long int))); }],
+ [AC_MSG_RESULT(l)
+ ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "l"'],
+ [AC_MSG_RESULT(ll)
+ ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "ll"'],
+ [AC_MSG_RESULT(default ll)
+ ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "ll"'])
+AC_SUBST(ISC_PLATFORM_QUADFORMAT)
+
+#
+# Security Stuff
+#
+AC_CHECK_FUNC(chroot, AC_DEFINE(HAVE_CHROOT))
+
+#
+# for accept, recvfrom, getpeername etc.
+#
+AC_MSG_CHECKING(for socket length type)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+int accept(int, struct sockaddr *, socklen_t *);
+],[],
+[ISC_SOCKLEN_T="#define ISC_SOCKLEN_T socklen_t"
+AC_MSG_RESULT(socklen_t)]
+,
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+int accept(int, struct sockaddr *, unsigned int *);
+],[],
+[ISC_SOCKLEN_T="#define ISC_SOCKLEN_T unsigned int"
+AC_MSG_RESULT(unsigned int)]
+,
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+int accept(int, struct sockaddr *, unsigned long *);
+],[],
+[ISC_SOCKLEN_T="#define ISC_SOCKLEN_T unsigned long"
+AC_MSG_RESULT(unsigned long)]
+,
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+int accept(int, struct sockaddr *, long *);
+],[],
+[ISC_SOCKLEN_T="#define ISC_SOCKLEN_T long"
+AC_MSG_RESULT(long)]
+,
+ISC_SOCKLEN_T="#define ISC_SOCKLEN_T int"
+AC_MSG_RESULT(int)
+))))
+AC_SUBST(ISC_SOCKLEN_T)
+
+AC_CHECK_FUNC(getgrouplist,
+AC_TRY_COMPILE(
+[#include <unistd.h>
+int
+getgrouplist(const char *name, int basegid, int *groups, int *ngroups) {
+}
+],
+[return (0);],
+GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, int basegid, int *groups, int *ngroups"
+,
+GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, gid_t basegid, gid_t *groups, int *ngroups"
+),
+GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, gid_t basegid, gid_t *groups, int *ngroups"
+AC_DEFINE(NEED_GETGROUPLIST)
+)
+AC_SUBST(GETGROUPLIST_ARGS)
+
+AC_CHECK_FUNC(setgroupent,,AC_DEFINE(NEED_SETGROUPENT))
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(getnetbyaddr_r,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#define _OSF_SOURCE
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+struct netent *
+getnetbyaddr_r(long net, int type, struct netent *result, char *buffer,
+int buflen) {}
+],
+[return (0)],
+[
+NET_R_ARGS="#define NET_R_ARGS char *buf, int buflen"
+NET_R_BAD="#define NET_R_BAD NULL"
+NET_R_COPY="#define NET_R_COPY buf, buflen"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS NET_R_ARGS"
+NET_R_OK="#define NET_R_OK nptr"
+NET_R_SETANSWER="#undef NET_R_SETANSWER"
+NET_R_RETURN="#define NET_R_RETURN struct netent *"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T long"
+NETENT_DATA="#undef NETENT_DATA"
+],
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#define _OSF_SOURCE
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getnetbyaddr_r (unsigned long int, int, struct netent *,
+ char *, size_t, struct netent **, int *);
+],
+[return (0)],
+[
+NET_R_ARGS="#define NET_R_ARGS char *buf, size_t buflen, struct netent **answerp, int *h_errnop"
+NET_R_BAD="#define NET_R_BAD ERANGE"
+NET_R_COPY="#define NET_R_COPY buf, buflen"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS char *buf, size_t buflen"
+NET_R_OK="#define NET_R_OK 0"
+NET_R_SETANSWER="#define NET_R_SETANSWER 1"
+NET_R_RETURN="#define NET_R_RETURN int"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T unsigned long int"
+NETENT_DATA="#undef NETENT_DATA"
+],
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#define _OSF_SOURCE
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int getnetbyaddr_r(int, int, struct netent *, struct netent_data *);
+],
+[return (0)],
+[
+NET_R_ARGS="#define NET_R_ARGS struct netent_data *ndptr"
+NET_R_BAD="#define NET_R_BAD (-1)"
+NET_R_COPY="#define NET_R_COPY ndptr"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS struct netent_data *ndptr"
+NET_R_OK="#define NET_R_OK 0"
+NET_R_SETANSWER="#undef NET_R_SETANSWER"
+NET_R_RETURN="#define NET_R_RETURN int"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T int"
+NETENT_DATA="#define NETENT_DATA 1"
+],
+AC_TRY_COMPILE(
+#undef __USE_MISC
+#define __USE_MISC
+[#include <netdb.h>
+int getnetbyaddr_r (in_addr_t, int, struct netent *, struct netent_data *);
+],
+[return (0)],
+[
+NET_R_ARGS="#define NET_R_ARGS struct netent_data *ndptr"
+NET_R_BAD="#define NET_R_BAD (-1)"
+NET_R_COPY="#define NET_R_COPY ndptr"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS struct netent_data *ndptr"
+NET_R_OK="#define NET_R_OK 0"
+NET_R_SETANSWER="#undef NET_R_SETANSWER"
+NET_R_RETURN="#define NET_R_RETURN int"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T long"
+NETENT_DATA="#define NETENT_DATA 1"
+],
+AC_TRY_COMPILE(
+#undef __USE_MISC
+#define __USE_MISC
+[#include <netdb.h>
+int getnetbyaddr_r (long, int, struct netent *, struct netent_data *);
+],
+[return (0)],
+[
+NET_R_ARGS="#define NET_R_ARGS struct netent_data *ndptr"
+NET_R_BAD="#define NET_R_BAD (-1)"
+NET_R_COPY="#define NET_R_COPY ndptr"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS struct netent_data *ndptr"
+NET_R_OK="#define NET_R_OK 0"
+NET_R_SETANSWER="#undef NET_R_SETANSWER"
+NET_R_RETURN="#define NET_R_RETURN int"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T long"
+NETENT_DATA="#define NETENT_DATA 1"
+],
+AC_TRY_COMPILE(
+#undef __USE_MISC
+#define __USE_MISC
+[#include <netdb.h>
+int getnetbyaddr_r (uint32_t, int, struct netent *,
+ char *, size_t, struct netent **, int *);
+],
+[return (0)],
+[
+NET_R_ARGS="#define NET_R_ARGS char *buf, size_t buflen, struct netent **answerp, int *h_errnop"
+NET_R_BAD="#define NET_R_BAD ERANGE"
+NET_R_COPY="#define NET_R_COPY buf, buflen"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS char *buf, size_t buflen"
+NET_R_OK="#define NET_R_OK 0"
+NET_R_SETANSWER="#define NET_R_SETANSWER 1"
+NET_R_RETURN="#define NET_R_RETURN int"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T unsigned long int"
+NETENT_DATA="#undef NETENT_DATA"
+],
+)
+)
+)
+)
+)
+)
+,
+NET_R_ARGS="#define NET_R_ARGS char *buf, int buflen"
+NET_R_BAD="#define NET_R_BAD NULL"
+NET_R_COPY="#define NET_R_COPY buf, buflen"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS NET_R_ARGS"
+NET_R_OK="#define NET_R_OK nptr"
+NET_R_SETANSWER="#undef NET_R_SETANSWER"
+NET_R_RETURN="#define NET_R_RETURN struct netent *"
+GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T long"
+NETENT_DATA="#undef NETENT_DATA"
+)
+esac
+
+case "$host" in
+*dec-osf*) GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T int" ;;
+esac
+AC_SUBST(NET_R_ARGS)
+AC_SUBST(NET_R_BAD)
+AC_SUBST(NET_R_COPY)
+AC_SUBST(NET_R_COPY_ARGS)
+AC_SUBST(NET_R_OK)
+AC_SUBST(NET_R_SETANSWER)
+AC_SUBST(NET_R_RETURN)
+AC_SUBST(GETNETBYADDR_ADDR_T)
+AC_SUBST(NETENT_DATA)
+
+AC_CHECK_FUNC(setnetent_r,
+AC_TRY_COMPILE(
+[
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void setnetent_r (int);
+] ,[return (0);],[
+NET_R_ENT_ARGS="#undef NET_R_ENT_ARGS /*empty*/"
+NET_R_SET_RESULT="#undef NET_R_SET_RESULT /*empty*/"
+NET_R_SET_RETURN="#define NET_R_SET_RETURN void"
+],
+AC_TRY_COMPILE(
+[
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int setnetent_r(int, struct netent_data *);
+] ,[return (0);],[
+NET_R_ENT_ARGS="#define NET_R_ENT_ARGS struct netent_data *ndptr"
+NET_R_SET_RESULT="#define NET_R_SET_RESULT NET_R_OK"
+NET_R_SET_RETURN="#define NET_R_SET_RETURN int"
+],
+)
+)
+,
+NET_R_ENT_ARGS="#undef NET_R_ENT_ARGS /*empty*/"
+NET_R_SET_RESULT="#undef NET_R_SET_RESULT /*empty*/"
+NET_R_SET_RETURN="#define NET_R_SET_RETURN void"
+)
+AC_SUBST(NET_R_ENT_ARGS)
+AC_SUBST(NET_R_SET_RESULT)
+AC_SUBST(NET_R_SET_RETURN)
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(endnetent_r,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endnetent_r (void);
+] ,[return (0);],[
+NET_R_END_RESULT="#define NET_R_END_RESULT(x) /*empty*/"
+NET_R_END_RETURN="#define NET_R_END_RETURN void"
+],
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int endnetent_r(struct netent_data *);
+] ,[return (0);],[
+NET_R_END_RESULT="#define NET_R_END_RESULT(x) return (x)"
+NET_R_END_RETURN="#define NET_R_END_RETURN int"
+],
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern void endnetent_r(struct netent_data *);
+] ,[return (0);],[
+NET_R_END_RESULT="#define NET_R_END_RESULT(x) /*empty*/"
+NET_R_END_RETURN="#define NET_R_END_RETURN void"
+],
+)
+)
+)
+,
+NET_R_END_RESULT="#define NET_R_END_RESULT(x) /*empty*/"
+NET_R_END_RETURN="#define NET_R_END_RETURN void"
+)
+esac
+AC_SUBST(NET_R_END_RESULT)
+AC_SUBST(NET_R_END_RETURN)
+
+AC_CHECK_FUNC(getgrnam_r,,AC_DEFINE(NEED_GETGRNAM_R))
+AC_CHECK_FUNC(getgrgid_r,,AC_DEFINE(NEED_GETGRGID_R))
+
+AC_CHECK_FUNC(getgrent_r,
+AC_TRY_COMPILE(
+[
+#include <grp.h>
+struct group *getgrent_r(struct group *grp, char *buffer,
+ int buflen) {}
+] ,[return (0);],[
+GROUP_R_ARGS="#define GROUP_R_ARGS char *buf, int buflen"
+GROUP_R_BAD="#define GROUP_R_BAD NULL"
+GROUP_R_OK="#define GROUP_R_OK gptr"
+GROUP_R_RETURN="#define GROUP_R_RETURN struct group *"
+],
+)
+,
+GROUP_R_ARGS="#define GROUP_R_ARGS char *buf, int buflen"
+GROUP_R_BAD="#define GROUP_R_BAD NULL"
+GROUP_R_OK="#define GROUP_R_OK gptr"
+GROUP_R_RETURN="#define GROUP_R_RETURN struct group *"
+AC_DEFINE(NEED_GETGRENT_R)
+)
+AC_SUBST(GROUP_R_ARGS)
+AC_SUBST(GROUP_R_BAD)
+AC_SUBST(GROUP_R_OK)
+AC_SUBST(GROUP_R_RETURN)
+
+AC_CHECK_FUNC(endgrent_r,
+,
+GROUP_R_END_RESULT="#define GROUP_R_END_RESULT(x) /*empty*/"
+GROUP_R_END_RETURN="#define GROUP_R_END_RETURN void"
+GROUP_R_ENT_ARGS="#define GROUP_R_ENT_ARGS void"
+AC_DEFINE(NEED_ENDGRENT_R)
+)
+AC_SUBST(GROUP_R_END_RESULT)
+AC_SUBST(GROUP_R_END_RETURN)
+AC_SUBST(GROUP_R_ENT_ARGS)
+
+AC_CHECK_FUNC(setgrent_r,
+,
+GROUP_R_SET_RESULT="#undef GROUP_R_SET_RESULT /*empty*/"
+GROUP_R_SET_RETURN="#define GROUP_R_SET_RETURN void"
+AC_DEFINE(NEED_SETGRENT_R)
+)
+AC_SUBST(GROUP_R_SET_RESULT)
+AC_SUBST(GROUP_R_SET_RETURN)
+
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(gethostbyname_r,
+AC_TRY_COMPILE(
+[
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+struct hostent *gethostbyname_r
+(const char *name, struct hostent *hp, char *buf, int len, int *h_errnop) {}
+],
+[return (0);],
+[
+HOST_R_ARGS="#define HOST_R_ARGS char *buf, int buflen, int *h_errnop"
+HOST_R_BAD="#define HOST_R_BAD NULL"
+HOST_R_COPY="#define HOST_R_COPY buf, buflen"
+HOST_R_COPY_ARGS="#define HOST_R_COPY_ARGS char *buf, int buflen"
+HOST_R_ERRNO="#define HOST_R_ERRNO *h_errnop = h_errno"
+HOST_R_OK="#define HOST_R_OK hptr"
+HOST_R_RETURN="#define HOST_R_RETURN struct hostent *"
+HOST_R_SETANSWER="#undef HOST_R_SETANSWER"
+HOSTENT_DATA="#undef HOSTENT_DATA"
+]
+,
+AC_TRY_COMPILE([
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int gethostbyname_r(const char *name,
+ struct hostent *result,
+ struct hostent_data *hdptr);
+],,[
+HOST_R_ARGS="#define HOST_R_ARGS struct hostent_data *hdptr"
+HOST_R_BAD="#define HOST_R_BAD (-1)"
+HOST_R_COPY="#define HOST_R_COPY hdptr"
+HOST_R_COPY_ARGS="#define HOST_R_COPY_ARGS HOST_R_ARGS"
+HOST_R_ERRNO="#undef HOST_R_ERRNO"
+HOST_R_OK="#define HOST_R_OK 0"
+HOST_R_RETURN="#define HOST_R_RETURN int"
+HOST_R_SETANSWER="#undef HOST_R_SETANSWER"
+HOSTENT_DATA="#define HOSTENT_DATA 1"
+],
+AC_TRY_COMPILE([
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int gethostbyname_r (const char *,
+ struct hostent *,
+ char *, size_t,
+ struct hostent **,
+ int *);
+],,[
+HOST_R_ARGS="#define HOST_R_ARGS char *buf, size_t buflen, struct hostent **answerp, int *h_errnop"
+HOST_R_BAD="#define HOST_R_BAD ERANGE"
+HOST_R_COPY="#define HOST_R_COPY buf, buflen"
+HOST_R_COPY_ARGS="#define HOST_R_COPY_ARGS char *buf, int buflen"
+HOST_R_ERRNO="#define HOST_R_ERRNO *h_errnop = h_errno"
+HOST_R_OK="#define HOST_R_OK 0"
+HOST_R_RETURN="#define HOST_R_RETURN int"
+HOST_R_SETANSWER="#define HOST_R_SETANSWER 1"
+HOSTENT_DATA="#undef HOSTENT_DATA"
+],
+)))
+,
+HOST_R_ARGS="#define HOST_R_ARGS char *buf, int buflen, int *h_errnop"
+HOST_R_BAD="#define HOST_R_BAD NULL"
+HOST_R_COPY="#define HOST_R_COPY buf, buflen"
+HOST_R_COPY_ARGS="#define HOST_R_COPY_ARGS char *buf, int buflen"
+HOST_R_ERRNO="#define HOST_R_ERRNO *h_errnop = h_errno"
+HOST_R_OK="#define HOST_R_OK hptr"
+HOST_R_RETURN="#define HOST_R_RETURN struct hostent *"
+HOST_R_SETANSWER="#undef HOST_R_SETANSWER"
+HOSTENT_DATA="#undef HOSTENT_DATA"
+)
+esac
+AC_SUBST(HOST_R_ARGS)
+AC_SUBST(HOST_R_BAD)
+AC_SUBST(HOST_R_COPY)
+AC_SUBST(HOST_R_COPY_ARGS)
+AC_SUBST(HOST_R_ERRNO)
+AC_SUBST(HOST_R_OK)
+AC_SUBST(HOST_R_RETURN)
+AC_SUBST(HOST_R_SETANSWER)
+AC_SUBST(HOSTENT_DATA)
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(endhostent_r,
+AC_TRY_COMPILE([
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int endhostent_r(struct hostent_data *buffer);
+], ,
+HOST_R_END_RESULT="#define HOST_R_END_RESULT(x) return (x)"
+HOST_R_END_RETURN="#define HOST_R_END_RETURN int"
+HOST_R_ENT_ARGS="#define HOST_R_ENT_ARGS struct hostent_data *hdptr"
+,
+AC_TRY_COMPILE([
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern void endhostent_r(struct hostent_data *ht_data);
+],[],[
+HOST_R_END_RESULT="#define HOST_R_END_RESULT(x)"
+HOST_R_END_RETURN="#define HOST_R_END_RETURN void"
+HOST_R_ENT_ARGS="#define HOST_R_ENT_ARGS struct hostent_data *hdptr"
+],
+AC_TRY_COMPILE([
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern void endhostent_r(void);
+],[],[
+HOST_R_END_RESULT="#define HOST_R_END_RESULT(x) /*empty*/"
+HOST_R_END_RETURN="#define HOST_R_END_RETURN void"
+HOST_R_ENT_ARGS="#undef HOST_R_ENT_ARGS /*empty*/"
+],
+)
+)
+)
+,
+HOST_R_END_RESULT="#define HOST_R_END_RESULT(x) /*empty*/"
+HOST_R_END_RETURN="#define HOST_R_END_RETURN void"
+HOST_R_ENT_ARGS="#undef HOST_R_ENT_ARGS /*empty*/"
+)
+esac;
+AC_SUBST(HOST_R_END_RESULT)
+AC_SUBST(HOST_R_END_RETURN)
+AC_SUBST(HOST_R_ENT_ARGS)
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(sethostent_r,
+AC_TRY_COMPILE([
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern void sethostent_r(int flag, struct hostent_data *ht_data);],[],
+[HOST_R_SET_RESULT="#undef HOST_R_SET_RESULT /*empty*/"
+HOST_R_SET_RETURN="#define HOST_R_SET_RETURN void"],
+AC_TRY_COMPILE([
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int sethostent_r(int flag, struct hostent_data *ht_data);],[],
+[HOST_R_SET_RESULT="#define HOST_R_SET_RESULT 0"
+HOST_R_SET_RETURN="#define HOST_R_SET_RETURN int"],
+AC_TRY_COMPILE([
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void sethostent_r (int);],[],
+[HOST_R_SET_RESULT="#undef HOST_R_SET_RESULT"
+HOST_R_SET_RETURN="#define HOST_R_SET_RETURN void"],
+)
+)
+)
+,
+HOST_R_SET_RESULT="#undef HOST_R_SET_RESULT"
+HOST_R_SET_RETURN="#define HOST_R_SET_RETURN void"
+)
+esac
+AC_SUBST(HOST_R_SET_RESULT)
+AC_SUBST(HOST_R_SET_RETURN)
+
+
+AC_MSG_CHECKING(struct passwd element pw_class)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <pwd.h>
+],[struct passwd *pw; pw->pw_class = "";],
+AC_MSG_RESULT(yes)
+AC_DEFINE(HAS_PW_CLASS)
+,
+ AC_MSG_RESULT(no)
+)
+
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <pwd.h>
+void
+setpwent(void) {}
+],
+[return (0);],
+SETPWENT_VOID="#define SETPWENT_VOID 1"
+,
+SETPWENT_VOID="#undef SETPWENT_VOID"
+)
+AC_SUBST(SETPWENT_VOID)
+
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <grp.h>
+void
+setgrent(void) {}
+],
+[return (0);],
+SETGRENT_VOID="#define SETGRENT_VOID 1"
+,
+SETGRENT_VOID="#undef SETGRENT_VOID"
+)
+AC_SUBST(SETGRENT_VOID)
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(getnetgrent_r,
+AC_TRY_COMPILE(
+[
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getnetgrent_r(char **m, char **u, char **d, char *b, int l) {}
+]
+,
+[return (0);],
+[
+NGR_R_ARGS="#define NGR_R_ARGS char *buf, int buflen"
+NGR_R_BAD="#define NGR_R_BAD (0)"
+NGR_R_COPY="#define NGR_R_COPY buf, buflen"
+NGR_R_COPY_ARGS="#define NGR_R_COPY_ARGS NGR_R_ARGS"
+NGR_R_OK="#define NGR_R_OK 1"
+NGR_R_RETURN="#define NGR_R_RETURN int"
+]
+,
+AC_TRY_COMPILE(
+[
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getnetgrent_r(char **m, char **u, char **d, char *b, size_t l) {}
+]
+,
+[return (0);],
+[
+NGR_R_ARGS="#define NGR_R_ARGS char *buf, size_t buflen"
+NGR_R_BAD="#define NGR_R_BAD (0)"
+NGR_R_COPY="#define NGR_R_COPY buf, buflen"
+NGR_R_COPY_ARGS="#define NGR_R_COPY_ARGS NGR_R_ARGS"
+NGR_R_OK="#define NGR_R_OK 1"
+NGR_R_RETURN="#define NGR_R_RETURN int"
+]
+,
+AC_TRY_COMPILE(
+[
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+extern int getnetgrent_r( char **, char **, char **, void **);
+]
+,
+[return (0);],
+[
+NGR_R_ARGS="#define NGR_R_ARGS void **buf"
+NGR_R_BAD="#define NGR_R_BAD (0)"
+NGR_R_COPY="#define NGR_R_COPY buf"
+NGR_R_COPY_ARGS="#define NGR_R_COPY_ARGS NGR_R_ARGS"
+NGR_R_OK="#define NGR_R_OK 1"
+NGR_R_RETURN="#define NGR_R_RETURN int"
+NGR_R_PRIVATE="#define NGR_R_PRIVATE 1"
+]
+,
+)
+)
+)
+,
+NGR_R_ARGS="#define NGR_R_ARGS char *buf, int buflen"
+NGR_R_BAD="#define NGR_R_BAD (0)"
+NGR_R_COPY="#define NGR_R_COPY buf, buflen"
+NGR_R_COPY_ARGS="#define NGR_R_COPY_ARGS NGR_R_ARGS"
+NGR_R_OK="#define NGR_R_OK 1"
+NGR_R_RETURN="#define NGR_R_RETURN int"
+)
+esac
+AC_SUBST(NGR_R_ARGS)
+AC_SUBST(NGR_R_BAD)
+AC_SUBST(NGR_R_COPY)
+AC_SUBST(NGR_R_COPY_ARGS)
+AC_SUBST(NGR_R_OK)
+AC_SUBST(NGR_R_RETURN)
+AC_SUBST(NGR_R_PRIVATE)
+
+AC_CHECK_FUNC(endnetgrent_r,
+AC_TRY_COMPILE(
+[
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endnetgrent_r(void **ptr);
+]
+,
+[return (0);]
+,
+[
+NGR_R_END_RESULT="#define NGR_R_END_RESULT(x) /* empty */"
+NGR_R_END_RETURN="#define NGR_R_END_RETURN void"
+NGR_R_ENT_ARGS="#define NGR_R_ENT_ARGS NGR_R_ARGS"
+]
+,
+[
+NGR_R_END_RESULT="#define NGR_R_END_RESULT(x) return (x)"
+NGR_R_END_RETURN="#define NGR_R_END_RETURN int"
+NGR_R_ENT_ARGS="#define NGR_R_ENT_ARGS NGR_R_ARGS"
+]
+)
+,
+NGR_R_END_RESULT="#define NGR_R_END_RESULT(x) /*empty*/"
+NGR_R_END_RETURN="#define NGR_R_END_RETURN void"
+NGR_R_ENT_ARGS="#undef NGR_R_ENT_ARGS /*empty*/"
+AC_DEFINE(NEED_ENDNETGRENT_R)
+)
+AC_SUBST(NGR_R_END_RESULT)
+AC_SUBST(NGR_R_END_RETURN)
+AC_SUBST(NGR_R_ENT_ARGS)
+
+AC_CHECK_FUNC(setnetgrent_r,
+[
+case "$host" in
+*bsdi*)
+ NGR_R_SET_RESULT="#undef NGR_R_SET_RESULT /*empty*/"
+ NGR_R_SET_RETURN="#define NGR_R_SET_RETURN void"
+ ;;
+*)
+ NGR_R_SET_RESULT="#define NGR_R_SET_RESULT NGR_R_OK"
+ NGR_R_SET_RETURN="#define NGR_R_SET_RETURN int"
+ ;;
+esac
+]
+,
+NGR_R_SET_RESULT="#undef NGR_R_SET_RESULT /*empty*/"
+NGR_R_SET_RETURN="#define NGR_R_SET_RETURN void"
+)
+AC_SUBST(NGR_R_SET_RESULT)
+AC_SUBST(NGR_R_SET_RETURN)
+
+AC_CHECK_FUNC(innetgr_r,,AC_DEFINE(NEED_INNETGR_R))
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(getprotoent_r,
+AC_TRY_COMPILE(
+[
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+struct protoent *getprotoent_r(struct protoent *result,
+ char *buffer, int buflen) {}
+]
+,
+[return (0);]
+,
+[
+PROTO_R_ARGS="#define PROTO_R_ARGS char *buf, int buflen"
+PROTO_R_BAD="#define PROTO_R_BAD NULL"
+PROTO_R_COPY="#define PROTO_R_COPY buf, buflen"
+PROTO_R_COPY_ARGS="#define PROTO_R_COPY_ARGS PROTO_R_ARGS"
+PROTO_R_OK="#define PROTO_R_OK pptr"
+PROTO_R_SETANSWER="#undef PROTO_R_SETANSWER"
+PROTO_R_RETURN="#define PROTO_R_RETURN struct protoent *"
+PROTOENT_DATA="#undef PROTOENT_DATA"
+]
+,
+AC_TRY_COMPILE(
+[
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getprotoent_r (struct protoent *, char *, size_t, struct protoent **);
+
+]
+,
+[return (0);]
+,
+[
+PROTO_R_ARGS="#define PROTO_R_ARGS char *buf, size_t buflen, struct protoent **answerp"
+PROTO_R_BAD="#define PROTO_R_BAD ERANGE"
+PROTO_R_COPY="#define PROTO_R_COPY buf, buflen"
+PROTO_R_COPY_ARGS="#define PROTO_R_COPY_ARGS char *buf, size_t buflen"
+PROTO_R_OK="#define PROTO_R_OK 0"
+PROTO_R_SETANSWER="#define PROTO_R_SETANSWER 1"
+PROTO_R_RETURN="#define PROTO_R_RETURN int"
+PROTOENT_DATA="#undef PROTOENT_DATA"
+]
+,
+AC_TRY_COMPILE(
+[
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int getprotoent_r (struct protoent *, struct protoent_data *prot_data);
+
+]
+,
+[return (0);]
+,
+[
+PROTO_R_ARGS="#define PROTO_R_ARGS struct protoent_data *prot_data"
+PROTO_R_BAD="#define PROTO_R_BAD (-1)"
+PROTO_R_COPY="#define PROTO_R_COPY prot_data"
+PROTO_R_COPY_ARGS="#define PROTO_R_COPY_ARGS struct protoent_data *pdptr"
+PROTO_R_OK="#define PROTO_R_OK 0"
+PROTO_R_SETANSWER="#undef PROTO_R_SETANSWER"
+PROTO_R_RETURN="#define PROTO_R_RETURN int"
+PROTOENT_DATA="#define PROTOENT_DATA 1"
+]
+,
+)
+)
+)
+,
+PROTO_R_ARGS="#define PROTO_R_ARGS char *buf, int buflen"
+PROTO_R_BAD="#define PROTO_R_BAD NULL"
+PROTO_R_COPY="#define PROTO_R_COPY buf, buflen"
+PROTO_R_COPY_ARGS="#define PROTO_R_COPY_ARGS PROTO_R_ARGS"
+PROTO_R_OK="#define PROTO_R_OK pptr"
+PROTO_R_SETANSWER="#undef PROTO_R_SETANSWER"
+PROTO_R_RETURN="#define PROTO_R_RETURN struct protoent *"
+PROTOENT_DATA="#undef PROTOENT_DATA"
+)
+;;
+esac
+AC_SUBST(PROTO_R_ARGS)
+AC_SUBST(PROTO_R_BAD)
+AC_SUBST(PROTO_R_COPY)
+AC_SUBST(PROTO_R_COPY_ARGS)
+AC_SUBST(PROTO_R_OK)
+AC_SUBST(PROTO_R_SETANSWER)
+AC_SUBST(PROTO_R_RETURN)
+AC_SUBST(PROTOENT_DATA)
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(endprotoent_r,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endprotoent_r(void);
+]
+,,
+[
+PROTO_R_END_RESULT="#define PROTO_R_END_RESULT(x) /*empty*/"
+PROTO_R_END_RETURN="#define PROTO_R_END_RETURN void"
+PROTO_R_ENT_ARGS="#undef PROTO_R_ENT_ARGS"
+PROTO_R_ENT_UNUSED="#undef PROTO_R_ENT_UNUSED"
+]
+,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endprotoent_r(struct protoent_data *);
+]
+,,
+[
+PROTO_R_END_RESULT="#define PROTO_R_END_RESULT(x) /*empty*/"
+PROTO_R_END_RETURN="#define PROTO_R_END_RETURN void"
+PROTO_R_ENT_ARGS="#define PROTO_R_ENT_ARGS struct protoent_data *proto_data"
+PROTO_R_ENT_UNUSED="#define PROTO_R_ENT_UNUSED UNUSED(proto_data)"
+]
+,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int endprotoent_r(struct protoent_data *);
+]
+,,
+[
+PROTO_R_END_RESULT="#define PROTO_R_END_RESULT(x) return(0)"
+PROTO_R_END_RETURN="#define PROTO_R_END_RETURN int"
+PROTO_R_ENT_ARGS="#define PROTO_R_ENT_ARGS struct protoent_data *proto_data"
+PROTO_R_ENT_UNUSED="#define PROTO_R_ENT_UNUSED UNUSED(proto_data)"
+]
+,
+)
+)
+)
+,
+PROTO_R_END_RESULT="#define PROTO_R_END_RESULT(x) /*empty*/"
+PROTO_R_END_RETURN="#define PROTO_R_END_RETURN void"
+PROTO_R_ENT_ARGS="#undef PROTO_R_ENT_ARGS /*empty*/"
+PROTO_R_ENT_UNUSED="#undef PROTO_R_ENT_UNUSED"
+)
+esac
+AC_SUBST(PROTO_R_END_RESULT)
+AC_SUBST(PROTO_R_END_RETURN)
+AC_SUBST(PROTO_R_ENT_ARGS)
+AC_SUBST(PROTO_R_ENT_UNUSED)
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(setprotoent_r,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void setprotoent_r __P((int));
+],[],
+PROTO_R_SET_RESULT="#undef PROTO_R_SET_RESULT"
+PROTO_R_SET_RETURN="#define PROTO_R_SET_RETURN void"
+,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int setprotoent_r (int, struct protoent_data *);
+],[],
+PROTO_R_SET_RESULT="#define PROTO_R_SET_RESULT (0)"
+PROTO_R_SET_RETURN="#define PROTO_R_SET_RETURN int"
+,
+)
+)
+,
+PROTO_R_SET_RESULT="#undef PROTO_R_SET_RESULT"
+PROTO_R_SET_RETURN="#define PROTO_R_SET_RETURN void"
+)
+esac
+AC_SUBST(PROTO_R_SET_RESULT)
+AC_SUBST(PROTO_R_SET_RETURN)
+
+AC_CHECK_FUNC(getpwent_r,
+AC_TRY_COMPILE(
+[
+#include <sys/types.h>
+#include <pwd.h>
+struct passwd *
+getpwent_r(struct passwd *pwptr, char *buf, int buflen) {}
+]
+,
+[]
+,
+PASS_R_ARGS="#define PASS_R_ARGS char *buf, int buflen"
+PASS_R_BAD="#define PASS_R_BAD NULL"
+PASS_R_COPY="#define PASS_R_COPY buf, buflen"
+PASS_R_COPY_ARGS="#define PASS_R_COPY_ARGS PASS_R_ARGS"
+PASS_R_OK="#define PASS_R_OK pwptr"
+PASS_R_RETURN="#define PASS_R_RETURN struct passwd *"
+,
+)
+,
+PASS_R_ARGS="#define PASS_R_ARGS char *buf, int buflen"
+PASS_R_BAD="#define PASS_R_BAD NULL"
+PASS_R_COPY="#define PASS_R_COPY buf, buflen"
+PASS_R_COPY_ARGS="#define PASS_R_COPY_ARGS PASS_R_ARGS"
+PASS_R_OK="#define PASS_R_OK pwptr"
+PASS_R_RETURN="#define PASS_R_RETURN struct passwd *"
+AC_DEFINE(NEED_GETPWENT_R)
+)
+AC_SUBST(PASS_R_ARGS)
+AC_SUBST(PASS_R_BAD)
+AC_SUBST(PASS_R_COPY)
+AC_SUBST(PASS_R_COPY_ARGS)
+AC_SUBST(PASS_R_OK)
+AC_SUBST(PASS_R_RETURN)
+
+AC_CHECK_FUNC(endpwent_r,
+AC_TRY_COMPILE(
+[
+#include <pwd.h>
+void endpwent_r(FILE **pwfp);
+], ,
+PASS_R_END_RESULT="#define PASS_R_END_RESULT(x) /*empty*/"
+PASS_R_END_RETURN="#define PASS_R_END_RETURN void"
+PASS_R_ENT_ARGS="#define PASS_R_ENT_ARGS FILE **pwptr"
+,
+)
+,
+PASS_R_END_RESULT="#define PASS_R_END_RESULT(x) /*empty*/"
+PASS_R_END_RETURN="#define PASS_R_END_RETURN void"
+PASS_R_ENT_ARGS="#undef PASS_R_ENT_ARGS"
+AC_DEFINE(NEED_ENDPWENT_R)
+)
+AC_SUBST(PASS_R_END_RESULT)
+AC_SUBST(PASS_R_END_RETURN)
+AC_SUBST(PASS_R_ENT_ARGS)
+AC_CHECK_FUNC(setpassent_r,,AC_DEFINE(NEED_SETPASSENT_R))
+AC_CHECK_FUNC(setpassent,,AC_DEFINE(NEED_SETPASSENT))
+
+AC_CHECK_FUNC(setpwent_r,
+AC_TRY_COMPILE([
+#include <pwd.h>
+void setpwent_r(FILE **pwfp);
+], ,
+PASS_R_SET_RESULT="#undef PASS_R_SET_RESULT /* empty */"
+PASS_R_SET_RETURN="#define PASS_R_SET_RETURN int"
+,
+AC_TRY_COMPILE([
+#include <pwd.h>
+int setpwent_r(FILE **pwfp);
+], ,
+PASS_R_SET_RESULT="#define PASS_R_SET_RESULT 0"
+PASS_R_SET_RETURN="#define PASS_R_SET_RETURN int"
+,
+)
+)
+,
+PASS_R_SET_RESULT="#undef PASS_R_SET_RESULT /*empty*/"
+PASS_R_SET_RETURN="#define PASS_R_SET_RETURN void"
+AC_DEFINE(NEED_SETPWENT_R)
+)
+AC_SUBST(PASS_R_SET_RESULT)
+AC_SUBST(PASS_R_SET_RETURN)
+
+AC_CHECK_FUNC(getpwnam_r,,AC_DEFINE(NEED_GETPWNAM_R))
+AC_CHECK_FUNC(getpwuid_r,,AC_DEFINE(NEED_GETPWUID_R))
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(getservent_r,
+AC_TRY_COMPILE([
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+struct servent *
+getservent_r(struct servent *result, char *buffer, int buflen) {}
+],[return (0);],
+[
+SERV_R_ARGS="#define SERV_R_ARGS char *buf, int buflen"
+SERV_R_BAD="#define SERV_R_BAD NULL"
+SERV_R_COPY="#define SERV_R_COPY buf, buflen"
+SERV_R_COPY_ARGS="#define SERV_R_COPY_ARGS SERV_R_ARGS"
+SERV_R_OK="#define SERV_R_OK sptr"
+SERV_R_SETANSWER="#undef SERV_R_SETANSWER"
+SERV_R_RETURN="#define SERV_R_RETURN struct servent *"
+]
+,
+AC_TRY_COMPILE([
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int
+getservent_r (struct servent *, char *, size_t, struct servent **);
+],[return (0);],
+[
+SERV_R_ARGS="#define SERV_R_ARGS char *buf, size_t buflen, struct servent **answerp"
+SERV_R_BAD="#define SERV_R_BAD ERANGE"
+SERV_R_COPY="#define SERV_R_COPY buf, buflen"
+SERV_R_COPY_ARGS="#define SERV_R_COPY_ARGS char *buf, size_t buflen"
+SERV_R_OK="#define SERV_R_OK (0)"
+SERV_R_SETANSWER="#define SERV_R_SETANSWER 1"
+SERV_R_RETURN="#define SERV_R_RETURN int"
+]
+,
+AC_TRY_COMPILE([
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int
+getservent_r (struct servent *, struct servent_data *serv_data);
+],[return (0);],
+[
+SERV_R_ARGS="#define SERV_R_ARGS struct servent_data *serv_data"
+SERV_R_BAD="#define SERV_R_BAD (-1)"
+SERV_R_COPY="#define SERV_R_COPY serv_data"
+SERV_R_COPY_ARGS="#define SERV_R_COPY_ARGS struct servent_data *sdptr"
+SERV_R_OK="#define SERV_R_OK (0)"
+SERV_R_SETANSWER="#undef SERV_R_SETANSWER"
+SERV_R_RETURN="#define SERV_R_RETURN int"
+SERVENT_DATA="#define SERVENT_DATA 1"
+]
+,
+)
+)
+)
+,
+SERV_R_ARGS="#define SERV_R_ARGS char *buf, int buflen"
+SERV_R_BAD="#define SERV_R_BAD NULL"
+SERV_R_COPY="#define SERV_R_COPY buf, buflen"
+SERV_R_COPY_ARGS="#define SERV_R_COPY_ARGS SERV_R_ARGS"
+SERV_R_OK="#define SERV_R_OK sptr"
+SERV_R_SETANSWER="#undef SERV_R_SETANSWER"
+SERV_R_RETURN="#define SERV_R_RETURN struct servent *"
+)
+esac
+AC_SUBST(SERV_R_ARGS)
+AC_SUBST(SERV_R_BAD)
+AC_SUBST(SERV_R_COPY)
+AC_SUBST(SERV_R_COPY_ARGS)
+AC_SUBST(SERV_R_OK)
+AC_SUBST(SERV_R_SETANSWER)
+AC_SUBST(SERV_R_RETURN)
+AC_SUBST(SERVENT_DATA)
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(endservent_r,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endservent_r(void);
+]
+,
+,
+[
+SERV_R_END_RESULT="#define SERV_R_END_RESULT(x) /*empty*/"
+SERV_R_END_RETURN="#define SERV_R_END_RETURN void "
+SERV_R_ENT_ARGS="#undef SERV_R_ENT_ARGS /*empty*/"
+SERV_R_ENT_UNUSED="#undef SERV_R_ENT_UNUSED /*empty*/"
+]
+,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void endservent_r(struct servent_data *serv_data);
+]
+,
+,
+[
+SERV_R_END_RESULT="#define SERV_R_END_RESULT(x) /*empty*/"
+SERV_R_END_RETURN="#define SERV_R_END_RETURN void "
+SERV_R_ENT_ARGS="#define SERV_R_ENT_ARGS struct servent_data *serv_data"
+SERV_R_ENT_UNUSED="#define SERV_R_ENT_UNUSED UNUSED(serv_data)"
+]
+,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int endservent_r(struct servent_data *serv_data);
+]
+,
+,
+[
+SERV_R_END_RESULT="#define SERV_R_END_RESULT(x) return(x)"
+SERV_R_END_RETURN="#define SERV_R_END_RETURN int "
+SERV_R_ENT_ARGS="#define SERV_R_ENT_ARGS struct servent_data *serv_data"
+SERV_R_ENT_UNUSED="#define SERV_R_ENT_UNUSED UNUSED(serv_data)"
+]
+,
+)
+)
+)
+,
+SERV_R_END_RESULT="#define SERV_R_END_RESULT(x) /*empty*/"
+SERV_R_END_RETURN="#define SERV_R_END_RETURN void "
+SERV_R_ENT_ARGS="#undef SERV_R_ENT_ARGS /*empty*/"
+SERV_R_ENT_UNUSED="#undef SERV_R_ENT_UNUSED /*empty*/"
+)
+esac
+AC_SUBST(SERV_R_END_RESULT)
+AC_SUBST(SERV_R_END_RETURN)
+AC_SUBST(SERV_R_ENT_ARGS)
+AC_SUBST(SERV_R_ENT_UNUSED)
+
+case $host in
+ia64-hp-hpux11.*)
+;;
+*)
+AC_CHECK_FUNC(setservent_r,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+void setservent_r(int);
+]
+,,
+[
+SERV_R_SET_RESULT="#undef SERV_R_SET_RESULT"
+SERV_R_SET_RETURN="#define SERV_R_SET_RETURN void"
+]
+,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <netdb.h>
+int setservent_r(int, struct servent_data *);
+]
+,,
+[
+SERV_R_SET_RESULT="#define SERV_R_SET_RESULT (0)"
+SERV_R_SET_RETURN="#define SERV_R_SET_RETURN int"
+]
+,
+)
+)
+,
+SERV_R_SET_RESULT="#undef SERV_R_SET_RESULT"
+SERV_R_SET_RETURN="#define SERV_R_SET_RETURN void"
+)
+esac
+AC_SUBST(SERV_R_SET_RESULT)
+AC_SUBST(SERV_R_SET_RETURN)
+
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <unistd.h>
+#include <netdb.h>
+int innetgr(const char *netgroup, const char *host, const char *user, const char *domain);
+]
+,,
+[
+INNETGR_ARGS="#undef INNETGR_ARGS"
+]
+,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <unistd.h>
+#include <netdb.h>
+int innetgr(char *netgroup, char *host, char *user, char *domain);
+]
+,,
+[
+INNETGR_ARGS="#define INNETGR_ARGS char *netgroup, char *host, char *user, char *domain"
+]
+,
+))
+
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <unistd.h>
+#include <netdb.h>
+void setnetgrent(const char *);
+]
+,,
+[
+SETNETGRENT_ARGS="#undef SETNETGRENT_ARGS"
+]
+,
+AC_TRY_COMPILE(
+[
+#undef _REENTRANT
+#define _REENTRANT
+#undef __USE_MISC
+#define __USE_MISC
+#include <unistd.h>
+#include <netdb.h>
+void setnetgrent(char *);
+]
+,,
+[
+SETNETGRENT_ARGS="#define SETNETGRENT_ARGS char *netgroup"
+]
+,
+))
+AC_SUBST(SETNETGRENT_ARGS)
+AC_SUBST(INNETGR_ARGS)
+
+#
+# Random remaining OS-specific issues involving compiler warnings.
+# XXXDCL print messages to indicate some compensation is being done?
+#
+BROKEN_IN6ADDR_INIT_MACROS="#undef BROKEN_IN6ADDR_INIT_MACROS"
+
+case "$host" in
+ *-aix5.1.*)
+ hack_shutup_pthreadmutexinit=yes
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-aix5.[[23]].*)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-bsdi3.1*)
+ hack_shutup_sputaux=yes
+ ;;
+ *-bsdi4.0*)
+ hack_shutup_sigwait=yes
+ hack_shutup_sputaux=yes
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-bsdi4.1*)
+ hack_shutup_stdargcast=yes
+ ;;
+ *-hpux11.11)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-osf5.1|*-osf5.1b)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-solaris2.8)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-solaris2.9)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+ *-solaris2.10)
+ hack_shutup_in6addr_init_macros=yes
+ ;;
+esac
+
+case "$hack_shutup_pthreadmutexinit" in
+ yes)
+ #
+ # Shut up PTHREAD_MUTEX_INITIALIZER unbraced
+ # initializer warnings.
+ #
+ AC_DEFINE(SHUTUP_MUTEX_INITIALIZER)
+ ;;
+esac
+
+case "$hack_shutup_sigwait" in
+ yes)
+ #
+ # Shut up a -Wmissing-prototypes warning for sigwait().
+ #
+ AC_DEFINE(SHUTUP_SIGWAIT)
+ ;;
+esac
+
+case "$hack_shutup_sputaux" in
+ yes)
+ #
+ # Shut up a -Wmissing-prototypes warning from <stdio.h>.
+ #
+ AC_DEFINE(SHUTUP_SPUTAUX)
+ ;;
+esac
+
+case "$hack_shutup_stdargcast" in
+ yes)
+ #
+ # Shut up a -Wcast-qual warning from va_start().
+ #
+ AC_DEFINE(SHUTUP_STDARG_CAST)
+ ;;
+esac
+
+case "$hack_shutup_in6addr_init_macros" in
+ yes)
+ AC_DEFINE(BROKEN_IN6ADDR_INIT_MACROS, 1, [Defined if IN6ADDR_ANY_INIT and IN6ADDR_LOOPBACK_INIT need to be redefined.] )
+ ;;
+esac
+
+#
+# Substitutions
+#
+AC_SUBST(BIND9_TOP_BUILDDIR)
+BIND9_TOP_BUILDDIR=`pwd`
+
+AC_SUBST_FILE(BIND9_INCLUDES)
+BIND9_INCLUDES=$BIND9_TOP_BUILDDIR/make/includes
+
+AC_SUBST_FILE(BIND9_MAKE_RULES)
+BIND9_MAKE_RULES=$BIND9_TOP_BUILDDIR/make/rules
+
+. $srcdir/../../version
+BIND9_VERSION="VERSION=${MAJORVER}.${MINORVER}.${PATCHVER}${RELEASETYPE}${RELEASEVER}"
+AC_SUBST(BIND9_VERSION)
+
+AC_SUBST_FILE(LIBBIND_API)
+LIBBIND_API=$srcdir/api
+
+AC_OUTPUT(
+ make/rules
+ make/mkdep
+ make/includes
+ Makefile
+ bsd/Makefile
+ dst/Makefile
+ include/Makefile
+ inet/Makefile
+ irs/Makefile
+ isc/Makefile
+ nameser/Makefile
+ port_after.h
+ port_before.h
+ resolv/Makefile
+ port/Makefile
+ ${PORT_DIR}/Makefile
+ ${PORT_INCLUDE}/Makefile
+)
+
+# Tell Emacs to edit this file in shell mode.
+# Local Variables:
+# mode: sh
+# End:
diff --git a/lib/bind/dst/Makefile.in b/lib/bind/dst/Makefile.in
new file mode 100644
index 0000000..c802840
--- /dev/null
+++ b/lib/bind/dst/Makefile.in
@@ -0,0 +1,32 @@
+# 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: Makefile.in,v 1.6 2004/03/05 05:05:09 marka Exp $
+
+srcdir= @srcdir@
+VPATH = @srcdir@
+
+OBJS= dst_api.@O@ hmac_link.@O@ md5_dgst.@O@ support.@O@
+
+SRCS= dst_api.c hmac_link.c md5_dgst.c support.c
+
+TARGETS= ${OBJS}
+
+CRYPTFLAGS= -DCYLINK_DSS -DHMAC_MD5 -DUSE_MD5 -DDNSSAFE
+
+CINCLUDES= -I.. -I${srcdir}/../include ${CRYPTINCL}
+CDEFINES= ${CRYPTFLAGS}
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/dst/dst_api.c b/lib/bind/dst/dst_api.c
new file mode 100644
index 0000000..a622ae3
--- /dev/null
+++ b/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.10.332.7 2007/09/26 04:41:47 each Exp $";
+#endif
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+/*
+ * This file contains the interface between the DST API and the crypto API.
+ * This is the only file that needs to be changed if the crypto system is
+ * changed. Exported functions are:
+ * void dst_init() Initialize the toolkit
+ * int dst_check_algorithm() Function to determines if alg is suppored.
+ * int dst_compare_keys() Function to compare two keys for equality.
+ * int dst_sign_data() Incremental signing routine.
+ * int dst_verify_data() Incremental verify routine.
+ * int dst_generate_key() Function to generate new KEY
+ * DST_KEY *dst_read_key() Function to retrieve private/public KEY.
+ * void dst_write_key() Function to write out a key.
+ * DST_KEY *dst_dnskey_to_key() Function to convert DNS KEY RR to a DST
+ * KEY structure.
+ * int dst_key_to_dnskey() Function to return a public key in DNS
+ * format binary
+ * DST_KEY *dst_buffer_to_key() Converst a data in buffer to KEY
+ * int *dst_key_to_buffer() Writes out DST_KEY key matterial in buffer
+ * void dst_free_key() Releases all memory referenced by key structure
+ */
+
+#include "port_before.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <memory.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dst_internal.h"
+#include "port_after.h"
+
+/* static variables */
+static int done_init = 0;
+dst_func *dst_t_func[DST_MAX_ALGS];
+const char *key_file_fmt_str = "Private-key-format: v%s\nAlgorithm: %d (%s)\n";
+const char *dst_path = "";
+
+/* internal I/O functions */
+static DST_KEY *dst_s_read_public_key(const char *in_name,
+ const u_int16_t in_id, int in_alg);
+static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key,
+ u_int16_t in_id, int in_alg);
+static int dst_s_write_public_key(const DST_KEY *key);
+static int dst_s_write_private_key(const DST_KEY *key);
+
+/* internal function to set up data structure */
+static DST_KEY *dst_s_get_key_struct(const char *name, const int alg,
+ const int flags, const int protocol,
+ const int bits);
+
+/*%
+ * dst_init
+ * This function initializes the Digital Signature Toolkit.
+ * Right now, it just checks the DSTKEYPATH environment variable.
+ * Parameters
+ * none
+ * Returns
+ * none
+ */
+void
+dst_init()
+{
+ char *s;
+ int len;
+
+ if (done_init != 0)
+ return;
+ done_init = 1;
+
+ s = getenv("DSTKEYPATH");
+ len = 0;
+ if (s) {
+ struct stat statbuf;
+
+ len = strlen(s);
+ if (len > PATH_MAX) {
+ EREPORT(("%s is longer than %d characters, ignoring\n",
+ s, PATH_MAX));
+ } else if (stat(s, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
+ EREPORT(("%s is not a valid directory\n", s));
+ } else {
+ char *tmp;
+ tmp = (char *) malloc(len + 2);
+ memcpy(tmp, s, len + 1);
+ if (tmp[strlen(tmp) - 1] != '/') {
+ tmp[strlen(tmp) + 1] = 0;
+ tmp[strlen(tmp)] = '/';
+ }
+ dst_path = tmp;
+ }
+ }
+ memset(dst_t_func, 0, sizeof(dst_t_func));
+ /* first one is selected */
+ dst_hmac_md5_init();
+}
+
+/*%
+ * dst_check_algorithm
+ * This function determines if the crypto system for the specified
+ * algorithm is present.
+ * Parameters
+ * alg 1 KEY_RSA
+ * 3 KEY_DSA
+ * 157 KEY_HMAC_MD5
+ * future algorithms TBD and registered with IANA.
+ * Returns
+ * 1 - The algorithm is available.
+ * 0 - The algorithm is not available.
+ */
+int
+dst_check_algorithm(const int alg)
+{
+ return (dst_t_func[alg] != NULL);
+}
+
+/*%
+ * dst_s_get_key_struct
+ * This function allocates key structure and fills in some of the
+ * fields of the structure.
+ * Parameters:
+ * name: the name of the key
+ * alg: the algorithm number
+ * flags: the dns flags of the key
+ * protocol: the dns protocol of the key
+ * bits: the size of the key
+ * Returns:
+ * NULL if error
+ * valid pointer otherwise
+ */
+static DST_KEY *
+dst_s_get_key_struct(const char *name, const int alg, const int flags,
+ const int protocol, const int bits)
+{
+ DST_KEY *new_key = NULL;
+
+ if (dst_check_algorithm(alg)) /*%< make sure alg is available */
+ new_key = (DST_KEY *) malloc(sizeof(*new_key));
+ if (new_key == NULL)
+ return (NULL);
+
+ memset(new_key, 0, sizeof(*new_key));
+ new_key->dk_key_name = strdup(name);
+ if (new_key->dk_key_name == NULL) {
+ free(new_key);
+ return (NULL);
+ }
+ new_key->dk_alg = alg;
+ new_key->dk_flags = flags;
+ new_key->dk_proto = protocol;
+ new_key->dk_KEY_struct = NULL;
+ new_key->dk_key_size = bits;
+ new_key->dk_func = dst_t_func[alg];
+ return (new_key);
+}
+
+/*%
+ * dst_compare_keys
+ * Compares two keys for equality.
+ * Parameters
+ * key1, key2 Two keys to be compared.
+ * Returns
+ * 0 The keys are equal.
+ * non-zero The keys are not equal.
+ */
+
+int
+dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+ if (key1 == key2)
+ return (0);
+ if (key1 == NULL || key2 == NULL)
+ return (4);
+ if (key1->dk_alg != key2->dk_alg)
+ return (1);
+ if (key1->dk_key_size != key2->dk_key_size)
+ return (2);
+ if (key1->dk_id != key2->dk_id)
+ return (3);
+ return (key1->dk_func->compare(key1, key2));
+}
+
+/*%
+ * dst_sign_data
+ * An incremental signing function. Data is signed in steps.
+ * First the context must be initialized (SIG_MODE_INIT).
+ * Then data is hashed (SIG_MODE_UPDATE). Finally the signature
+ * itself is created (SIG_MODE_FINAL). This function can be called
+ * once with INIT, UPDATE and FINAL modes all set, or it can be
+ * called separately with a different mode set for each step. The
+ * UPDATE step can be repeated.
+ * Parameters
+ * mode A bit mask used to specify operation(s) to be performed.
+ * SIG_MODE_INIT 1 Initialize digest
+ * SIG_MODE_UPDATE 2 Add data to digest
+ * SIG_MODE_FINAL 4 Generate signature
+ * from signature
+ * SIG_MODE_ALL (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL
+ * data Data to be signed.
+ * len The length in bytes of data to be signed.
+ * in_key Contains a private key to sign with.
+ * KEY structures should be handled (created, converted,
+ * compared, stored, freed) by the DST.
+ * signature
+ * The location to which the signature will be written.
+ * sig_len Length of the signature field in bytes.
+ * Return
+ * 0 Successfull INIT or Update operation
+ * &gt;0 success FINAL (sign) operation
+ * &lt;0 failure
+ */
+
+int
+dst_sign_data(const int mode, DST_KEY *in_key, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ DUMP(data, mode, len, "dst_sign_data()");
+
+ if (mode & SIG_MODE_FINAL &&
+ (in_key->dk_KEY_struct == NULL || signature == NULL))
+ return (MISSING_KEY_OR_SIGNATURE);
+
+ if (in_key->dk_func && in_key->dk_func->sign)
+ return (in_key->dk_func->sign(mode, in_key, context, data, len,
+ signature, sig_len));
+ return (UNKNOWN_KEYALG);
+}
+
+/*%
+ * dst_verify_data
+ * An incremental verify function. Data is verified in steps.
+ * First the context must be initialized (SIG_MODE_INIT).
+ * Then data is hashed (SIG_MODE_UPDATE). Finally the signature
+ * is verified (SIG_MODE_FINAL). This function can be called
+ * once with INIT, UPDATE and FINAL modes all set, or it can be
+ * called separately with a different mode set for each step. The
+ * UPDATE step can be repeated.
+ * Parameters
+ * mode Operations to perform this time.
+ * SIG_MODE_INIT 1 Initialize digest
+ * SIG_MODE_UPDATE 2 add data to digest
+ * SIG_MODE_FINAL 4 verify signature
+ * SIG_MODE_ALL
+ * (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL)
+ * data Data to pass through the hash function.
+ * len Length of the data in bytes.
+ * in_key Key for verification.
+ * signature Location of signature.
+ * sig_len Length of the signature in bytes.
+ * Returns
+ * 0 Verify success
+ * Non-Zero Verify Failure
+ */
+
+int
+dst_verify_data(const int mode, DST_KEY *in_key, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ DUMP(data, mode, len, "dst_verify_data()");
+ if (mode & SIG_MODE_FINAL &&
+ (in_key->dk_KEY_struct == NULL || signature == NULL))
+ return (MISSING_KEY_OR_SIGNATURE);
+
+ if (in_key->dk_func == NULL || in_key->dk_func->verify == NULL)
+ return (UNSUPPORTED_KEYALG);
+ return (in_key->dk_func->verify(mode, in_key, context, data, len,
+ signature, sig_len));
+}
+
+/*%
+ * dst_read_private_key
+ * Access a private key. First the list of private keys that have
+ * already been read in is searched, then the key accessed on disk.
+ * If the private key can be found, it is returned. If the key cannot
+ * be found, a null pointer is returned. The options specify required
+ * key characteristics. If the private key requested does not have
+ * these characteristics, it will not be read.
+ * Parameters
+ * in_keyname The private key name.
+ * in_id The id of the private key.
+ * options DST_FORCE_READ Read from disk - don't use a previously
+ * read key.
+ * DST_CAN_SIGN The key must be useable for signing.
+ * DST_NO_AUTHEN The key must be useable for authentication.
+ * DST_STANDARD Return any key
+ * Returns
+ * NULL If there is no key found in the current directory or
+ * this key has not been loaded before.
+ * !NULL Success - KEY structure returned.
+ */
+
+DST_KEY *
+dst_read_key(const char *in_keyname, const u_int16_t in_id,
+ const int in_alg, const int type)
+{
+ char keyname[PATH_MAX];
+ DST_KEY *dg_key = NULL, *pubkey = NULL;
+
+ if (!dst_check_algorithm(in_alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_read_private_key(): Algorithm %d not suppored\n",
+ in_alg));
+ return (NULL);
+ }
+ if ((type & (DST_PUBLIC | DST_PRIVATE)) == 0)
+ return (NULL);
+ if (in_keyname == NULL) {
+ EREPORT(("dst_read_private_key(): Null key name passed in\n"));
+ return (NULL);
+ } else if (strlen(in_keyname) >= sizeof(keyname)) {
+ EREPORT(("dst_read_private_key(): keyname too big\n"));
+ return (NULL);
+ } else
+ strcpy(keyname, in_keyname);
+
+ /* before I read in the public key, check if it is allowed to sign */
+ if ((pubkey = dst_s_read_public_key(keyname, in_id, in_alg)) == NULL)
+ return (NULL);
+
+ if (type == DST_PUBLIC)
+ return pubkey;
+
+ if (!(dg_key = dst_s_get_key_struct(keyname, pubkey->dk_alg,
+ pubkey->dk_flags, pubkey->dk_proto,
+ 0)))
+ return (dg_key);
+ /* Fill in private key and some fields in the general key structure */
+ if (dst_s_read_private_key_file(keyname, dg_key, pubkey->dk_id,
+ pubkey->dk_alg) == 0)
+ dg_key = dst_free_key(dg_key);
+
+ (void)dst_free_key(pubkey);
+ return (dg_key);
+}
+
+int
+dst_write_key(const DST_KEY *key, const int type)
+{
+ int pub = 0, priv = 0;
+
+ if (key == NULL)
+ return (0);
+ if (!dst_check_algorithm(key->dk_alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_write_key(): Algorithm %d not suppored\n",
+ key->dk_alg));
+ return (UNSUPPORTED_KEYALG);
+ }
+ if ((type & (DST_PRIVATE|DST_PUBLIC)) == 0)
+ return (0);
+
+ if (type & DST_PUBLIC)
+ if ((pub = dst_s_write_public_key(key)) < 0)
+ return (pub);
+ if (type & DST_PRIVATE)
+ if ((priv = dst_s_write_private_key(key)) < 0)
+ return (priv);
+ return (priv+pub);
+}
+
+/*%
+ * dst_write_private_key
+ * Write a private key to disk. The filename will be of the form:
+ * K&lt;key-&gt;dk_name&gt;+&lt;key-&gt;dk_alg+&gt;&lt;key-d&gt;k_id.&gt;&lt;private key suffix&gt;.
+ * 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
+ * &gt;= 0 Correct behavior. Returns length of encoded key value
+ * written to disk.
+ * &lt; 0 error.
+ */
+
+static int
+dst_s_write_private_key(const DST_KEY *key)
+{
+ u_char encoded_block[RAW_KEY_SIZE];
+ char file[PATH_MAX];
+ int len;
+ FILE *fp;
+
+ /* First encode the key into the portable key format */
+ if (key == NULL)
+ return (-1);
+ if (key->dk_KEY_struct == NULL)
+ return (0); /*%< null key has no private key */
+ if (key->dk_func == NULL || key->dk_func->to_file_fmt == NULL) {
+ EREPORT(("dst_write_private_key(): Unsupported operation %d\n",
+ key->dk_alg));
+ return (-5);
+ } else if ((len = key->dk_func->to_file_fmt(key, (char *)encoded_block,
+ sizeof(encoded_block))) <= 0) {
+ EREPORT(("dst_write_private_key(): Failed encoding private RSA bsafe key %d\n", len));
+ return (-8);
+ }
+ /* Now I can create the file I want to use */
+ dst_s_build_filename(file, key->dk_key_name, key->dk_id, key->dk_alg,
+ PRIVATE_KEY, PATH_MAX);
+
+ /* Do not overwrite an existing file */
+ if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) {
+ int nn;
+ if ((nn = fwrite(encoded_block, 1, len, fp)) != len) {
+ EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n",
+ file, len, nn, errno));
+ fclose(fp);
+ return (-5);
+ }
+ fclose(fp);
+ } else {
+ EREPORT(("dst_write_private_key(): Can not create file %s\n"
+ ,file));
+ return (-6);
+ }
+ memset(encoded_block, 0, len);
+ return (len);
+}
+
+/*%
+*
+ * dst_read_public_key
+ * Read a public key from disk and store in a DST key structure.
+ * Parameters
+ * in_name K&lt;in_name&gt;&lt;in_id&gt;.&lt;public key suffix&gt; 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 &lt;flags&gt; &lt;protocol&gt; &lt;algorithm&gt; &lt;key&gt;
+ * flags, proto, alg stored as decimal (or hex numbers FIXME).
+ * (FIXME: handle parentheses for line continuation.)
+ */
+ if ((fp = dst_s_fopen(name, "r", 0)) == NULL) {
+ EREPORT(("dst_read_public_key(): Public Key not found %s\n",
+ name));
+ return (NULL);
+ }
+ /* Skip domain name, which ends at first blank */
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ /* Skip blank to get to next field */
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+
+ /* Skip optional TTL -- if initial digit, skip whole word. */
+ if (isdigit(c)) {
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ }
+ /* Skip optional "IN" */
+ if (c == 'I' || c == 'i') {
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ }
+ /* Locate and skip "KEY" */
+ if (c != 'K' && c != 'k') {
+ EREPORT(("\"KEY\" doesn't appear in file: %s", name));
+ return NULL;
+ }
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ ungetc(c, fp); /*%< return the charcter to the input field */
+ /* Handle hex!! FIXME. */
+
+ if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) {
+ EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n"
+ ,name));
+ return (NULL);
+ }
+ /* read in the key string */
+ fgets(enckey, sizeof(enckey), fp);
+
+ /* If we aren't at end-of-file, something is wrong. */
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ if (!feof(fp)) {
+ EREPORT(("Key too long in file: %s", name));
+ return NULL;
+ }
+ fclose(fp);
+
+ if ((len = strlen(enckey)) <= 0)
+ return (NULL);
+
+ /* discard \n */
+ enckey[--len] = '\0';
+
+ /* remove leading spaces */
+ for (notspace = (char *) enckey; isspace((*notspace)&0xff); len--)
+ notspace++;
+
+ dlen = b64_pton(notspace, deckey, sizeof(deckey));
+ if (dlen < 0) {
+ EREPORT(("dst_read_public_key: bad return from b64_pton = %d",
+ dlen));
+ return (NULL);
+ }
+ /* store key and info in a key structure that is returned */
+/* return dst_store_public_key(in_name, alg, proto, 666, flags, deckey,
+ dlen);*/
+ return dst_buffer_to_key(in_name, alg, flags, proto, deckey, dlen);
+}
+
+/*%
+ * dst_write_public_key
+ * Write a key to disk in DNS format.
+ * Parameters
+ * key Pointer to a DST key structure.
+ * Returns
+ * 0 Failure
+ * 1 Success
+ */
+
+static int
+dst_s_write_public_key(const DST_KEY *key)
+{
+ FILE *fp;
+ char filename[PATH_MAX];
+ u_char out_key[RAW_KEY_SIZE];
+ char enc_key[RAW_KEY_SIZE];
+ int len = 0;
+ int mode;
+
+ memset(out_key, 0, sizeof(out_key));
+ if (key == NULL) {
+ EREPORT(("dst_write_public_key(): No key specified \n"));
+ return (0);
+ } else if ((len = dst_key_to_dnskey(key, out_key, sizeof(out_key)))< 0)
+ return (0);
+
+ /* Make the filename */
+ if (dst_s_build_filename(filename, key->dk_key_name, key->dk_id,
+ key->dk_alg, PUBLIC_KEY, PATH_MAX) == -1) {
+ EREPORT(("dst_write_public_key(): Cannot make filename from %s, %d, and %s\n",
+ key->dk_key_name, key->dk_id, PUBLIC_KEY));
+ return (0);
+ }
+ /* XXX in general this should be a check for symmetric keys */
+ mode = (key->dk_alg == KEY_HMAC_MD5) ? 0600 : 0644;
+ /* create public key file */
+ if ((fp = dst_s_fopen(filename, "w+", mode)) == NULL) {
+ EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n",
+ filename, errno));
+ return (0);
+ }
+ /*write out key first base64 the key data */
+ if (key->dk_flags & DST_EXTEND_FLAG)
+ b64_ntop(&out_key[6], len - 6, enc_key, sizeof(enc_key));
+ else
+ b64_ntop(&out_key[4], len - 4, enc_key, sizeof(enc_key));
+ fprintf(fp, "%s IN KEY %d %d %d %s\n",
+ key->dk_key_name,
+ key->dk_flags, key->dk_proto, key->dk_alg, enc_key);
+ fclose(fp);
+ return (1);
+}
+
+/*%
+ * dst_dnskey_to_public_key
+ * This function converts the contents of a DNS KEY RR into a DST
+ * key structure.
+ * Paramters
+ * len Length of the RDATA of the KEY RR RDATA
+ * rdata A pointer to the the KEY RR RDATA.
+ * in_name Key name to be stored in key structure.
+ * Returns
+ * NULL Failure
+ * NON-NULL Success. Pointer to key structure.
+ * Caller's responsibility to free() it.
+ */
+
+DST_KEY *
+dst_dnskey_to_key(const char *in_name, const u_char *rdata, const int len)
+{
+ DST_KEY *key_st;
+ int alg ;
+ int start = DST_KEY_START;
+
+ if (rdata == NULL || len <= DST_KEY_ALG) /*%< no data */
+ return (NULL);
+ alg = (u_int8_t) rdata[DST_KEY_ALG];
+ if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_dnskey_to_key(): Algorithm %d not suppored\n",
+ alg));
+ return (NULL);
+ }
+
+ if (in_name == NULL)
+ return (NULL);
+
+ if ((key_st = dst_s_get_key_struct(in_name, alg, 0, 0, 0)) == NULL)
+ return (NULL);
+
+ key_st->dk_id = dst_s_dns_key_id(rdata, len);
+ key_st->dk_flags = dst_s_get_int16(rdata);
+ key_st->dk_proto = (u_int16_t) rdata[DST_KEY_PROT];
+ if (key_st->dk_flags & DST_EXTEND_FLAG) {
+ u_int32_t ext_flags;
+ ext_flags = (u_int32_t) dst_s_get_int16(&rdata[DST_EXT_FLAG]);
+ key_st->dk_flags = key_st->dk_flags | (ext_flags << 16);
+ start += 2;
+ }
+ /*
+ * now point to the begining of the data representing the encoding
+ * of the key
+ */
+ if (key_st->dk_func && key_st->dk_func->from_dns_key) {
+ if (key_st->dk_func->from_dns_key(key_st, &rdata[start],
+ len - start) > 0)
+ return (key_st);
+ } else
+ EREPORT(("dst_dnskey_to_public_key(): unsuppored alg %d\n",
+ alg));
+
+ SAFE_FREE(key_st);
+ return (key_st);
+}
+
+/*%
+ * dst_public_key_to_dnskey
+ * Function to encode a public key into DNS KEY wire format
+ * Parameters
+ * key Key structure to encode.
+ * out_storage Location to write the encoded key to.
+ * out_len Size of the output array.
+ * Returns
+ * <0 Failure
+ * >=0 Number of bytes written to out_storage
+ */
+
+int
+dst_key_to_dnskey(const DST_KEY *key, u_char *out_storage,
+ const int out_len)
+{
+ u_int16_t val;
+ int loc = 0;
+ int enc_len = 0;
+ if (key == NULL)
+ return (-1);
+
+ if (!dst_check_algorithm(key->dk_alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_key_to_dnskey(): Algorithm %d not suppored\n",
+ key->dk_alg));
+ return (UNSUPPORTED_KEYALG);
+ }
+ memset(out_storage, 0, out_len);
+ val = (u_int16_t)(key->dk_flags & 0xffff);
+ dst_s_put_int16(out_storage, val);
+ loc += 2;
+
+ out_storage[loc++] = (u_char) key->dk_proto;
+ out_storage[loc++] = (u_char) key->dk_alg;
+
+ if (key->dk_flags > 0xffff) { /*%< Extended flags */
+ val = (u_int16_t)((key->dk_flags >> 16) & 0xffff);
+ dst_s_put_int16(&out_storage[loc], val);
+ loc += 2;
+ }
+ if (key->dk_KEY_struct == NULL)
+ return (loc);
+ if (key->dk_func && key->dk_func->to_dns_key) {
+ enc_len = key->dk_func->to_dns_key(key,
+ (u_char *) &out_storage[loc],
+ out_len - loc);
+ if (enc_len > 0)
+ return (enc_len + loc);
+ else
+ return (-1);
+ } else
+ EREPORT(("dst_key_to_dnskey(): Unsupported ALG %d\n",
+ key->dk_alg));
+ return (-1);
+}
+
+/*%
+ * dst_buffer_to_key
+ * Function to encode a string of raw data into a DST key
+ * Parameters
+ * alg The algorithm (HMAC only)
+ * key A pointer to the data
+ * keylen The length of the data
+ * Returns
+ * NULL an error occurred
+ * NON-NULL the DST key
+ */
+DST_KEY *
+dst_buffer_to_key(const char *key_name, /*!< name of the key */
+ const int alg, /*!< algorithm */
+ const int flags, /*!< dns flags */
+ const int protocol, /*!< dns protocol */
+ const u_char *key_buf, /*!< key in dns wire fmt */
+ const int key_len) /*!< size of key */
+{
+
+ DST_KEY *dkey = NULL;
+ int dnslen;
+ u_char dns[2048];
+
+ if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_buffer_to_key(): Algorithm %d not suppored\n", alg));
+ return (NULL);
+ }
+
+ dkey = dst_s_get_key_struct(key_name, alg, flags, protocol, -1);
+
+ if (dkey == NULL || dkey->dk_func == NULL ||
+ dkey->dk_func->from_dns_key == NULL)
+ return (dst_free_key(dkey));
+
+ if (dkey->dk_func->from_dns_key(dkey, key_buf, key_len) < 0) {
+ EREPORT(("dst_buffer_to_key(): dst_buffer_to_hmac failed\n"));
+ return (dst_free_key(dkey));
+ }
+
+ dnslen = dst_key_to_dnskey(dkey, dns, sizeof(dns));
+ dkey->dk_id = dst_s_dns_key_id(dns, dnslen);
+ return (dkey);
+}
+
+int
+dst_key_to_buffer(DST_KEY *key, u_char *out_buff, int buf_len)
+{
+ int len;
+ /* this function will extrac the secret of HMAC into a buffer */
+ if (key == NULL)
+ return (0);
+ if (key->dk_func != NULL && key->dk_func->to_dns_key != NULL) {
+ len = key->dk_func->to_dns_key(key, out_buff, buf_len);
+ if (len < 0)
+ return (0);
+ return (len);
+ }
+ return (0);
+}
+
+/*%
+ * dst_s_read_private_key_file
+ * Function reads in private key from a file.
+ * Fills out the KEY structure.
+ * Parameters
+ * name Name of the key to be read.
+ * pk_key Structure that the key is returned in.
+ * in_id Key identifier (tag)
+ * Return
+ * 1 if everthing works
+ * 0 if there is any problem
+ */
+
+static int
+dst_s_read_private_key_file(char *name, DST_KEY *pk_key, u_int16_t in_id,
+ int in_alg)
+{
+ int cnt, alg, len, major, minor, file_major, file_minor;
+ int ret, id;
+ char filename[PATH_MAX];
+ u_char in_buff[RAW_KEY_SIZE], *p;
+ FILE *fp;
+ int dnslen;
+ u_char dns[2048];
+
+ if (name == NULL || pk_key == NULL) {
+ EREPORT(("dst_read_private_key_file(): No key name given\n"));
+ return (0);
+ }
+ /* Make the filename */
+ if (dst_s_build_filename(filename, name, in_id, in_alg, PRIVATE_KEY,
+ PATH_MAX) == -1) {
+ EREPORT(("dst_read_private_key(): Cannot make filename from %s, %d, and %s\n",
+ name, in_id, PRIVATE_KEY));
+ return (0);
+ }
+ /* first check if we can find the key file */
+ if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) {
+ EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n",
+ filename, dst_path[0] ? dst_path :
+ (char *) getcwd(NULL, PATH_MAX - 1)));
+ return (0);
+ }
+ /* now read the header info from the file */
+ if ((cnt = fread(in_buff, 1, sizeof(in_buff), fp)) < 5) {
+ fclose(fp);
+ EREPORT(("dst_s_read_private_key_file: error reading file %s (empty file)\n",
+ filename));
+ return (0);
+ }
+ /* decrypt key */
+ fclose(fp);
+ if (memcmp(in_buff, "Private-key-format: v", 20) != 0)
+ goto fail;
+ len = cnt;
+ p = in_buff;
+
+ if (!dst_s_verify_str((const char **) (void *)&p,
+ "Private-key-format: v")) {
+ EREPORT(("dst_s_read_private_key_file(): Not a Key file/Decrypt failed %s\n", name));
+ goto fail;
+ }
+ /* read in file format */
+ sscanf((char *)p, "%d.%d", &file_major, &file_minor);
+ sscanf(KEY_FILE_FORMAT, "%d.%d", &major, &minor);
+ if (file_major < 1) {
+ EREPORT(("dst_s_read_private_key_file(): Unknown keyfile %d.%d version for %s\n",
+ file_major, file_minor, name));
+ goto fail;
+ } else if (file_major > major || file_minor > minor)
+ EREPORT((
+ "dst_s_read_private_key_file(): Keyfile %s version higher than mine %d.%d MAY FAIL\n",
+ name, file_major, file_minor));
+
+ while (*p++ != '\n') ; /*%< skip to end of line */
+
+ if (!dst_s_verify_str((const char **) (void *)&p, "Algorithm: "))
+ goto fail;
+
+ if (sscanf((char *)p, "%d", &alg) != 1)
+ goto fail;
+ while (*p++ != '\n') ; /*%< skip to end of line */
+
+ if (pk_key->dk_key_name && !strcmp(pk_key->dk_key_name, name))
+ SAFE_FREE2(pk_key->dk_key_name, strlen(pk_key->dk_key_name));
+ pk_key->dk_key_name = (char *) strdup(name);
+
+ /* allocate and fill in key structure */
+ if (pk_key->dk_func == NULL || pk_key->dk_func->from_file_fmt == NULL)
+ goto fail;
+
+ ret = pk_key->dk_func->from_file_fmt(pk_key, (char *)p, &in_buff[len] - p);
+ if (ret < 0)
+ goto fail;
+
+ dnslen = dst_key_to_dnskey(pk_key, dns, sizeof(dns));
+ id = dst_s_dns_key_id(dns, dnslen);
+
+ /* Make sure the actual key tag matches the input tag used in the filename
+ */
+ if (id != in_id) {
+ EREPORT(("dst_s_read_private_key_file(): actual tag of key read %d != input tag used to build filename %d.\n", id, in_id));
+ goto fail;
+ }
+ pk_key->dk_id = (u_int16_t) id;
+ pk_key->dk_alg = alg;
+ memset(in_buff, 0, cnt);
+ return (1);
+
+ fail:
+ memset(in_buff, 0, cnt);
+ return (0);
+}
+
+/*%
+ * Generate and store a public/private keypair.
+ * Keys will be stored in formatted files.
+ *
+ * Parameters
+ &
+ *\par name Name of the new key. Used to create key files
+ *\li K&lt;name&gt;+&lt;alg&gt;+&lt;id&gt;.public and K&lt;name&gt;+&lt;alg&gt;+&lt;id&gt;.private.
+ *\par bits Size of the new key in bits.
+ *\par exp What exponent to use:
+ *\li 0 use exponent 3
+ *\li non-zero use Fermant4
+ *\par flags The default value of the DNS Key flags.
+ *\li The DNS Key RR Flag field is defined in RFC2065,
+ * section 3.3. The field has 16 bits.
+ *\par protocol
+ *\li Default value of the DNS Key protocol field.
+ *\li The DNS Key protocol field is defined in RFC2065,
+ * section 3.4. The field has 8 bits.
+ *\par alg What algorithm to use. Currently defined:
+ *\li KEY_RSA 1
+ *\li KEY_DSA 3
+ *\li KEY_HMAC 157
+ *\par out_id The key tag is returned.
+ *
+ * Return
+ *\li NULL Failure
+ *\li non-NULL the generated key pair
+ * Caller frees the result, and its dk_name pointer.
+ */
+DST_KEY *
+dst_generate_key(const char *name, const int bits, const int exp,
+ const int flags, const int protocol, const int alg)
+{
+ DST_KEY *new_key = NULL;
+ int dnslen;
+ u_char dns[2048];
+
+ if (name == NULL)
+ return (NULL);
+
+ if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_generate_key(): Algorithm %d not suppored\n", alg));
+ return (NULL);
+ }
+
+ new_key = dst_s_get_key_struct(name, alg, flags, protocol, bits);
+ if (new_key == NULL)
+ return (NULL);
+ if (bits == 0) /*%< null key we are done */
+ return (new_key);
+ if (new_key->dk_func == NULL || new_key->dk_func->generate == NULL) {
+ EREPORT(("dst_generate_key_pair():Unsupported algorithm %d\n",
+ alg));
+ return (dst_free_key(new_key));
+ }
+ if (new_key->dk_func->generate(new_key, exp) <= 0) {
+ EREPORT(("dst_generate_key_pair(): Key generation failure %s %d %d %d\n",
+ new_key->dk_key_name, new_key->dk_alg,
+ new_key->dk_key_size, exp));
+ return (dst_free_key(new_key));
+ }
+
+ dnslen = dst_key_to_dnskey(new_key, dns, sizeof(dns));
+ if (dnslen != UNSUPPORTED_KEYALG)
+ new_key->dk_id = dst_s_dns_key_id(dns, dnslen);
+ else
+ new_key->dk_id = 0;
+
+ return (new_key);
+}
+
+/*%
+ * Release all data structures pointed to by a key structure.
+ *
+ * Parameters
+ *\li f_key Key structure to be freed.
+ */
+
+DST_KEY *
+dst_free_key(DST_KEY *f_key)
+{
+
+ if (f_key == NULL)
+ return (f_key);
+ if (f_key->dk_func && f_key->dk_func->destroy)
+ f_key->dk_KEY_struct =
+ f_key->dk_func->destroy(f_key->dk_KEY_struct);
+ else {
+ EREPORT(("dst_free_key(): Unknown key alg %d\n",
+ f_key->dk_alg));
+ }
+ if (f_key->dk_KEY_struct) {
+ free(f_key->dk_KEY_struct);
+ f_key->dk_KEY_struct = NULL;
+ }
+ if (f_key->dk_key_name)
+ SAFE_FREE(f_key->dk_key_name);
+ SAFE_FREE(f_key);
+ return (NULL);
+}
+
+/*%
+ * Return the maximim size of signature from the key specified in bytes
+ *
+ * Parameters
+ *\li key
+ *
+ * Returns
+ * \li bytes
+ */
+int
+dst_sig_size(DST_KEY *key) {
+ switch (key->dk_alg) {
+ case KEY_HMAC_MD5:
+ return (16);
+ case KEY_HMAC_SHA1:
+ return (20);
+ case KEY_RSA:
+ return (key->dk_key_size + 7) / 8;
+ case KEY_DSA:
+ return (40);
+ default:
+ EREPORT(("dst_sig_size(): Unknown key alg %d\n", key->dk_alg));
+ return -1;
+ }
+}
+
+/*! \file */
diff --git a/lib/bind/dst/dst_internal.h b/lib/bind/dst/dst_internal.h
new file mode 100644
index 0000000..e9bc6fc
--- /dev/null
+++ b/lib/bind/dst/dst_internal.h
@@ -0,0 +1,155 @@
+#ifndef DST_INTERNAL_H
+#define DST_INTERNAL_H
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+#include <limits.h>
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#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 <isc/dst.h>
+/*
+ * define what crypto systems are supported for RSA,
+ * BSAFE is prefered over RSAREF; only one can be set at any time
+ */
+#if defined(BSAFE) && defined(RSAREF)
+# error "Cannot have both BSAFE and RSAREF defined"
+#endif
+
+/* Declare dst_lib specific constants */
+#define KEY_FILE_FORMAT "1.2"
+
+/* suffixes for key file names */
+#define PRIVATE_KEY "private"
+#define PUBLIC_KEY "key"
+
+/* error handling */
+#ifdef REPORT_ERRORS
+#define EREPORT(str) printf str
+#else
+#define EREPORT(str) (void)0
+#endif
+
+/* use our own special macro to FRRE memory */
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(a) \
+do{if(a != NULL){memset(a,0, sizeof(*a)); free(a); a=NULL;}} while (0)
+#define SAFE_FREE2(a,s) if (a != NULL && (long)s > 0){memset(a,0, s);free(a); a=NULL;}
+#endif
+
+typedef struct dst_func {
+ int (*sign)(const int mode, DST_KEY *key, void **context,
+ const u_int8_t *data, const int len,
+ u_int8_t *signature, const int sig_len);
+ int (*verify)(const int mode, DST_KEY *key, void **context,
+ const u_int8_t *data, const int len,
+ const u_int8_t *signature, const int sig_len);
+ int (*compare)(const DST_KEY *key1, const DST_KEY *key2);
+ int (*generate)(DST_KEY *key, int parms);
+ void *(*destroy)(void *key);
+ /* conversion functions */
+ int (*to_dns_key)(const DST_KEY *key, u_int8_t *out,
+ const int out_len);
+ int (*from_dns_key)(DST_KEY *key, const u_int8_t *str,
+ const int str_len);
+ int (*to_file_fmt)(const DST_KEY *key, char *out,
+ const int out_len);
+ int (*from_file_fmt)(DST_KEY *key, const char *out,
+ const int out_len);
+
+} dst_func;
+
+extern dst_func *dst_t_func[DST_MAX_ALGS];
+extern const char *key_file_fmt_str;
+extern const char *dst_path;
+
+#ifndef DST_HASH_SIZE
+#define DST_HASH_SIZE 20 /*%< RIPEMD160 and SHA-1 are 20 bytes MD5 is 16 */
+#endif
+
+int dst_bsafe_init(void);
+
+int dst_rsaref_init(void);
+
+int dst_hmac_md5_init(void);
+
+int dst_cylink_init(void);
+
+int dst_eay_dss_init(void);
+
+/* from higher level support routines */
+int dst_s_calculate_bits( const u_int8_t *str, const int max_bits);
+int dst_s_verify_str( const char **buf, const char *str);
+
+
+/* conversion between dns names and key file names */
+size_t dst_s_filename_length( const char *name, const char *suffix);
+int dst_s_build_filename( char *filename, const char *name,
+ u_int16_t id, int alg, const char *suffix,
+ size_t filename_length);
+
+FILE *dst_s_fopen (const char *filename, const char *mode, int perm);
+
+/*%
+ * read and write network byte order into u_int?_t
+ * all of these should be retired
+ */
+u_int16_t dst_s_get_int16( const u_int8_t *buf);
+void dst_s_put_int16( u_int8_t *buf, const u_int16_t val);
+
+u_int32_t dst_s_get_int32( const u_int8_t *buf);
+void dst_s_put_int32( u_int8_t *buf, const u_int32_t val);
+
+#ifdef DUMP
+# undef DUMP
+# define DUMP(a,b,c,d) dst_s_dump(a,b,c,d)
+#else
+# define DUMP(a,b,c,d)
+#endif
+void
+dst_s_dump(const int mode, const u_char *data, const int size,
+ const char *msg);
+
+
+
+#endif /* DST_INTERNAL_H */
+/*! \file */
diff --git a/lib/bind/dst/hmac_link.c b/lib/bind/dst/hmac_link.c
new file mode 100644
index 0000000..b97a996
--- /dev/null
+++ b/lib/bind/dst/hmac_link.c
@@ -0,0 +1,489 @@
+#ifdef HMAC_MD5
+#ifndef LINT
+static const char rcsid[] = "$Header: /proj/cvs/prod/bind9/lib/bind/dst/hmac_link.c,v 1.3.164.5 2007/09/26 04:41:47 each Exp $";
+#endif
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+
+/*%
+ * This file contains an implementation of the HMAC-MD5 algorithm.
+ */
+#include "port_before.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dst_internal.h"
+
+#ifdef USE_MD5
+# ifndef HAVE_MD5
+# include "md5.h"
+# else
+# ifdef SOLARIS2
+# include <sys/md5.h>
+# endif
+# endif
+# ifndef _MD5_H_
+# define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */
+# endif
+#endif
+
+#include "port_after.h"
+
+
+#define HMAC_LEN 64
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5c
+#define MD5_LEN 16
+
+
+typedef struct hmackey {
+ u_char hk_ipad[64], hk_opad[64];
+} HMAC_Key;
+
+
+/**************************************************************************
+ * dst_hmac_md5_sign
+ * Call HMAC signing functions to sign a block of data.
+ * There are three steps to signing, INIT (initialize structures),
+ * UPDATE (hash (more) data), FINAL (generate a signature). This
+ * routine performs one or more of these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * priv_key key to use for signing.
+ * context the context to be used in this digest
+ * data data to be signed.
+ * len length in bytes of data.
+ * signature location to store signature.
+ * sig_len size of the signature location
+ * returns
+ * N Success on SIG_MODE_FINAL = returns signature length in bytes
+ * 0 Success on SIG_MODE_INIT and UPDATE
+ * <0 Failure
+ */
+
+static int
+dst_hmac_md5_sign(const int mode, DST_KEY *d_key, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ HMAC_Key *key;
+ int sign_len = 0;
+ MD5_CTX *ctx = NULL;
+
+ if (d_key == NULL || d_key->dk_KEY_struct == NULL)
+ return (-1);
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (MD5_CTX *) malloc(sizeof(*ctx));
+ else if (context)
+ ctx = (MD5_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ key = (HMAC_Key *) d_key->dk_KEY_struct;
+
+ if (mode & SIG_MODE_INIT) {
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_ipad, HMAC_LEN);
+ }
+
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
+ MD5Update(ctx, data, len);
+
+ if (mode & SIG_MODE_FINAL) {
+ if (signature == NULL || sig_len < MD5_LEN)
+ return (SIGN_FINAL_FAILURE);
+ MD5Final(signature, ctx);
+
+ /* perform outer MD5 */
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_opad, HMAC_LEN);
+ MD5Update(ctx, signature, MD5_LEN);
+ MD5Final(signature, ctx);
+ sign_len = MD5_LEN;
+ SAFE_FREE(ctx);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (sign_len);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_verify()
+ * Calls HMAC verification routines. There are three steps to
+ * verification, INIT (initialize structures), UPDATE (hash (more) data),
+ * FINAL (generate a signature). This routine performs one or more of
+ * these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * dkey key to use for verify.
+ * data data signed.
+ * len length in bytes of data.
+ * signature signature.
+ * sig_len length in bytes of signature.
+ * returns
+ * 0 Success
+ * <0 Failure
+ */
+
+static int
+dst_hmac_md5_verify(const int mode, DST_KEY *d_key, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ HMAC_Key *key;
+ MD5_CTX *ctx = NULL;
+
+ if (d_key == NULL || d_key->dk_KEY_struct == NULL)
+ return (-1);
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (MD5_CTX *) malloc(sizeof(*ctx));
+ else if (context)
+ ctx = (MD5_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ key = (HMAC_Key *) d_key->dk_KEY_struct;
+ if (mode & SIG_MODE_INIT) {
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_ipad, HMAC_LEN);
+ }
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
+ MD5Update(ctx, data, len);
+
+ if (mode & SIG_MODE_FINAL) {
+ u_char digest[MD5_LEN];
+ if (signature == NULL || key == NULL || sig_len != MD5_LEN)
+ return (VERIFY_FINAL_FAILURE);
+ MD5Final(digest, ctx);
+
+ /* perform outer MD5 */
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_opad, HMAC_LEN);
+ MD5Update(ctx, digest, MD5_LEN);
+ MD5Final(digest, ctx);
+
+ SAFE_FREE(ctx);
+ if (memcmp(digest, signature, MD5_LEN) != 0)
+ return (VERIFY_FINAL_FAILURE);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (0);
+}
+
+
+/**************************************************************************
+ * dst_buffer_to_hmac_md5
+ * Converts key from raw data to an HMAC Key
+ * This function gets in a pointer to the data
+ * Parameters
+ * hkey the HMAC key to be filled in
+ * key the key in raw format
+ * keylen the length of the key
+ * Return
+ * 0 Success
+ * <0 Failure
+ */
+static int
+dst_buffer_to_hmac_md5(DST_KEY *dkey, const u_char *key, const int keylen)
+{
+ int i;
+ HMAC_Key *hkey = NULL;
+ MD5_CTX ctx;
+ int local_keylen = keylen;
+ u_char tk[MD5_LEN];
+
+ if (dkey == NULL || key == NULL || keylen < 0)
+ return (-1);
+
+ if ((hkey = (HMAC_Key *) malloc(sizeof(HMAC_Key))) == NULL)
+ return (-2);
+
+ memset(hkey->hk_ipad, 0, sizeof(hkey->hk_ipad));
+ memset(hkey->hk_opad, 0, sizeof(hkey->hk_opad));
+
+ /* if key is longer than HMAC_LEN bytes reset it to key=MD5(key) */
+ if (keylen > HMAC_LEN) {
+ MD5Init(&ctx);
+ MD5Update(&ctx, key, keylen);
+ MD5Final(tk, &ctx);
+ memset((void *) &ctx, 0, sizeof(ctx));
+ key = tk;
+ local_keylen = MD5_LEN;
+ }
+ /* start out by storing key in pads */
+ memcpy(hkey->hk_ipad, key, local_keylen);
+ memcpy(hkey->hk_opad, key, local_keylen);
+
+ /* XOR key with hk_ipad and opad values */
+ for (i = 0; i < HMAC_LEN; i++) {
+ hkey->hk_ipad[i] ^= HMAC_IPAD;
+ hkey->hk_opad[i] ^= HMAC_OPAD;
+ }
+ dkey->dk_key_size = local_keylen;
+ dkey->dk_KEY_struct = (void *) hkey;
+ return (1);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_key_to_file_format
+ * Encodes an HMAC Key into the portable file format.
+ * Parameters
+ * hkey HMAC KEY structure
+ * buff output buffer
+ * buff_len size of output buffer
+ * Return
+ * 0 Failure - null input hkey
+ * -1 Failure - not enough space in output area
+ * N Success - Length of data returned in buff
+ */
+
+static int
+dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff,
+ const int buff_len)
+{
+ char *bp;
+ int len, i, key_len;
+ u_char key[HMAC_LEN];
+ HMAC_Key *hkey;
+
+ if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+ return (0);
+ /*
+ * Using snprintf() would be so much simpler here.
+ */
+ if (buff == NULL ||
+ buff_len <= (int)(strlen(key_file_fmt_str) +
+ strlen(KEY_FILE_FORMAT) + 4))
+ return (-1); /*%< no OR not enough space in output area */
+ hkey = (HMAC_Key *) dkey->dk_KEY_struct;
+ memset(buff, 0, buff_len); /*%< just in case */
+ /* write file header */
+ sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC");
+
+ bp = buff + strlen(buff);
+
+ memset(key, 0, HMAC_LEN);
+ for (i = 0; i < HMAC_LEN; i++)
+ key[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
+ for (i = HMAC_LEN - 1; i >= 0; i--)
+ if (key[i] != 0)
+ break;
+ key_len = i + 1;
+
+ if (buff_len - (bp - buff) < 6)
+ return (-1);
+ strcat(bp, "Key: ");
+ bp += strlen("Key: ");
+
+ len = b64_ntop(key, key_len, bp, buff_len - (bp - buff));
+ if (len < 0)
+ return (-1);
+ bp += len;
+ if (buff_len - (bp - buff) < 2)
+ return (-1);
+ *(bp++) = '\n';
+ *bp = '\0';
+
+ return (bp - buff);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_key_from_file_format
+ * Converts contents of a key file into an HMAC key.
+ * Parameters
+ * hkey structure to put key into
+ * buff buffer containing the encoded key
+ * buff_len the length of the buffer
+ * Return
+ * n >= 0 Foot print of the key converted
+ * n < 0 Error in conversion
+ */
+
+static int
+dst_hmac_md5_key_from_file_format(DST_KEY *dkey, const char *buff,
+ const int buff_len)
+{
+ const char *p = buff, *eol;
+ u_char key[HMAC_LEN+1]; /* b64_pton needs more than 64 bytes do decode
+ * it should probably be fixed rather than doing
+ * this
+ */
+ u_char *tmp;
+ int key_len, len;
+
+ if (dkey == NULL)
+ return (-2);
+ if (buff == NULL || buff_len < 0)
+ return (-1);
+
+ memset(key, 0, sizeof(key));
+
+ if (!dst_s_verify_str(&p, "Key: "))
+ return (-3);
+
+ eol = strchr(p, '\n');
+ if (eol == NULL)
+ return (-4);
+ len = eol - p;
+ tmp = malloc(len + 2);
+ if (tmp == NULL)
+ return (-5);
+ memcpy(tmp, p, len);
+ *(tmp + len) = 0x0;
+ key_len = b64_pton((char *)tmp, key, HMAC_LEN+1); /*%< see above */
+ SAFE_FREE2(tmp, len + 2);
+
+ if (dst_buffer_to_hmac_md5(dkey, key, key_len) < 0) {
+ return (-6);
+ }
+ return (0);
+}
+
+/*%
+ * dst_hmac_md5_to_dns_key()
+ * function to extract hmac key from DST_KEY structure
+ * intput:
+ * in_key: HMAC-MD5 key
+ * output:
+ * out_str: buffer to write ot
+ * out_len: size of output buffer
+ * returns:
+ * number of bytes written to output buffer
+ */
+static int
+dst_hmac_md5_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+ const int out_len)
+{
+
+ HMAC_Key *hkey;
+ int i;
+
+ if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+ out_len <= in_key->dk_key_size || out_str == NULL)
+ return (-1);
+
+ hkey = (HMAC_Key *) in_key->dk_KEY_struct;
+ for (i = 0; i < in_key->dk_key_size; i++)
+ out_str[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
+ return (i);
+}
+
+/**************************************************************************
+ * dst_hmac_md5_compare_keys
+ * Compare two keys for equality.
+ * Return
+ * 0 The keys are equal
+ * NON-ZERO The keys are not equal
+ */
+
+static int
+dst_hmac_md5_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+ HMAC_Key *hkey1 = (HMAC_Key *) key1->dk_KEY_struct;
+ HMAC_Key *hkey2 = (HMAC_Key *) key2->dk_KEY_struct;
+ return memcmp(hkey1->hk_ipad, hkey2->hk_ipad, HMAC_LEN);
+}
+
+/**************************************************************************
+ * dst_hmac_md5_free_key_structure
+ * Frees all (none) dynamically allocated structures in hkey
+ */
+
+static void *
+dst_hmac_md5_free_key_structure(void *key)
+{
+ HMAC_Key *hkey = key;
+ SAFE_FREE(hkey);
+ return (NULL);
+}
+
+
+/***************************************************************************
+ * dst_hmac_md5_generate_key
+ * Creates a HMAC key of size size with a maximum size of 63 bytes
+ * generating a HMAC key larger than 63 bytes makes no sense as that key
+ * is digested before use.
+ */
+
+static int
+dst_hmac_md5_generate_key(DST_KEY *key, const int nothing)
+{
+ (void)key;
+ (void)nothing;
+ return (-1);
+}
+
+/*%
+ * dst_hmac_md5_init() Function to answer set up function pointers for HMAC
+ * related functions
+ */
+int
+#ifdef SUNW_LIBMD5
+dst_md5_hmac_init()
+#else
+dst_hmac_md5_init()
+#endif
+{
+ if (dst_t_func[KEY_HMAC_MD5] != NULL)
+ return (1);
+ dst_t_func[KEY_HMAC_MD5] = malloc(sizeof(struct dst_func));
+ if (dst_t_func[KEY_HMAC_MD5] == NULL)
+ return (0);
+ memset(dst_t_func[KEY_HMAC_MD5], 0, sizeof(struct dst_func));
+ dst_t_func[KEY_HMAC_MD5]->sign = dst_hmac_md5_sign;
+ dst_t_func[KEY_HMAC_MD5]->verify = dst_hmac_md5_verify;
+ dst_t_func[KEY_HMAC_MD5]->compare = dst_hmac_md5_compare_keys;
+ dst_t_func[KEY_HMAC_MD5]->generate = dst_hmac_md5_generate_key;
+ dst_t_func[KEY_HMAC_MD5]->destroy = dst_hmac_md5_free_key_structure;
+ dst_t_func[KEY_HMAC_MD5]->to_dns_key = dst_hmac_md5_to_dns_key;
+ dst_t_func[KEY_HMAC_MD5]->from_dns_key = dst_buffer_to_hmac_md5;
+ dst_t_func[KEY_HMAC_MD5]->to_file_fmt = dst_hmac_md5_key_to_file_format;
+ dst_t_func[KEY_HMAC_MD5]->from_file_fmt = dst_hmac_md5_key_from_file_format;
+ return (1);
+}
+
+#else
+#define dst_hmac_md5_init __dst_hmac_md5_init
+
+int
+dst_hmac_md5_init(){
+ return (0);
+}
+#endif
+
+/*! \file */
diff --git a/lib/bind/dst/md5.h b/lib/bind/dst/md5.h
new file mode 100644
index 0000000..b1ed9e1
--- /dev/null
+++ b/lib/bind/dst/md5.h
@@ -0,0 +1,108 @@
+/* crypto/md/md5.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_MD5_H
+#define HEADER_MD5_H
+
+#ifndef HAVE_MD5
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MD5_CBLOCK 64
+#define MD5_LBLOCK 16
+#define MD5_BLOCK 16
+#define MD5_LAST_BLOCK 56
+#define MD5_LENGTH_BLOCK 8
+#define MD5_DIGEST_LENGTH 16
+
+typedef struct MD5state_st
+ {
+ unsigned long A,B,C,D;
+ unsigned long Nl,Nh;
+ unsigned long data[MD5_LBLOCK];
+ int num;
+ } MD5_CTX;
+
+#ifndef NOPROTO
+void MD5_Init(MD5_CTX *c);
+void MD5_Update(MD5_CTX *c, const unsigned char *data, unsigned long len);
+void MD5_Final(unsigned char *md, MD5_CTX *c);
+unsigned char *MD5(unsigned char *d, unsigned long n, unsigned char *md);
+#else
+void MD5_Init();
+void MD5_Update();
+void MD5_Final();
+unsigned char *MD5();
+#endif
+
+/* to provide backward compatabilty to RSAREF calls ogud@tis.com 1997/11/14 */
+#define MD5Init(c) MD5_Init(c)
+#define MD5Update(c,data, len) MD5_Update(c,data,len)
+#define MD5Final(md, c) MD5_Final(md, c)
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#else
+#include <sys/md5.h>
+#endif /* HAVE_MD5 */
+
+/*! \file */
diff --git a/lib/bind/dst/md5_dgst.c b/lib/bind/dst/md5_dgst.c
new file mode 100644
index 0000000..76b0505
--- /dev/null
+++ b/lib/bind/dst/md5_dgst.c
@@ -0,0 +1,374 @@
+/* crypto/md/md5_dgst.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifdef USE_MD5 /*%< Added by ogud@tis.com 1998/1/26 */
+#include <port_before.h>
+#ifndef HAVE_MD5
+#include <stdio.h>
+#include "md5_locl.h"
+#include <port_after.h>
+
+const char *MD5_version="MD5 part of SSLeay 0.8.1 19-Jul-1997";
+
+/*! \file
+ * \brief
+ * Implemented from RFC1321 The MD5 Message-Digest Algorithm
+ */
+
+#define INIT_DATA_A (unsigned long)0x67452301L
+#define INIT_DATA_B (unsigned long)0xefcdab89L
+#define INIT_DATA_C (unsigned long)0x98badcfeL
+#define INIT_DATA_D (unsigned long)0x10325476L
+
+#ifndef NOPROTO
+static void md5_block(MD5_CTX *c, unsigned long *p);
+#else
+static void md5_block();
+#endif
+
+void MD5_Init(c)
+MD5_CTX *c;
+ {
+ c->A=INIT_DATA_A;
+ c->B=INIT_DATA_B;
+ c->C=INIT_DATA_C;
+ c->D=INIT_DATA_D;
+ c->Nl=0;
+ c->Nh=0;
+ c->num=0;
+ }
+
+void MD5_Update(c, data, len)
+MD5_CTX *c;
+register const unsigned char *data;
+unsigned long len;
+ {
+ register ULONG *p;
+ int sw,sc;
+ ULONG l;
+
+ if (len == 0U) return;
+
+ l=(c->Nl+(len<<3))&0xffffffffL;
+ /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to
+ * Wei Dai <weidai@eskimo.com> 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 (; sw<MD5_LBLOCK; sw++)
+ {
+ c2l(data,l);
+ p[sw]=l;
+ }
+ len-=(MD5_CBLOCK-c->num);
+
+ 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 <altitude@cic.net> 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 (; i<MD5_LBLOCK; i++)
+ p[i]=0;
+ md5_block(c,p);
+ i=0;
+ }
+ for (; i<(MD5_LBLOCK-2); i++)
+ p[i]=0;
+ p[MD5_LBLOCK-2]=c->Nl;
+ p[MD5_LBLOCK-1]=c->Nh;
+ md5_block(c,p);
+ cp=md;
+ l=c->A; l2c(l,cp);
+ l=c->B; l2c(l,cp);
+ l=c->C; l2c(l,cp);
+ l=c->D; l2c(l,cp);
+
+ /* clear stuff, md5_block may be leaving some stuff on the stack
+ * but I'm not worried :-) */
+ c->num=0;
+/* memset((char *)&c,0,sizeof(c));*/
+ }
+
+#ifdef undef
+int printit(l)
+unsigned long *l;
+ {
+ int i,ii;
+
+ for (i=0; i<2; i++)
+ {
+ for (ii=0; ii<8; ii++)
+ {
+ fprintf(stderr,"%08lx ",l[i*8+ii]);
+ }
+ fprintf(stderr,"\n");
+ }
+ }
+#endif
+#endif /* HAVE_MD5 */
+#endif /* USE_MD5 */
diff --git a/lib/bind/dst/md5_locl.h b/lib/bind/dst/md5_locl.h
new file mode 100644
index 0000000..657fe8c
--- /dev/null
+++ b/lib/bind/dst/md5_locl.h
@@ -0,0 +1,193 @@
+/* crypto/md/md5_locl.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#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 <weidai@eskimo.com> */
+#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 <weidai@eskimo.com>, the above can be
+ * simplified to the code below. Wei attributes these optimisations
+ * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel.
+ */
+#define F(x,y,z) ((((y) ^ (z)) & (x)) ^ (z))
+#define G(x,y,z) ((((x) ^ (y)) & (z)) ^ (y))
+#define H(x,y,z) ((x) ^ (y) ^ (z))
+#define I(x,y,z) (((x) | (~(z))) ^ (y))
+
+#undef ROTATE
+#if defined(WIN32)
+#define ROTATE(a,n) _lrotl(a,n)
+#else
+#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#endif
+
+
+#define R0(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+F((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };\
+
+#define R1(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+G((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
+
+#define R2(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+H((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
+
+#define R3(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+I((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
+
+/*! \file */
diff --git a/lib/bind/dst/support.c b/lib/bind/dst/support.c
new file mode 100644
index 0000000..ec228d0
--- /dev/null
+++ b/lib/bind/dst/support.c
@@ -0,0 +1,342 @@
+static const char rcsid[] = "$Header: /proj/cvs/prod/bind9/lib/bind/dst/support.c,v 1.3.332.3 2005/10/11 00:25:09 marka Exp $";
+
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+
+#include "port_before.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <memory.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dst_internal.h"
+
+#include "port_after.h"
+
+/*%
+ * dst_s_verify_str()
+ * Validate that the input string(*str) is at the head of the input
+ * buffer(**buf). If so, move the buffer head pointer (*buf) to
+ * the first byte of data following the string(*str).
+ * Parameters
+ * buf Input buffer.
+ * str Input string.
+ * Return
+ * 0 *str is not the head of **buff
+ * 1 *str is the head of **buff, *buf is is advanced to
+ * the tail of **buf.
+ */
+
+int
+dst_s_verify_str(const char **buf, const char *str)
+{
+ int b, s;
+ if (*buf == NULL) /*%< error checks */
+ return (0);
+ if (str == NULL || *str == '\0')
+ return (1);
+
+ b = strlen(*buf); /*%< get length of strings */
+ s = strlen(str);
+ if (s > b || strncmp(*buf, str, s)) /*%< check if same */
+ return (0); /*%< not a match */
+ (*buf) += s; /*%< advance pointer */
+ return (1);
+}
+
+/*%
+ * dst_s_calculate_bits
+ * Given a binary number represented in a u_char[], determine
+ * the number of significant bits used.
+ * Parameters
+ * str An input character string containing a binary number.
+ * max_bits The maximum possible significant bits.
+ * Return
+ * N The number of significant bits in str.
+ */
+
+int
+dst_s_calculate_bits(const u_char *str, const int max_bits)
+{
+ const u_char *p = str;
+ u_char i, j = 0x80;
+ int bits;
+ for (bits = max_bits; *p == 0x00 && bits > 0; p++)
+ bits -= 8;
+ for (i = *p; (i & j) != j; j >>= 1)
+ bits--;
+ return (bits);
+}
+
+/*%
+ * calculates a checksum used in dst for an id.
+ * takes an array of bytes and a length.
+ * returns a 16 bit checksum.
+ */
+u_int16_t
+dst_s_id_calc(const u_char *key, const int keysize)
+{
+ u_int32_t ac;
+ const u_char *kp = key;
+ int size = keysize;
+
+ if (!key || (keysize <= 0))
+ return (0xffffU);
+
+ for (ac = 0; size > 1; size -= 2, kp += 2)
+ ac += ((*kp) << 8) + *(kp + 1);
+
+ if (size > 0)
+ ac += ((*kp) << 8);
+ ac += (ac >> 16) & 0xffff;
+
+ return (ac & 0xffff);
+}
+
+/*%
+ * dst_s_dns_key_id() Function to calculate DNSSEC footprint from KEY record
+ * rdata
+ * Input:
+ * dns_key_rdata: the raw data in wire format
+ * rdata_len: the size of the input data
+ * Output:
+ * the key footprint/id calculated from the key data
+ */
+u_int16_t
+dst_s_dns_key_id(const u_char *dns_key_rdata, const int rdata_len)
+{
+ if (!dns_key_rdata)
+ return 0;
+
+ /* compute id */
+ if (dns_key_rdata[3] == KEY_RSA) /*%< Algorithm RSA */
+ return dst_s_get_int16((const u_char *)
+ &dns_key_rdata[rdata_len - 3]);
+ else if (dns_key_rdata[3] == KEY_HMAC_MD5)
+ /* compatibility */
+ return 0;
+ else
+ /* compute a checksum on the key part of the key rr */
+ return dst_s_id_calc(dns_key_rdata, rdata_len);
+}
+
+/*%
+ * dst_s_get_int16
+ * This routine extracts a 16 bit integer from a two byte character
+ * string. The character string is assumed to be in network byte
+ * order and may be unaligned. The number returned is in host order.
+ * Parameter
+ * buf A two byte character string.
+ * Return
+ * The converted integer value.
+ */
+
+u_int16_t
+dst_s_get_int16(const u_char *buf)
+{
+ register u_int16_t a = 0;
+ a = ((u_int16_t)(buf[0] << 8)) | ((u_int16_t)(buf[1]));
+ return (a);
+}
+
+/*%
+ * dst_s_get_int32
+ * This routine extracts a 32 bit integer from a four byte character
+ * string. The character string is assumed to be in network byte
+ * order and may be unaligned. The number returned is in host order.
+ * Parameter
+ * buf A four byte character string.
+ * Return
+ * The converted integer value.
+ */
+
+u_int32_t
+dst_s_get_int32(const u_char *buf)
+{
+ register u_int32_t a = 0;
+ a = ((u_int32_t)(buf[0] << 24)) | ((u_int32_t)(buf[1] << 16)) |
+ ((u_int32_t)(buf[2] << 8)) | ((u_int32_t)(buf[3]));
+ return (a);
+}
+
+/*%
+ * dst_s_put_int16
+ * Take a 16 bit integer and store the value in a two byte
+ * character string. The integer is assumed to be in network
+ * order and the string is returned in host order.
+ *
+ * Parameters
+ * buf Storage for a two byte character string.
+ * val 16 bit integer.
+ */
+
+void
+dst_s_put_int16(u_int8_t *buf, const u_int16_t val)
+{
+ buf[0] = (u_int8_t)(val >> 8);
+ buf[1] = (u_int8_t)(val);
+}
+
+/*%
+ * dst_s_put_int32
+ * Take a 32 bit integer and store the value in a four byte
+ * character string. The integer is assumed to be in network
+ * order and the string is returned in host order.
+ *
+ * Parameters
+ * buf Storage for a four byte character string.
+ * val 32 bit integer.
+ */
+
+void
+dst_s_put_int32(u_int8_t *buf, const u_int32_t val)
+{
+ buf[0] = (u_int8_t)(val >> 24);
+ buf[1] = (u_int8_t)(val >> 16);
+ buf[2] = (u_int8_t)(val >> 8);
+ buf[3] = (u_int8_t)(val);
+}
+
+/*%
+ * dst_s_filename_length
+ *
+ * This function returns the number of bytes needed to hold the
+ * filename for a key file. '/', '\' and ':' are not allowed.
+ * form: K&lt;keyname&gt;+&lt;alg&gt;+&lt;id&gt;.&lt;suffix&gt;
+ *
+ * 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&lt;keyname&gt;&lt;id&gt;.&lt;suffix&gt;
+ * form: K&lt;keyname&gt;+&lt;alg&gt;+&lt;id&gt;.&lt;suffix&gt;
+ *
+ * Returns -1 if the conversion fails:
+ * if the filename would be too long for space allotted
+ * if the filename would contain a '\', '/' or ':'
+ * Returns 0 on success
+ */
+
+int
+dst_s_build_filename(char *filename, const char *name, u_int16_t id,
+ int alg, const char *suffix, size_t filename_length)
+{
+ u_int32_t my_id;
+ if (filename == NULL)
+ return (-1);
+ memset(filename, 0, filename_length);
+ if (name == NULL)
+ return (-1);
+ if (suffix == NULL)
+ return (-1);
+ if (filename_length < 1 + strlen(name) + 4 + 6 + 1 + strlen(suffix))
+ return (-1);
+ my_id = id;
+ sprintf(filename, "K%s+%03d+%05d.%s", name, alg, my_id,
+ (const char *) suffix);
+ if (strrchr(filename, '/'))
+ return (-1);
+ if (strrchr(filename, '\\'))
+ return (-1);
+ if (strrchr(filename, ':'))
+ return (-1);
+ return (0);
+}
+
+/*%
+ * dst_s_fopen ()
+ * Open a file in the dst_path directory. If perm is specified, the
+ * file is checked for existence first, and not opened if it exists.
+ * Parameters
+ * filename File to open
+ * mode Mode to open the file (passed directly to fopen)
+ * perm File permission, if creating a new file.
+ * Returns
+ * NULL Failure
+ * NON-NULL (FILE *) of opened file.
+ */
+FILE *
+dst_s_fopen(const char *filename, const char *mode, int perm)
+{
+ FILE *fp;
+ char pathname[PATH_MAX];
+
+ if (strlen(filename) + strlen(dst_path) >= sizeof(pathname))
+ return (NULL);
+
+ if (*dst_path != '\0') {
+ strcpy(pathname, dst_path);
+ strcat(pathname, filename);
+ } else
+ strcpy(pathname, filename);
+
+ fp = fopen(pathname, mode);
+ if (perm)
+ chmod(pathname, perm);
+ return (fp);
+}
+
+void
+dst_s_dump(const int mode, const u_char *data, const int size,
+ const char *msg)
+{
+ UNUSED(data);
+
+ if (size > 0) {
+#ifdef LONG_TEST
+ static u_char scratch[1000];
+ int n ;
+ n = b64_ntop(data, scratch, size, sizeof(scratch));
+ printf("%s: %x %d %s\n", msg, mode, n, scratch);
+#else
+ printf("%s,%x %d\n", msg, mode, size);
+#endif
+ }
+}
+
+/*! \file */
diff --git a/lib/bind/include/Makefile.in b/lib/bind/include/Makefile.in
new file mode 100644
index 0000000..d07ea7a
--- /dev/null
+++ b/lib/bind/include/Makefile.in
@@ -0,0 +1,47 @@
+# 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: Makefile.in,v 1.4 2004/03/05 05:05:11 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+HEADERS=fd_setsize.h hesiod.h irp.h irs.h netdb.h netgroup.h res_update.h \
+ resolv.h
+AHEADERS= arpa/inet.h arpa/nameser.h arpa/nameser_compat.h
+IHEADERS= isc/assertions.h isc/ctl.h isc/dst.h isc/eventlib.h isc/heap.h \
+ isc/irpmarshall.h isc/list.h isc/logging.h isc/memcluster.h \
+ isc/misc.h isc/tree.h
+
+all:
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir} \
+ ${DESTDIR}${includedir}/arpa ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}; \
+ done
+ for i in ${IHEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/isc; \
+ done
+ for i in ${AHEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/arpa; \
+ done
+
diff --git a/lib/bind/include/arpa/inet.h b/lib/bind/include/arpa/inet.h
new file mode 100644
index 0000000..d84987b
--- /dev/null
+++ b/lib/bind/include/arpa/inet.h
@@ -0,0 +1,126 @@
+/*
+ * ++Copyright++ 1983, 1993
+ * -
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*%
+ * @(#)inet.h 8.1 (Berkeley) 6/2/93
+ * $Id: inet.h,v 1.2.18.1 2005/04/27 05:00:50 sra Exp $
+ */
+
+#ifndef _INET_H_
+#define _INET_H_
+
+/* External definitions for functions in inet(3) */
+
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+#include <sys/cdefs.h>
+
+#define inet_addr __inet_addr
+#define inet_aton __inet_aton
+#define inet_lnaof __inet_lnaof
+#define inet_makeaddr __inet_makeaddr
+#define inet_neta __inet_neta
+#define inet_netof __inet_netof
+#define inet_network __inet_network
+#define inet_net_ntop __inet_net_ntop
+#define inet_net_pton __inet_net_pton
+#define inet_cidr_ntop __inet_cidr_ntop
+#define inet_cidr_pton __inet_cidr_pton
+#define inet_ntoa __inet_ntoa
+#define inet_pton __inet_pton
+#define inet_ntop __inet_ntop
+#define inet_nsap_addr __inet_nsap_addr
+#define inet_nsap_ntoa __inet_nsap_ntoa
+
+__BEGIN_DECLS
+unsigned long inet_addr __P((const char *));
+int inet_aton __P((const char *, struct in_addr *));
+unsigned long inet_lnaof __P((struct in_addr));
+struct in_addr inet_makeaddr __P((u_long , u_long));
+char * inet_neta __P((u_long, char *, size_t));
+unsigned long inet_netof __P((struct in_addr));
+unsigned long inet_network __P((const char *));
+char *inet_net_ntop __P((int, const void *, int, char *, size_t));
+int inet_net_pton __P((int, const char *, void *, size_t));
+char *inet_cidr_ntop __P((int, const void *, int, char *, size_t));
+int inet_cidr_pton __P((int, const char *, void *, int *));
+/*const*/ char *inet_ntoa __P((struct in_addr));
+int inet_pton __P((int, const char *, void *));
+const char *inet_ntop __P((int, const void *, char *, size_t));
+u_int inet_nsap_addr __P((const char *, u_char *, int));
+char *inet_nsap_ntoa __P((int, const u_char *, char *));
+__END_DECLS
+
+#if defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)
+/*
+ * Macros for number representation conversion.
+ *
+ * netinet/in.h is another location for these macros
+ */
+#ifndef ntohl
+#define ntohl(x) (x)
+#define ntohs(x) (x)
+#define htonl(x) (x)
+#define htons(x) (x)
+#endif
+#endif
+
+#endif /* !_INET_H_ */
+
+/*! \file */
diff --git a/lib/bind/include/arpa/nameser.h b/lib/bind/include/arpa/nameser.h
new file mode 100644
index 0000000..b3a7849
--- /dev/null
+++ b/lib/bind/include/arpa/nameser.h
@@ -0,0 +1,574 @@
+/*
+ * 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.7.18.1 2005/04/27 05:00:50 sra Exp $
+ */
+
+#ifndef _ARPA_NAMESER_H_
+#define _ARPA_NAMESER_H_
+
+/*! \file */
+
+#define BIND_4_COMPAT
+
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+#include <sys/cdefs.h>
+
+/*%
+ * Revision information. This is the release date in YYYYMMDD format.
+ * It can change every day so the right thing to do with it is use it
+ * in preprocessor commands such as "#if (__NAMESER > 19931104)". Do not
+ * compare for equality; rather, use it to determine whether your libbind.a
+ * contains a new enough lib/nameser/ to support the feature you need.
+ */
+
+#define __NAMESER 19991006 /*%< New interface version stamp. */
+/*
+ * Define constants based on RFC0883, RFC1034, RFC 1035
+ */
+#define NS_PACKETSZ 512 /*%< default UDP packet size */
+#define NS_MAXDNAME 1025 /*%< maximum domain name */
+#define NS_MAXMSG 65535 /*%< maximum message size */
+#define NS_MAXCDNAME 255 /*%< maximum compressed domain name */
+#define NS_MAXLABEL 63 /*%< maximum length of domain label */
+#define NS_HFIXEDSZ 12 /*%< #/bytes of fixed data in header */
+#define NS_QFIXEDSZ 4 /*%< #/bytes of fixed data in query */
+#define NS_RRFIXEDSZ 10 /*%< #/bytes of fixed data in r record */
+#define NS_INT32SZ 4 /*%< #/bytes of data in a u_int32_t */
+#define NS_INT16SZ 2 /*%< #/bytes of data in a u_int16_t */
+#define NS_INT8SZ 1 /*%< #/bytes of data in a u_int8_t */
+#define NS_INADDRSZ 4 /*%< IPv4 T_A */
+#define NS_IN6ADDRSZ 16 /*%< IPv6 T_AAAA */
+#define NS_CMPRSFLGS 0xc0 /*%< Flag bits indicating name compression. */
+#define NS_DEFAULTPORT 53 /*%< For both TCP and UDP. */
+/*
+ * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord()
+ * in synch with it.
+ */
+typedef enum __ns_sect {
+ ns_s_qd = 0, /*%< Query: Question. */
+ ns_s_zn = 0, /*%< Update: Zone. */
+ ns_s_an = 1, /*%< Query: Answer. */
+ ns_s_pr = 1, /*%< Update: Prerequisites. */
+ ns_s_ns = 2, /*%< Query: Name servers. */
+ ns_s_ud = 2, /*%< Update: Update. */
+ ns_s_ar = 3, /*%< Query|Update: Additional records. */
+ ns_s_max = 4
+} ns_sect;
+
+/*%
+ * This is a message handle. It is caller allocated and has no dynamic data.
+ * This structure is intended to be opaque to all but ns_parse.c, thus the
+ * leading _'s on the member names. Use the accessor functions, not the _'s.
+ */
+typedef struct __ns_msg {
+ const u_char *_msg, *_eom;
+ u_int16_t _id, _flags, _counts[ns_s_max];
+ const u_char *_sections[ns_s_max];
+ ns_sect _sect;
+ int _rrnum;
+ const u_char *_msg_ptr;
+} ns_msg;
+
+/* Private data structure - do not use from outside library. */
+struct _ns_flagdata { int mask, shift; };
+extern struct _ns_flagdata _ns_flagdata[];
+
+/* Accessor macros - this is part of the public interface. */
+
+#define ns_msg_id(handle) ((handle)._id + 0)
+#define ns_msg_base(handle) ((handle)._msg + 0)
+#define ns_msg_end(handle) ((handle)._eom + 0)
+#define ns_msg_size(handle) ((handle)._eom - (handle)._msg)
+#define ns_msg_count(handle, section) ((handle)._counts[section] + 0)
+
+/*%
+ * This is a parsed record. It is caller allocated and has no dynamic data.
+ */
+typedef struct __ns_rr {
+ char name[NS_MAXDNAME];
+ u_int16_t type;
+ u_int16_t rr_class;
+ u_int32_t ttl;
+ u_int16_t rdlength;
+ const u_char * rdata;
+} ns_rr;
+
+/* Accessor macros - this is part of the public interface. */
+#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".")
+#define ns_rr_type(rr) ((ns_type)((rr).type + 0))
+#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0))
+#define ns_rr_ttl(rr) ((rr).ttl + 0)
+#define ns_rr_rdlen(rr) ((rr).rdlength + 0)
+#define ns_rr_rdata(rr) ((rr).rdata + 0)
+
+/*%
+ * These don't have to be in the same order as in the packet flags word,
+ * and they can even overlap in some cases, but they will need to be kept
+ * in synch with ns_parse.c:ns_flagdata[].
+ */
+typedef enum __ns_flag {
+ ns_f_qr, /*%< Question/Response. */
+ ns_f_opcode, /*%< Operation code. */
+ ns_f_aa, /*%< Authoritative Answer. */
+ ns_f_tc, /*%< Truncation occurred. */
+ ns_f_rd, /*%< Recursion Desired. */
+ ns_f_ra, /*%< Recursion Available. */
+ ns_f_z, /*%< MBZ. */
+ ns_f_ad, /*%< Authentic Data (DNSSEC). */
+ ns_f_cd, /*%< Checking Disabled (DNSSEC). */
+ ns_f_rcode, /*%< Response code. */
+ ns_f_max
+} ns_flag;
+
+/*%
+ * Currently defined opcodes.
+ */
+typedef enum __ns_opcode {
+ ns_o_query = 0, /*%< Standard query. */
+ ns_o_iquery = 1, /*%< Inverse query (deprecated/unsupported). */
+ ns_o_status = 2, /*%< Name server status query (unsupported). */
+ /* Opcode 3 is undefined/reserved. */
+ ns_o_notify = 4, /*%< Zone change notification. */
+ ns_o_update = 5, /*%< Zone update message. */
+ ns_o_max = 6
+} ns_opcode;
+
+/*%
+ * Currently defined response codes.
+ */
+typedef enum __ns_rcode {
+ ns_r_noerror = 0, /*%< No error occurred. */
+ ns_r_formerr = 1, /*%< Format error. */
+ ns_r_servfail = 2, /*%< Server failure. */
+ ns_r_nxdomain = 3, /*%< Name error. */
+ ns_r_notimpl = 4, /*%< Unimplemented. */
+ ns_r_refused = 5, /*%< Operation refused. */
+ /* these are for BIND_UPDATE */
+ ns_r_yxdomain = 6, /*%< Name exists */
+ ns_r_yxrrset = 7, /*%< RRset exists */
+ ns_r_nxrrset = 8, /*%< RRset does not exist */
+ ns_r_notauth = 9, /*%< Not authoritative for zone */
+ ns_r_notzone = 10, /*%< Zone of record different from zone section */
+ ns_r_max = 11,
+ /* The following are EDNS extended rcodes */
+ ns_r_badvers = 16,
+ /* The following are TSIG errors */
+ ns_r_badsig = 16,
+ ns_r_badkey = 17,
+ ns_r_badtime = 18
+} ns_rcode;
+
+/* BIND_UPDATE */
+typedef enum __ns_update_operation {
+ ns_uop_delete = 0,
+ ns_uop_add = 1,
+ ns_uop_max = 2
+} ns_update_operation;
+
+/*%
+ * This structure is used for TSIG authenticated messages
+ */
+struct ns_tsig_key {
+ char name[NS_MAXDNAME], alg[NS_MAXDNAME];
+ unsigned char *data;
+ int len;
+};
+typedef struct ns_tsig_key ns_tsig_key;
+
+/*%
+ * This structure is used for TSIG authenticated TCP messages
+ */
+struct ns_tcp_tsig_state {
+ int counter;
+ struct dst_key *key;
+ void *ctx;
+ unsigned char sig[NS_PACKETSZ];
+ int siglen;
+};
+typedef struct ns_tcp_tsig_state ns_tcp_tsig_state;
+
+#define NS_TSIG_FUDGE 300
+#define NS_TSIG_TCP_COUNT 100
+#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT"
+
+#define NS_TSIG_ERROR_NO_TSIG -10
+#define NS_TSIG_ERROR_NO_SPACE -11
+#define NS_TSIG_ERROR_FORMERR -12
+
+/*%
+ * Currently defined type values for resources and queries.
+ */
+typedef enum __ns_type {
+ ns_t_invalid = 0, /*%< Cookie. */
+ ns_t_a = 1, /*%< Host address. */
+ ns_t_ns = 2, /*%< Authoritative server. */
+ ns_t_md = 3, /*%< Mail destination. */
+ ns_t_mf = 4, /*%< Mail forwarder. */
+ ns_t_cname = 5, /*%< Canonical name. */
+ ns_t_soa = 6, /*%< Start of authority zone. */
+ ns_t_mb = 7, /*%< Mailbox domain name. */
+ ns_t_mg = 8, /*%< Mail group member. */
+ ns_t_mr = 9, /*%< Mail rename name. */
+ ns_t_null = 10, /*%< Null resource record. */
+ ns_t_wks = 11, /*%< Well known service. */
+ ns_t_ptr = 12, /*%< Domain name pointer. */
+ ns_t_hinfo = 13, /*%< Host information. */
+ ns_t_minfo = 14, /*%< Mailbox information. */
+ ns_t_mx = 15, /*%< Mail routing information. */
+ ns_t_txt = 16, /*%< Text strings. */
+ ns_t_rp = 17, /*%< Responsible person. */
+ ns_t_afsdb = 18, /*%< AFS cell database. */
+ ns_t_x25 = 19, /*%< X_25 calling address. */
+ ns_t_isdn = 20, /*%< ISDN calling address. */
+ ns_t_rt = 21, /*%< Router. */
+ ns_t_nsap = 22, /*%< NSAP address. */
+ ns_t_nsap_ptr = 23, /*%< Reverse NSAP lookup (deprecated). */
+ ns_t_sig = 24, /*%< Security signature. */
+ ns_t_key = 25, /*%< Security key. */
+ ns_t_px = 26, /*%< X.400 mail mapping. */
+ ns_t_gpos = 27, /*%< Geographical position (withdrawn). */
+ ns_t_aaaa = 28, /*%< Ip6 Address. */
+ ns_t_loc = 29, /*%< Location Information. */
+ ns_t_nxt = 30, /*%< Next domain (security). */
+ ns_t_eid = 31, /*%< Endpoint identifier. */
+ ns_t_nimloc = 32, /*%< Nimrod Locator. */
+ ns_t_srv = 33, /*%< Server Selection. */
+ ns_t_atma = 34, /*%< ATM Address */
+ ns_t_naptr = 35, /*%< Naming Authority PoinTeR */
+ ns_t_kx = 36, /*%< Key Exchange */
+ ns_t_cert = 37, /*%< Certification record */
+ ns_t_a6 = 38, /*%< IPv6 address (deprecates AAAA) */
+ ns_t_dname = 39, /*%< Non-terminal DNAME (for IPv6) */
+ ns_t_sink = 40, /*%< Kitchen sink (experimentatl) */
+ ns_t_opt = 41, /*%< EDNS0 option (meta-RR) */
+ ns_t_apl = 42, /*%< Address prefix list (RFC3123) */
+ ns_t_tkey = 249, /*%< Transaction key */
+ ns_t_tsig = 250, /*%< Transaction signature. */
+ ns_t_ixfr = 251, /*%< Incremental zone transfer. */
+ ns_t_axfr = 252, /*%< Transfer zone of authority. */
+ ns_t_mailb = 253, /*%< Transfer mailbox records. */
+ ns_t_maila = 254, /*%< Transfer mail agent records. */
+ ns_t_any = 255, /*%< Wildcard match. */
+ ns_t_zxfr = 256, /*%< BIND-specific, nonstandard. */
+ ns_t_max = 65536
+} ns_type;
+
+/* Exclusively a QTYPE? (not also an RTYPE) */
+#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \
+ (t) == ns_t_mailb || (t) == ns_t_maila)
+/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */
+#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt)
+/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */
+#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t))
+#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr)
+#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \
+ (t) == ns_t_zxfr)
+
+/*%
+ * Values for class field
+ */
+typedef enum __ns_class {
+ ns_c_invalid = 0, /*%< Cookie. */
+ ns_c_in = 1, /*%< Internet. */
+ ns_c_2 = 2, /*%< unallocated/unsupported. */
+ ns_c_chaos = 3, /*%< MIT Chaos-net. */
+ ns_c_hs = 4, /*%< MIT Hesiod. */
+ /* Query class values which do not appear in resource records */
+ ns_c_none = 254, /*%< for prereq. sections in update requests */
+ ns_c_any = 255, /*%< Wildcard match. */
+ ns_c_max = 65536
+} ns_class;
+
+/* DNSSEC constants. */
+
+typedef enum __ns_key_types {
+ ns_kt_rsa = 1, /*%< key type RSA/MD5 */
+ ns_kt_dh = 2, /*%< Diffie Hellman */
+ ns_kt_dsa = 3, /*%< Digital Signature Standard (MANDATORY) */
+ ns_kt_private = 254 /*%< Private key type starts with OID */
+} ns_key_types;
+
+typedef enum __ns_cert_types {
+ cert_t_pkix = 1, /*%< PKIX (X.509v3) */
+ cert_t_spki = 2, /*%< SPKI */
+ cert_t_pgp = 3, /*%< PGP */
+ cert_t_url = 253, /*%< URL private type */
+ cert_t_oid = 254 /*%< OID private type */
+} ns_cert_types;
+
+/* Flags field of the KEY RR rdata. */
+#define NS_KEY_TYPEMASK 0xC000 /*%< Mask for "type" bits */
+#define NS_KEY_TYPE_AUTH_CONF 0x0000 /*%< Key usable for both */
+#define NS_KEY_TYPE_CONF_ONLY 0x8000 /*%< Key usable for confidentiality */
+#define NS_KEY_TYPE_AUTH_ONLY 0x4000 /*%< Key usable for authentication */
+#define NS_KEY_TYPE_NO_KEY 0xC000 /*%< No key usable for either; no key */
+/* The type bits can also be interpreted independently, as single bits: */
+#define NS_KEY_NO_AUTH 0x8000 /*%< Key unusable for authentication */
+#define NS_KEY_NO_CONF 0x4000 /*%< Key unusable for confidentiality */
+#define NS_KEY_RESERVED2 0x2000 /* Security is *mandatory* if bit=0 */
+#define NS_KEY_EXTENDED_FLAGS 0x1000 /*%< reserved - must be zero */
+#define NS_KEY_RESERVED4 0x0800 /*%< reserved - must be zero */
+#define NS_KEY_RESERVED5 0x0400 /*%< reserved - must be zero */
+#define NS_KEY_NAME_TYPE 0x0300 /*%< these bits determine the type */
+#define NS_KEY_NAME_USER 0x0000 /*%< key is assoc. with user */
+#define NS_KEY_NAME_ENTITY 0x0200 /*%< key is assoc. with entity eg host */
+#define NS_KEY_NAME_ZONE 0x0100 /*%< key is zone key */
+#define NS_KEY_NAME_RESERVED 0x0300 /*%< reserved meaning */
+#define NS_KEY_RESERVED8 0x0080 /*%< reserved - must be zero */
+#define NS_KEY_RESERVED9 0x0040 /*%< reserved - must be zero */
+#define NS_KEY_RESERVED10 0x0020 /*%< reserved - must be zero */
+#define NS_KEY_RESERVED11 0x0010 /*%< reserved - must be zero */
+#define NS_KEY_SIGNATORYMASK 0x000F /*%< key can sign RR's of same name */
+#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \
+ NS_KEY_RESERVED4 | \
+ NS_KEY_RESERVED5 | \
+ NS_KEY_RESERVED8 | \
+ NS_KEY_RESERVED9 | \
+ NS_KEY_RESERVED10 | \
+ NS_KEY_RESERVED11 )
+#define NS_KEY_RESERVED_BITMASK2 0xFFFF /*%< no bits defined here */
+/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */
+#define NS_ALG_MD5RSA 1 /*%< MD5 with RSA */
+#define NS_ALG_DH 2 /*%< Diffie Hellman KEY */
+#define NS_ALG_DSA 3 /*%< DSA KEY */
+#define NS_ALG_DSS NS_ALG_DSA
+#define NS_ALG_EXPIRE_ONLY 253 /*%< No alg, no security */
+#define NS_ALG_PRIVATE_OID 254 /*%< Key begins with OID giving alg */
+/* Protocol values */
+/* value 0 is reserved */
+#define NS_KEY_PROT_TLS 1
+#define NS_KEY_PROT_EMAIL 2
+#define NS_KEY_PROT_DNSSEC 3
+#define NS_KEY_PROT_IPSEC 4
+#define NS_KEY_PROT_ANY 255
+
+/* Signatures */
+#define NS_MD5RSA_MIN_BITS 512 /*%< Size of a mod or exp in bits */
+#define NS_MD5RSA_MAX_BITS 4096
+ /* Total of binary mod and exp */
+#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3)
+ /* Max length of text sig block */
+#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4)
+#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8)
+#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8)
+
+#define NS_DSA_SIG_SIZE 41
+#define NS_DSA_MIN_SIZE 213
+#define NS_DSA_MAX_BYTES 405
+
+/* Offsets into SIG record rdata to find various values */
+#define NS_SIG_TYPE 0 /*%< Type flags */
+#define NS_SIG_ALG 2 /*%< Algorithm */
+#define NS_SIG_LABELS 3 /*%< How many labels in name */
+#define NS_SIG_OTTL 4 /*%< Original TTL */
+#define NS_SIG_EXPIR 8 /*%< Expiration time */
+#define NS_SIG_SIGNED 12 /*%< Signature time */
+#define NS_SIG_FOOT 16 /*%< Key footprint */
+#define NS_SIG_SIGNER 18 /*%< Domain name of who signed it */
+/* How RR types are represented as bit-flags in NXT records */
+#define NS_NXT_BITS 8
+#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS)))
+#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS)))
+#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS)))
+#define NS_NXT_MAX 127
+
+/*%
+ * EDNS0 extended flags, 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 <arpa/nameser_compat.h>
+#endif
+
+#endif /* !_ARPA_NAMESER_H_ */
+/*! \file */
diff --git a/lib/bind/include/arpa/nameser_compat.h b/lib/bind/include/arpa/nameser_compat.h
new file mode 100644
index 0000000..3713293
--- /dev/null
+++ b/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.5.18.3 2006/05/19 02:36:00 marka Exp $
+ */
+
+#ifndef _ARPA_NAMESER_COMPAT_
+#define _ARPA_NAMESER_COMPAT_
+
+#define __BIND 19950621 /*%< (DEAD) interface version stamp. */
+#ifndef BYTE_ORDER
+#if (BSD >= 199103)
+# include <machine/endian.h>
+#else
+#ifdef __linux
+# include <endian.h>
+#else
+#define LITTLE_ENDIAN 1234 /*%< least-significant byte first (vax, pc) */
+#define BIG_ENDIAN 4321 /*%< most-significant byte first (IBM, net) */
+#define PDP_ENDIAN 3412 /*%< LSB first in word, MSW first in long (pdp) */
+#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \
+ defined(__i386__) || defined(__i386) || defined(__amd64__) || \
+ defined(__x86_64__) || defined(MIPSEL) || defined(_MIPSEL) || \
+ defined(BIT_ZERO_ON_RIGHT) || defined(__alpha__) || defined(__alpha) || \
+ (defined(__Lynx__) && defined(__x86__))
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
+ defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
+ defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
+ defined(apollo) || defined(__convex__) || defined(_CRAY) || \
+ defined(__hppa) || defined(__hp9000) || \
+ defined(__hp9000s300) || defined(__hp9000s700) || \
+ defined(__hp3000s900) || defined(__hpux) || defined(MPE) || \
+ defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc) || \
+ (defined(__Lynx__) && \
+ (defined(__68k__) || defined(__sparc__) || defined(__powerpc__)))
+#define BYTE_ORDER BIG_ENDIAN
+#endif
+#endif /* __linux */
+#endif /* BSD */
+#endif /* BYTE_ORDER */
+
+#if !defined(BYTE_ORDER) || \
+ (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \
+ BYTE_ORDER != PDP_ENDIAN)
+ /* you must determine what the correct bit order is for
+ * your compiler - the next line is an intentional error
+ * which will force your compiles to bomb until you fix
+ * the above macros.
+ */
+ error "Undefined or invalid BYTE_ORDER";
+#endif
+
+/*%
+ * Structure for query header. The order of the fields is machine- and
+ * compiler-dependent, depending on the byte/bit order and the layout
+ * of bit fields. We use bit fields only in int variables, as this
+ * is all ANSI requires. This requires a somewhat confusing rearrangement.
+ */
+
+typedef struct {
+ unsigned id :16; /*%< query identification number */
+#if BYTE_ORDER == BIG_ENDIAN
+ /* fields in third byte */
+ unsigned qr: 1; /*%< response flag */
+ unsigned opcode: 4; /*%< purpose of message */
+ unsigned aa: 1; /*%< authoritive answer */
+ unsigned tc: 1; /*%< truncated message */
+ unsigned rd: 1; /*%< recursion desired */
+ /* fields in fourth byte */
+ unsigned ra: 1; /*%< recursion available */
+ unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */
+ unsigned ad: 1; /*%< authentic data from named */
+ unsigned cd: 1; /*%< checking disabled by resolver */
+ unsigned rcode :4; /*%< response code */
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+ /* fields in third byte */
+ unsigned rd :1; /*%< recursion desired */
+ unsigned tc :1; /*%< truncated message */
+ unsigned aa :1; /*%< authoritive answer */
+ unsigned opcode :4; /*%< purpose of message */
+ unsigned qr :1; /*%< response flag */
+ /* fields in fourth byte */
+ unsigned rcode :4; /*%< response code */
+ unsigned cd: 1; /*%< checking disabled by resolver */
+ unsigned ad: 1; /*%< authentic data from named */
+ unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */
+ unsigned ra :1; /*%< recursion available */
+#endif
+ /* remaining bytes */
+ unsigned qdcount :16; /*%< number of question entries */
+ unsigned ancount :16; /*%< number of answer entries */
+ unsigned nscount :16; /*%< number of authority entries */
+ unsigned arcount :16; /*%< number of resource entries */
+} HEADER;
+
+#define PACKETSZ NS_PACKETSZ
+#define MAXDNAME NS_MAXDNAME
+#define MAXCDNAME NS_MAXCDNAME
+#define MAXLABEL NS_MAXLABEL
+#define HFIXEDSZ NS_HFIXEDSZ
+#define QFIXEDSZ NS_QFIXEDSZ
+#define RRFIXEDSZ NS_RRFIXEDSZ
+#define INT32SZ NS_INT32SZ
+#define INT16SZ NS_INT16SZ
+#define INT8SZ NS_INT8SZ
+#define INADDRSZ NS_INADDRSZ
+#define IN6ADDRSZ NS_IN6ADDRSZ
+#define INDIR_MASK NS_CMPRSFLGS
+#define NAMESERVER_PORT NS_DEFAULTPORT
+
+#define S_ZONE ns_s_zn
+#define S_PREREQ ns_s_pr
+#define S_UPDATE ns_s_ud
+#define S_ADDT ns_s_ar
+
+#define QUERY ns_o_query
+#define IQUERY ns_o_iquery
+#define STATUS ns_o_status
+#define NS_NOTIFY_OP ns_o_notify
+#define NS_UPDATE_OP ns_o_update
+
+#define NOERROR ns_r_noerror
+#define FORMERR ns_r_formerr
+#define SERVFAIL ns_r_servfail
+#define NXDOMAIN ns_r_nxdomain
+#define NOTIMP ns_r_notimpl
+#define REFUSED ns_r_refused
+#define YXDOMAIN ns_r_yxdomain
+#define YXRRSET ns_r_yxrrset
+#define NXRRSET ns_r_nxrrset
+#define NOTAUTH ns_r_notauth
+#define NOTZONE ns_r_notzone
+/*#define BADSIG ns_r_badsig*/
+/*#define BADKEY ns_r_badkey*/
+/*#define BADTIME ns_r_badtime*/
+
+
+#define DELETE ns_uop_delete
+#define ADD ns_uop_add
+
+#define T_A ns_t_a
+#define T_NS ns_t_ns
+#define T_MD ns_t_md
+#define T_MF ns_t_mf
+#define T_CNAME ns_t_cname
+#define T_SOA ns_t_soa
+#define T_MB ns_t_mb
+#define T_MG ns_t_mg
+#define T_MR ns_t_mr
+#define T_NULL ns_t_null
+#define T_WKS ns_t_wks
+#define T_PTR ns_t_ptr
+#define T_HINFO ns_t_hinfo
+#define T_MINFO ns_t_minfo
+#define T_MX ns_t_mx
+#define T_TXT ns_t_txt
+#define T_RP ns_t_rp
+#define T_AFSDB ns_t_afsdb
+#define T_X25 ns_t_x25
+#define T_ISDN ns_t_isdn
+#define T_RT ns_t_rt
+#define T_NSAP ns_t_nsap
+#define T_NSAP_PTR ns_t_nsap_ptr
+#define T_SIG ns_t_sig
+#define T_KEY ns_t_key
+#define T_PX ns_t_px
+#define T_GPOS ns_t_gpos
+#define T_AAAA ns_t_aaaa
+#define T_LOC ns_t_loc
+#define T_NXT ns_t_nxt
+#define T_EID ns_t_eid
+#define T_NIMLOC ns_t_nimloc
+#define T_SRV ns_t_srv
+#define T_ATMA ns_t_atma
+#define T_NAPTR ns_t_naptr
+#define T_A6 ns_t_a6
+#define T_TSIG ns_t_tsig
+#define T_IXFR ns_t_ixfr
+#define T_AXFR ns_t_axfr
+#define T_MAILB ns_t_mailb
+#define T_MAILA ns_t_maila
+#define T_ANY ns_t_any
+
+#define C_IN ns_c_in
+#define C_CHAOS ns_c_chaos
+#define C_HS ns_c_hs
+/* BIND_UPDATE */
+#define C_NONE ns_c_none
+#define C_ANY ns_c_any
+
+#define GETSHORT NS_GET16
+#define GETLONG NS_GET32
+#define PUTSHORT NS_PUT16
+#define PUTLONG NS_PUT32
+
+#endif /* _ARPA_NAMESER_COMPAT_ */
+/*! \file */
diff --git a/lib/bind/include/fd_setsize.h b/lib/bind/include/fd_setsize.h
new file mode 100644
index 0000000..0e21049
--- /dev/null
+++ b/lib/bind/include/fd_setsize.h
@@ -0,0 +1,10 @@
+#ifndef _FD_SETSIZE_H
+#define _FD_SETSIZE_H
+
+/*%
+ * If you need a bigger FD_SETSIZE, this is NOT the place to set it.
+ * This file is a fallback for BIND ports which don't specify their own.
+ */
+
+#endif /* _FD_SETSIZE_H */
+/*! \file */
diff --git a/lib/bind/include/hesiod.h b/lib/bind/include/hesiod.h
new file mode 100644
index 0000000..30c08d0
--- /dev/null
+++ b/lib/bind/include/hesiod.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file
+ * \brief
+ * This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>.
+ */
+
+/*
+ * $Id: hesiod.h,v 1.3.18.1 2005/04/27 05:00:49 sra Exp $
+ */
+
+#ifndef _HESIOD_H_INCLUDED
+#define _HESIOD_H_INCLUDED
+
+int hesiod_init __P((void **));
+void hesiod_end __P((void *));
+char * hesiod_to_bind __P((void *, const char *, const char *));
+char ** hesiod_resolve __P((void *, const char *, const char *));
+void hesiod_free_list __P((void *, char **));
+struct __res_state * __hesiod_res_get __P((void *));
+void __hesiod_res_set __P((void *, struct __res_state *,
+ void (*)(void *)));
+
+#endif /*_HESIOD_H_INCLUDED*/
diff --git a/lib/bind/include/irp.h b/lib/bind/include/irp.h
new file mode 100644
index 0000000..21d8f48
--- /dev/null
+++ b/lib/bind/include/irp.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irp.h,v 1.3.18.1 2005/04/27 05:00:49 sra Exp $
+ */
+
+#ifndef _IRP_H_INCLUDED
+#define _IRP_H_INCLUDED
+
+/*! \file */
+
+#define IRPD_TIMEOUT 30 /*%< seconds */
+#define IRPD_MAXSESS 50 /*%< number of simultaneous sessions. */
+#define IRPD_PORT 6660 /*%< 10 times the number of the beast. */
+#define IRPD_PATH "/var/run/irpd" /*%< af_unix socket path */
+
+/* If sets the environment variable IRPDSERVER to an IP address
+ (e.g. "192.5.5.1"), then that's the host the client expects irpd to be
+ running on. */
+#define IRPD_HOST_ENV "IRPDSERVER"
+
+/* Protocol response codes. */
+#define IRPD_WELCOME_CODE 200
+#define IRPD_NOT_WELCOME_CODE 500
+
+#define IRPD_GETHOST_ERROR 510
+#define IRPD_GETHOST_NONE 210
+#define IRPD_GETHOST_OK 211
+#define IRPD_GETHOST_SETOK 212
+
+#define IRPD_GETNET_ERROR 520
+#define IRPD_GETNET_NONE 220
+#define IRPD_GETNET_OK 221
+#define IRPD_GETNET_SETOK 222
+
+#define IRPD_GETUSER_ERROR 530
+#define IRPD_GETUSER_NONE 230
+#define IRPD_GETUSER_OK 231
+#define IRPD_GETUSER_SETOK 232
+
+#define IRPD_GETGROUP_ERROR 540
+#define IRPD_GETGROUP_NONE 240
+#define IRPD_GETGROUP_OK 241
+#define IRPD_GETGROUP_SETOK 242
+
+#define IRPD_GETSERVICE_ERROR 550
+#define IRPD_GETSERVICE_NONE 250
+#define IRPD_GETSERVICE_OK 251
+#define IRPD_GETSERVICE_SETOK 252
+
+#define IRPD_GETPROTO_ERROR 560
+#define IRPD_GETPROTO_NONE 260
+#define IRPD_GETPROTO_OK 261
+#define IRPD_GETPROTO_SETOK 262
+
+#define IRPD_GETNETGR_ERROR 570
+#define IRPD_GETNETGR_NONE 270
+#define IRPD_GETNETGR_OK 271
+#define IRPD_GETNETGR_NOMORE 272
+#define IRPD_GETNETGR_MATCHES 273
+#define IRPD_GETNETGR_NOMATCH 274
+#define IRPD_GETNETGR_SETOK 275
+#define IRPD_GETNETGR_SETERR 276
+
+#define irs_irp_read_body __irs_irp_read_body
+#define irs_irp_read_response __irs_irp_read_response
+#define irs_irp_disconnect __irs_irp_disconnect
+#define irs_irp_connect __irs_irp_connect
+#define irs_irp_connection_setup __irs_irp_connection_setup
+#define irs_irp_send_command __irs_irp_send_command
+
+struct irp_p;
+
+char *irs_irp_read_body(struct irp_p *, size_t *);
+int irs_irp_read_response(struct irp_p *, char *, size_t);
+void irs_irp_disconnect(struct irp_p *);
+int irs_irp_connect(struct irp_p *);
+int irs_irp_is_connected(struct irp_p *);
+int irs_irp_connection_setup(struct irp_p *, int *);
+#ifdef __GNUC__
+int irs_irp_send_command(struct irp_p *, const char *, ...)
+ __attribute__((__format__(__printf__, 2, 3)));
+#else
+int irs_irp_send_command(struct irp_p *, const char *, ...);
+#endif
+int irs_irp_get_full_response(struct irp_p *, int *, char *, size_t,
+ char **, size_t *);
+int irs_irp_read_line(struct irp_p *, char *, int);
+
+#endif
+
+/*! \file */
diff --git a/lib/bind/include/irs.h b/lib/bind/include/irs.h
new file mode 100644
index 0000000..582ba5b
--- /dev/null
+++ b/lib/bind/include/irs.h
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irs.h,v 1.4.18.1 2005/04/27 05:00:49 sra Exp $
+ */
+
+#ifndef _IRS_H_INCLUDED
+#define _IRS_H_INCLUDED
+
+/*! \file */
+
+#include <sys/types.h>
+
+#include <arpa/nameser.h>
+
+#include <grp.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <pwd.h>
+
+/*%
+ * This is the group map class.
+ */
+struct irs_gr {
+ void * private;
+ void (*close) __P((struct irs_gr *));
+ struct group * (*next) __P((struct irs_gr *));
+ struct group * (*byname) __P((struct irs_gr *, const char *));
+ struct group * (*bygid) __P((struct irs_gr *, gid_t));
+ int (*list) __P((struct irs_gr *, const char *,
+ gid_t, gid_t *, int *));
+ void (*rewind) __P((struct irs_gr *));
+ void (*minimize) __P((struct irs_gr *));
+ struct __res_state * (*res_get) __P((struct irs_gr *));
+ void (*res_set) __P((struct irs_gr *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is the password map class.
+ */
+struct irs_pw {
+ void * private;
+ void (*close) __P((struct irs_pw *));
+ struct passwd * (*next) __P((struct irs_pw *));
+ struct passwd * (*byname) __P((struct irs_pw *, const char *));
+ struct passwd * (*byuid) __P((struct irs_pw *, uid_t));
+ void (*rewind) __P((struct irs_pw *));
+ void (*minimize) __P((struct irs_pw *));
+ struct __res_state * (*res_get) __P((struct irs_pw *));
+ void (*res_set) __P((struct irs_pw *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is the service map class.
+ */
+struct irs_sv {
+ void * private;
+ void (*close) __P((struct irs_sv *));
+ struct servent *(*byname) __P((struct irs_sv *,
+ const char *, const char *));
+ struct servent *(*byport) __P((struct irs_sv *, int, const char *));
+ struct servent *(*next) __P((struct irs_sv *));
+ void (*rewind) __P((struct irs_sv *));
+ void (*minimize) __P((struct irs_sv *));
+ struct __res_state * (*res_get) __P((struct irs_sv *));
+ void (*res_set) __P((struct irs_sv *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is the protocols map class.
+ */
+struct irs_pr {
+ void * private;
+ void (*close) __P((struct irs_pr *));
+ struct protoent *(*byname) __P((struct irs_pr *, const char *));
+ struct protoent *(*bynumber) __P((struct irs_pr *, int));
+ struct protoent *(*next) __P((struct irs_pr *));
+ void (*rewind) __P((struct irs_pr *));
+ void (*minimize) __P((struct irs_pr *));
+ struct __res_state * (*res_get) __P((struct irs_pr *));
+ void (*res_set) __P((struct irs_pr *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is the hosts map class.
+ */
+struct irs_ho {
+ void * private;
+ void (*close) __P((struct irs_ho *));
+ struct hostent *(*byname) __P((struct irs_ho *, const char *));
+ struct hostent *(*byname2) __P((struct irs_ho *, const char *, int));
+ struct hostent *(*byaddr) __P((struct irs_ho *,
+ const void *, int, int));
+ struct hostent *(*next) __P((struct irs_ho *));
+ void (*rewind) __P((struct irs_ho *));
+ void (*minimize) __P((struct irs_ho *));
+ struct __res_state * (*res_get) __P((struct irs_ho *));
+ void (*res_set) __P((struct irs_ho *, res_state,
+ void (*)(void *)));
+ struct addrinfo *(*addrinfo) __P((struct irs_ho *, const char *,
+ const struct addrinfo *));
+};
+
+/*%
+ * This is the networks map class.
+ */
+struct irs_nw {
+ void * private;
+ void (*close) __P((struct irs_nw *));
+ struct nwent * (*byname) __P((struct irs_nw *, const char *, int));
+ struct nwent * (*byaddr) __P((struct irs_nw *, void *, int, int));
+ struct nwent * (*next) __P((struct irs_nw *));
+ void (*rewind) __P((struct irs_nw *));
+ void (*minimize) __P((struct irs_nw *));
+ struct __res_state * (*res_get) __P((struct irs_nw *));
+ void (*res_set) __P((struct irs_nw *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is the netgroups map class.
+ */
+struct irs_ng {
+ void * private;
+ void (*close) __P((struct irs_ng *));
+ int (*next) __P((struct irs_ng *, const char **,
+ const char **, const char **));
+ int (*test) __P((struct irs_ng *, const char *,
+ const char *, const char *,
+ const char *));
+ void (*rewind) __P((struct irs_ng *, const char *));
+ void (*minimize) __P((struct irs_ng *));
+};
+
+/*%
+ * This is the generic map class, which copies the front of all others.
+ */
+struct irs_map {
+ void * private;
+ void (*close) __P((void *));
+};
+
+/*%
+ * This is the accessor class. It contains pointers to all of the
+ * initializers for the map classes for a particular accessor.
+ */
+struct irs_acc {
+ void * private;
+ void (*close) __P((struct irs_acc *));
+ struct irs_gr * (*gr_map) __P((struct irs_acc *));
+ struct irs_pw * (*pw_map) __P((struct irs_acc *));
+ struct irs_sv * (*sv_map) __P((struct irs_acc *));
+ struct irs_pr * (*pr_map) __P((struct irs_acc *));
+ struct irs_ho * (*ho_map) __P((struct irs_acc *));
+ struct irs_nw * (*nw_map) __P((struct irs_acc *));
+ struct irs_ng * (*ng_map) __P((struct irs_acc *));
+ struct __res_state * (*res_get) __P((struct irs_acc *));
+ void (*res_set) __P((struct irs_acc *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is because the official definition of "struct netent" has no
+ * concept of CIDR even though it allows variant address families (on
+ * output but not input). The compatibility stubs convert the structs
+ * below into "struct netent"'s.
+ */
+struct nwent {
+ char *n_name; /*%< official name of net */
+ char **n_aliases; /*%< alias list */
+ int n_addrtype; /*%< net address type */
+ void *n_addr; /*%< network address */
+ int n_length; /*%< address length, in bits */
+};
+
+/*%
+ * Hide external function names from POSIX.
+ */
+#define irs_gen_acc __irs_gen_acc
+#define irs_lcl_acc __irs_lcl_acc
+#define irs_dns_acc __irs_dns_acc
+#define irs_nis_acc __irs_nis_acc
+#define irs_irp_acc __irs_irp_acc
+#define irs_destroy __irs_destroy
+#define irs_dns_gr __irs_dns_gr
+#define irs_dns_ho __irs_dns_ho
+#define irs_dns_nw __irs_dns_nw
+#define irs_dns_pr __irs_dns_pr
+#define irs_dns_pw __irs_dns_pw
+#define irs_dns_sv __irs_dns_sv
+#define irs_gen_gr __irs_gen_gr
+#define irs_gen_ho __irs_gen_ho
+#define irs_gen_ng __irs_gen_ng
+#define irs_gen_nw __irs_gen_nw
+#define irs_gen_pr __irs_gen_pr
+#define irs_gen_pw __irs_gen_pw
+#define irs_gen_sv __irs_gen_sv
+#define irs_irp_get_full_response __irs_irp_get_full_response
+#define irs_irp_gr __irs_irp_gr
+#define irs_irp_ho __irs_irp_ho
+#define irs_irp_is_connected __irs_irp_is_connected
+#define irs_irp_ng __irs_irp_ng
+#define irs_irp_nw __irs_irp_nw
+#define irs_irp_pr __irs_irp_pr
+#define irs_irp_pw __irs_irp_pw
+#define irs_irp_read_line __irs_irp_read_line
+#define irs_irp_sv __irs_irp_sv
+#define irs_lcl_gr __irs_lcl_gr
+#define irs_lcl_ho __irs_lcl_ho
+#define irs_lcl_ng __irs_lcl_ng
+#define irs_lcl_nw __irs_lcl_nw
+#define irs_lcl_pr __irs_lcl_pr
+#define irs_lcl_pw __irs_lcl_pw
+#define irs_lcl_sv __irs_lcl_sv
+#define irs_nis_gr __irs_nis_gr
+#define irs_nis_ho __irs_nis_ho
+#define irs_nis_ng __irs_nis_ng
+#define irs_nis_nw __irs_nis_nw
+#define irs_nis_pr __irs_nis_pr
+#define irs_nis_pw __irs_nis_pw
+#define irs_nis_sv __irs_nis_sv
+#define net_data_create __net_data_create
+#define net_data_destroy __net_data_destroy
+#define net_data_minimize __net_data_minimize
+
+/*%
+ * Externs.
+ */
+extern struct irs_acc * irs_gen_acc __P((const char *, const char *));
+extern struct irs_acc * irs_lcl_acc __P((const char *));
+extern struct irs_acc * irs_dns_acc __P((const char *));
+extern struct irs_acc * irs_nis_acc __P((const char *));
+extern struct irs_acc * irs_irp_acc __P((const char *));
+
+extern void irs_destroy __P((void));
+
+/*%
+ * These forward declarations are for the semi-private functions in
+ * the get*.c files. Each of these funcs implements the real get*
+ * functionality and the standard versions are just wrappers that
+ * call these. Apart from the wrappers, only irpd is expected to
+ * call these directly, hence these decls are put here and not in
+ * the /usr/include replacements.
+ */
+
+struct net_data; /*%< forward */
+/*
+ * net_data_create gets a singleton net_data object. net_data_init
+ * creates as many net_data objects as times it is called. Clients using
+ * the default interface will use net_data_create by default. Servers will
+ * probably want net_data_init (one call per client)
+ */
+struct net_data *net_data_create __P((const char *));
+struct net_data *net_data_init __P((const char *));
+void net_data_destroy __P((void *));
+
+extern struct group *getgrent_p __P((struct net_data *));
+extern struct group *getgrnam_p __P((const char *, struct net_data *));
+extern struct group *getgrgid_p __P((gid_t, struct net_data *));
+extern int setgroupent_p __P((int, struct net_data *));
+extern void endgrent_p __P((struct net_data *));
+extern int getgrouplist_p __P((const char *, gid_t, gid_t *, int *,
+ struct net_data *));
+
+#ifdef SETGRENT_VOID
+extern void setgrent_p __P((struct net_data *));
+#else
+extern int setgrent_p __P((struct net_data *));
+#endif
+
+extern struct hostent *gethostbyname_p __P((const char *,
+ struct net_data *));
+extern struct hostent *gethostbyname2_p __P((const char *, int,
+ struct net_data *));
+extern struct hostent *gethostbyaddr_p __P((const char *, int, int,
+ struct net_data *));
+extern struct hostent *gethostent_p __P((struct net_data *));
+extern void sethostent_p __P((int, struct net_data *));
+extern void endhostent_p __P((struct net_data *));
+extern struct hostent *getipnodebyname_p __P((const char *, int, int, int *,
+ struct net_data *));
+extern struct hostent *getipnodebyaddr_p __P((const void *, size_t,
+ int, int *, struct net_data *));
+
+extern struct netent *getnetent_p __P((struct net_data *));
+extern struct netent *getnetbyname_p __P((const char *, struct net_data *));
+extern struct netent *getnetbyaddr_p __P((unsigned long, int,
+ struct net_data *));
+extern void setnetent_p __P((int, struct net_data *));
+extern void endnetent_p __P((struct net_data *));
+
+extern void setnetgrent_p __P((const char *, struct net_data *));
+extern void endnetgrent_p __P((struct net_data *));
+extern int innetgr_p __P((const char *, const char *, const char *,
+ const char *, struct net_data *));
+extern int getnetgrent_p __P((const char **, const char **,
+ const char **, struct net_data *));
+
+extern struct protoent *getprotoent_p __P((struct net_data *));
+extern struct protoent *getprotobyname_p __P((const char *,
+ struct net_data *));
+extern struct protoent *getprotobynumber_p __P((int, struct net_data *));
+extern void setprotoent_p __P((int, struct net_data *));
+extern void endprotoent_p __P((struct net_data *));
+
+
+extern struct passwd *getpwent_p __P((struct net_data *));
+extern struct passwd *getpwnam_p __P((const char *, struct net_data *));
+extern struct passwd *getpwuid_p __P((uid_t, struct net_data *));
+extern int setpassent_p __P((int, struct net_data *));
+extern void endpwent_p __P((struct net_data *));
+
+#ifdef SETPWENT_VOID
+extern void setpwent_p __P((struct net_data *));
+#else
+extern int setpwent_p __P((struct net_data *));
+#endif
+
+extern struct servent *getservent_p __P((struct net_data *));
+extern struct servent *getservbyname_p __P((const char *, const char *,
+ struct net_data *));
+extern struct servent *getservbyport_p __P((int, const char *,
+ struct net_data *));
+extern void setservent_p __P((int, struct net_data *));
+extern void endservent_p __P((struct net_data *));
+
+#endif /*_IRS_H_INCLUDED*/
+
+/*! \file */
diff --git a/lib/bind/include/isc/assertions.h b/lib/bind/include/isc/assertions.h
new file mode 100644
index 0000000..2ed768d
--- /dev/null
+++ b/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.2.18.1 2005/04/27 05:00:50 sra 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 */
+/*! \file */
diff --git a/lib/bind/include/isc/ctl.h b/lib/bind/include/isc/ctl.h
new file mode 100644
index 0000000..0f6fe94
--- /dev/null
+++ b/lib/bind/include/isc/ctl.h
@@ -0,0 +1,112 @@
+#ifndef ISC_CTL_H
+#define ISC_CTL_H
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: ctl.h,v 1.4.18.1 2005/04/27 05:00:51 sra Exp $
+ */
+
+/*! \file */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <isc/eventlib.h>
+
+/* Macros. */
+
+#define CTL_MORE 0x0001 /*%< More will be / should be sent. */
+#define CTL_EXIT 0x0002 /*%< Close connection after this. */
+#define CTL_DATA 0x0004 /*%< Go into / this is DATA mode. */
+/* Types. */
+
+struct ctl_cctx;
+struct ctl_sctx;
+struct ctl_sess;
+struct ctl_verb;
+
+enum ctl_severity { ctl_debug, ctl_warning, ctl_error };
+
+typedef void (*ctl_logfunc)(enum ctl_severity, const char *, ...);
+
+typedef void (*ctl_verbfunc)(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *, const char *,
+ u_int, const void *, void *);
+
+typedef void (*ctl_srvrdone)(struct ctl_sctx *, struct ctl_sess *, void *);
+
+typedef void (*ctl_clntdone)(struct ctl_cctx *, void *, const char *, u_int);
+
+struct ctl_verb {
+ const char * name;
+ ctl_verbfunc func;
+ const char * help;
+};
+
+/* General symbols. */
+
+#define ctl_logger __ctl_logger
+
+#ifdef __GNUC__
+void ctl_logger(enum ctl_severity, const char *, ...)
+ __attribute__((__format__(__printf__, 2, 3)));
+#else
+void ctl_logger(enum ctl_severity, const char *, ...);
+#endif
+
+/* Client symbols. */
+
+#define ctl_client __ctl_client
+#define ctl_endclient __ctl_endclient
+#define ctl_command __ctl_command
+
+struct ctl_cctx * ctl_client(evContext, const struct sockaddr *, size_t,
+ const struct sockaddr *, size_t,
+ ctl_clntdone, void *,
+ u_int, ctl_logfunc);
+void ctl_endclient(struct ctl_cctx *);
+int ctl_command(struct ctl_cctx *, const char *, size_t,
+ ctl_clntdone, void *);
+
+/* Server symbols. */
+
+#define ctl_server __ctl_server
+#define ctl_endserver __ctl_endserver
+#define ctl_response __ctl_response
+#define ctl_sendhelp __ctl_sendhelp
+#define ctl_getcsctx __ctl_getcsctx
+#define ctl_setcsctx __ctl_setcsctx
+
+struct ctl_sctx * ctl_server(evContext, const struct sockaddr *, size_t,
+ const struct ctl_verb *,
+ u_int, u_int,
+ u_int, int, int,
+ ctl_logfunc, void *);
+void ctl_endserver(struct ctl_sctx *);
+void ctl_response(struct ctl_sess *, u_int,
+ const char *, u_int, const void *,
+ ctl_srvrdone, void *,
+ const char *, size_t);
+void ctl_sendhelp(struct ctl_sess *, u_int);
+void * ctl_getcsctx(struct ctl_sess *);
+void * ctl_setcsctx(struct ctl_sess *, void *);
+
+#endif /*ISC_CTL_H*/
+
+/*! \file */
diff --git a/lib/bind/include/isc/dst.h b/lib/bind/include/isc/dst.h
new file mode 100644
index 0000000..90a9e67
--- /dev/null
+++ b/lib/bind/include/isc/dst.h
@@ -0,0 +1,168 @@
+#ifndef DST_H
+#define DST_H
+
+#ifndef HAS_DST_KEY
+typedef struct dst_key {
+ char *dk_key_name; /*%< name of the key */
+ int dk_key_size; /*%< this is the size of the key in bits */
+ int dk_proto; /*%< what protocols this key can be used for */
+ int dk_alg; /*%< algorithm number from key record */
+ u_int32_t dk_flags; /*%< and the flags of the public key */
+ u_int16_t dk_id; /*%< identifier of the key */
+} DST_KEY;
+#endif /* HAS_DST_KEY */
+/*
+ * do not taint namespace
+ */
+#define dst_bsafe_init __dst_bsafe_init
+#define dst_buffer_to_key __dst_buffer_to_key
+#define dst_check_algorithm __dst_check_algorithm
+#define dst_compare_keys __dst_compare_keys
+#define dst_cylink_init __dst_cylink_init
+#define dst_dnskey_to_key __dst_dnskey_to_key
+#define dst_eay_dss_init __dst_eay_dss_init
+#define dst_free_key __dst_free_key
+#define dst_generate_key __dst_generate_key
+#define dst_hmac_md5_init __dst_hmac_md5_init
+#define dst_init __dst_init
+#define dst_key_to_buffer __dst_key_to_buffer
+#define dst_key_to_dnskey __dst_key_to_dnskey
+#define dst_read_key __dst_read_key
+#define dst_rsaref_init __dst_rsaref_init
+#define dst_s_build_filename __dst_s_build_filename
+#define dst_s_calculate_bits __dst_s_calculate_bits
+#define dst_s_conv_bignum_b64_to_u8 __dst_s_conv_bignum_b64_to_u8
+#define dst_s_conv_bignum_u8_to_b64 __dst_s_conv_bignum_u8_to_b64
+#define dst_s_dns_key_id __dst_s_dns_key_id
+#define dst_s_dump __dst_s_dump
+#define dst_s_filename_length __dst_s_filename_length
+#define dst_s_fopen __dst_s_fopen
+#define dst_s_get_int16 __dst_s_get_int16
+#define dst_s_get_int32 __dst_s_get_int32
+#define dst_s_id_calc __dst_s_id_calc
+#define dst_s_put_int16 __dst_s_put_int16
+#define dst_s_put_int32 __dst_s_put_int32
+#define dst_s_quick_random __dst_s_quick_random
+#define dst_s_quick_random_set __dst_s_quick_random_set
+#define dst_s_random __dst_s_random
+#define dst_s_semi_random __dst_s_semi_random
+#define dst_s_verify_str __dst_s_verify_str
+#define dst_sig_size __dst_sig_size
+#define dst_sign_data __dst_sign_data
+#define dst_verify_data __dst_verify_data
+#define dst_write_key __dst_write_key
+
+/*
+ * DST Crypto API defintions
+ */
+void dst_init(void);
+int dst_check_algorithm(const int);
+
+
+int dst_sign_data(const int, /*!< specifies INIT/UPDATE/FINAL/ALL */
+ DST_KEY *, /*!< the key to use */
+ void **, /*!< pointer to state structure */
+ const u_char *, /*!< data to be signed */
+ const int, /*!< length of input data */
+ u_char *, /*!< buffer to write signature to */
+ const int); /*!< size of output buffer */
+int dst_verify_data(const int, /*!< specifies INIT/UPDATE/FINAL/ALL */
+ DST_KEY *, /*!< the key to use */
+ void **, /*!< pointer to state structure */
+ const u_char *, /*!< data to be verified */
+ const int, /*!< length of input data */
+ const u_char *, /*!< buffer containing signature */
+ const int); /*!< length of signature */
+DST_KEY *dst_read_key(const char *, /*!< name of key */
+ const u_int16_t, /*!< key tag identifier */
+ const int, /*!< key algorithm */
+ const int); /*!< Private/PublicKey wanted */
+int dst_write_key(const DST_KEY *, /*!< key to write out */
+ const int); /*!< Public/Private */
+DST_KEY *dst_dnskey_to_key(const char *, /*!< KEY record name */
+ const u_char *, /*!< KEY RDATA */
+ const int); /*!< size of input buffer */
+int dst_key_to_dnskey(const DST_KEY *, /*!< key to translate */
+ u_char *, /*!< output buffer */
+ const int); /*!< size of out_storage */
+DST_KEY *dst_buffer_to_key(const char *, /*!< name of the key */
+ const int, /*!< algorithm */
+ const int, /*!< dns flags */
+ const int, /*!< dns protocol */
+ const u_char *, /*!< key in dns wire fmt */
+ const int); /*!< size of key */
+int dst_key_to_buffer(DST_KEY *, u_char *, int);
+
+DST_KEY *dst_generate_key(const char *, /*!< name of new key */
+ const int, /*!< key algorithm to generate */
+ const int, /*!< size of new key */
+ const int, /*!< alg dependent parameter */
+ const int, /*!< key DNS flags */
+ const int); /*!< key DNS protocol */
+DST_KEY *dst_free_key(DST_KEY *);
+int dst_compare_keys(const DST_KEY *, const DST_KEY *);
+
+int dst_sig_size(DST_KEY *);
+
+
+/* support for dns key tags/ids */
+u_int16_t dst_s_dns_key_id(const u_char *, const int);
+u_int16_t dst_s_id_calc(const u_char *, const int);
+
+/* Used by callers as well as by the library. */
+#define RAW_KEY_SIZE 8192 /*%< large enough to store any key */
+/* DST_API control flags */
+/* These are used used in functions dst_sign_data and dst_verify_data */
+#define SIG_MODE_INIT 1 /*%< initialize digest */
+#define SIG_MODE_UPDATE 2 /*%< add data to digest */
+#define SIG_MODE_FINAL 4 /*%< generate/verify signature */
+#define SIG_MODE_ALL (SIG_MODE_INIT|SIG_MODE_UPDATE|SIG_MODE_FINAL)
+
+/* Flags for dst_read_private_key() */
+#define DST_FORCE_READ 0x1000000
+#define DST_CAN_SIGN 0x010F
+#define DST_NO_AUTHEN 0x8000
+#define DST_EXTEND_FLAG 0x1000
+#define DST_STANDARD 0
+#define DST_PRIVATE 0x2000000
+#define DST_PUBLIC 0x4000000
+#define DST_RAND_SEMI 1
+#define DST_RAND_STD 2
+#define DST_RAND_KEY 3
+#define DST_RAND_DSS 4
+
+
+/* DST algorithm codes */
+#define KEY_RSA 1
+#define KEY_DH 2
+#define KEY_DSA 3
+#define KEY_PRIVATE 254
+#define KEY_EXPAND 255
+#define KEY_HMAC_MD5 157
+#define KEY_HMAC_SHA1 158
+#define UNKNOWN_KEYALG 0
+#define DST_MAX_ALGS KEY_HMAC_SHA1
+
+/* DST constants to locations in KEY record changes in new KEY record */
+#define DST_FLAGS_SIZE 2
+#define DST_KEY_PROT 2
+#define DST_KEY_ALG 3
+#define DST_EXT_FLAG 4
+#define DST_KEY_START 4
+
+#ifndef SIGN_F_NOKEY
+#define SIGN_F_NOKEY 0xC000
+#endif
+
+/* error codes from dst routines */
+#define SIGN_INIT_FAILURE (-23)
+#define SIGN_UPDATE_FAILURE (-24)
+#define SIGN_FINAL_FAILURE (-25)
+#define VERIFY_INIT_FAILURE (-26)
+#define VERIFY_UPDATE_FAILURE (-27)
+#define VERIFY_FINAL_FAILURE (-28)
+#define MISSING_KEY_OR_SIGNATURE (-30)
+#define UNSUPPORTED_KEYALG (-31)
+
+#endif /* DST_H */
+/*! \file */
diff --git a/lib/bind/include/isc/eventlib.h b/lib/bind/include/isc/eventlib.h
new file mode 100644
index 0000000..598c71c
--- /dev/null
+++ b/lib/bind/include/isc/eventlib.h
@@ -0,0 +1,204 @@
+/*
+ * 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.3.18.2 2005/07/28 07:38:07 marka Exp $
+ */
+
+#ifndef _EVENTLIB_H
+#define _EVENTLIB_H
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#ifndef __P
+# define __EVENTLIB_P_DEFINED
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+/* In the absence of branded types... */
+typedef struct { void *opaque; } evConnID;
+typedef struct { void *opaque; } evFileID;
+typedef struct { void *opaque; } evStreamID;
+typedef struct { void *opaque; } evTimerID;
+typedef struct { void *opaque; } evWaitID;
+typedef struct { void *opaque; } evContext;
+typedef struct { void *opaque; } evEvent;
+
+#define evInitID(id) ((id)->opaque = NULL)
+#define evTestID(id) ((id).opaque != NULL)
+
+typedef void (*evConnFunc)__P((evContext, void *, int, const void *, int,
+ const void *, int));
+typedef void (*evFileFunc)__P((evContext, void *, int, int));
+typedef void (*evStreamFunc)__P((evContext, void *, int, int));
+typedef void (*evTimerFunc)__P((evContext, void *,
+ struct timespec, struct timespec));
+typedef void (*evWaitFunc)__P((evContext, void *, const void *));
+
+typedef struct { unsigned char mask[256/8]; } evByteMask;
+#define EV_BYTEMASK_BYTE(b) ((b) / 8)
+#define EV_BYTEMASK_MASK(b) (1 << ((b) % 8))
+#define EV_BYTEMASK_SET(bm, b) \
+ ((bm).mask[EV_BYTEMASK_BYTE(b)] |= EV_BYTEMASK_MASK(b))
+#define EV_BYTEMASK_CLR(bm, b) \
+ ((bm).mask[EV_BYTEMASK_BYTE(b)] &= ~EV_BYTEMASK_MASK(b))
+#define EV_BYTEMASK_TST(bm, b) \
+ ((bm).mask[EV_BYTEMASK_BYTE(b)] & EV_BYTEMASK_MASK(b))
+
+#define EV_POLL 1
+#define EV_WAIT 2
+#define EV_NULL 4
+
+#define EV_READ 1
+#define EV_WRITE 2
+#define EV_EXCEPT 4
+
+#define EV_WASNONBLOCKING 8 /* Internal library use. */
+
+/* eventlib.c */
+#define evCreate __evCreate
+#define evSetDebug __evSetDebug
+#define evDestroy __evDestroy
+#define evGetNext __evGetNext
+#define evDispatch __evDispatch
+#define evDrop __evDrop
+#define evMainLoop __evMainLoop
+#define evHighestFD __evHighestFD
+#define evGetOption __evGetOption
+#define evSetOption __evSetOption
+
+int evCreate __P((evContext *));
+void evSetDebug __P((evContext, int, FILE *));
+int evDestroy __P((evContext));
+int evGetNext __P((evContext, evEvent *, int));
+int evDispatch __P((evContext, evEvent));
+void evDrop __P((evContext, evEvent));
+int evMainLoop __P((evContext));
+int evHighestFD __P((evContext));
+int evGetOption __P((evContext *, const char *, int *));
+int evSetOption __P((evContext *, const char *, int));
+
+/* ev_connects.c */
+#define evListen __evListen
+#define evConnect __evConnect
+#define evCancelConn __evCancelConn
+#define evHold __evHold
+#define evUnhold __evUnhold
+#define evTryAccept __evTryAccept
+
+int evListen __P((evContext, int, int, evConnFunc, void *, evConnID *));
+int evConnect __P((evContext, int, const void *, int,
+ evConnFunc, void *, evConnID *));
+int evCancelConn __P((evContext, evConnID));
+int evHold __P((evContext, evConnID));
+int evUnhold __P((evContext, evConnID));
+int evTryAccept __P((evContext, evConnID, int *));
+
+/* ev_files.c */
+#define evSelectFD __evSelectFD
+#define evDeselectFD __evDeselectFD
+
+int evSelectFD __P((evContext, int, int, evFileFunc, void *, evFileID *));
+int evDeselectFD __P((evContext, evFileID));
+
+/* ev_streams.c */
+#define evConsIovec __evConsIovec
+#define evWrite __evWrite
+#define evRead __evRead
+#define evTimeRW __evTimeRW
+#define evUntimeRW __evUntimeRW
+#define evCancelRW __evCancelRW
+
+struct iovec evConsIovec __P((void *, size_t));
+int evWrite __P((evContext, int, const struct iovec *, int,
+ evStreamFunc func, void *, evStreamID *));
+int evRead __P((evContext, int, const struct iovec *, int,
+ evStreamFunc func, void *, evStreamID *));
+int evTimeRW __P((evContext, evStreamID, evTimerID timer));
+int evUntimeRW __P((evContext, evStreamID));
+int evCancelRW __P((evContext, evStreamID));
+
+/* ev_timers.c */
+#define evConsTime __evConsTime
+#define evAddTime __evAddTime
+#define evSubTime __evSubTime
+#define evCmpTime __evCmpTime
+#define evTimeSpec __evTimeSpec
+#define evTimeVal __evTimeVal
+
+#define evNowTime __evNowTime
+#define evUTCTime __evUTCTime
+#define evLastEventTime __evLastEventTime
+#define evSetTimer __evSetTimer
+#define evClearTimer __evClearTimer
+#define evConfigTimer __evConfigTimer
+#define evResetTimer __evResetTimer
+#define evSetIdleTimer __evSetIdleTimer
+#define evClearIdleTimer __evClearIdleTimer
+#define evResetIdleTimer __evResetIdleTimer
+#define evTouchIdleTimer __evTouchIdleTimer
+
+struct timespec evConsTime __P((time_t sec, long nsec));
+struct timespec evAddTime __P((struct timespec, struct timespec));
+struct timespec evSubTime __P((struct timespec, struct timespec));
+struct timespec evNowTime __P((void));
+struct timespec evUTCTime __P((void));
+struct timespec evLastEventTime __P((evContext));
+struct timespec evTimeSpec __P((struct timeval));
+struct timeval evTimeVal __P((struct timespec));
+int evCmpTime __P((struct timespec, struct timespec));
+int evSetTimer __P((evContext, evTimerFunc, void *, struct timespec,
+ struct timespec, evTimerID *));
+int evClearTimer __P((evContext, evTimerID));
+int evConfigTimer __P((evContext, evTimerID, const char *param,
+ int value));
+int evResetTimer __P((evContext, evTimerID, evTimerFunc, void *,
+ struct timespec, struct timespec));
+int evSetIdleTimer __P((evContext, evTimerFunc, void *, struct timespec,
+ evTimerID *));
+int evClearIdleTimer __P((evContext, evTimerID));
+int evResetIdleTimer __P((evContext, evTimerID, evTimerFunc, void *,
+ struct timespec));
+int evTouchIdleTimer __P((evContext, evTimerID));
+
+/* ev_waits.c */
+#define evWaitFor __evWaitFor
+#define evDo __evDo
+#define evUnwait __evUnwait
+#define evDefer __evDefer
+
+int evWaitFor __P((evContext, const void *, evWaitFunc, void *, evWaitID *));
+int evDo __P((evContext, const void *));
+int evUnwait __P((evContext, evWaitID));
+int evDefer __P((evContext, evWaitFunc, void *));
+
+#ifdef __EVENTLIB_P_DEFINED
+# undef __P
+#endif
+
+#endif /*_EVENTLIB_H*/
+
+/*! \file */
diff --git a/lib/bind/include/isc/heap.h b/lib/bind/include/isc/heap.h
new file mode 100644
index 0000000..384d507
--- /dev/null
+++ b/lib/bind/include/isc/heap.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+typedef int (*heap_higher_priority_func)(void *, void *);
+typedef void (*heap_index_func)(void *, int);
+typedef void (*heap_for_each_func)(void *, void *);
+
+typedef struct heap_context {
+ int array_size;
+ int array_size_increment;
+ int heap_size;
+ void **heap;
+ heap_higher_priority_func higher_priority;
+ heap_index_func index;
+} *heap_context;
+
+#define heap_new __heap_new
+#define heap_free __heap_free
+#define heap_insert __heap_insert
+#define heap_delete __heap_delete
+#define heap_increased __heap_increased
+#define heap_decreased __heap_decreased
+#define heap_element __heap_element
+#define heap_for_each __heap_for_each
+
+heap_context heap_new(heap_higher_priority_func, heap_index_func, int);
+int heap_free(heap_context);
+int heap_insert(heap_context, void *);
+int heap_delete(heap_context, int);
+int heap_increased(heap_context, int);
+int heap_decreased(heap_context, int);
+void * heap_element(heap_context, int);
+int heap_for_each(heap_context, heap_for_each_func, void *);
+
+/*! \file */
diff --git a/lib/bind/include/isc/irpmarshall.h b/lib/bind/include/isc/irpmarshall.h
new file mode 100644
index 0000000..ef57701
--- /dev/null
+++ b/lib/bind/include/isc/irpmarshall.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irpmarshall.h,v 1.3.18.1 2005/04/27 05:00:51 sra Exp $
+ */
+
+#ifndef _IRPMARSHALL_H_INCLUDED
+#define _IRPMARSHALL_H_INCLUDED
+
+/* Hide function names */
+#define irp_marshall_gr __irp_marshall_gr
+#define irp_marshall_ho __irp_marshall_ho
+#define irp_marshall_ne __irp_marshall_ne
+#define irp_marshall_ng __irp_marshall_ng
+#define irp_marshall_nw __irp_marshall_nw
+#define irp_marshall_pr __irp_marshall_pr
+#define irp_marshall_pw __irp_marshall_pw
+#define irp_marshall_sv __irp_marshall_sv
+#define irp_unmarshall_gr __irp_unmarshall_gr
+#define irp_unmarshall_ho __irp_unmarshall_ho
+#define irp_unmarshall_ne __irp_unmarshall_ne
+#define irp_unmarshall_ng __irp_unmarshall_ng
+#define irp_unmarshall_nw __irp_unmarshall_nw
+#define irp_unmarshall_pr __irp_unmarshall_pr
+#define irp_unmarshall_pw __irp_unmarshall_pw
+#define irp_unmarshall_sv __irp_unmarshall_sv
+
+#define MAXPADDRSIZE (sizeof "255.255.255.255" + 1)
+#define ADDR_T_STR(x) (x == AF_INET ? "AF_INET" :\
+ (x == AF_INET6 ? "AF_INET6" : "UNKNOWN"))
+
+/* See comment below on usage */
+int irp_marshall_pw(const struct passwd *, char **, size_t *);
+int irp_unmarshall_pw(struct passwd *, char *);
+int irp_marshall_gr(const struct group *, char **, size_t *);
+int irp_unmarshall_gr(struct group *, char *);
+int irp_marshall_sv(const struct servent *, char **, size_t *);
+int irp_unmarshall_sv(struct servent *, char *);
+int irp_marshall_pr(struct protoent *, char **, size_t *);
+int irp_unmarshall_pr(struct protoent *, char *);
+int irp_marshall_ho(struct hostent *, char **, size_t *);
+int irp_unmarshall_ho(struct hostent *, char *);
+int irp_marshall_ng(const char *, const char *, const char *,
+ char **, size_t *);
+int irp_unmarshall_ng(const char **, const char **, const char **, char *);
+int irp_marshall_nw(struct nwent *, char **, size_t *);
+int irp_unmarshall_nw(struct nwent *, char *);
+int irp_marshall_ne(struct netent *, char **, size_t *);
+int irp_unmarshall_ne(struct netent *, char *);
+
+/*! \file
+ * \brief
+ * Functions to marshall and unmarshall various system data structures. We
+ * use a printable ascii format that is as close to various system config
+ * files as reasonable (e.g. /etc/passwd format).
+ *
+ * We are not forgiving with unmarhsalling misformatted buffers. In
+ * particular whitespace in fields is not ignored. So a formatted password
+ * entry "brister :1364:100:...." will yield a username of "brister "
+ *
+ * We potentially do a lot of mallocs to fill fields that are of type
+ * (char **) like a hostent h_addr field. Building (for example) the
+ * h_addr field and its associated addresses all in one buffer is
+ * certainly possible, but not done here.
+ *
+ * The following description is true for all the marshalling functions:
+ *
+ * int irp_marshall_XX(struct yyyy *XX, char **buffer, size_t *len);
+ *
+ * The argument XX (of type struct passwd for example) is marshalled in the
+ * buffer pointed at by *BUFFER, which is of length *LEN. Returns 0
+ * on success and -1 on failure. Failure will occur if *LEN is
+ * smaller than needed.
+ *
+ * If BUFFER is NULL, then *LEN is set to the size of the buffer
+ * needed to marshall the data and no marshalling is actually done.
+ *
+ * If *BUFFER is NULL, then a buffer large enough will be allocated
+ * with memget() and the size allocated will be stored in *LEN. An extra 2
+ * bytes will be allocated for the client to append CRLF if wanted. The
+ * value of *LEN will include these two bytes.
+ *
+ * All the marshalling functions produce a buffer with the fields
+ * separated by colons (except for the hostent marshalling, which uses '@'
+ * to separate fields). Fields that have multiple subfields (like the
+ * gr_mem field in struct group) have their subparts separated by
+ * commas.
+ *
+ * int irp_unmarshall_XX(struct YYYYY *XX, char *buffer);
+ *
+ * The unmashalling functions break apart the buffer and store the
+ * values in the struct pointed to by XX. All pointer values inside
+ * XX are allocated with malloc. All arrays of pointers have a NULL
+ * as the last element.
+ */
+
+#endif
diff --git a/lib/bind/include/isc/list.h b/lib/bind/include/isc/list.h
new file mode 100644
index 0000000..c85c667
--- /dev/null
+++ b/lib/bind/include/isc/list.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef LIST_H
+#define LIST_H 1
+#include <isc/assertions.h>
+
+#define LIST(type) struct { type *head, *tail; }
+#define INIT_LIST(list) \
+ do { (list).head = NULL; (list).tail = NULL; } while (0)
+
+#define LINK(type) struct { type *prev, *next; }
+#define INIT_LINK_TYPE(elt, link, type) \
+ do { \
+ (elt)->link.prev = (type *)(-1); \
+ (elt)->link.next = (type *)(-1); \
+ } while (0)
+#define INIT_LINK(elt, link) \
+ INIT_LINK_TYPE(elt, link, void)
+#define LINKED(elt, link) ((void *)((elt)->link.prev) != (void *)(-1))
+
+#define HEAD(list) ((list).head)
+#define TAIL(list) ((list).tail)
+#define EMPTY(list) ((list).head == NULL)
+
+#define PREPEND(list, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((list).head != NULL) \
+ (list).head->link.prev = (elt); \
+ else \
+ (list).tail = (elt); \
+ (elt)->link.prev = NULL; \
+ (elt)->link.next = (list).head; \
+ (list).head = (elt); \
+ } while (0)
+
+#define APPEND(list, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((list).tail != NULL) \
+ (list).tail->link.next = (elt); \
+ else \
+ (list).head = (elt); \
+ (elt)->link.prev = (list).tail; \
+ (elt)->link.next = NULL; \
+ (list).tail = (elt); \
+ } while (0)
+
+#define UNLINK_TYPE(list, elt, link, type) \
+ do { \
+ INSIST(LINKED(elt, link));\
+ if ((elt)->link.next != NULL) \
+ (elt)->link.next->link.prev = (elt)->link.prev; \
+ else { \
+ INSIST((list).tail == (elt)); \
+ (list).tail = (elt)->link.prev; \
+ } \
+ if ((elt)->link.prev != NULL) \
+ (elt)->link.prev->link.next = (elt)->link.next; \
+ else { \
+ INSIST((list).head == (elt)); \
+ (list).head = (elt)->link.next; \
+ } \
+ INIT_LINK_TYPE(elt, link, type); \
+ } while (0)
+#define UNLINK(list, elt, link) \
+ UNLINK_TYPE(list, elt, link, void)
+
+#define PREV(elt, link) ((elt)->link.prev)
+#define NEXT(elt, link) ((elt)->link.next)
+
+#define INSERT_BEFORE(list, before, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((before)->link.prev == NULL) \
+ PREPEND(list, elt, link); \
+ else { \
+ (elt)->link.prev = (before)->link.prev; \
+ (before)->link.prev = (elt); \
+ (elt)->link.prev->link.next = (elt); \
+ (elt)->link.next = (before); \
+ } \
+ } while (0)
+
+#define INSERT_AFTER(list, after, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((after)->link.next == NULL) \
+ APPEND(list, elt, link); \
+ else { \
+ (elt)->link.next = (after)->link.next; \
+ (after)->link.next = (elt); \
+ (elt)->link.next->link.prev = (elt); \
+ (elt)->link.prev = (after); \
+ } \
+ } while (0)
+
+#define ENQUEUE(list, elt, link) APPEND(list, elt, link)
+#define DEQUEUE(list, elt, link) UNLINK(list, elt, link)
+
+#endif /* LIST_H */
+/*! \file */
diff --git a/lib/bind/include/isc/logging.h b/lib/bind/include/isc/logging.h
new file mode 100644
index 0000000..c539443
--- /dev/null
+++ b/lib/bind/include/isc/logging.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef LOGGING_H
+#define LOGGING_H
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#define log_critical (-5)
+#define log_error (-4)
+#define log_warning (-3)
+#define log_notice (-2)
+#define log_info (-1)
+#define log_debug(level) (level)
+
+typedef enum { log_syslog, log_file, log_null } log_channel_type;
+
+#define LOG_MAX_VERSIONS 99
+
+#define LOG_CLOSE_STREAM 0x0001
+#define LOG_TIMESTAMP 0x0002
+#define LOG_TRUNCATE 0x0004
+#define LOG_USE_CONTEXT_LEVEL 0x0008
+#define LOG_PRINT_LEVEL 0x0010
+#define LOG_REQUIRE_DEBUG 0x0020
+#define LOG_CHANNEL_BROKEN 0x0040
+#define LOG_PRINT_CATEGORY 0x0080
+#define LOG_CHANNEL_OFF 0x0100
+
+typedef struct log_context *log_context;
+typedef struct log_channel *log_channel;
+
+#define LOG_OPTION_DEBUG 0x01
+#define LOG_OPTION_LEVEL 0x02
+
+#define log_open_stream __log_open_stream
+#define log_close_stream __log_close_stream
+#define log_get_stream __log_get_stream
+#define log_get_filename __log_get_filename
+#define log_check_channel __log_check_channel
+#define log_check __log_check
+#define log_vwrite __log_vwrite
+#define log_write __log_write
+#define log_new_context __log_new_context
+#define log_free_context __log_free_context
+#define log_add_channel __log_add_channel
+#define log_remove_channel __log_remove_channel
+#define log_option __log_option
+#define log_category_is_active __log_category_is_active
+#define log_new_syslog_channel __log_new_syslog_channel
+#define log_new_file_channel __log_new_file_channel
+#define log_set_file_owner __log_set_file_owner
+#define log_new_null_channel __log_new_null_channel
+#define log_inc_references __log_inc_references
+#define log_dec_references __log_dec_references
+#define log_get_channel_type __log_get_channel_type
+#define log_free_channel __log_free_channel
+#define log_close_debug_channels __log_close_debug_channels
+
+FILE * log_open_stream(log_channel);
+int log_close_stream(log_channel);
+FILE * log_get_stream(log_channel);
+char * log_get_filename(log_channel);
+int log_check_channel(log_context, int, log_channel);
+int log_check(log_context, int, int);
+#ifdef __GNUC__
+void log_vwrite(log_context, int, int, const char *,
+ va_list args)
+ __attribute__((__format__(__printf__, 4, 0)));
+void log_write(log_context, int, int, const char *, ...)
+ __attribute__((__format__(__printf__, 4, 5)));
+#else
+void log_vwrite(log_context, int, int, const char *,
+ va_list args);
+void log_write(log_context, int, int, const char *, ...);
+#endif
+int log_new_context(int, char **, log_context *);
+void log_free_context(log_context);
+int log_add_channel(log_context, int, log_channel);
+int log_remove_channel(log_context, int, log_channel);
+int log_option(log_context, int, int);
+int log_category_is_active(log_context, int);
+log_channel log_new_syslog_channel(unsigned int, int, int);
+log_channel log_new_file_channel(unsigned int, int, const char *,
+ FILE *, unsigned int,
+ unsigned long);
+int log_set_file_owner(log_channel, uid_t, gid_t);
+log_channel log_new_null_channel(void);
+int log_inc_references(log_channel);
+int log_dec_references(log_channel);
+log_channel_type log_get_channel_type(log_channel);
+int log_free_channel(log_channel);
+void log_close_debug_channels(log_context);
+
+#endif /* !LOGGING_H */
+/*! \file */
diff --git a/lib/bind/include/isc/memcluster.h b/lib/bind/include/isc/memcluster.h
new file mode 100644
index 0000000..0923deb
--- /dev/null
+++ b/lib/bind/include/isc/memcluster.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MEMCLUSTER_H
+#define MEMCLUSTER_H
+
+#include <stdio.h>
+
+#define meminit __meminit
+#ifdef MEMCLUSTER_DEBUG
+#define memget(s) __memget_debug(s, __FILE__, __LINE__)
+#define memput(p, s) __memput_debug(p, s, __FILE__, __LINE__)
+#else /*MEMCLUSTER_DEBUG*/
+#ifdef MEMCLUSTER_RECORD
+#define memget(s) __memget_record(s, __FILE__, __LINE__)
+#define memput(p, s) __memput_record(p, s, __FILE__, __LINE__)
+#else /*MEMCLUSTER_RECORD*/
+#define memget __memget
+#define memput __memput
+#endif /*MEMCLUSTER_RECORD*/
+#endif /*MEMCLUSTER_DEBUG*/
+#define memstats __memstats
+#define memactive __memactive
+
+int meminit(size_t, size_t);
+void * __memget(size_t);
+void __memput(void *, size_t);
+void * __memget_debug(size_t, const char *, int);
+void __memput_debug(void *, size_t, const char *, int);
+void * __memget_record(size_t, const char *, int);
+void __memput_record(void *, size_t, const char *, int);
+void memstats(FILE *);
+int memactive(void);
+
+#endif /* MEMCLUSTER_H */
+/*! \file */
diff --git a/lib/bind/include/isc/misc.h b/lib/bind/include/isc/misc.h
new file mode 100644
index 0000000..d2e98ac
--- /dev/null
+++ b/lib/bind/include/isc/misc.h
@@ -0,0 +1,43 @@
+/*
+ * 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.4.18.1 2005/04/27 05:00:52 sra Exp $
+ */
+
+#ifndef _ISC_MISC_H
+#define _ISC_MISC_H
+
+/*! \file */
+
+#include <stdio.h>
+
+#define bitncmp __bitncmp
+/*#define isc_movefile __isc_movefile */
+
+extern int bitncmp(const void *, const void *, int);
+extern int isc_movefile(const char *, const char *);
+
+extern int isc_gethexstring(unsigned char *, size_t, int, FILE *,
+ int *);
+extern void isc_puthexstring(FILE *, const unsigned char *, size_t,
+ size_t, size_t, const char *);
+extern void isc_tohex(const unsigned char *, size_t, char *);
+
+#endif /*_ISC_MISC_H*/
+
+/*! \file */
diff --git a/lib/bind/include/isc/tree.h b/lib/bind/include/isc/tree.h
new file mode 100644
index 0000000..8096a8d
--- /dev/null
+++ b/lib/bind/include/isc/tree.h
@@ -0,0 +1,59 @@
+/* tree.h - declare structures used by tree library
+ *
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 27jun86 [broken out of tree.c]
+ *
+ * $Id: tree.h,v 1.2.164.1 2005/04/27 05:00:52 sra Exp $
+ */
+
+
+#ifndef _TREE_H_INCLUDED
+#define _TREE_H_INCLUDED
+
+
+#ifndef __P
+# if defined(__STDC__) || defined(__GNUC__)
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+/*%
+ * tree_t is our package-specific anonymous pointer.
+ */
+#if defined(__STDC__) || defined(__GNUC__)
+typedef void *tree_t;
+#else
+typedef char *tree_t;
+#endif
+
+/*%
+ * Do not taint namespace
+ */
+#define tree_add __tree_add
+#define tree_delete __tree_delete
+#define tree_init __tree_init
+#define tree_mung __tree_mung
+#define tree_srch __tree_srch
+#define tree_trav __tree_trav
+
+
+typedef struct tree_s {
+ tree_t data;
+ struct tree_s *left, *right;
+ short bal;
+ }
+ tree;
+
+
+void tree_init __P((tree **));
+tree_t tree_srch __P((tree **, int (*)(), tree_t));
+tree_t tree_add __P((tree **, int (*)(), tree_t, void (*)()));
+int tree_delete __P((tree **, int (*)(), tree_t, void (*)()));
+int tree_trav __P((tree **, int (*)()));
+void tree_mung __P((tree **, void (*)()));
+
+
+#endif /* _TREE_H_INCLUDED */
+/*! \file */
diff --git a/lib/bind/include/netdb.h b/lib/bind/include/netdb.h
new file mode 100644
index 0000000..66dd13d
--- /dev/null
+++ b/lib/bind/include/netdb.h
@@ -0,0 +1,582 @@
+/*
+ * ++Copyright++ 1980, 1983, 1988, 1993
+ * -
+ * Copyright (c) 1980, 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * Portions Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by WIDE Project and
+ * its contributors.
+ * 4. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * @(#)netdb.h 8.1 (Berkeley) 6/2/93
+ * $Id: netdb.h,v 1.15.18.6 2006/10/02 01:23:09 marka Exp $
+ */
+
+#ifndef _NETDB_H_
+#define _NETDB_H_
+
+#include <sys/param.h>
+#include <sys/types.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#endif
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+
+#ifndef _PATH_HEQUIV
+#define _PATH_HEQUIV "/etc/hosts.equiv"
+#endif
+#ifndef _PATH_HOSTS
+#define _PATH_HOSTS "/etc/hosts"
+#endif
+#ifndef _PATH_NETWORKS
+#define _PATH_NETWORKS "/etc/networks"
+#endif
+#ifndef _PATH_PROTOCOLS
+#define _PATH_PROTOCOLS "/etc/protocols"
+#endif
+#ifndef _PATH_SERVICES
+#define _PATH_SERVICES "/etc/services"
+#endif
+
+#if (__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
+#define __h_errno __h_errno_location
+#endif
+__BEGIN_DECLS
+extern int * __h_errno __P((void));
+__END_DECLS
+#if defined(_REENTRANT) || \
+ (__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
+#define h_errno (*__h_errno())
+#else
+extern int h_errno;
+#endif
+
+/*%
+ * Structures returned by network data base library. All addresses are
+ * supplied in host order, and returned in network order (suitable for
+ * use in system calls).
+ */
+struct hostent {
+ char *h_name; /*%< official name of host */
+ char **h_aliases; /*%< alias list */
+ int h_addrtype; /*%< host address type */
+ int h_length; /*%< length of address */
+ char **h_addr_list; /*%< list of addresses from name server */
+#define h_addr h_addr_list[0] /*%< address, for backward compatiblity */
+};
+
+/*%
+ * Assumption here is that a network number
+ * fits in an unsigned long -- probably a poor one.
+ */
+struct netent {
+ char *n_name; /*%< official name of net */
+ char **n_aliases; /*%< alias list */
+ int n_addrtype; /*%< net address type */
+ unsigned long n_net; /*%< network # */
+};
+
+struct servent {
+ char *s_name; /*%< official service name */
+ char **s_aliases; /*%< alias list */
+ int s_port; /*%< port # */
+ char *s_proto; /*%< protocol to use */
+};
+
+struct protoent {
+ char *p_name; /*%< official protocol name */
+ char **p_aliases; /*%< alias list */
+ int p_proto; /*%< protocol # */
+};
+
+struct addrinfo {
+ int ai_flags; /*%< AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /*%< PF_xxx */
+ int ai_socktype; /*%< SOCK_xxx */
+ int ai_protocol; /*%< 0 or IPPROTO_xxx for IPv4 and IPv6 */
+#if defined(sun) && defined(_SOCKLEN_T)
+#ifdef __sparcv9
+ int _ai_pad;
+#endif
+ socklen_t ai_addrlen;
+#else
+ size_t ai_addrlen; /*%< length of ai_addr */
+#endif
+#ifdef __linux
+ struct sockaddr *ai_addr; /*%< binary address */
+ char *ai_canonname; /*%< canonical name for hostname */
+#else
+ char *ai_canonname; /*%< canonical name for hostname */
+ struct sockaddr *ai_addr; /*%< binary address */
+#endif
+ struct addrinfo *ai_next; /*%< next structure in linked list */
+};
+
+/*%
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (left in extern int h_errno).
+ */
+
+#define NETDB_INTERNAL -1 /*%< see errno */
+#define NETDB_SUCCESS 0 /*%< no problem */
+#define HOST_NOT_FOUND 1 /*%< Authoritative Answer Host not found */
+#define TRY_AGAIN 2 /*%< Non-Authoritive Host not found, or SERVERFAIL */
+#define NO_RECOVERY 3 /*%< Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define NO_DATA 4 /*%< Valid name, no data record of requested type */
+#define NO_ADDRESS NO_DATA /*%< no address, look for MX record */
+/*
+ * Error return codes from getaddrinfo()
+ */
+#define EAI_ADDRFAMILY 1 /*%< address family for hostname not supported */
+#define EAI_AGAIN 2 /*%< temporary failure in name resolution */
+#define EAI_BADFLAGS 3 /*%< invalid value for ai_flags */
+#define EAI_FAIL 4 /*%< non-recoverable failure in name resolution */
+#define EAI_FAMILY 5 /*%< ai_family not supported */
+#define EAI_MEMORY 6 /*%< memory allocation failure */
+#define EAI_NODATA 7 /*%< no address associated with hostname */
+#define EAI_NONAME 8 /*%< hostname nor servname provided, or not known */
+#define EAI_SERVICE 9 /*%< servname not supported for ai_socktype */
+#define EAI_SOCKTYPE 10 /*%< ai_socktype not supported */
+#define EAI_SYSTEM 11 /*%< system error returned in errno */
+#define EAI_BADHINTS 12
+#define EAI_PROTOCOL 13
+#define EAI_MAX 14
+
+/*%
+ * Flag values for getaddrinfo()
+ */
+#define AI_PASSIVE 0x00000001
+#define AI_CANONNAME 0x00000002
+#define AI_NUMERICHOST 0x00000004
+#define AI_MASK 0x00000007
+
+/*%
+ * Flag values for getipnodebyname()
+ */
+#define AI_V4MAPPED 0x00000008
+#define AI_ALL 0x00000010
+#define AI_ADDRCONFIG 0x00000020
+#define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG)
+
+/*%
+ * Constants for getnameinfo()
+ */
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+/*%
+ * Flag values for getnameinfo()
+ */
+#define NI_NOFQDN 0x00000001
+#define NI_NUMERICHOST 0x00000002
+#define NI_NAMEREQD 0x00000004
+#define NI_NUMERICSERV 0x00000008
+#define NI_DGRAM 0x00000010
+#define NI_WITHSCOPEID 0x00000020
+#define NI_NUMERICSCOPE 0x00000040
+
+/*%
+ * Scope delimit character
+ */
+#define SCOPE_DELIMITER '%'
+
+
+#ifdef _REENTRANT
+#if defined (__hpux) || defined(__osf__) || defined(_AIX)
+#define _MAXALIASES 35
+#define _MAXLINELEN 1024
+#define _MAXADDRS 35
+#define _HOSTBUFSIZE (BUFSIZ + 1)
+
+struct hostent_data {
+ struct in_addr host_addr;
+ char *h_addr_ptrs[_MAXADDRS + 1];
+ char hostaddr[_MAXADDRS];
+ char hostbuf[_HOSTBUFSIZE];
+ char *host_aliases[_MAXALIASES];
+ char *host_addrs[2];
+ FILE *hostf;
+#ifdef __osf__
+ int svc_gethostflag;
+ int svc_gethostbind;
+#endif
+#ifdef __hpux
+ short _nsw_src;
+ short _flags;
+ char *current;
+ int currentlen;
+#endif
+};
+
+struct netent_data {
+ FILE *net_fp;
+#if defined(__osf__) || defined(_AIX)
+ char line[_MAXLINELEN];
+#endif
+#ifdef __hpux
+ char line[_MAXLINELEN+1];
+#endif
+ char *net_aliases[_MAXALIASES];
+#ifdef __osf__
+ int _net_stayopen;
+ int svc_getnetflag;
+#endif
+#ifdef __hpux
+ short _nsw_src;
+ short _flags;
+ char *current;
+ int currentlen;
+#endif
+#ifdef _AIX
+ int _net_stayopen;
+ char *current;
+ int currentlen;
+ void *_net_reserv1; /* reserved for future use */
+ void *_net_reserv2; /* reserved for future use */
+#endif
+};
+
+struct protoent_data {
+ FILE *proto_fp;
+#ifdef _AIX
+ int _proto_stayopen;
+ char line[_MAXLINELEN];
+#endif
+#ifdef __osf__
+ char line[1024];
+#endif
+#ifdef __hpux
+ char line[_MAXLINELEN+1];
+#endif
+ char *proto_aliases[_MAXALIASES];
+#ifdef __osf__
+ int _proto_stayopen;
+ int svc_getprotoflag;
+#endif
+#ifdef __hpux
+ short _nsw_src;
+ short _flags;
+ char *current;
+ int currentlen;
+#endif
+#ifdef _AIX
+ int currentlen;
+ char *current;
+ void *_proto_reserv1; /* reserved for future use */
+ void *_proto_reserv2; /* reserved for future use */
+#endif
+};
+
+struct servent_data {
+ FILE *serv_fp;
+#if defined(__osf__) || defined(_AIX)
+ char line[_MAXLINELEN];
+#endif
+#ifdef __hpux
+ char line[_MAXLINELEN+1];
+#endif
+ char *serv_aliases[_MAXALIASES];
+#ifdef __osf__
+ int _serv_stayopen;
+ int svc_getservflag;
+#endif
+#ifdef __hpux
+ short _nsw_src;
+ short _flags;
+ char *current;
+ int currentlen;
+#endif
+#ifdef _AIX
+ int _serv_stayopen;
+ char *current;
+ int currentlen;
+ void *_serv_reserv1; /* reserved for future use */
+ void *_serv_reserv2; /* reserved for future use */
+#endif
+};
+#endif
+#endif
+__BEGIN_DECLS
+void endhostent __P((void));
+void endnetent __P((void));
+void endprotoent __P((void));
+void endservent __P((void));
+void freehostent __P((struct hostent *));
+struct hostent *gethostbyaddr __P((const char *, int, int));
+struct hostent *gethostbyname __P((const char *));
+struct hostent *gethostbyname2 __P((const char *, int));
+struct hostent *gethostent __P((void));
+struct hostent *getipnodebyaddr __P((const void *, size_t, int, int *));
+struct hostent *getipnodebyname __P((const char *, int, int, int *));
+struct netent *getnetbyaddr __P((unsigned long, int));
+struct netent *getnetbyname __P((const char *));
+struct netent *getnetent __P((void));
+struct protoent *getprotobyname __P((const char *));
+struct protoent *getprotobynumber __P((int));
+struct protoent *getprotoent __P((void));
+struct servent *getservbyname __P((const char *, const char *));
+struct servent *getservbyport __P((int, const char *));
+struct servent *getservent __P((void));
+void herror __P((const char *));
+const char *hstrerror __P((int));
+void sethostent __P((int));
+/* void sethostfile __P((const char *)); */
+void setnetent __P((int));
+void setprotoent __P((int));
+void setservent __P((int));
+int getaddrinfo __P((const char *, const char *,
+ const struct addrinfo *, struct addrinfo **));
+int getnameinfo __P((const struct sockaddr *, size_t, char *,
+ size_t, char *, size_t, int));
+void freeaddrinfo __P((struct addrinfo *));
+const char *gai_strerror __P((int));
+struct hostent *getipnodebyname __P((const char *, int, int, int *));
+struct hostent *getipnodebyaddr __P((const void *, size_t, int, int *));
+void freehostent __P((struct hostent *));
+#ifdef __GLIBC__
+int getnetgrent __P((/* const */ char **, /* const */ char **,
+ /* const */ char **));
+void setnetgrent __P((const char *));
+void endnetgrent __P((void));
+int innetgr __P((const char *, const char *, const char *,
+ const char *));
+#endif
+
+#ifdef _REENTRANT
+#if defined(__hpux) || defined(__osf__) || defined(_AIX)
+int gethostbyaddr_r __P((const char *, int, int, struct hostent *,
+ struct hostent_data *));
+int gethostbyname_r __P((const char *, struct hostent *,
+ struct hostent_data *));
+int gethostent_r __P((struct hostent *, struct hostent_data *));
+#if defined(_AIX)
+void sethostent_r __P((int, struct hostent_data *));
+#else
+int sethostent_r __P((int, struct hostent_data *));
+#endif
+#if defined(__hpux)
+int endhostent_r __P((struct hostent_data *));
+#else
+void endhostent_r __P((struct hostent_data *));
+#endif
+
+#if defined(__hpux) || defined(__osf__)
+int getnetbyaddr_r __P((int, int,
+ struct netent *, struct netent_data *));
+#else
+int getnetbyaddr_r __P((long, int,
+ struct netent *, struct netent_data *));
+#endif
+int getnetbyname_r __P((const char *,
+ struct netent *, struct netent_data *));
+int getnetent_r __P((struct netent *, struct netent_data *));
+int setnetent_r __P((int, struct netent_data *));
+#ifdef __hpux
+int endnetent_r __P((struct netent_data *buffer));
+#else
+void endnetent_r __P((struct netent_data *buffer));
+#endif
+
+int getprotobyname_r __P((const char *,
+ struct protoent *, struct protoent_data *));
+int getprotobynumber_r __P((int,
+ struct protoent *, struct protoent_data *));
+int getprotoent_r __P((struct protoent *, struct protoent_data *));
+int setprotoent_r __P((int, struct protoent_data *));
+#ifdef __hpux
+int endprotoent_r __P((struct protoent_data *));
+#else
+void endprotoent_r __P((struct protoent_data *));
+#endif
+
+int getservbyname_r __P((const char *, const char *,
+ struct servent *, struct servent_data *));
+int getservbyport_r __P((int, const char *,
+ struct servent *, struct servent_data *));
+int getservent_r __P((struct servent *, struct servent_data *));
+int setservent_r __P((int, struct servent_data *));
+#ifdef __hpux
+int endservent_r __P((struct servent_data *));
+#else
+void endservent_r __P((struct servent_data *));
+#endif
+#ifdef _AIX
+int setnetgrent_r __P((const char *, void **));
+void endnetgrent_r __P((void **));
+/*
+ * Note: AIX's netdb.h declares innetgr_r() as:
+ * int innetgr_r(char *, char *, char *, char *, struct innetgr_data *);
+ */
+int innetgr_r __P((const char *, const char *, const char *,
+ const char *));
+#endif
+#else
+ /* defined(sun) || defined(bsdi) */
+#if defined(__GLIBC__) || defined(__FreeBSD__) && (__FreeBSD_version + 0 >= 601103)
+int gethostbyaddr_r __P((const char *, int, int, struct hostent *,
+ char *, size_t, struct hostent **, int *));
+int gethostbyname_r __P((const char *, struct hostent *,
+ char *, size_t, struct hostent **, int *));
+int gethostent_r __P((struct hostent *, char *, size_t,
+ struct hostent **, int *));
+#else
+struct hostent *gethostbyaddr_r __P((const char *, int, int, struct hostent *,
+ char *, int, int *));
+struct hostent *gethostbyname_r __P((const char *, struct hostent *,
+ char *, int, int *));
+struct hostent *gethostent_r __P((struct hostent *, char *, int, int *));
+#endif
+void sethostent_r __P((int));
+void endhostent_r __P((void));
+
+#if defined(__GLIBC__) || defined(__FreeBSD__) && (__FreeBSD_version + 0 >= 601103)
+int getnetbyname_r __P((const char *, struct netent *,
+ char *, size_t, struct netent **, int*));
+int getnetbyaddr_r __P((unsigned long int, int, struct netent *,
+ char *, size_t, struct netent **, int*));
+int getnetent_r __P((struct netent *, char *, size_t, struct netent **, int*));
+#else
+struct netent *getnetbyname_r __P((const char *, struct netent *,
+ char *, int));
+struct netent *getnetbyaddr_r __P((long, int, struct netent *,
+ char *, int));
+struct netent *getnetent_r __P((struct netent *, char *, int));
+#endif
+void setnetent_r __P((int));
+void endnetent_r __P((void));
+
+#if defined(__GLIBC__) || defined(__FreeBSD__) && (__FreeBSD_version + 0 >= 601103)
+int getprotobyname_r __P((const char *, struct protoent *, char *,
+ size_t, struct protoent **));
+int getprotobynumber_r __P((int, struct protoent *, char *, size_t,
+ struct protoent **));
+int getprotoent_r __P((struct protoent *, char *, size_t, struct protoent **));
+#else
+struct protoent *getprotobyname_r __P((const char *,
+ struct protoent *, char *, int));
+struct protoent *getprotobynumber_r __P((int,
+ struct protoent *, char *, int));
+struct protoent *getprotoent_r __P((struct protoent *, char *, int));
+#endif
+void setprotoent_r __P((int));
+void endprotoent_r __P((void));
+
+#if defined(__GLIBC__) || defined(__FreeBSD__) && (__FreeBSD_version + 0 >= 601103)
+int getservbyname_r __P((const char *name, const char *,
+ struct servent *, char *, size_t, struct servent **));
+int getservbyport_r __P((int port, const char *,
+ struct servent *, char *, size_t, struct servent **));
+int getservent_r __P((struct servent *, char *, size_t, struct servent **));
+#else
+struct servent *getservbyname_r __P((const char *name, const char *,
+ struct servent *, char *, int));
+struct servent *getservbyport_r __P((int port, const char *,
+ struct servent *, char *, int));
+struct servent *getservent_r __P((struct servent *, char *, int));
+#endif
+void setservent_r __P((int));
+void endservent_r __P((void));
+
+#ifdef __GLIBC__
+int getnetgrent_r __P((char **, char **, char **, char *, size_t));
+#endif
+
+#endif
+#endif
+__END_DECLS
+
+/* This is nec'y to make this include file properly replace the sun version. */
+#ifdef sun
+#ifdef __GNU_LIBRARY__
+#include <rpc/netdb.h>
+#else
+struct rpcent {
+ char *r_name; /*%< name of server for this rpc program */
+ char **r_aliases; /*%< alias list */
+ int r_number; /*%< rpc program number */
+};
+struct rpcent *getrpcbyname(), *getrpcbynumber(), *getrpcent();
+#endif /* __GNU_LIBRARY__ */
+#endif /* sun */
+#endif /* !_NETDB_H_ */
+/*! \file */
diff --git a/lib/bind/include/netgroup.h b/lib/bind/include/netgroup.h
new file mode 100644
index 0000000..e4be459
--- /dev/null
+++ b/lib/bind/include/netgroup.h
@@ -0,0 +1,26 @@
+#ifndef netgroup_h
+#define netgroup_h
+#ifndef __GLIBC__
+
+/*
+ * The standard is crazy. These values "belong" to getnetgrent() and
+ * shouldn't be altered by the caller.
+ */
+int getnetgrent __P((/* const */ char **, /* const */ char **,
+ /* const */ char **));
+
+int getnetgrent_r __P((char **, char **, char **, char *, int));
+
+void endnetgrent __P((void));
+
+#ifdef __osf__
+int innetgr __P((char *, char *, char *, char *));
+void setnetgrent __P((char *));
+#else
+void setnetgrent __P((const char *));
+int innetgr __P((const char *, const char *, const char *, const char *));
+#endif
+#endif
+#endif
+
+/*! \file */
diff --git a/lib/bind/include/res_update.h b/lib/bind/include/res_update.h
new file mode 100644
index 0000000..2e6f171
--- /dev/null
+++ b/lib/bind/include/res_update.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: res_update.h,v 1.2.18.1 2005/04/27 05:00:49 sra Exp $
+ */
+
+#ifndef __RES_UPDATE_H
+#define __RES_UPDATE_H
+
+/*! \file */
+
+#include <sys/types.h>
+#include <arpa/nameser.h>
+#include <isc/list.h>
+#include <resolv.h>
+
+/*%
+ * This RR-like structure is particular to UPDATE.
+ */
+struct ns_updrec {
+ LINK(struct ns_updrec) r_link, r_glink;
+ ns_sect r_section; /*%< ZONE/PREREQUISITE/UPDATE */
+ char * r_dname; /*%< owner of the RR */
+ ns_class r_class; /*%< class number */
+ ns_type r_type; /*%< type number */
+ u_int32_t r_ttl; /*%< time to live */
+ u_char * r_data; /*%< rdata fields as text string */
+ u_int r_size; /*%< size of r_data field */
+ int r_opcode; /*%< type of operation */
+ /* following fields for private use by the resolver/server routines */
+ struct databuf *r_dp; /*%< databuf to process */
+ struct databuf *r_deldp; /*%< databuf's deleted/overwritten */
+ u_int r_zone; /*%< zone number on server */
+};
+typedef struct ns_updrec ns_updrec;
+typedef LIST(ns_updrec) ns_updque;
+
+#define res_mkupdate __res_mkupdate
+#define res_update __res_update
+#define res_mkupdrec __res_mkupdrec
+#define res_freeupdrec __res_freeupdrec
+#define res_nmkupdate __res_nmkupdate
+#define res_nupdate __res_nupdate
+
+int res_mkupdate __P((ns_updrec *, u_char *, int));
+int res_update __P((ns_updrec *));
+ns_updrec * res_mkupdrec __P((int, const char *, u_int, u_int, u_long));
+void res_freeupdrec __P((ns_updrec *));
+int res_nmkupdate __P((res_state, ns_updrec *, u_char *, int));
+int res_nupdate __P((res_state, ns_updrec *, ns_tsig_key *));
+
+#endif /*__RES_UPDATE_H*/
+
+/*! \file */
diff --git a/lib/bind/include/resolv.h b/lib/bind/include/resolv.h
new file mode 100644
index 0000000..66d84fc
--- /dev/null
+++ b/lib/bind/include/resolv.h
@@ -0,0 +1,505 @@
+/*
+ * 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.19.18.3 2005/08/25 04:43:51 marka Exp $
+ */
+
+#ifndef _RESOLV_H_
+#define _RESOLV_H_
+
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <arpa/nameser.h>
+
+/*%
+ * 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 <resolv.h>.
+ * 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
+#ifdef __linux
+__BEGIN_DECLS
+extern struct __res_state * __res_state(void);
+__END_DECLS
+#endif
+#ifndef __BIND_NOSTATIC
+extern struct __res_state _res;
+#endif
+#endif
+
+#ifndef __BIND_NOSTATIC
+#define fp_nquery __fp_nquery
+#define fp_query __fp_query
+#define hostalias __hostalias
+#define p_query __p_query
+#define res_close __res_close
+#define res_init __res_init
+#define res_isourserver __res_isourserver
+#define res_mkquery __res_mkquery
+#define res_query __res_query
+#define res_querydomain __res_querydomain
+#define res_search __res_search
+#define res_send __res_send
+#define res_sendsigned __res_sendsigned
+
+__BEGIN_DECLS
+void fp_nquery __P((const u_char *, int, FILE *));
+void fp_query __P((const u_char *, FILE *));
+const char * hostalias __P((const char *));
+void p_query __P((const u_char *));
+void res_close __P((void));
+int res_init __P((void));
+int res_isourserver __P((const struct sockaddr_in *));
+int res_mkquery __P((int, const char *, int, int, const u_char *,
+ int, const u_char *, u_char *, int));
+int res_query __P((const char *, int, int, u_char *, int));
+int res_querydomain __P((const char *, const char *, int, int,
+ u_char *, int));
+int res_search __P((const char *, int, int, u_char *, int));
+int res_send __P((const u_char *, int, u_char *, int));
+int res_sendsigned __P((const u_char *, int, ns_tsig_key *,
+ u_char *, int));
+__END_DECLS
+#endif
+
+#if !defined(SHARED_LIBBIND) || defined(LIB)
+/*
+ * If libbind is a shared object (well, DLL anyway)
+ * these externs break the linker when resolv.h is
+ * included by a lib client (like named)
+ * Make them go away if a client is including this
+ *
+ */
+extern const struct res_sym __p_key_syms[];
+extern const struct res_sym __p_cert_syms[];
+extern const struct res_sym __p_class_syms[];
+extern const struct res_sym __p_type_syms[];
+extern const struct res_sym __p_rcode_syms[];
+#endif /* SHARED_LIBBIND */
+
+#define b64_ntop __b64_ntop
+#define b64_pton __b64_pton
+#define dn_comp __dn_comp
+#define dn_count_labels __dn_count_labels
+#define dn_expand __dn_expand
+#define dn_skipname __dn_skipname
+#define fp_resstat __fp_resstat
+#define loc_aton __loc_aton
+#define loc_ntoa __loc_ntoa
+#define p_cdname __p_cdname
+#define p_cdnname __p_cdnname
+#define p_class __p_class
+#define p_fqname __p_fqname
+#define p_fqnname __p_fqnname
+#define p_option __p_option
+#define p_secstodate __p_secstodate
+#define p_section __p_section
+#define p_time __p_time
+#define p_type __p_type
+#define p_rcode __p_rcode
+#define p_sockun __p_sockun
+#define putlong __putlong
+#define putshort __putshort
+#define res_dnok __res_dnok
+#define res_findzonecut __res_findzonecut
+#define res_findzonecut2 __res_findzonecut2
+#define res_hnok __res_hnok
+#define res_hostalias __res_hostalias
+#define res_mailok __res_mailok
+#define res_nameinquery __res_nameinquery
+#define res_nclose __res_nclose
+#define res_ninit __res_ninit
+#define res_nmkquery __res_nmkquery
+#define res_pquery __res_pquery
+#define res_nquery __res_nquery
+#define res_nquerydomain __res_nquerydomain
+#define res_nsearch __res_nsearch
+#define res_nsend __res_nsend
+#define res_nsendsigned __res_nsendsigned
+#define res_nisourserver __res_nisourserver
+#define res_ownok __res_ownok
+#define res_queriesmatch __res_queriesmatch
+#define res_randomid __res_randomid
+#define sym_ntop __sym_ntop
+#define sym_ntos __sym_ntos
+#define sym_ston __sym_ston
+#define res_nopt __res_nopt
+#define res_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_ */
+/*! \file */
diff --git a/lib/bind/include/resolv_mt.h b/lib/bind/include/resolv_mt.h
new file mode 100644
index 0000000..27963a1
--- /dev/null
+++ b/lib/bind/include/resolv_mt.h
@@ -0,0 +1,47 @@
+#ifndef _RESOLV_MT_H
+#define _RESOLV_MT_H
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+/* Access functions for the libresolv private interface */
+
+int __res_enable_mt(void);
+int __res_disable_mt(void);
+
+/* Per-thread context */
+
+typedef struct {
+int no_hosts_fallback_private;
+int retry_save;
+int retry_private;
+char inet_nsap_ntoa_tmpbuf[255*3];
+char sym_ntos_unname[20];
+char sym_ntop_unname[20];
+char p_option_nbuf[40];
+char p_time_nbuf[40];
+char precsize_ntoa_retbuf[sizeof "90000000.00"];
+char loc_ntoa_tmpbuf[sizeof
+"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
+char p_secstodate_output[15];
+} mtctxres_t;
+
+/* Thread-specific data (TSD) */
+
+mtctxres_t *___mtctxres(void);
+#define mtctxres (___mtctxres())
+
+/* Various static data that should be TSD */
+
+#define sym_ntos_unname (mtctxres->sym_ntos_unname)
+#define sym_ntop_unname (mtctxres->sym_ntop_unname)
+#define inet_nsap_ntoa_tmpbuf (mtctxres->inet_nsap_ntoa_tmpbuf)
+#define p_option_nbuf (mtctxres->p_option_nbuf)
+#define p_time_nbuf (mtctxres->p_time_nbuf)
+#define precsize_ntoa_retbuf (mtctxres->precsize_ntoa_retbuf)
+#define loc_ntoa_tmpbuf (mtctxres->loc_ntoa_tmpbuf)
+#define p_secstodate_output (mtctxres->p_secstodate_output)
+
+#endif /* _RESOLV_MT_H */
diff --git a/lib/bind/inet/Makefile.in b/lib/bind/inet/Makefile.in
new file mode 100644
index 0000000..7eb297c
--- /dev/null
+++ b/lib/bind/inet/Makefile.in
@@ -0,0 +1,35 @@
+# 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: Makefile.in,v 1.5 2004/03/05 05:05:13 marka Exp $
+
+srcdir= @srcdir@
+VPATH = @srcdir@
+
+OBJS= inet_addr.@O@ inet_cidr_ntop.@O@ inet_cidr_pton.@O@ inet_data.@O@ \
+ inet_lnaof.@O@ inet_makeaddr.@O@ inet_net_ntop.@O@ inet_net_pton.@O@ \
+ inet_neta.@O@ inet_netof.@O@ inet_network.@O@ inet_ntoa.@O@ \
+ inet_ntop.@O@ inet_pton.@O@ nsap_addr.@O@
+
+SRCS= inet_addr.c inet_cidr_ntop.c inet_cidr_pton.c inet_data.c \
+ inet_lnaof.c inet_makeaddr.c inet_net_ntop.c inet_net_pton.c \
+ inet_neta.c inet_netof.c inet_network.c inet_ntoa.c \
+ inet_ntop.c inet_pton.c nsap_addr.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I${srcdir}/../include
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/inet/inet_addr.c b/lib/bind/inet/inet_addr.c
new file mode 100644
index 0000000..c95622d
--- /dev/null
+++ b/lib/bind/inet/inet_addr.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 1983, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
+static const char rcsid[] = "$Id: inet_addr.c,v 1.4.18.1 2005/04/27 05:00:52 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+
+#include "port_after.h"
+
+/*%
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ */
+u_long
+inet_addr(const char *cp) {
+ struct in_addr val;
+
+ if (inet_aton(cp, &val))
+ return (val.s_addr);
+ return (INADDR_NONE);
+}
+
+/*%
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+int
+inet_aton(const char *cp, struct in_addr *addr) {
+ u_long val;
+ int base, n;
+ char c;
+ u_int8_t parts[4];
+ u_int8_t *pp = parts;
+ int digit;
+
+ c = *cp;
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, isdigit=decimal.
+ */
+ if (!isdigit((unsigned char)c))
+ return (0);
+ val = 0; base = 10; digit = 0;
+ if (c == '0') {
+ c = *++cp;
+ if (c == 'x' || c == 'X')
+ base = 16, c = *++cp;
+ else {
+ base = 8;
+ digit = 1 ;
+ }
+ }
+ for (;;) {
+ if (isascii(c) && isdigit((unsigned char)c)) {
+ if (base == 8 && (c == '8' || c == '9'))
+ return (0);
+ val = (val * base) + (c - '0');
+ c = *++cp;
+ digit = 1;
+ } else if (base == 16 && isascii(c) &&
+ isxdigit((unsigned char)c)) {
+ val = (val << 4) |
+ (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
+ c = *++cp;
+ digit = 1;
+ } else
+ break;
+ }
+ if (c == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16 bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3 || val > 0xffU)
+ return (0);
+ *pp++ = val;
+ c = *++cp;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (c != '\0' && (!isascii(c) || !isspace((unsigned char)c)))
+ return (0);
+ /*
+ * Did we get a valid digit?
+ */
+ if (!digit)
+ return (0);
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n) {
+ case 1: /*%< a -- 32 bits */
+ break;
+
+ case 2: /*%< a.b -- 8.24 bits */
+ if (val > 0xffffffU)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /*%< a.b.c -- 8.8.16 bits */
+ if (val > 0xffffU)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /*%< a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xffU)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr != NULL)
+ addr->s_addr = htonl(val);
+ return (1);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_cidr_ntop.c b/lib/bind/inet/inet_cidr_ntop.c
new file mode 100644
index 0000000..645b3cd
--- /dev/null
+++ b/lib/bind/inet/inet_cidr_ntop.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_cidr_ntop.c,v 1.4.18.3 2006/10/11 02:32:47 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static char *
+inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size);
+static char *
+inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size);
+
+/*%
+ * char *
+ * inet_cidr_ntop(af, src, bits, dst, size)
+ * convert network address from network to presentation format.
+ * "src"'s size is determined from its "af".
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
+ * as called for by inet_net_ntop() but it can be a host address with
+ * an included netmask.
+ * author:
+ * Paul Vixie (ISC), October 1998
+ */
+char *
+inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {
+ switch (af) {
+ case AF_INET:
+ return (inet_cidr_ntop_ipv4(src, bits, dst, size));
+ case AF_INET6:
+ return (inet_cidr_ntop_ipv6(src, bits, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+}
+
+static int
+decoct(const u_char *src, int bytes, char *dst, size_t size) {
+ char *odst = dst;
+ char *t;
+ int b;
+
+ for (b = 1; b <= bytes; b++) {
+ if (size < sizeof "255.")
+ return (0);
+ t = dst;
+ dst += SPRINTF((dst, "%u", *src++));
+ if (b != bytes) {
+ *dst++ = '.';
+ *dst = '\0';
+ }
+ size -= (size_t)(dst - t);
+ }
+ return (dst - odst);
+}
+
+/*%
+ * static char *
+ * inet_cidr_ntop_ipv4(src, bits, dst, size)
+ * convert IPv4 network address from network to presentation format.
+ * "src"'s size is determined from its "af".
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0b11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), October 1998
+ */
+static char *
+inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {
+ char *odst = dst;
+ size_t len = 4;
+ size_t b;
+ size_t bytes;
+
+ if ((bits < -1) || (bits > 32)) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Find number of significant bytes in address. */
+ if (bits == -1)
+ len = 4;
+ else
+ for (len = 1, b = 1 ; b < 4U; b++)
+ if (*(src + b))
+ len = b + 1;
+
+ /* Format whole octets plus nonzero trailing octets. */
+ bytes = (((bits <= 0) ? 1 : bits) + 7) / 8;
+ if (len > bytes)
+ bytes = len;
+ b = decoct(src, bytes, dst, size);
+ if (b == 0U)
+ goto emsgsize;
+ dst += b;
+ size -= b;
+
+ if (bits != -1) {
+ /* Format CIDR /width. */
+ if (size < sizeof "/32")
+ goto emsgsize;
+ dst += SPRINTF((dst, "/%u", bits));
+ }
+
+ return (odst);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+static char *
+inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
+ char *tp;
+ struct { int base, len; } best, cur;
+ u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i;
+
+ if ((bits < -1) || (bits > 128)) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0;
+ cur.base = -1;
+ cur.len = 0;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 && (best.len == 6 ||
+ (best.len == 7 && words[7] != 0x0001) ||
+ (best.len == 5 && words[5] == 0xffff))) {
+ int n;
+
+ if (src[15] || bits == -1 || bits > 120)
+ n = 4;
+ else if (src[14] || bits > 112)
+ n = 3;
+ else
+ n = 2;
+ n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp));
+ if (n == 0) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+ tp += strlen(tp);
+ break;
+ }
+ tp += SPRINTF((tp, "%x", words[i]));
+ }
+
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (NS_IN6ADDRSZ / NS_INT16SZ))
+ *tp++ = ':';
+ *tp = '\0';
+
+ if (bits != -1)
+ tp += SPRINTF((tp, "/%u", bits));
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_cidr_pton.c b/lib/bind/inet/inet_cidr_pton.c
new file mode 100644
index 0000000..b55e3ea
--- /dev/null
+++ b/lib/bind/inet/inet_cidr_pton.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_cidr_pton.c,v 1.5.18.1 2005/04/27 05:00:53 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <isc/assertions.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static int inet_cidr_pton_ipv4 __P((const char *src, u_char *dst,
+ int *bits, int ipv6));
+static int inet_cidr_pton_ipv6 __P((const char *src, u_char *dst,
+ int *bits));
+
+static int getbits(const char *, int ipv6);
+
+/*%
+ * int
+ * inet_cidr_pton(af, src, dst, *bits)
+ * convert network address from presentation to network format.
+ * accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
+ * "dst" is assumed large enough for its "af". "bits" is set to the
+ * /CIDR prefix length, which can have defaults (like /32 for IPv4).
+ * return:
+ * -1 if an error occurred (inspect errno; ENOENT means bad format).
+ * 0 if successful conversion occurred.
+ * note:
+ * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
+ * as called for by inet_net_pton() but it can be a host address with
+ * an included netmask.
+ * author:
+ * Paul Vixie (ISC), October 1998
+ */
+int
+inet_cidr_pton(int af, const char *src, void *dst, int *bits) {
+ switch (af) {
+ case AF_INET:
+ return (inet_cidr_pton_ipv4(src, dst, bits, 0));
+ case AF_INET6:
+ return (inet_cidr_pton_ipv6(src, dst, bits));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+}
+
+static const char digits[] = "0123456789";
+
+static int
+inet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) {
+ const u_char *odst = dst;
+ int n, ch, tmp, bits;
+ size_t size = 4;
+
+ /* Get the mantissa. */
+ while (ch = *src++, (isascii(ch) && isdigit(ch))) {
+ tmp = 0;
+ do {
+ n = strchr(digits, ch) - digits;
+ INSIST(n >= 0 && n <= 9);
+ tmp *= 10;
+ tmp += n;
+ if (tmp > 255)
+ goto enoent;
+ } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
+ if (size-- == 0U)
+ goto emsgsize;
+ *dst++ = (u_char) tmp;
+ if (ch == '\0' || ch == '/')
+ break;
+ if (ch != '.')
+ goto enoent;
+ }
+
+ /* Get the prefix length if any. */
+ bits = -1;
+ if (ch == '/' && dst > odst) {
+ bits = getbits(src, ipv6);
+ if (bits == -2)
+ goto enoent;
+ } else if (ch != '\0')
+ goto enoent;
+
+ /* Prefix length can default to /32 only if all four octets spec'd. */
+ if (bits == -1) {
+ if (dst - odst == 4)
+ bits = ipv6 ? 128 : 32;
+ else
+ goto enoent;
+ }
+
+ /* If nothing was written to the destination, we found no address. */
+ if (dst == odst)
+ goto enoent;
+
+ /* If prefix length overspecifies mantissa, life is bad. */
+ if (((bits - (ipv6 ? 96 : 0)) / 8) > (dst - odst))
+ goto enoent;
+
+ /* Extend address to four octets. */
+ while (size-- > 0U)
+ *dst++ = 0;
+
+ *pbits = bits;
+ return (0);
+
+ enoent:
+ errno = ENOENT;
+ return (-1);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+static int
+inet_cidr_pton_ipv6(const char *src, u_char *dst, int *pbits) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ u_int val;
+ int bits;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ bits = -1;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return (0);
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_cidr_pton_ipv4(curtok, tp, &bits, 1) == 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /*%< '\\0' was seen by inet_pton4(). */
+ }
+ if (ch == '/') {
+ bits = getbits(src, 1);
+ if (bits == -2)
+ goto enoent;
+ break;
+ }
+ goto enoent;
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ goto emsgsize;
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ goto enoent;
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+
+ *pbits = bits;
+ return (0);
+
+ enoent:
+ errno = ENOENT;
+ return (-1);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+static int
+getbits(const char *src, int ipv6) {
+ int bits = 0;
+ char *cp, ch;
+
+ if (*src == '\0') /*%< syntax */
+ return (-2);
+ do {
+ ch = *src++;
+ cp = strchr(digits, ch);
+ if (cp == NULL) /*%< syntax */
+ return (-2);
+ bits *= 10;
+ bits += cp - digits;
+ if (bits == 0 && *src != '\0') /*%< no leading zeros */
+ return (-2);
+ if (bits > (ipv6 ? 128 : 32)) /*%< range error */
+ return (-2);
+ } while (*src != '\0');
+
+ return (bits);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_data.c b/lib/bind/inet/inet_data.c
new file mode 100644
index 0000000..f3fa25b
--- /dev/null
+++ b/lib/bind/inet/inet_data.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$Id: inet_data.c,v 1.3.18.1 2005/04/27 05:00:53 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+const struct in6_addr isc_in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr isc_in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+
+/*! \file */
diff --git a/lib/bind/inet/inet_lnaof.c b/lib/bind/inet/inet_lnaof.c
new file mode 100644
index 0000000..70ac409
--- /dev/null
+++ b/lib/bind/inet/inet_lnaof.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_lnaof.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*%
+ * Return the local network address portion of an
+ * internet address; handles class a/b/c network
+ * number formats.
+ */
+u_long
+inet_lnaof(in)
+ struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return ((i)&IN_CLASSA_HOST);
+ else if (IN_CLASSB(i))
+ return ((i)&IN_CLASSB_HOST);
+ else
+ return ((i)&IN_CLASSC_HOST);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_makeaddr.c b/lib/bind/inet/inet_makeaddr.c
new file mode 100644
index 0000000..c56cb3e
--- /dev/null
+++ b/lib/bind/inet/inet_makeaddr.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_makeaddr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*%
+ * Formulate an Internet address from network + host. Used in
+ * building addresses stored in the ifnet structure.
+ */
+struct in_addr
+inet_makeaddr(net, host)
+ u_long net, host;
+{
+ struct in_addr a;
+
+ if (net < 128U)
+ a.s_addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
+ else if (net < 65536U)
+ a.s_addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
+ else if (net < 16777216L)
+ a.s_addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
+ else
+ a.s_addr = net | host;
+ a.s_addr = htonl(a.s_addr);
+ return (a);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_net_ntop.c b/lib/bind/inet/inet_net_ntop.c
new file mode 100644
index 0000000..a1ac243
--- /dev/null
+++ b/lib/bind/inet/inet_net_ntop.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.3.18.2 2006/06/20 02:51:32 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static char * inet_net_ntop_ipv4 __P((const u_char *src, int bits,
+ char *dst, size_t size));
+static char * inet_net_ntop_ipv6 __P((const u_char *src, int bits,
+ char *dst, size_t size));
+
+/*%
+ * char *
+ * inet_net_ntop(af, src, bits, dst, size)
+ * convert network number from network to presentation format.
+ * generates CIDR style result always.
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * author:
+ * Paul Vixie (ISC), July 1996
+ */
+char *
+inet_net_ntop(af, src, bits, dst, size)
+ int af;
+ const void *src;
+ int bits;
+ char *dst;
+ size_t size;
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_net_ntop_ipv4(src, bits, dst, size));
+ case AF_INET6:
+ return (inet_net_ntop_ipv6(src, bits, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+}
+
+/*%
+ * static char *
+ * inet_net_ntop_ipv4(src, bits, dst, size)
+ * convert IPv4 network number from network to presentation format.
+ * generates CIDR style result always.
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0b11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), July 1996
+ */
+static char *
+inet_net_ntop_ipv4(src, bits, dst, size)
+ const u_char *src;
+ int bits;
+ char *dst;
+ size_t size;
+{
+ char *odst = dst;
+ char *t;
+ u_int m;
+ int b;
+
+ if (bits < 0 || bits > 32) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (bits == 0) {
+ if (size < sizeof "0")
+ goto emsgsize;
+ *dst++ = '0';
+ size--;
+ *dst = '\0';
+ }
+
+ /* Format whole octets. */
+ for (b = bits / 8; b > 0; b--) {
+ if (size <= sizeof "255.")
+ goto emsgsize;
+ t = dst;
+ dst += SPRINTF((dst, "%u", *src++));
+ if (b > 1) {
+ *dst++ = '.';
+ *dst = '\0';
+ }
+ size -= (size_t)(dst - t);
+ }
+
+ /* Format partial octet. */
+ b = bits % 8;
+ if (b > 0) {
+ if (size <= sizeof ".255")
+ goto emsgsize;
+ t = dst;
+ if (dst != odst)
+ *dst++ = '.';
+ m = ((1 << b) - 1) << (8 - b);
+ dst += SPRINTF((dst, "%u", *src & m));
+ size -= (size_t)(dst - t);
+ }
+
+ /* Format CIDR /width. */
+ if (size <= sizeof "/32")
+ goto emsgsize;
+ dst += SPRINTF((dst, "/%u", bits));
+ return (odst);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+/*%
+ * static char *
+ * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
+ * convert IPv6 network number from network to presentation format.
+ * generates CIDR style result always. Picks the shortest representation
+ * unless the IP is really IPv4.
+ * always prints specified number of bits (bits).
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0x11110000 in its fourth octet.
+ * author:
+ * Vadim Kogan (UCB), June 2001
+ * Original version (IPv4) by Paul Vixie (ISC), July 1996
+ */
+
+static char *
+inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
+ u_int m;
+ int b;
+ int p;
+ int zero_s, zero_l, tmp_zero_s, tmp_zero_l;
+ int i;
+ int is_ipv4 = 0;
+ unsigned char inbuf[16];
+ char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+ char *cp;
+ int words;
+ u_char *s;
+
+ if (bits < 0 || bits > 128) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ cp = outbuf;
+
+ if (bits == 0) {
+ *cp++ = ':';
+ *cp++ = ':';
+ *cp = '\0';
+ } else {
+ /* Copy src to private buffer. Zero host part. */
+ p = (bits + 7) / 8;
+ memcpy(inbuf, src, p);
+ memset(inbuf + p, 0, 16 - p);
+ b = bits % 8;
+ if (b != 0) {
+ m = ~0 << (8 - b);
+ inbuf[p-1] &= m;
+ }
+
+ s = inbuf;
+
+ /* how many words need to be displayed in output */
+ words = (bits + 15) / 16;
+ if (words == 1)
+ words = 2;
+
+ /* Find the longest substring of zero's */
+ zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
+ for (i = 0; i < (words * 2); i += 2) {
+ if ((s[i] | s[i+1]) == 0) {
+ if (tmp_zero_l == 0)
+ tmp_zero_s = i / 2;
+ tmp_zero_l++;
+ } else {
+ if (tmp_zero_l && zero_l < tmp_zero_l) {
+ zero_s = tmp_zero_s;
+ zero_l = tmp_zero_l;
+ tmp_zero_l = 0;
+ }
+ }
+ }
+
+ if (tmp_zero_l && zero_l < tmp_zero_l) {
+ zero_s = tmp_zero_s;
+ zero_l = tmp_zero_l;
+ }
+
+ if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
+ ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
+ ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
+ is_ipv4 = 1;
+
+ /* Format whole words. */
+ for (p = 0; p < words; p++) {
+ if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
+ /* Time to skip some zeros */
+ if (p == zero_s)
+ *cp++ = ':';
+ if (p == words - 1)
+ *cp++ = ':';
+ s++;
+ s++;
+ continue;
+ }
+
+ if (is_ipv4 && p > 5 ) {
+ *cp++ = (p == 6) ? ':' : '.';
+ cp += SPRINTF((cp, "%u", *s++));
+ /* we can potentially drop the last octet */
+ if (p != 7 || bits > 120) {
+ *cp++ = '.';
+ cp += SPRINTF((cp, "%u", *s++));
+ }
+ } else {
+ if (cp != outbuf)
+ *cp++ = ':';
+ cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
+ s += 2;
+ }
+ }
+ }
+ /* Format CIDR /width. */
+ sprintf(cp, "/%u", bits);
+ if (strlen(outbuf) + 1 > size)
+ goto emsgsize;
+ strcpy(dst, outbuf);
+
+ return (dst);
+
+emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_net_pton.c b/lib/bind/inet/inet_net_pton.c
new file mode 100644
index 0000000..d3de33b
--- /dev/null
+++ b/lib/bind/inet/inet_net_pton.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_net_pton.c,v 1.7.18.1 2005/04/27 05:00:53 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <isc/assertions.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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);
+ }
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_neta.c b/lib/bind/inet/inet_neta.c
new file mode 100644
index 0000000..bc3b601
--- /dev/null
+++ b/lib/bind/inet/inet_neta.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_neta.c,v 1.2.18.1 2005/04/27 05:00:53 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/*%
+ * char *
+ * inet_neta(src, dst, size)
+ * format a u_long network number into presentation format.
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * format of ``src'' is as for inet_network().
+ * author:
+ * Paul Vixie (ISC), July 1996
+ */
+char *
+inet_neta(src, dst, size)
+ u_long src;
+ char *dst;
+ size_t size;
+{
+ char *odst = dst;
+ char *tp;
+
+ while (src & 0xffffffff) {
+ u_char b = (src & 0xff000000) >> 24;
+
+ src <<= 8;
+ if (b) {
+ if (size < sizeof "255.")
+ goto emsgsize;
+ tp = dst;
+ dst += SPRINTF((dst, "%u", b));
+ if (src != 0L) {
+ *dst++ = '.';
+ *dst = '\0';
+ }
+ size -= (size_t)(dst - tp);
+ }
+ }
+ if (dst == odst) {
+ if (size < sizeof "0.0.0.0")
+ goto emsgsize;
+ strcpy(dst, "0.0.0.0");
+ }
+ return (odst);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_netof.c b/lib/bind/inet/inet_netof.c
new file mode 100644
index 0000000..c228e3d
--- /dev/null
+++ b/lib/bind/inet/inet_netof.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_netof.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*%
+ * Return the network number from an internet
+ * address; handles class a/b/c network #'s.
+ */
+u_long
+inet_netof(in)
+ struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
+ else if (IN_CLASSB(i))
+ return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
+ else
+ return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_network.c b/lib/bind/inet/inet_network.c
new file mode 100644
index 0000000..4758a00
--- /dev/null
+++ b/lib/bind/inet/inet_network.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_network.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+#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);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_ntoa.c b/lib/bind/inet/inet_ntoa.c
new file mode 100644
index 0000000..1d566be
--- /dev/null
+++ b/lib/bind/inet/inet_ntoa.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: inet_ntoa.c,v 1.1.352.1 2005/04/27 05:00:54 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+/*%
+ * Convert network-format internet address
+ * to base 256 d.d.d.d representation.
+ */
+/*const*/ char *
+inet_ntoa(struct in_addr in) {
+ static char ret[18];
+
+ strcpy(ret, "[inet_ntoa error]");
+ (void) inet_ntop(AF_INET, &in, ret, sizeof ret);
+ return (ret);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_ntop.c b/lib/bind/inet/inet_ntop.c
new file mode 100644
index 0000000..9ab38bc
--- /dev/null
+++ b/lib/bind/inet/inet_ntop.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_ntop.c,v 1.3.18.2 2005/11/03 23:02:22 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/*%
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size));
+static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size));
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *
+inet_ntop(af, src, dst, size)
+ int af;
+ const void *src;
+ char *dst;
+ size_t size;
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address
+ * return:
+ * `dst' (as a const)
+ * notes:
+ * (1) uses no statics
+ * (2) takes a u_char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(src, dst, size)
+ const u_char *src;
+ char *dst;
+ size_t size;
+{
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+
+ if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6(src, dst, size)
+ const u_char *src;
+ char *dst;
+ size_t size;
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ struct { int base, len; } best, cur;
+ u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0;
+ cur.base = -1;
+ cur.len = 0;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 && (best.len == 6 ||
+ (best.len == 7 && words[7] != 0x0001) ||
+ (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+ return (NULL);
+ tp += strlen(tp);
+ break;
+ }
+ tp += SPRINTF((tp, "%x", words[i]));
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (NS_IN6ADDRSZ / NS_INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/inet_pton.c b/lib/bind/inet/inet_pton.c
new file mode 100644
index 0000000..66b4c6a
--- /dev/null
+++ b/lib/bind/inet/inet_pton.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_pton.c,v 1.3.18.2 2005/07/28 07:38:07 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <string.h>
+#include <errno.h>
+#include "port_after.h"
+
+/*%
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4 __P((const char *src, u_char *dst));
+static int inet_pton6 __P((const char *src, u_char *dst));
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+inet_pton(af, src, dst)
+ int af;
+ const char *src;
+ void *dst;
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(src, dst)
+ const char *src;
+ u_char *dst;
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ u_char tmp[NS_INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ u_int new = *tp * 10 + (pch - digits);
+
+ if (saw_digit && *tp == 0)
+ return (0);
+ if (new > 255)
+ return (0);
+ *tp = new;
+ if (!saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ memcpy(dst, tmp, NS_INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(src, dst)
+ const char *src;
+ u_char *dst;
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, seen_xdigits;
+ u_int val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ seen_xdigits = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (++seen_xdigits > 4)
+ return (0);
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!seen_xdigits) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return (0);
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ seen_xdigits = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ seen_xdigits = 0;
+ break; /*%< '\\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (seen_xdigits) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ return (0);
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+ return (1);
+}
+
+/*! \file */
diff --git a/lib/bind/inet/nsap_addr.c b/lib/bind/inet/nsap_addr.c
new file mode 100644
index 0000000..d8fe87c
--- /dev/null
+++ b/lib/bind/inet/nsap_addr.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nsap_addr.c,v 1.3.18.2 2005/07/28 07:38:08 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv.h>
+#include <resolv_mt.h>
+
+#include "port_after.h"
+
+static char
+xtob(int c) {
+ return (c - (((c >= '0') && (c <= '9')) ? '0' : '7'));
+}
+
+u_int
+inet_nsap_addr(const char *ascii, u_char *binary, int maxlen) {
+ u_char c, nib;
+ u_int len = 0;
+
+ if (ascii[0] != '0' || (ascii[1] != 'x' && ascii[1] != 'X'))
+ return (0);
+ ascii += 2;
+
+ while ((c = *ascii++) != '\0' && len < (u_int)maxlen) {
+ if (c == '.' || c == '+' || c == '/')
+ continue;
+ if (!isascii(c))
+ return (0);
+ if (islower(c))
+ c = toupper(c);
+ if (isxdigit(c)) {
+ nib = xtob(c);
+ c = *ascii++;
+ if (c != '\0') {
+ c = toupper(c);
+ if (isxdigit(c)) {
+ *binary++ = (nib << 4) | xtob(c);
+ len++;
+ } else
+ return (0);
+ }
+ else
+ return (0);
+ }
+ else
+ return (0);
+ }
+ return (len);
+}
+
+char *
+inet_nsap_ntoa(int binlen, const u_char *binary, char *ascii) {
+ int nib;
+ int i;
+ char *tmpbuf = inet_nsap_ntoa_tmpbuf;
+ char *start;
+
+ if (ascii)
+ start = ascii;
+ else {
+ ascii = tmpbuf;
+ start = tmpbuf;
+ }
+
+ *ascii++ = '0';
+ *ascii++ = 'x';
+
+ if (binlen > 255)
+ binlen = 255;
+
+ for (i = 0; i < binlen; i++) {
+ nib = *binary >> 4;
+ *ascii++ = nib + (nib < 10 ? '0' : '7');
+ nib = *binary++ & 0x0f;
+ *ascii++ = nib + (nib < 10 ? '0' : '7');
+ if (((i % 2) == 0 && (i + 1) < binlen))
+ *ascii++ = '.';
+ }
+ *ascii = '\0';
+ return (start);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/Makefile.in b/lib/bind/irs/Makefile.in
new file mode 100644
index 0000000..ce6f5f2
--- /dev/null
+++ b/lib/bind/irs/Makefile.in
@@ -0,0 +1,70 @@
+# 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: Makefile.in,v 1.8.18.2 2004/12/07 00:53:48 marka Exp $
+
+srcdir= @srcdir@
+VPATH = @srcdir@
+
+WANT_IRS_THREADS_OBJS= gethostent_r.@O@ getnetent_r.@O@ getnetgrent_r.@O@ \
+ getprotoent_r.@O@ getservent_r.@O@
+
+WANT_IRS_NISGR_OBJS= nis_gr.@O@
+WANT_IRS_GR_OBJS= dns_gr.@O@ irp_gr.@O@ lcl_gr.@O@ gen_gr.@O@ getgrent.@O@ \
+ @WANT_IRS_NISGR_OBJS@ @WANT_IRS_THREADSGR_OBJS@
+
+WANT_IRS_THREADSPW_OBJS=getpwent_r.@O@
+WANT_IRS_NISPW_OBJS= nis_pw.@O@
+WANT_IRS_DBPW_OBJS=irp_pw.@O@ lcl_pw.@O@
+WANT_IRS_PW_OBJS= dns_pw.@O@ gen_pw.@O@ getpwent.@O@ \
+ @WANT_IRS_DBPW_OBJS@ @WANT_IRS_NISPW_OBJS@ @WANT_IRS_THREADSPW_OBJS@
+
+WANT_IRS_NIS_OBJS= \
+ nis_ho.@O@ nis_ng.@O@ nis_nw.@O@ nis_pr.@O@ nis_sv.@O@
+
+OBJS= @WANT_IRS_GR_OBJS@ @WANT_IRS_NIS_OBJS@ @WANT_IRS_THREADS_OBJS@ \
+ @WANT_IRS_PW_OBJS@ \
+ dns.@O@ dns_ho.@O@ dns_nw.@O@ dns_pr.@O@ \
+ dns_sv.@O@ gai_strerror.@O@ gen.@O@ gen_ho.@O@ \
+ gen_ng.@O@ gen_nw.@O@ gen_pr.@O@ gen_sv.@O@ \
+ getaddrinfo.@O@ gethostent.@O@ \
+ getnameinfo.@O@ getnetent.@O@ \
+ getnetgrent.@O@ getprotoent.@O@ getservent.@O@ \
+ hesiod.@O@ irp.@O@ irp_ho.@O@ irp_ng.@O@ irp_nw.@O@ \
+ irp_pr.@O@ irp_sv.@O@ irpmarshall.@O@ irs_data.@O@ \
+ lcl.@O@ lcl_ho.@O@ lcl_ng.@O@ lcl_nw.@O@ lcl_pr.@O@ \
+ lcl_sv.@O@ nis.@O@ nul_ng.@O@ util.@O@
+
+SRCS= dns.c dns_gr.c dns_ho.c dns_nw.c dns_pr.c dns_pw.c \
+ dns_sv.c gai_strerror.c gen.c gen_gr.c gen_ho.c \
+ gen_ng.c gen_nw.c gen_pr.c gen_pw.c gen_sv.c \
+ getaddrinfo.c getgrent.c gethostent.c \
+ getnameinfo.c getnetent.c getnetent_r.c \
+ getnetgrent.c getprotoent.c getpwent.c getservent.c \
+ hesiod.c irp.c irp_gr.c irp_ho.c irp_ng.c irp_nw.c \
+ irp_pr.c irp_pw.c irp_sv.c irpmarshall.c irs_data.c \
+ lcl.c lcl_gr.c lcl_ho.c lcl_ng.c lcl_nw.c lcl_pr.c \
+ lcl_pw.c lcl_sv.c nis.c nis_gr.c nis_ho.c nis_ng.c \
+ nis_nw.c nis_pr.c nis_pw.c nis_sv.c nul_ng.c \
+ util.c getgrent_r.c gethostent_r.c getnetgrent_r.c getprotoent_r.c \
+ getpwent_r.c getservent_r.c
+
+WANT_IRS_THREADSGR_OBJS=getgrent_r.@O@
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I${srcdir}/../include
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/irs/dns.c b/lib/bind/irs/dns.c
new file mode 100644
index 0000000..b78a1d6
--- /dev/null
+++ b/lib/bind/irs/dns.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns.c,v 1.3.18.2 2006/03/10 00:20:08 marka Exp $";
+#endif
+
+/*! \file
+ * \brief
+ * dns.c --- this is the top-level accessor function for the dns
+ */
+
+#include "port_before.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* forward */
+
+static void dns_close(struct irs_acc *);
+static struct __res_state * dns_res_get(struct irs_acc *);
+static void dns_res_set(struct irs_acc *, struct __res_state *,
+ void (*)(void *));
+
+/* public */
+
+struct irs_acc *
+irs_dns_acc(const char *options) {
+ struct irs_acc *acc;
+ struct dns_p *dns;
+
+ UNUSED(options);
+
+ if (!(acc = memget(sizeof *acc))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(acc, 0x5e, sizeof *acc);
+ if (!(dns = memget(sizeof *dns))) {
+ errno = ENOMEM;
+ memput(acc, sizeof *acc);
+ return (NULL);
+ }
+ memset(dns, 0x5e, sizeof *dns);
+ dns->res = NULL;
+ dns->free_res = NULL;
+ if (hesiod_init(&dns->hes_ctx) < 0) {
+ /*
+ * We allow the dns accessor class to initialize
+ * despite hesiod failing to initialize correctly,
+ * since dns host queries don't depend on hesiod.
+ */
+ dns->hes_ctx = NULL;
+ }
+ acc->private = dns;
+#ifdef WANT_IRS_GR
+ acc->gr_map = irs_dns_gr;
+#else
+ acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+ acc->pw_map = irs_dns_pw;
+#else
+ acc->pw_map = NULL;
+#endif
+ acc->sv_map = irs_dns_sv;
+ acc->pr_map = irs_dns_pr;
+ acc->ho_map = irs_dns_ho;
+ acc->nw_map = irs_dns_nw;
+ acc->ng_map = irs_nul_ng;
+ acc->res_get = dns_res_get;
+ acc->res_set = dns_res_set;
+ acc->close = dns_close;
+ return (acc);
+}
+
+/* methods */
+static struct __res_state *
+dns_res_get(struct irs_acc *this) {
+ struct dns_p *dns = (struct dns_p *)this->private;
+
+ if (dns->res == NULL) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (res == NULL)
+ return (NULL);
+ memset(res, 0, sizeof *res);
+ dns_res_set(this, res, free);
+ }
+
+ if ((dns->res->options & RES_INIT) == 0U &&
+ res_ninit(dns->res) < 0)
+ return (NULL);
+
+ return (dns->res);
+}
+
+static void
+dns_res_set(struct irs_acc *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct dns_p *dns = (struct dns_p *)this->private;
+
+ if (dns->res && dns->free_res) {
+ res_nclose(dns->res);
+ (*dns->free_res)(dns->res);
+ }
+ dns->res = res;
+ dns->free_res = free_res;
+}
+
+static void
+dns_close(struct irs_acc *this) {
+ struct dns_p *dns;
+
+ dns = (struct dns_p *)this->private;
+ if (dns->res && dns->free_res)
+ (*dns->free_res)(dns->res);
+ if (dns->hes_ctx)
+ hesiod_end(dns->hes_ctx);
+ memput(dns, sizeof *dns);
+ memput(this, sizeof *this);
+}
+
diff --git a/lib/bind/irs/dns_gr.c b/lib/bind/irs/dns_gr.c
new file mode 100644
index 0000000..358e5a7
--- /dev/null
+++ b/lib/bind/irs/dns_gr.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns_gr.c,v 1.3.18.1 2005/04/27 05:00:54 sra Exp $";
+#endif
+
+/*! \file
+ * \brief
+ * dns_gr.c --- this file contains the functions for accessing
+ * group information from Hesiod.
+ */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_GR
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+
+#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/lib/bind/irs/dns_ho.c b/lib/bind/irs/dns_ho.c
new file mode 100644
index 0000000..d1d6f5a
--- /dev/null
+++ b/lib/bind/irs/dns_ho.c
@@ -0,0 +1,1142 @@
+/*
+ * 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.14.18.7 2006/12/07 03:54:24 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "dns_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+/* Definitions. */
+
+#define MAXALIASES 35
+#define MAXADDRS 35
+
+#define MAXPACKET (65535) /*%< Maximum TCP message size */
+#define BOUNDS_CHECK(ptr, count) \
+ if ((ptr) + (count) > eom) { \
+ had_error++; \
+ continue; \
+ } else (void)0
+
+typedef union {
+ HEADER hdr;
+ u_char buf[MAXPACKET];
+} querybuf;
+
+struct dns_res_target {
+ struct dns_res_target *next;
+ querybuf qbuf; /*%< query buffer */
+ u_char *answer; /*%< buffer to put answer */
+ int anslen; /*%< size of answer buffer */
+ int qclass, qtype; /*%< class and type of query */
+ int action; /*%< condition whether query is really issued */
+ char qname[MAXDNAME +1]; /*%< domain name */
+#if 0
+ int n; /*%< result length */
+#endif
+};
+enum {RESTGT_DOALWAYS, RESTGT_AFTERFAILURE, RESTGT_IGNORE};
+enum {RESQRY_SUCCESS, RESQRY_FAIL};
+
+struct pvt {
+ struct hostent host;
+ char * h_addr_ptrs[MAXADDRS + 1];
+ char * host_aliases[MAXALIASES];
+ char hostbuf[8*1024];
+ u_char host_addr[16]; /*%< IPv4 or IPv6 */
+ struct __res_state *res;
+ void (*free_res)(void *);
+};
+
+typedef union {
+ int32_t al;
+ char ac;
+} align;
+
+static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
+static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+/* Note: the IPv6 loopback address is in the "tunnel" space */
+static const u_char v6local[] = { 0,0, 0,1 }; /*%< last 4 bytes of IPv6 addr */
+/* Forwards. */
+
+static void ho_close(struct irs_ho *this);
+static struct hostent * ho_byname(struct irs_ho *this, const char *name);
+static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
+ int af);
+static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ int len, int af);
+static struct hostent * ho_next(struct irs_ho *this);
+static void ho_rewind(struct irs_ho *this);
+static void ho_minimize(struct irs_ho *this);
+static struct __res_state * ho_res_get(struct irs_ho *this);
+static void ho_res_set(struct irs_ho *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+ const struct addrinfo *pai);
+
+static void map_v4v6_hostent(struct hostent *hp, char **bp,
+ char *ep);
+static void addrsort(res_state, char **, int);
+static struct hostent * gethostans(struct irs_ho *this,
+ const u_char *ansbuf, int anslen,
+ const char *qname, int qtype,
+ int af, int size,
+ struct addrinfo **ret_aip,
+ const struct addrinfo *pai);
+static int add_hostent(struct pvt *pvt, char *bp, char **hap,
+ struct addrinfo *ai);
+static int init(struct irs_ho *this);
+
+/* Exports. */
+
+struct irs_ho *
+irs_dns_ho(struct irs_acc *this) {
+ struct irs_ho *ho;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+
+ if (!(ho = memget(sizeof *ho))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ho, 0x5e, sizeof *ho);
+ ho->private = pvt;
+ ho->close = ho_close;
+ ho->byname = ho_byname;
+ ho->byname2 = ho_byname2;
+ ho->byaddr = ho_byaddr;
+ ho->next = ho_next;
+ ho->rewind = ho_rewind;
+ ho->minimize = ho_minimize;
+ ho->res_get = ho_res_get;
+ ho->res_set = ho_res_set;
+ ho->addrinfo = ho_addrinfo;
+ return (ho);
+}
+
+/* Methods. */
+
+static void
+ho_close(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ho_minimize(this);
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (pvt->res->options & RES_USE_INET6) {
+ hp = ho_byname2(this, name, AF_INET6);
+ if (hp)
+ return (hp);
+ }
+ return (ho_byname2(this, name, AF_INET));
+}
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp = NULL;
+ int n, size;
+ char tmp[NS_MAXDNAME];
+ const char *cp;
+ struct addrinfo ai;
+ struct dns_res_target *q, *p;
+ int querystate = RESQRY_FAIL;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ q = memget(sizeof(*q));
+ if (q == NULL) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ memset(q, 0, sizeof(*q));
+
+ switch (af) {
+ case AF_INET:
+ size = INADDRSZ;
+ q->qclass = C_IN;
+ q->qtype = T_A;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->action = RESTGT_DOALWAYS;
+ break;
+ case AF_INET6:
+ size = IN6ADDRSZ;
+ q->qclass = C_IN;
+ q->qtype = T_AAAA;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->action = RESTGT_DOALWAYS;
+ break;
+ default:
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = EAFNOSUPPORT;
+ hp = NULL;
+ goto cleanup;
+ }
+
+ /*
+ * if there aren't any dots, it could be a user-level alias.
+ * this is also done in res_nquery() since we are not the only
+ * function that looks up host names.
+ */
+ if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name,
+ tmp, sizeof tmp)))
+ name = cp;
+
+ for (p = q; p; p = p->next) {
+ switch(p->action) {
+ case RESTGT_DOALWAYS:
+ break;
+ case RESTGT_AFTERFAILURE:
+ if (querystate == RESQRY_SUCCESS)
+ continue;
+ break;
+ case RESTGT_IGNORE:
+ continue;
+ }
+
+ if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype,
+ p->answer, p->anslen)) < 0) {
+ querystate = RESQRY_FAIL;
+ continue;
+ }
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_family = af;
+ if ((hp = gethostans(this, p->answer, n, name, p->qtype,
+ af, size, NULL,
+ (const struct addrinfo *)&ai)) != NULL)
+ goto cleanup; /*%< no more loop is necessary */
+ querystate = RESQRY_FAIL;
+ continue;
+ }
+
+ cleanup:
+ if (q != NULL)
+ memput(q, sizeof(*q));
+ return(hp);
+}
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ const u_char *uaddr = addr;
+ char *qp;
+ struct hostent *hp = NULL;
+ struct addrinfo ai;
+ struct dns_res_target *q, *q2, *p;
+ int n, size, i;
+ int querystate = RESQRY_FAIL;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ q = memget(sizeof(*q));
+ q2 = memget(sizeof(*q2));
+ if (q == NULL || q2 == NULL) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ memset(q, 0, sizeof(*q));
+ memset(q2, 0, sizeof(*q2));
+
+ if (af == AF_INET6 && len == IN6ADDRSZ &&
+ (!memcmp(uaddr, mapped, sizeof mapped) ||
+ (!memcmp(uaddr, tunnelled, sizeof tunnelled) &&
+ memcmp(&uaddr[sizeof tunnelled], v6local, sizeof(v6local))))) {
+ /* Unmap. */
+ addr = (const char *)addr + sizeof mapped;
+ uaddr += sizeof mapped;
+ af = AF_INET;
+ len = INADDRSZ;
+ }
+ switch (af) {
+ case AF_INET:
+ size = INADDRSZ;
+ q->qclass = C_IN;
+ q->qtype = T_PTR;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->action = RESTGT_DOALWAYS;
+ break;
+ case AF_INET6:
+ size = IN6ADDRSZ;
+ q->qclass = C_IN;
+ q->qtype = T_PTR;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->next = q2;
+ q->action = RESTGT_DOALWAYS;
+ q2->qclass = C_IN;
+ q2->qtype = T_PTR;
+ q2->answer = q2->qbuf.buf;
+ q2->anslen = sizeof(q2->qbuf);
+ if ((pvt->res->options & RES_NO_NIBBLE2) != 0U)
+ q2->action = RESTGT_IGNORE;
+ else
+ q2->action = RESTGT_AFTERFAILURE;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ hp = NULL;
+ goto cleanup;
+ }
+ if (size > len) {
+ errno = EINVAL;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ hp = NULL;
+ goto cleanup;
+ }
+ switch (af) {
+ case AF_INET:
+ qp = q->qname;
+ (void) sprintf(qp, "%u.%u.%u.%u.in-addr.arpa",
+ (uaddr[3] & 0xff),
+ (uaddr[2] & 0xff),
+ (uaddr[1] & 0xff),
+ (uaddr[0] & 0xff));
+ break;
+ case AF_INET6:
+ if (q->action != RESTGT_IGNORE) {
+ const char *nibsuff = res_get_nibblesuffix(pvt->res);
+ qp = q->qname;
+ for (n = IN6ADDRSZ - 1; n >= 0; n--) {
+ i = SPRINTF((qp, "%x.%x.",
+ uaddr[n] & 0xf,
+ (uaddr[n] >> 4) & 0xf));
+ if (i != 4)
+ abort();
+ qp += i;
+ }
+ if (strlen(q->qname) + strlen(nibsuff) + 1 >
+ sizeof q->qname) {
+ errno = ENAMETOOLONG;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ hp = NULL;
+ goto cleanup;
+ }
+ strcpy(qp, nibsuff); /* (checked) */
+ }
+ if (q2->action != RESTGT_IGNORE) {
+ const char *nibsuff2 = res_get_nibblesuffix2(pvt->res);
+ qp = q2->qname;
+ for (n = IN6ADDRSZ - 1; n >= 0; n--) {
+ i = SPRINTF((qp, "%x.%x.",
+ uaddr[n] & 0xf,
+ (uaddr[n] >> 4) & 0xf));
+ if (i != 4)
+ abort();
+ qp += i;
+ }
+ if (strlen(q2->qname) + strlen(nibsuff2) + 1 >
+ sizeof q2->qname) {
+ errno = ENAMETOOLONG;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ hp = NULL;
+ goto cleanup;
+ }
+ strcpy(qp, nibsuff2); /* (checked) */
+ }
+ break;
+ default:
+ abort();
+ }
+
+ for (p = q; p; p = p->next) {
+ switch(p->action) {
+ case RESTGT_DOALWAYS:
+ break;
+ case RESTGT_AFTERFAILURE:
+ if (querystate == RESQRY_SUCCESS)
+ continue;
+ break;
+ case RESTGT_IGNORE:
+ continue;
+ }
+
+ if ((n = res_nquery(pvt->res, p->qname, p->qclass, p->qtype,
+ p->answer, p->anslen)) < 0) {
+ querystate = RESQRY_FAIL;
+ continue;
+ }
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_family = af;
+ hp = gethostans(this, p->answer, n, p->qname, T_PTR, af, size,
+ NULL, (const struct addrinfo *)&ai);
+ if (!hp) {
+ querystate = RESQRY_FAIL;
+ continue;
+ }
+
+ memcpy(pvt->host_addr, addr, len);
+ pvt->h_addr_ptrs[0] = (char *)pvt->host_addr;
+ pvt->h_addr_ptrs[1] = NULL;
+ if (af == AF_INET && (pvt->res->options & RES_USE_INET6)) {
+ map_v4v6_address((char*)pvt->host_addr,
+ (char*)pvt->host_addr);
+ pvt->host.h_addrtype = AF_INET6;
+ pvt->host.h_length = IN6ADDRSZ;
+ }
+
+ RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+ goto cleanup; /*%< no more loop is necessary. */
+ }
+ hp = NULL; /*%< H_ERRNO was set by subroutines */
+ cleanup:
+ if (q != NULL)
+ memput(q, sizeof(*q));
+ if (q2 != NULL)
+ memput(q2, sizeof(*q2));
+ return(hp);
+}
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+
+ UNUSED(this);
+
+ return (NULL);
+}
+
+static void
+ho_rewind(struct irs_ho *this) {
+
+ UNUSED(this);
+
+ /* NOOP */
+}
+
+static void
+ho_minimize(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+}
+
+static struct __res_state *
+ho_res_get(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ ho_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+/* XXX */
+extern struct addrinfo *addr2addrinfo __P((const struct addrinfo *,
+ const char *));
+
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ int n;
+ char tmp[NS_MAXDNAME];
+ const char *cp;
+ struct dns_res_target *q, *q2, *p;
+ struct addrinfo sentinel, *cur;
+ int querystate = RESQRY_FAIL;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ q = memget(sizeof(*q));
+ q2 = memget(sizeof(*q2));
+ if (q == NULL || q2 == NULL) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ memset(q, 0, sizeof(*q2));
+ memset(q2, 0, sizeof(*q2));
+
+ switch (pai->ai_family) {
+ case AF_UNSPEC:
+ /* prefer IPv6 */
+ q->qclass = C_IN;
+ q->qtype = T_AAAA;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->next = q2;
+ q->action = RESTGT_DOALWAYS;
+ q2->qclass = C_IN;
+ q2->qtype = T_A;
+ q2->answer = q2->qbuf.buf;
+ q2->anslen = sizeof(q2->qbuf);
+ q2->action = RESTGT_DOALWAYS;
+ break;
+ case AF_INET:
+ q->qclass = C_IN;
+ q->qtype = T_A;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->action = RESTGT_DOALWAYS;
+ break;
+ case AF_INET6:
+ q->qclass = C_IN;
+ q->qtype = T_AAAA;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->action = RESTGT_DOALWAYS;
+ break;
+ default:
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /*%< better error? */
+ goto cleanup;
+ }
+
+ /*
+ * if there aren't any dots, it could be a user-level alias.
+ * this is also done in res_nquery() since we are not the only
+ * function that looks up host names.
+ */
+ if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name,
+ tmp, sizeof tmp)))
+ name = cp;
+
+ for (p = q; p; p = p->next) {
+ struct addrinfo *ai;
+
+ switch(p->action) {
+ case RESTGT_DOALWAYS:
+ break;
+ case RESTGT_AFTERFAILURE:
+ if (querystate == RESQRY_SUCCESS)
+ continue;
+ break;
+ case RESTGT_IGNORE:
+ continue;
+ }
+
+ if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype,
+ p->answer, p->anslen)) < 0) {
+ querystate = RESQRY_FAIL;
+ continue;
+ }
+ (void)gethostans(this, p->answer, n, name, p->qtype,
+ pai->ai_family, /*%< XXX: meaningless */
+ 0, &ai, pai);
+ if (ai) {
+ querystate = RESQRY_SUCCESS;
+ cur->ai_next = ai;
+ while (cur->ai_next)
+ cur = cur->ai_next;
+ } else
+ querystate = RESQRY_FAIL;
+ }
+
+ cleanup:
+ if (q != NULL)
+ memput(q, sizeof(*q));
+ if (q2 != NULL)
+ memput(q2, sizeof(*q2));
+ return(sentinel.ai_next);
+}
+
+static void
+ho_res_set(struct irs_ho *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+}
+
+/* Private. */
+
+static struct hostent *
+gethostans(struct irs_ho *this,
+ const u_char *ansbuf, int anslen, const char *qname, int qtype,
+ int af, int size, /*!< meaningless for addrinfo cases */
+ struct addrinfo **ret_aip, const struct addrinfo *pai)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ int type, class, ancount, qdcount, n, haveanswer, had_error;
+ int error = NETDB_SUCCESS;
+ int (*name_ok)(const char *);
+ const HEADER *hp;
+ const u_char *eom;
+ const u_char *eor;
+ const u_char *cp;
+ const char *tname;
+ const char *hname;
+ char *bp, *ep, **ap, **hap;
+ char tbuf[MAXDNAME+1];
+ struct addrinfo sentinel, *cur, ai;
+
+ if (pai == NULL) abort();
+ if (ret_aip != NULL)
+ *ret_aip = NULL;
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ tname = qname;
+ eom = ansbuf + anslen;
+ switch (qtype) {
+ case T_A:
+ case T_AAAA:
+ case T_ANY: /*%< use T_ANY only for T_A/T_AAAA lookup */
+ name_ok = res_hnok;
+ break;
+ case T_PTR:
+ name_ok = res_dnok;
+ break;
+ default:
+ abort();
+ }
+
+ pvt->host.h_addrtype = af;
+ pvt->host.h_length = size;
+ hname = pvt->host.h_name = NULL;
+
+ /*
+ * Find first satisfactory answer.
+ */
+ if (ansbuf + HFIXEDSZ > eom) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ hp = (const HEADER *)ansbuf;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ bp = pvt->hostbuf;
+ ep = pvt->hostbuf + sizeof(pvt->hostbuf);
+ cp = ansbuf + HFIXEDSZ;
+ if (qdcount != 1) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ n = dn_expand(ansbuf, eom, cp, bp, ep - bp);
+ if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ cp += n + QFIXEDSZ;
+ if (cp > eom) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
+ /* res_nsend() has already verified that the query name is the
+ * same as the one we sent; this just gets the expanded name
+ * (i.e., with the succeeding search-domain tacked on).
+ */
+ n = strlen(bp) + 1; /*%< for the \\0 */
+ if (n > MAXHOSTNAMELEN) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ pvt->host.h_name = bp;
+ hname = bp;
+ bp += n;
+ /* The qname can be abbreviated, but hname is now absolute. */
+ qname = pvt->host.h_name;
+ }
+ ap = pvt->host_aliases;
+ *ap = NULL;
+ pvt->host.h_aliases = pvt->host_aliases;
+ hap = pvt->h_addr_ptrs;
+ *hap = NULL;
+ pvt->host.h_addr_list = pvt->h_addr_ptrs;
+ haveanswer = 0;
+ had_error = 0;
+ while (ancount-- > 0 && cp < eom && !had_error) {
+ n = dn_expand(ansbuf, eom, cp, bp, ep - bp);
+ if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) {
+ had_error++;
+ continue;
+ }
+ cp += n; /*%< name */
+ BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
+ type = ns_get16(cp);
+ cp += INT16SZ; /*%< type */
+ class = ns_get16(cp);
+ cp += INT16SZ + INT32SZ; /*%< class, TTL */
+ n = ns_get16(cp);
+ cp += INT16SZ; /*%< len */
+ BOUNDS_CHECK(cp, n);
+ if (class != C_IN) {
+ cp += n;
+ continue;
+ }
+ eor = cp + n;
+ if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
+ type == T_CNAME) {
+ if (haveanswer) {
+ int level = LOG_CRIT;
+#ifdef LOG_SECURITY
+ level |= LOG_SECURITY;
+#endif
+ syslog(level,
+ "gethostans: possible attempt to exploit buffer overflow while looking up %s",
+ *qname ? qname : ".");
+ }
+ n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf);
+ if (n < 0 || !maybe_ok(pvt->res, tbuf, name_ok)) {
+ had_error++;
+ continue;
+ }
+ cp += n;
+ /* Store alias. */
+ if (ap >= &pvt->host_aliases[MAXALIASES-1])
+ continue;
+ *ap++ = bp;
+ n = strlen(bp) + 1; /*%< for the \\0 */
+ bp += n;
+ /* Get canonical name. */
+ n = strlen(tbuf) + 1; /*%< for the \\0 */
+ if (n > (ep - bp) || n > MAXHOSTNAMELEN) {
+ had_error++;
+ continue;
+ }
+ strcpy(bp, tbuf); /* (checked) */
+ pvt->host.h_name = bp;
+ hname = bp;
+ bp += n;
+ continue;
+ }
+ if (qtype == T_PTR && type == T_CNAME) {
+ n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf);
+ if (n < 0 || !maybe_dnok(pvt->res, tbuf)) {
+ had_error++;
+ continue;
+ }
+ cp += n;
+#ifdef RES_USE_DNAME
+ if ((pvt->res->options & RES_USE_DNAME) != 0U)
+#endif
+ {
+ /*
+ * We may be able to check this regardless
+ * of the USE_DNAME bit, but we add the check
+ * for now since the DNAME support is
+ * experimental.
+ */
+ if (ns_samename(tname, bp) != 1)
+ continue;
+ }
+ /* Get canonical name. */
+ n = strlen(tbuf) + 1; /*%< for the \\0 */
+ if (n > (ep - bp)) {
+ had_error++;
+ continue;
+ }
+ strcpy(bp, tbuf); /* (checked) */
+ tname = bp;
+ bp += n;
+ continue;
+ }
+ if (qtype == T_ANY) {
+ if (!(type == T_A || type == T_AAAA)) {
+ cp += n;
+ continue;
+ }
+ } else if (type != qtype) {
+ cp += n;
+ continue;
+ }
+ switch (type) {
+ case T_PTR:
+ if (ret_aip != NULL) {
+ /* addrinfo never needs T_PTR */
+ cp += n;
+ continue;
+ }
+ if (ns_samename(tname, bp) != 1) {
+ cp += n;
+ continue;
+ }
+ n = dn_expand(ansbuf, eor, cp, bp, ep - bp);
+ if (n < 0 || !maybe_hnok(pvt->res, bp) ||
+ n >= MAXHOSTNAMELEN) {
+ had_error++;
+ break;
+ }
+ cp += n;
+ if (!haveanswer) {
+ pvt->host.h_name = bp;
+ hname = bp;
+ }
+ else if (ap < &pvt->host_aliases[MAXALIASES-1])
+ *ap++ = bp;
+ else
+ n = -1;
+ if (n != -1) {
+ n = strlen(bp) + 1; /*%< for the \\0 */
+ bp += n;
+ }
+ break;
+ case T_A:
+ case T_AAAA:
+ if (ns_samename(hname, bp) != 1) {
+ cp += n;
+ continue;
+ }
+ if (type == T_A && n != INADDRSZ) {
+ cp += n;
+ continue;
+ }
+ if (type == T_AAAA && n != IN6ADDRSZ) {
+ cp += n;
+ continue;
+ }
+
+ /* make addrinfo. don't overwrite constant PAI */
+ ai = *pai;
+ ai.ai_family = (type == T_AAAA) ? AF_INET6 : AF_INET;
+ cur->ai_next = addr2addrinfo(
+ (const struct addrinfo *)&ai,
+ (const char *)cp);
+ if (cur->ai_next == NULL)
+ had_error++;
+
+ if (!haveanswer) {
+ int nn;
+
+ nn = strlen(bp) + 1; /*%< for the \\0 */
+ if (nn >= MAXHOSTNAMELEN) {
+ cp += n;
+ had_error++;
+ continue;
+ }
+ pvt->host.h_name = bp;
+ hname = bp;
+ bp += nn;
+ }
+ /* Ensure alignment. */
+ bp = (char *)(((u_long)bp + (sizeof(align) - 1)) &
+ ~(sizeof(align) - 1));
+ /* Avoid overflows. */
+ if (bp + n > &pvt->hostbuf[sizeof(pvt->hostbuf) - 1]) {
+ had_error++;
+ continue;
+ }
+ if (ret_aip) { /*%< need addrinfo. keep it. */
+ while (cur->ai_next)
+ cur = cur->ai_next;
+ } else if (cur->ai_next) { /*%< need hostent */
+ struct addrinfo *aip = cur->ai_next;
+
+ for (aip = cur->ai_next; aip;
+ aip = aip->ai_next) {
+ int m;
+
+ m = add_hostent(pvt, bp, hap, aip);
+ if (m < 0) {
+ had_error++;
+ break;
+ }
+ if (m == 0)
+ continue;
+ if (hap < &pvt->h_addr_ptrs[MAXADDRS-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) - 1])
+ 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/lib/bind/irs/dns_nw.c b/lib/bind/irs/dns_nw.c
new file mode 100644
index 0000000..1d03a52
--- /dev/null
+++ b/lib/bind/irs/dns_nw.c
@@ -0,0 +1,591 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns_nw.c,v 1.9.18.3 2005/04/27 05:00:55 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "dns_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+/* Definitions. */
+
+#define MAXALIASES 35
+
+#define MAXPACKET (64*1024)
+
+struct pvt {
+ struct nwent net;
+ char * ali[MAXALIASES];
+ char buf[BUFSIZ+1];
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+typedef union {
+ long al;
+ char ac;
+} align;
+
+enum by_what { by_addr, by_name };
+
+/* Forwards. */
+
+static void nw_close(struct irs_nw *);
+static struct nwent * nw_byname(struct irs_nw *, const char *, int);
+static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int);
+static struct nwent * nw_next(struct irs_nw *);
+static void nw_rewind(struct irs_nw *);
+static void nw_minimize(struct irs_nw *);
+static struct __res_state * nw_res_get(struct irs_nw *this);
+static void nw_res_set(struct irs_nw *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+
+static struct nwent * get1101byaddr(struct irs_nw *, u_char *, int);
+static struct nwent * get1101byname(struct irs_nw *, const char *);
+static struct nwent * get1101answer(struct irs_nw *,
+ u_char *ansbuf, int anslen,
+ enum by_what by_what,
+ int af, const char *name,
+ const u_char *addr, int addrlen);
+static struct nwent * get1101mask(struct irs_nw *this, struct nwent *);
+static int make1101inaddr(const u_char *, int, char *, int);
+static void normalize_name(char *name);
+static int init(struct irs_nw *this);
+
+/* Exports. */
+
+struct irs_nw *
+irs_dns_nw(struct irs_acc *this) {
+ struct irs_nw *nw;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(nw = memget(sizeof *nw))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(nw, 0x5e, sizeof *nw);
+ nw->private = pvt;
+ nw->close = nw_close;
+ nw->byname = nw_byname;
+ nw->byaddr = nw_byaddr;
+ nw->next = nw_next;
+ nw->rewind = nw_rewind;
+ nw->minimize = nw_minimize;
+ nw->res_get = nw_res_get;
+ nw->res_set = nw_res_set;
+ return (nw);
+}
+
+/* Methods. */
+
+static void
+nw_close(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ nw_minimize(this);
+
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ switch (af) {
+ case AF_INET:
+ return (get1101byname(this, name));
+ default:
+ (void)NULL;
+ }
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = EAFNOSUPPORT;
+ return (NULL);
+}
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int len, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ switch (af) {
+ case AF_INET:
+ return (get1101byaddr(this, net, len));
+ default:
+ (void)NULL;
+ }
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = EAFNOSUPPORT;
+ return (NULL);
+}
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+
+ UNUSED(this);
+
+ return (NULL);
+}
+
+static void
+nw_rewind(struct irs_nw *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+static void
+nw_minimize(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+}
+
+static struct __res_state *
+nw_res_get(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ nw_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+nw_res_set(struct irs_nw *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+}
+
+/* Private. */
+
+static struct nwent *
+get1101byname(struct irs_nw *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ u_char *ansbuf;
+ int anslen;
+ struct nwent *result;
+
+ ansbuf = memget(MAXPACKET);
+ if (ansbuf == NULL) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ anslen = res_nsearch(pvt->res, name, C_IN, T_PTR, ansbuf, MAXPACKET);
+ if (anslen < 0) {
+ memput(ansbuf, MAXPACKET);
+ return (NULL);
+ }
+ result = get1101mask(this, get1101answer(this, ansbuf, anslen, by_name,
+ AF_INET, name, NULL, 0));
+ memput(ansbuf, MAXPACKET);
+ return (result);
+}
+
+static struct nwent *
+get1101byaddr(struct irs_nw *this, u_char *net, int len) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char qbuf[sizeof "255.255.255.255.in-addr.arpa"];
+ struct nwent *result;
+ u_char *ansbuf;
+ int anslen;
+
+ if (len < 1 || len > 32) {
+ errno = EINVAL;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ if (make1101inaddr(net, len, qbuf, sizeof qbuf) < 0)
+ return (NULL);
+ ansbuf = memget(MAXPACKET);
+ if (ansbuf == NULL) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ anslen = res_nquery(pvt->res, qbuf, C_IN, T_PTR, ansbuf, MAXPACKET);
+ if (anslen < 0) {
+ memput(ansbuf, MAXPACKET);
+ return (NULL);
+ }
+ result = get1101mask(this, get1101answer(this, ansbuf, anslen, by_addr,
+ AF_INET, NULL, net, len));
+ memput(ansbuf, MAXPACKET);
+ return (result);
+}
+
+static struct nwent *
+get1101answer(struct irs_nw *this,
+ u_char *ansbuf, int anslen, enum by_what by_what,
+ int af, const char *name, const u_char *addr, int addrlen)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ int type, class, ancount, qdcount, haveanswer;
+ char *bp, *ep, **ap;
+ u_char *cp, *eom;
+ HEADER *hp;
+
+ /* Initialize, and parse header. */
+ eom = ansbuf + anslen;
+ if (ansbuf + HFIXEDSZ > eom) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ hp = (HEADER *)ansbuf;
+ cp = ansbuf + HFIXEDSZ;
+ qdcount = ntohs(hp->qdcount);
+ while (qdcount-- > 0) {
+ int n = dn_skipname(cp, eom);
+ cp += n + QFIXEDSZ;
+ if (n < 0 || cp > eom) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ }
+ ancount = ntohs(hp->ancount);
+ if (!ancount) {
+ if (hp->aa)
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ else
+ RES_SET_H_ERRNO(pvt->res, TRY_AGAIN);
+ return (NULL);
+ }
+
+ /* Prepare a return structure. */
+ bp = pvt->buf;
+ ep = pvt->buf + sizeof(pvt->buf);
+ pvt->net.n_name = NULL;
+ pvt->net.n_aliases = pvt->ali;
+ pvt->net.n_addrtype = af;
+ pvt->net.n_addr = NULL;
+ pvt->net.n_length = addrlen;
+
+ /* Save input key if given. */
+ switch (by_what) {
+ case by_name:
+ if (name != NULL) {
+ int n = strlen(name) + 1;
+
+ if (n > (ep - bp)) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ pvt->net.n_name = strcpy(bp, name); /* (checked) */
+ bp += n;
+ }
+ break;
+ case by_addr:
+ if (addr != NULL && addrlen != 0) {
+ int n = addrlen / 8 + ((addrlen % 8) != 0);
+
+ if (INADDRSZ > (ep - bp)) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ memset(bp, 0, INADDRSZ);
+ memcpy(bp, addr, n);
+ pvt->net.n_addr = bp;
+ bp += INADDRSZ;
+ }
+ break;
+ default:
+ abort();
+ }
+
+ /* Parse the answer, collect aliases. */
+ ap = pvt->ali;
+ haveanswer = 0;
+ while (--ancount >= 0 && cp < eom) {
+ int n = dn_expand(ansbuf, eom, cp, bp, ep - bp);
+
+ cp += n; /*%< Owner */
+ if (n < 0 || !maybe_dnok(pvt->res, bp) ||
+ cp + 3 * INT16SZ + INT32SZ > eom) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ GETSHORT(type, cp); /*%< Type */
+ GETSHORT(class, cp); /*%< Class */
+ cp += INT32SZ; /*%< TTL */
+ GETSHORT(n, cp); /*%< RDLENGTH */
+ if (class == C_IN && type == T_PTR) {
+ int nn;
+
+ nn = dn_expand(ansbuf, eom, cp, bp, ep - bp);
+ if (nn < 0 || !maybe_hnok(pvt->res, bp) || nn != n) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ normalize_name(bp);
+ switch (by_what) {
+ case by_addr: {
+ if (pvt->net.n_name == NULL)
+ pvt->net.n_name = bp;
+ else if (ns_samename(pvt->net.n_name, bp) == 1)
+ break;
+ else
+ *ap++ = bp;
+ nn = strlen(bp) + 1;
+ bp += nn;
+ haveanswer++;
+ break;
+ }
+ case by_name: {
+ u_int b1, b2, b3, b4;
+
+ if (pvt->net.n_addr != NULL ||
+ sscanf(bp, "%u.%u.%u.%u.in-addr.arpa",
+ &b1, &b2, &b3, &b4) != 4)
+ break;
+ if ((ep - bp) < INADDRSZ) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ pvt->net.n_addr = bp;
+ *bp++ = b4;
+ *bp++ = b3;
+ *bp++ = b2;
+ *bp++ = b1;
+ pvt->net.n_length = INADDRSZ * 8;
+ haveanswer++;
+ }
+ }
+ }
+ cp += n; /*%< RDATA */
+ }
+ if (!haveanswer) {
+ RES_SET_H_ERRNO(pvt->res, TRY_AGAIN);
+ return (NULL);
+ }
+ *ap = NULL;
+
+ return (&pvt->net);
+}
+
+static struct nwent *
+get1101mask(struct irs_nw *this, struct nwent *nwent) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char qbuf[sizeof "255.255.255.255.in-addr.arpa"], owner[MAXDNAME];
+ int anslen, type, class, ancount, qdcount;
+ u_char *ansbuf, *cp, *eom;
+ HEADER *hp;
+
+ if (!nwent)
+ return (NULL);
+ if (make1101inaddr(nwent->n_addr, nwent->n_length, qbuf, sizeof qbuf)
+ < 0) {
+ /* "First, do no harm." */
+ return (nwent);
+ }
+
+ ansbuf = memget(MAXPACKET);
+ if (ansbuf == NULL) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ /* Query for the A RR that would hold this network's mask. */
+ anslen = res_nquery(pvt->res, qbuf, C_IN, T_A, ansbuf, MAXPACKET);
+ if (anslen < HFIXEDSZ) {
+ memput(ansbuf, MAXPACKET);
+ return (nwent);
+ }
+
+ /* Initialize, and parse header. */
+ hp = (HEADER *)ansbuf;
+ cp = ansbuf + HFIXEDSZ;
+ eom = ansbuf + anslen;
+ qdcount = ntohs(hp->qdcount);
+ while (qdcount-- > 0) {
+ int n = dn_skipname(cp, eom);
+ cp += n + QFIXEDSZ;
+ if (n < 0 || cp > eom) {
+ memput(ansbuf, MAXPACKET);
+ return (nwent);
+ }
+ }
+ ancount = ntohs(hp->ancount);
+
+ /* Parse the answer, collect aliases. */
+ while (--ancount >= 0 && cp < eom) {
+ int n = dn_expand(ansbuf, eom, cp, owner, sizeof owner);
+
+ if (n < 0 || !maybe_dnok(pvt->res, owner))
+ break;
+ cp += n; /*%< Owner */
+ if (cp + 3 * INT16SZ + INT32SZ > eom)
+ break;
+ GETSHORT(type, cp); /*%< Type */
+ GETSHORT(class, cp); /*%< Class */
+ cp += INT32SZ; /*%< TTL */
+ GETSHORT(n, cp); /*%< RDLENGTH */
+ if (cp + n > eom)
+ break;
+ if (n == INADDRSZ && class == C_IN && type == T_A &&
+ ns_samename(qbuf, owner) == 1) {
+ /* This A RR indicates the actual netmask. */
+ int nn, mm;
+
+ nwent->n_length = 0;
+ for (nn = 0; nn < INADDRSZ; nn++)
+ for (mm = 7; mm >= 0; mm--)
+ if (cp[nn] & (1 << mm))
+ nwent->n_length++;
+ else
+ break;
+ }
+ cp += n; /*%< RDATA */
+ }
+ memput(ansbuf, MAXPACKET);
+ return (nwent);
+}
+
+static int
+make1101inaddr(const u_char *net, int bits, char *name, int size) {
+ int n, m;
+ char *ep;
+
+ ep = name + size;
+
+ /* Zero fill any whole bytes left out of the prefix. */
+ for (n = (32 - bits) / 8; n > 0; n--) {
+ if (ep - name < (int)(sizeof "0."))
+ goto emsgsize;
+ m = SPRINTF((name, "0."));
+ name += m;
+ }
+
+ /* Format the partial byte, if any, within the prefix. */
+ if ((n = bits % 8) != 0) {
+ if (ep - name < (int)(sizeof "255."))
+ goto emsgsize;
+ m = SPRINTF((name, "%u.",
+ net[bits / 8] & ~((1 << (8 - n)) - 1)));
+ name += m;
+ }
+
+ /* Format the whole bytes within the prefix. */
+ for (n = bits / 8; n > 0; n--) {
+ if (ep - name < (int)(sizeof "255."))
+ goto emsgsize;
+ m = SPRINTF((name, "%u.", net[n - 1]));
+ name += m;
+ }
+
+ /* Add the static text. */
+ if (ep - name < (int)(sizeof "in-addr.arpa"))
+ goto emsgsize;
+ (void) SPRINTF((name, "in-addr.arpa"));
+ return (0);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+static void
+normalize_name(char *name) {
+ char *t;
+
+ /* Make lower case. */
+ for (t = name; *t; t++)
+ if (isascii((unsigned char)*t) && isupper((unsigned char)*t))
+ *t = tolower((*t)&0xff);
+
+ /* Remove trailing dots. */
+ while (t > name && t[-1] == '.')
+ *--t = '\0';
+}
+
+static int
+init(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !nw_res_get(this))
+ return (-1);
+ if (((pvt->res->options & RES_INIT) == 0U) &&
+ res_ninit(pvt->res) == -1)
+ return (-1);
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/dns_p.h b/lib/bind/irs/dns_p.h
new file mode 100644
index 0000000..a19ff2d
--- /dev/null
+++ b/lib/bind/irs/dns_p.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: dns_p.h,v 1.3.18.1 2005/04/27 05:00:55 sra Exp $
+ */
+
+#ifndef _DNS_P_H_INCLUDED
+#define _DNS_P_H_INCLUDED
+
+#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
+ (ok)(nm) != 0)
+#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
+#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
+
+/*%
+ * Object state.
+ */
+struct dns_p {
+ void *hes_ctx;
+ struct __res_state *res;
+ void (*free_res) __P((void *));
+};
+
+/*
+ * Methods.
+ */
+
+extern struct irs_gr * irs_dns_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_dns_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_dns_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_dns_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_dns_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_dns_nw __P((struct irs_acc *));
+
+#endif /*_DNS_P_H_INCLUDED*/
+
+/*! \file */
diff --git a/lib/bind/irs/dns_pr.c b/lib/bind/irs/dns_pr.c
new file mode 100644
index 0000000..7582f85
--- /dev/null
+++ b/lib/bind/irs/dns_pr.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns_pr.c,v 1.4.18.1 2005/04/27 05:00:55 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* Types. */
+
+struct pvt {
+ struct dns_p * dns;
+ struct protoent proto;
+ char * prbuf;
+};
+
+/* Forward. */
+
+static void pr_close(struct irs_pr *);
+static struct protoent * pr_byname(struct irs_pr *, const char *);
+static struct protoent * pr_bynumber(struct irs_pr *, int);
+static struct protoent * pr_next(struct irs_pr *);
+static void pr_rewind(struct irs_pr *);
+static void pr_minimize(struct irs_pr *);
+static struct __res_state * pr_res_get(struct irs_pr *);
+static void pr_res_set(struct irs_pr *,
+ struct __res_state *,
+ void (*)(void *));
+
+static struct protoent * parse_hes_list(struct irs_pr *, char **);
+
+/* Public. */
+
+struct irs_pr *
+irs_dns_pr(struct irs_acc *this) {
+ struct dns_p *dns = (struct dns_p *)this->private;
+ struct pvt *pvt;
+ struct irs_pr *pr;
+
+ if (!dns->hes_ctx) {
+ errno = ENODEV;
+ return (NULL);
+ }
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(pr = memget(sizeof *pr))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pr, 0x5e, sizeof *pr);
+ pvt->dns = dns;
+ pr->private = pvt;
+ pr->byname = pr_byname;
+ pr->bynumber = pr_bynumber;
+ pr->next = pr_next;
+ pr->rewind = pr_rewind;
+ pr->close = pr_close;
+ pr->minimize = pr_minimize;
+ pr->res_get = pr_res_get;
+ pr->res_set = pr_res_set;
+ return (pr);
+}
+
+/* Methods. */
+
+static void
+pr_close(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->proto.p_aliases)
+ free(pvt->proto.p_aliases);
+ if (pvt->prbuf)
+ free(pvt->prbuf);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+ struct protoent *proto;
+ char **hes_list;
+
+ if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "protocol")))
+ return (NULL);
+
+ proto = parse_hes_list(this, hes_list);
+ hesiod_free_list(dns->hes_ctx, hes_list);
+ return (proto);
+}
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int num) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+ struct protoent *proto;
+ char numstr[16];
+ char **hes_list;
+
+ sprintf(numstr, "%d", num);
+ if (!(hes_list = hesiod_resolve(dns->hes_ctx, numstr, "protonum")))
+ return (NULL);
+
+ proto = parse_hes_list(this, hes_list);
+ hesiod_free_list(dns->hes_ctx, hes_list);
+ return (proto);
+}
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+ UNUSED(this);
+ errno = ENODEV;
+ return (NULL);
+}
+
+static void
+pr_rewind(struct irs_pr *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+static void
+pr_minimize(struct irs_pr *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+static struct __res_state *
+pr_res_get(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+
+ return (__hesiod_res_get(dns->hes_ctx));
+}
+
+static void
+pr_res_set(struct irs_pr *this, struct __res_state * res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+
+ __hesiod_res_set(dns->hes_ctx, res, free_res);
+}
+
+/* Private. */
+
+static struct protoent *
+parse_hes_list(struct irs_pr *this, char **hes_list) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *p, *cp, **cpp, **new;
+ int num = 0;
+ int max = 0;
+
+ for (cpp = hes_list; *cpp; cpp++) {
+ cp = *cpp;
+
+ /* Strip away comments, if any. */
+ if ((p = strchr(cp, '#')))
+ *p = 0;
+
+ /* Skip blank lines. */
+ p = cp;
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (!*p)
+ continue;
+
+ /* OK, we've got a live one. Let's parse it for real. */
+ if (pvt->prbuf)
+ free(pvt->prbuf);
+ pvt->prbuf = strdup(cp);
+
+ p = pvt->prbuf;
+ pvt->proto.p_name = p;
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (!*p)
+ continue;
+ *p++ = '\0';
+
+ pvt->proto.p_proto = atoi(p);
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (*p)
+ *p++ = '\0';
+
+ while (*p) {
+ if ((num + 1) >= max || !pvt->proto.p_aliases) {
+ max += 10;
+ new = realloc(pvt->proto.p_aliases,
+ max * sizeof(char *));
+ if (!new) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ pvt->proto.p_aliases = new;
+ }
+ pvt->proto.p_aliases[num++] = p;
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (*p)
+ *p++ = '\0';
+ }
+ if (!pvt->proto.p_aliases)
+ pvt->proto.p_aliases = malloc(sizeof(char *));
+ if (!pvt->proto.p_aliases)
+ goto cleanup;
+ pvt->proto.p_aliases[num] = NULL;
+ return (&pvt->proto);
+ }
+
+ cleanup:
+ if (pvt->proto.p_aliases) {
+ free(pvt->proto.p_aliases);
+ pvt->proto.p_aliases = NULL;
+ }
+ if (pvt->prbuf) {
+ free(pvt->prbuf);
+ pvt->prbuf = NULL;
+ }
+ return (NULL);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/dns_pw.c b/lib/bind/irs/dns_pw.c
new file mode 100644
index 0000000..62c61d5
--- /dev/null
+++ b/lib/bind/irs/dns_pw.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns_pw.c,v 1.2.18.1 2005/04/27 05:00:55 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* Types. */
+
+struct pvt {
+ struct dns_p * dns;
+ struct passwd passwd;
+ char * pwbuf;
+};
+
+/* Forward. */
+
+static void pw_close(struct irs_pw *);
+static struct passwd * pw_byname(struct irs_pw *, const char *);
+static struct passwd * pw_byuid(struct irs_pw *, uid_t);
+static struct passwd * pw_next(struct irs_pw *);
+static void pw_rewind(struct irs_pw *);
+static void pw_minimize(struct irs_pw *);
+static struct __res_state * pw_res_get(struct irs_pw *);
+static void pw_res_set(struct irs_pw *,
+ struct __res_state *,
+ void (*)(void *));
+
+static struct passwd * getpwcommon(struct irs_pw *, const char *,
+ const char *);
+
+/* Public. */
+
+struct irs_pw *
+irs_dns_pw(struct irs_acc *this) {
+ struct dns_p *dns = (struct dns_p *)this->private;
+ struct irs_pw *pw;
+ struct pvt *pvt;
+
+ if (!dns || !dns->hes_ctx) {
+ errno = ENODEV;
+ return (NULL);
+ }
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->dns = dns;
+ if (!(pw = memget(sizeof *pw))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pw, 0x5e, sizeof *pw);
+ pw->private = pvt;
+ pw->close = pw_close;
+ pw->byname = pw_byname;
+ pw->byuid = pw_byuid;
+ pw->next = pw_next;
+ pw->rewind = pw_rewind;
+ pw->minimize = pw_minimize;
+ pw->res_get = pw_res_get;
+ pw->res_set = pw_res_set;
+ return (pw);
+}
+
+/* Methods. */
+
+static void
+pw_close(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->pwbuf)
+ free(pvt->pwbuf);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct passwd *
+pw_byname(struct irs_pw *this, const char *nam) {
+ return (getpwcommon(this, nam, "passwd"));
+}
+
+static struct passwd *
+pw_byuid(struct irs_pw *this, uid_t uid) {
+ char uidstr[16];
+
+ sprintf(uidstr, "%lu", (u_long)uid);
+ return (getpwcommon(this, uidstr, "uid"));
+}
+
+static struct passwd *
+pw_next(struct irs_pw *this) {
+ UNUSED(this);
+ errno = ENODEV;
+ return (NULL);
+}
+
+static void
+pw_rewind(struct irs_pw *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+static void
+pw_minimize(struct irs_pw *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+static struct __res_state *
+pw_res_get(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+
+ return (__hesiod_res_get(dns->hes_ctx));
+}
+
+static void
+pw_res_set(struct irs_pw *this, struct __res_state * res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+
+ __hesiod_res_set(dns->hes_ctx, res, free_res);
+}
+
+/* Private. */
+
+static struct passwd *
+getpwcommon(struct irs_pw *this, const char *arg, const char *type) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char **hes_list, *cp;
+
+ if (!(hes_list = hesiod_resolve(pvt->dns->hes_ctx, arg, type)))
+ return (NULL);
+ if (!*hes_list) {
+ hesiod_free_list(pvt->dns->hes_ctx, hes_list);
+ errno = ENOENT;
+ return (NULL);
+ }
+
+ memset(&pvt->passwd, 0, sizeof pvt->passwd);
+ if (pvt->pwbuf)
+ free(pvt->pwbuf);
+ pvt->pwbuf = strdup(*hes_list);
+ hesiod_free_list(pvt->dns->hes_ctx, hes_list);
+
+ cp = pvt->pwbuf;
+ pvt->passwd.pw_name = cp;
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->passwd.pw_passwd = cp;
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->passwd.pw_uid = atoi(cp);
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->passwd.pw_gid = atoi(cp);
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->passwd.pw_gecos = cp;
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->passwd.pw_dir = cp;
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->passwd.pw_shell = cp;
+ return (&pvt->passwd);
+
+ cleanup:
+ free(pvt->pwbuf);
+ pvt->pwbuf = NULL;
+ return (NULL);
+}
+
+#endif /* WANT_IRS_PW */
+/*! \file */
diff --git a/lib/bind/irs/dns_sv.c b/lib/bind/irs/dns_sv.c
new file mode 100644
index 0000000..fcb25ac
--- /dev/null
+++ b/lib/bind/irs/dns_sv.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns_sv.c,v 1.4.18.1 2005/04/27 05:00:55 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* Definitions */
+
+struct pvt {
+ struct dns_p * dns;
+ struct servent serv;
+ char * svbuf;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward. */
+
+static void sv_close(struct irs_sv *);
+static struct servent * sv_byname(struct irs_sv *,
+ const char *, const char *);
+static struct servent * sv_byport(struct irs_sv *, int, const char *);
+static struct servent * sv_next(struct irs_sv *);
+static void sv_rewind(struct irs_sv *);
+static void sv_minimize(struct irs_sv *);
+#ifdef SV_RES_SETGET
+static struct __res_state * sv_res_get(struct irs_sv *);
+static void sv_res_set(struct irs_sv *,
+ struct __res_state *,
+ void (*)(void *));
+#endif
+
+static struct servent * parse_hes_list(struct irs_sv *,
+ char **, const char *);
+
+/* Public */
+
+struct irs_sv *
+irs_dns_sv(struct irs_acc *this) {
+ struct dns_p *dns = (struct dns_p *)this->private;
+ struct irs_sv *sv;
+ struct pvt *pvt;
+
+ if (!dns || !dns->hes_ctx) {
+ errno = ENODEV;
+ return (NULL);
+ }
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->dns = dns;
+ if (!(sv = memget(sizeof *sv))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(sv, 0x5e, sizeof *sv);
+ sv->private = pvt;
+ sv->byname = sv_byname;
+ sv->byport = sv_byport;
+ sv->next = sv_next;
+ sv->rewind = sv_rewind;
+ sv->close = sv_close;
+ sv->minimize = sv_minimize;
+#ifdef SV_RES_SETGET
+ sv->res_get = sv_res_get;
+ sv->res_set = sv_res_set;
+#else
+ sv->res_get = NULL; /*%< sv_res_get; */
+ sv->res_set = NULL; /*%< sv_res_set; */
+#endif
+ return (sv);
+}
+
+/* Methods */
+
+static void
+sv_close(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->serv.s_aliases)
+ free(pvt->serv.s_aliases);
+ if (pvt->svbuf)
+ free(pvt->svbuf);
+
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+ struct servent *s;
+ char **hes_list;
+
+ if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "service")))
+ return (NULL);
+
+ s = parse_hes_list(this, hes_list, proto);
+ hesiod_free_list(dns->hes_ctx, hes_list);
+ return (s);
+}
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+ struct servent *s;
+ char portstr[16];
+ char **hes_list;
+
+ sprintf(portstr, "%d", ntohs(port));
+ if (!(hes_list = hesiod_resolve(dns->hes_ctx, portstr, "port")))
+ return (NULL);
+
+ s = parse_hes_list(this, hes_list, proto);
+ hesiod_free_list(dns->hes_ctx, hes_list);
+ return (s);
+}
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+ UNUSED(this);
+ errno = ENODEV;
+ return (NULL);
+}
+
+static void
+sv_rewind(struct irs_sv *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+/* Private */
+
+static struct servent *
+parse_hes_list(struct irs_sv *this, char **hes_list, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *p, *cp, **cpp, **new;
+ int proto_len;
+ int num = 0;
+ int max = 0;
+
+ for (cpp = hes_list; *cpp; cpp++) {
+ cp = *cpp;
+
+ /* Strip away comments, if any. */
+ if ((p = strchr(cp, '#')))
+ *p = 0;
+
+ /* Check to make sure the protocol matches. */
+ p = cp;
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (!*p)
+ continue;
+ if (proto) {
+ proto_len = strlen(proto);
+ if (strncasecmp(++p, proto, proto_len) != 0)
+ continue;
+ if (p[proto_len] && !isspace(p[proto_len]&0xff))
+ continue;
+ }
+ /* OK, we've got a live one. Let's parse it for real. */
+ if (pvt->svbuf)
+ free(pvt->svbuf);
+ pvt->svbuf = strdup(cp);
+
+ p = pvt->svbuf;
+ pvt->serv.s_name = p;
+ while (*p && !isspace(*p&0xff))
+ p++;
+ if (!*p)
+ continue;
+ *p++ = '\0';
+
+ pvt->serv.s_proto = p;
+ while (*p && !isspace(*p&0xff))
+ p++;
+ if (!*p)
+ continue;
+ *p++ = '\0';
+
+ pvt->serv.s_port = htons((u_short) atoi(p));
+ while (*p && !isspace(*p&0xff))
+ p++;
+ if (*p)
+ *p++ = '\0';
+
+ while (*p) {
+ if ((num + 1) >= max || !pvt->serv.s_aliases) {
+ max += 10;
+ new = realloc(pvt->serv.s_aliases,
+ max * sizeof(char *));
+ if (!new) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ pvt->serv.s_aliases = new;
+ }
+ pvt->serv.s_aliases[num++] = p;
+ while (*p && !isspace(*p&0xff))
+ p++;
+ if (*p)
+ *p++ = '\0';
+ }
+ if (!pvt->serv.s_aliases)
+ pvt->serv.s_aliases = malloc(sizeof(char *));
+ if (!pvt->serv.s_aliases)
+ goto cleanup;
+ pvt->serv.s_aliases[num] = NULL;
+ return (&pvt->serv);
+ }
+
+ cleanup:
+ if (pvt->serv.s_aliases) {
+ free(pvt->serv.s_aliases);
+ pvt->serv.s_aliases = NULL;
+ }
+ if (pvt->svbuf) {
+ free(pvt->svbuf);
+ pvt->svbuf = NULL;
+ }
+ return (NULL);
+}
+
+static void
+sv_minimize(struct irs_sv *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+#ifdef SV_RES_SETGET
+static struct __res_state *
+sv_res_get(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+
+ return (__hesiod_res_get(dns->hes_ctx));
+}
+
+static void
+sv_res_set(struct irs_sv *this, struct __res_state * res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+
+ __hesiod_res_set(dns->hes_ctx, res, free_res);
+}
+#endif
+
+/*! \file */
diff --git a/lib/bind/irs/gai_strerror.c b/lib/bind/irs/gai_strerror.c
new file mode 100644
index 0000000..9ca1c4b
--- /dev/null
+++ b/lib/bind/irs/gai_strerror.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2001 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <port_before.h>
+#include <netdb.h>
+#include <port_after.h>
+
+#ifdef DO_PTHREADS
+#include <pthread.h>
+#include <stdlib.h>
+#endif
+
+static const char *gai_errlist[] = {
+ "no error",
+ "address family not supported for name",/*%< EAI_ADDRFAMILY */
+ "temporary failure", /*%< EAI_AGAIN */
+ "invalid flags", /*%< EAI_BADFLAGS */
+ "permanent failure", /*%< EAI_FAIL */
+ "address family not supported", /*%< EAI_FAMILY */
+ "memory failure", /*%< EAI_MEMORY */
+ "no address", /*%< EAI_NODATA */
+ "unknown name or service", /*%< EAI_NONAME */
+ "service not supported for socktype", /*%< EAI_SERVICE */
+ "socktype not supported", /*%< EAI_SOCKTYPE */
+ "system failure", /*%< EAI_SYSTEM */
+ "bad hints", /*%< EAI_BADHINTS */
+ "bad protocol", /*%< EAI_PROTOCOL */
+ "unknown error" /*%< Must be last. */
+};
+
+static const int gai_nerr = (sizeof(gai_errlist)/sizeof(*gai_errlist));
+
+#define EAI_BUFSIZE 128
+
+const char *
+gai_strerror(int ecode) {
+#ifndef DO_PTHREADS
+ static char buf[EAI_BUFSIZE];
+#else /* DO_PTHREADS */
+#ifndef LIBBIND_MUTEX_INITIALIZER
+#define LIBBIND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#endif
+ static pthread_mutex_t lock = LIBBIND_MUTEX_INITIALIZER;
+ static pthread_key_t key;
+ static int once = 0;
+ char *buf;
+#endif
+
+ if (ecode >= 0 && ecode < (gai_nerr - 1))
+ return (gai_errlist[ecode]);
+
+#ifdef DO_PTHREADS
+ if (!once) {
+ if (pthread_mutex_lock(&lock) != 0)
+ goto unknown;
+ if (!once) {
+ if (pthread_key_create(&key, free) != 0) {
+ (void)pthread_mutex_unlock(&lock);
+ goto unknown;
+ }
+ once = 1;
+ }
+ if (pthread_mutex_unlock(&lock) != 0)
+ goto unknown;
+ }
+
+ buf = pthread_getspecific(key);
+ if (buf == NULL) {
+ buf = malloc(EAI_BUFSIZE);
+ if (buf == NULL)
+ goto unknown;
+ if (pthread_setspecific(key, buf) != 0) {
+ free(buf);
+ goto unknown;
+ }
+ }
+#endif
+ /*
+ * XXX This really should be snprintf(buf, EAI_BUFSIZE, ...).
+ * It is safe until message catalogs are used.
+ */
+ sprintf(buf, "%s: %d", gai_errlist[gai_nerr - 1], ecode);
+ return (buf);
+
+#ifdef DO_PTHREADS
+ unknown:
+ return ("unknown error");
+#endif
+}
+
+/*! \file */
diff --git a/lib/bind/irs/gen.c b/lib/bind/irs/gen.c
new file mode 100644
index 0000000..8e9146e
--- /dev/null
+++ b/lib/bind/irs/gen.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen.c,v 1.5.18.2 2005/04/27 05:00:56 sra Exp $";
+#endif
+
+/*! \file
+ * \brief
+ * this is the top level dispatcher
+ *
+ * The dispatcher is implemented as an accessor class; it is an
+ * accessor class that calls other accessor classes, as controlled by a
+ * configuration file.
+ *
+ * A big difference between this accessor class and others is that the
+ * map class initializers are NULL, and the map classes are already
+ * filled in with method functions that will do the right thing.
+ */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <isc/assertions.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Definitions */
+
+struct nameval {
+ const char * name;
+ int val;
+};
+
+static const struct nameval acc_names[irs_nacc+1] = {
+ { "local", irs_lcl },
+ { "dns", irs_dns },
+ { "nis", irs_nis },
+ { "irp", irs_irp },
+ { NULL, irs_nacc }
+};
+
+typedef struct irs_acc *(*accinit) __P((const char *options));
+
+static const accinit accs[irs_nacc+1] = {
+ irs_lcl_acc,
+ irs_dns_acc,
+#ifdef WANT_IRS_NIS
+ irs_nis_acc,
+#else
+ NULL,
+#endif
+ irs_irp_acc,
+ NULL
+};
+
+static const struct nameval map_names[irs_nmap+1] = {
+ { "group", irs_gr },
+ { "passwd", irs_pw },
+ { "services", irs_sv },
+ { "protocols", irs_pr },
+ { "hosts", irs_ho },
+ { "networks", irs_nw },
+ { "netgroup", irs_ng },
+ { NULL, irs_nmap }
+};
+
+static const struct nameval option_names[] = {
+ { "merge", IRS_MERGE },
+ { "continue", IRS_CONTINUE },
+ { NULL, 0 }
+};
+
+/* Forward */
+
+static void gen_close(struct irs_acc *);
+static struct __res_state * gen_res_get(struct irs_acc *);
+static void gen_res_set(struct irs_acc *, struct __res_state *,
+ void (*)(void *));
+static int find_name(const char *, const struct nameval nv[]);
+static void init_map_rules(struct gen_p *, const char *conf_file);
+static struct irs_rule *release_rule(struct irs_rule *);
+static int add_rule(struct gen_p *,
+ enum irs_map_id, enum irs_acc_id,
+ const char *);
+
+/* Public */
+
+struct irs_acc *
+irs_gen_acc(const char *options, const char *conf_file) {
+ struct irs_acc *acc;
+ struct gen_p *irs;
+
+ if (!(acc = memget(sizeof *acc))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(acc, 0x5e, sizeof *acc);
+ if (!(irs = memget(sizeof *irs))) {
+ errno = ENOMEM;
+ memput(acc, sizeof *acc);
+ return (NULL);
+ }
+ memset(irs, 0x5e, sizeof *irs);
+ irs->options = strdup(options);
+ irs->res = NULL;
+ irs->free_res = NULL;
+ memset(irs->accessors, 0, sizeof irs->accessors);
+ memset(irs->map_rules, 0, sizeof irs->map_rules);
+ init_map_rules(irs, conf_file);
+ acc->private = irs;
+#ifdef WANT_IRS_GR
+ acc->gr_map = irs_gen_gr;
+#else
+ acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+ acc->pw_map = irs_gen_pw;
+#else
+ acc->pw_map = NULL;
+#endif
+ acc->sv_map = irs_gen_sv;
+ acc->pr_map = irs_gen_pr;
+ acc->ho_map = irs_gen_ho;
+ acc->nw_map = irs_gen_nw;
+ acc->ng_map = irs_gen_ng;
+ acc->res_get = gen_res_get;
+ acc->res_set = gen_res_set;
+ acc->close = gen_close;
+ return (acc);
+}
+
+/* Methods */
+
+static struct __res_state *
+gen_res_get(struct irs_acc *this) {
+ struct gen_p *irs = (struct gen_p *)this->private;
+
+ if (irs->res == NULL) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (res == NULL)
+ return (NULL);
+ memset(res, 0, sizeof *res);
+ gen_res_set(this, res, free);
+ }
+
+ if (((irs->res->options & RES_INIT) == 0U) && res_ninit(irs->res) < 0)
+ return (NULL);
+
+ return (irs->res);
+}
+
+static void
+gen_res_set(struct irs_acc *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct gen_p *irs = (struct gen_p *)this->private;
+#if 0
+ struct irs_rule *rule;
+ struct irs_ho *ho;
+ struct irs_nw *nw;
+#endif
+
+ if (irs->res && irs->free_res) {
+ res_nclose(irs->res);
+ (*irs->free_res)(irs->res);
+ }
+
+ irs->res = res;
+ irs->free_res = free_res;
+
+#if 0
+ for (rule = irs->map_rules[irs_ho]; rule; rule = rule->next) {
+ ho = rule->inst->ho;
+
+ (*ho->res_set)(ho, res, NULL);
+ }
+ for (rule = irs->map_rules[irs_nw]; rule; rule = rule->next) {
+ nw = rule->inst->nw;
+
+ (*nw->res_set)(nw, res, NULL);
+ }
+#endif
+}
+
+static void
+gen_close(struct irs_acc *this) {
+ struct gen_p *irs = (struct gen_p *)this->private;
+ int n;
+
+ /* Search rules. */
+ for (n = 0; n < irs_nmap; n++)
+ while (irs->map_rules[n] != NULL)
+ irs->map_rules[n] = release_rule(irs->map_rules[n]);
+
+ /* Access methods. */
+ for (n = 0; n < irs_nacc; n++) {
+ /* Map objects. */
+ if (irs->accessors[n].gr != NULL)
+ (*irs->accessors[n].gr->close)(irs->accessors[n].gr);
+ if (irs->accessors[n].pw != NULL)
+ (*irs->accessors[n].pw->close)(irs->accessors[n].pw);
+ if (irs->accessors[n].sv != NULL)
+ (*irs->accessors[n].sv->close)(irs->accessors[n].sv);
+ if (irs->accessors[n].pr != NULL)
+ (*irs->accessors[n].pr->close)(irs->accessors[n].pr);
+ if (irs->accessors[n].ho != NULL)
+ (*irs->accessors[n].ho->close)(irs->accessors[n].ho);
+ if (irs->accessors[n].nw != NULL)
+ (*irs->accessors[n].nw->close)(irs->accessors[n].nw);
+ if (irs->accessors[n].ng != NULL)
+ (*irs->accessors[n].ng->close)(irs->accessors[n].ng);
+ /* Enclosing accessor. */
+ if (irs->accessors[n].acc != NULL)
+ (*irs->accessors[n].acc->close)(irs->accessors[n].acc);
+ }
+
+ /* The options string was strdup'd. */
+ free((void*)irs->options);
+
+ if (irs->res && irs->free_res)
+ (*irs->free_res)(irs->res);
+
+ /* The private data container. */
+ memput(irs, sizeof *irs);
+
+ /* The object. */
+ memput(this, sizeof *this);
+}
+
+/* Private */
+
+static int
+find_name(const char *name, const struct nameval names[]) {
+ int n;
+
+ for (n = 0; names[n].name != NULL; n++)
+ if (strcmp(name, names[n].name) == 0)
+ return (names[n].val);
+ return (-1);
+}
+
+static struct irs_rule *
+release_rule(struct irs_rule *rule) {
+ struct irs_rule *next = rule->next;
+
+ memput(rule, sizeof *rule);
+ return (next);
+}
+
+static int
+add_rule(struct gen_p *irs,
+ enum irs_map_id map, enum irs_acc_id acc,
+ const char *options)
+{
+ struct irs_rule **rules, *last, *tmp, *new;
+ struct irs_inst *inst;
+ const char *cp;
+ int n;
+
+#ifndef WANT_IRS_GR
+ if (map == irs_gr)
+ return (-1);
+#endif
+#ifndef WANT_IRS_PW
+ if (map == irs_pw)
+ return (-1);
+#endif
+#ifndef WANT_IRS_NIS
+ if (acc == irs_nis)
+ return (-1);
+#endif
+ new = memget(sizeof *new);
+ if (new == NULL)
+ return (-1);
+ memset(new, 0x5e, sizeof *new);
+ new->next = NULL;
+
+ new->inst = &irs->accessors[acc];
+
+ new->flags = 0;
+ cp = options;
+ while (cp && *cp) {
+ char option[50], *next;
+
+ next = strchr(cp, ',');
+ if (next)
+ n = next++ - cp;
+ else
+ n = strlen(cp);
+ if ((size_t)n > sizeof option - 1)
+ n = sizeof option - 1;
+ strncpy(option, cp, n);
+ option[n] = '\0';
+
+ n = find_name(option, option_names);
+ if (n >= 0)
+ new->flags |= n;
+
+ cp = next;
+ }
+
+ rules = &irs->map_rules[map];
+ for (last = NULL, tmp = *rules;
+ tmp != NULL;
+ last = tmp, tmp = tmp->next)
+ (void)NULL;
+ if (last == NULL)
+ *rules = new;
+ else
+ last->next = new;
+
+ /* Try to instantiate map accessors for this if necessary & approp. */
+ inst = &irs->accessors[acc];
+ if (inst->acc == NULL && accs[acc] != NULL)
+ inst->acc = (*accs[acc])(irs->options);
+ if (inst->acc != NULL) {
+ if (inst->gr == NULL && inst->acc->gr_map != NULL)
+ inst->gr = (*inst->acc->gr_map)(inst->acc);
+ if (inst->pw == NULL && inst->acc->pw_map != NULL)
+ inst->pw = (*inst->acc->pw_map)(inst->acc);
+ if (inst->sv == NULL && inst->acc->sv_map != NULL)
+ inst->sv = (*inst->acc->sv_map)(inst->acc);
+ if (inst->pr == NULL && inst->acc->pr_map != NULL)
+ inst->pr = (*inst->acc->pr_map)(inst->acc);
+ if (inst->ho == NULL && inst->acc->ho_map != NULL)
+ inst->ho = (*inst->acc->ho_map)(inst->acc);
+ if (inst->nw == NULL && inst->acc->nw_map != NULL)
+ inst->nw = (*inst->acc->nw_map)(inst->acc);
+ if (inst->ng == NULL && inst->acc->ng_map != NULL)
+ inst->ng = (*inst->acc->ng_map)(inst->acc);
+ }
+
+ return (0);
+}
+
+static void
+default_map_rules(struct gen_p *irs) {
+ /* Install time honoured and proved BSD style rules as default. */
+ add_rule(irs, irs_gr, irs_lcl, "");
+ add_rule(irs, irs_pw, irs_lcl, "");
+ add_rule(irs, irs_sv, irs_lcl, "");
+ add_rule(irs, irs_pr, irs_lcl, "");
+ add_rule(irs, irs_ho, irs_dns, "continue");
+ add_rule(irs, irs_ho, irs_lcl, "");
+ add_rule(irs, irs_nw, irs_dns, "continue");
+ add_rule(irs, irs_nw, irs_lcl, "");
+ add_rule(irs, irs_ng, irs_lcl, "");
+}
+
+static void
+init_map_rules(struct gen_p *irs, const char *conf_file) {
+ char line[1024], pattern[40], mapname[20], accname[20], options[100];
+ FILE *conf;
+
+ if (conf_file == NULL)
+ conf_file = _PATH_IRS_CONF ;
+
+ /* A conf file of "" means compiled in defaults. Irpd wants this */
+ if (conf_file[0] == '\0' || (conf = fopen(conf_file, "r")) == NULL) {
+ default_map_rules(irs);
+ return;
+ }
+ (void) sprintf(pattern, "%%%lus %%%lus %%%lus\n",
+ (unsigned long)sizeof mapname,
+ (unsigned long)sizeof accname,
+ (unsigned long)sizeof options);
+ while (fgets(line, sizeof line, conf)) {
+ enum irs_map_id map;
+ enum irs_acc_id acc;
+ char *tmp;
+ int n;
+
+ for (tmp = line;
+ isascii((unsigned char)*tmp) &&
+ isspace((unsigned char)*tmp);
+ tmp++)
+ (void)NULL;
+ if (*tmp == '#' || *tmp == '\n' || *tmp == '\0')
+ continue;
+ n = sscanf(tmp, pattern, mapname, accname, options);
+ if (n < 2)
+ continue;
+ if (n < 3)
+ options[0] = '\0';
+
+ n = find_name(mapname, map_names);
+ INSIST(n < irs_nmap);
+ if (n < 0)
+ continue;
+ map = (enum irs_map_id) n;
+
+ n = find_name(accname, acc_names);
+ INSIST(n < irs_nacc);
+ if (n < 0)
+ continue;
+ acc = (enum irs_acc_id) n;
+
+ add_rule(irs, map, acc, options);
+ }
+ fclose(conf);
+}
diff --git a/lib/bind/irs/gen_gr.c b/lib/bind/irs/gen_gr.c
new file mode 100644
index 0000000..0829ed8
--- /dev/null
+++ b/lib/bind/irs/gen_gr.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_gr.c,v 1.6.18.2 2005/04/27 05:00:56 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_GR
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <sys/types.h>
+
+#include <isc/assertions.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Definitions */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ struct irs_gr * gr;
+ /*
+ * Need space to store the entries read from the group file.
+ * The members list also needs space per member, and the
+ * strings making up the user names must be allocated
+ * somewhere. Rather than doing lots of small allocations,
+ * we keep one buffer and resize it as needed.
+ */
+ struct group group;
+ size_t nmemb; /*%< Malloc'd max index of gr_mem[]. */
+ char * membuf;
+ size_t membufsize;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward */
+
+static void gr_close(struct irs_gr *);
+static struct group * gr_next(struct irs_gr *);
+static struct group * gr_byname(struct irs_gr *, const char *);
+static struct group * gr_bygid(struct irs_gr *, gid_t);
+static void gr_rewind(struct irs_gr *);
+static int gr_list(struct irs_gr *, const char *,
+ gid_t, gid_t *, int *);
+static void gr_minimize(struct irs_gr *);
+static struct __res_state * gr_res_get(struct irs_gr *);
+static void gr_res_set(struct irs_gr *,
+ struct __res_state *,
+ void (*)(void *));
+
+static int grmerge(struct irs_gr *gr, const struct group *src,
+ int preserve);
+
+static int countvec(char **vec);
+static int isnew(char **old, char *new);
+static int countnew(char **old, char **new);
+static size_t sizenew(char **old, char **new);
+static int newgid(int, gid_t *, gid_t);
+
+/* Macros */
+
+#define FREE_IF(x) do { if ((x) != NULL) { free(x); (x) = NULL; } } while (0)
+
+/* Public */
+
+struct irs_gr *
+irs_gen_gr(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_gr *gr;
+ struct pvt *pvt;
+
+ if (!(gr = memget(sizeof *gr))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(gr, 0x5e, sizeof *gr);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(gr, sizeof *gr);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->rules = accpvt->map_rules[irs_gr];
+ pvt->rule = pvt->rules;
+ gr->private = pvt;
+ gr->close = gr_close;
+ gr->next = gr_next;
+ gr->byname = gr_byname;
+ gr->bygid = gr_bygid;
+ gr->rewind = gr_rewind;
+ gr->list = gr_list;
+ gr->minimize = gr_minimize;
+ gr->res_get = gr_res_get;
+ gr->res_set = gr_res_set;
+ return (gr);
+}
+
+/* Methods. */
+
+static void
+gr_close(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct group *
+gr_next(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct group *rval;
+ struct irs_gr *gr;
+
+ while (pvt->rule) {
+ gr = pvt->rule->inst->gr;
+ rval = (*gr->next)(gr);
+ if (rval)
+ return (rval);
+ if (!(pvt->rule->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ gr = pvt->rule->inst->gr;
+ (*gr->rewind)(gr);
+ }
+ }
+ return (NULL);
+}
+
+static struct group *
+gr_byname(struct irs_gr *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct group *tval;
+ struct irs_gr *gr;
+ int dirty;
+
+ dirty = 0;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ gr = rule->inst->gr;
+ tval = (*gr->byname)(gr, name);
+ if (tval) {
+ if (!grmerge(this, tval, dirty++))
+ return (NULL);
+ if (!(rule->flags & IRS_MERGE))
+ break;
+ } else {
+ if (!(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ }
+ if (dirty)
+ return (&pvt->group);
+ return (NULL);
+}
+
+static struct group *
+gr_bygid(struct irs_gr *this, gid_t gid) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct group *tval;
+ struct irs_gr *gr;
+ int dirty;
+
+ dirty = 0;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ gr = rule->inst->gr;
+ tval = (*gr->bygid)(gr, gid);
+ if (tval) {
+ if (!grmerge(this, tval, dirty++))
+ return (NULL);
+ if (!(rule->flags & IRS_MERGE))
+ break;
+ } else {
+ if (!(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ }
+ if (dirty)
+ return (&pvt->group);
+ return (NULL);
+}
+
+static void
+gr_rewind(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_gr *gr;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ gr = pvt->rule->inst->gr;
+ (*gr->rewind)(gr);
+ }
+}
+
+static int
+gr_list(struct irs_gr *this, const char *name,
+ gid_t basegid, gid_t *groups, int *ngroups)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct irs_gr *gr;
+ int t_ngroups, maxgroups;
+ gid_t *t_groups;
+ int n, t, rval = 0;
+
+ maxgroups = *ngroups;
+ *ngroups = 0;
+ t_groups = (gid_t *)malloc(maxgroups * sizeof(gid_t));
+ if (!t_groups) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ t_ngroups = maxgroups;
+ gr = rule->inst->gr;
+ t = (*gr->list)(gr, name, basegid, t_groups, &t_ngroups);
+ for (n = 0; n < t_ngroups; n++) {
+ if (newgid(*ngroups, groups, t_groups[n])) {
+ if (*ngroups == maxgroups) {
+ rval = -1;
+ goto done;
+ }
+ groups[(*ngroups)++] = t_groups[n];
+ }
+ }
+ if (t == 0) {
+ if (!(rule->flags & IRS_MERGE))
+ break;
+ } else {
+ if (!(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ }
+ done:
+ free(t_groups);
+ return (rval);
+}
+
+static void
+gr_minimize(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_gr *gr = rule->inst->gr;
+
+ (*gr->minimize)(gr);
+ }
+}
+
+static struct __res_state *
+gr_res_get(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ gr_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+gr_res_set(struct irs_gr *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_gr *gr = rule->inst->gr;
+
+ if (gr->res_set)
+ (*gr->res_set)(gr, pvt->res, NULL);
+ }
+}
+
+/* Private. */
+
+static int
+grmerge(struct irs_gr *this, const struct group *src, int preserve) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *cp, **m, **p, *oldmembuf, *ep;
+ int n, ndst, nnew;
+ size_t used;
+
+ if (!preserve) {
+ pvt->group.gr_gid = src->gr_gid;
+ if (pvt->nmemb < 1) {
+ m = malloc(sizeof *m);
+ if (m == NULL) {
+ /* No harm done, no work done. */
+ return (0);
+ }
+ pvt->group.gr_mem = m;
+ pvt->nmemb = 1;
+ }
+ pvt->group.gr_mem[0] = NULL;
+ }
+ ndst = countvec(pvt->group.gr_mem);
+ nnew = countnew(pvt->group.gr_mem, src->gr_mem);
+
+ /*
+ * Make sure destination member array is large enough.
+ * p points to new portion.
+ */
+ n = ndst + nnew + 1;
+ if ((size_t)n > pvt->nmemb) {
+ m = realloc(pvt->group.gr_mem, n * sizeof *m);
+ if (m == NULL) {
+ /* No harm done, no work done. */
+ return (0);
+ }
+ pvt->group.gr_mem = m;
+ pvt->nmemb = n;
+ }
+ p = pvt->group.gr_mem + ndst;
+
+ /*
+ * Enlarge destination membuf; cp points at new portion.
+ */
+ n = sizenew(pvt->group.gr_mem, src->gr_mem);
+ INSIST((nnew == 0) == (n == 0));
+ if (!preserve) {
+ n += strlen(src->gr_name) + 1;
+ n += strlen(src->gr_passwd) + 1;
+ }
+ if (n == 0) {
+ /* No work to do. */
+ return (1);
+ }
+ used = preserve ? pvt->membufsize : 0;
+ cp = malloc(used + n);
+ if (cp == NULL) {
+ /* No harm done, no work done. */
+ return (0);
+ }
+ ep = cp + used + n;
+ if (used != 0)
+ memcpy(cp, pvt->membuf, used);
+ oldmembuf = pvt->membuf;
+ pvt->membuf = cp;
+ pvt->membufsize = used + n;
+ cp += used;
+
+ /*
+ * Adjust group.gr_mem.
+ */
+ if (pvt->membuf != oldmembuf)
+ for (m = pvt->group.gr_mem; *m; m++)
+ *m = pvt->membuf + (*m - oldmembuf);
+
+ /*
+ * Add new elements.
+ */
+ for (m = src->gr_mem; *m; m++)
+ if (isnew(pvt->group.gr_mem, *m)) {
+ *p++ = cp;
+ *p = NULL;
+ n = strlen(*m) + 1;
+ if (n > ep - cp) {
+ FREE_IF(oldmembuf);
+ return (0);
+ }
+ strcpy(cp, *m); /* (checked) */
+ cp += n;
+ }
+ if (preserve) {
+ pvt->group.gr_name = pvt->membuf +
+ (pvt->group.gr_name - oldmembuf);
+ pvt->group.gr_passwd = pvt->membuf +
+ (pvt->group.gr_passwd - oldmembuf);
+ } else {
+ pvt->group.gr_name = cp;
+ n = strlen(src->gr_name) + 1;
+ if (n > ep - cp) {
+ FREE_IF(oldmembuf);
+ return (0);
+ }
+ strcpy(cp, src->gr_name); /* (checked) */
+ cp += n;
+
+ pvt->group.gr_passwd = cp;
+ n = strlen(src->gr_passwd) + 1;
+ if (n > ep - cp) {
+ FREE_IF(oldmembuf);
+ return (0);
+ }
+ strcpy(cp, src->gr_passwd); /* (checked) */
+ cp += n;
+ }
+ FREE_IF(oldmembuf);
+ INSIST(cp >= pvt->membuf && cp <= &pvt->membuf[pvt->membufsize]);
+ return (1);
+}
+
+static int
+countvec(char **vec) {
+ int n = 0;
+
+ while (*vec++)
+ n++;
+ return (n);
+}
+
+static int
+isnew(char **old, char *new) {
+ for (; *old; old++)
+ if (strcmp(*old, new) == 0)
+ return (0);
+ return (1);
+}
+
+static int
+countnew(char **old, char **new) {
+ int n = 0;
+
+ for (; *new; new++)
+ n += isnew(old, *new);
+ return (n);
+}
+
+static size_t
+sizenew(char **old, char **new) {
+ size_t n = 0;
+
+ for (; *new; new++)
+ if (isnew(old, *new))
+ n += strlen(*new) + 1;
+ return (n);
+}
+
+static int
+newgid(int ngroups, gid_t *groups, gid_t group) {
+ ngroups--, groups++;
+ for (; ngroups-- > 0; groups++)
+ if (*groups == group)
+ return (0);
+ return (1);
+}
+
+#endif /* WANT_IRS_GR */
+/*! \file */
diff --git a/lib/bind/irs/gen_ho.c b/lib/bind/irs/gen_ho.c
new file mode 100644
index 0000000..c5e09da
--- /dev/null
+++ b/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.3.18.2 2006/03/10 00:20:08 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Definitions */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ struct irs_ho * ho;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forwards */
+
+static void ho_close(struct irs_ho *this);
+static struct hostent * ho_byname(struct irs_ho *this, const char *name);
+static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
+ int af);
+static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ int len, int af);
+static struct hostent * ho_next(struct irs_ho *this);
+static void ho_rewind(struct irs_ho *this);
+static void ho_minimize(struct irs_ho *this);
+static struct __res_state * ho_res_get(struct irs_ho *this);
+static void ho_res_set(struct irs_ho *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+ const struct addrinfo *pai);
+
+static int init(struct irs_ho *this);
+
+/* Exports */
+
+struct irs_ho *
+irs_gen_ho(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_ho *ho;
+ struct pvt *pvt;
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(ho = memget(sizeof *ho))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ho, 0x5e, sizeof *ho);
+ pvt->rules = accpvt->map_rules[irs_ho];
+ pvt->rule = pvt->rules;
+ ho->private = pvt;
+ ho->close = ho_close;
+ ho->byname = ho_byname;
+ ho->byname2 = ho_byname2;
+ ho->byaddr = ho_byaddr;
+ ho->next = ho_next;
+ ho->rewind = ho_rewind;
+ ho->minimize = ho_minimize;
+ ho->res_get = ho_res_get;
+ ho->res_set = ho_res_set;
+ ho->addrinfo = ho_addrinfo;
+ return (ho);
+}
+
+/* Methods. */
+
+static void
+ho_close(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ho_minimize(this);
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct hostent *rval;
+ struct irs_ho *ho;
+ int therrno = NETDB_INTERNAL;
+ int softerror = 0;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ ho = rule->inst->ho;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = 0;
+ rval = (*ho->byname)(ho, name);
+ if (rval != NULL)
+ return (rval);
+ if (softerror == 0 &&
+ pvt->res->res_h_errno != HOST_NOT_FOUND &&
+ pvt->res->res_h_errno != NETDB_INTERNAL) {
+ softerror = 1;
+ therrno = pvt->res->res_h_errno;
+ }
+ if (rule->flags & IRS_CONTINUE)
+ continue;
+ /*
+ * The value TRY_AGAIN can mean that the service
+ * is not available, or just that this particular name
+ * cannot be resolved now. We use the errno ECONNREFUSED
+ * to distinguish. If a lookup sets that errno when
+ * H_ERRNO is TRY_AGAIN, we continue to try other lookup
+ * functions, otherwise we return the TRY_AGAIN error.
+ */
+ if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
+ break;
+ }
+ if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+ RES_SET_H_ERRNO(pvt->res, therrno);
+ return (NULL);
+}
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct hostent *rval;
+ struct irs_ho *ho;
+ int therrno = NETDB_INTERNAL;
+ int softerror = 0;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ ho = rule->inst->ho;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = 0;
+ rval = (*ho->byname2)(ho, name, af);
+ if (rval != NULL)
+ return (rval);
+ if (softerror == 0 &&
+ pvt->res->res_h_errno != HOST_NOT_FOUND &&
+ pvt->res->res_h_errno != NETDB_INTERNAL) {
+ softerror = 1;
+ therrno = pvt->res->res_h_errno;
+ }
+ if (rule->flags & IRS_CONTINUE)
+ continue;
+ /*
+ * See the comments in ho_byname() explaining
+ * the interpretation of TRY_AGAIN and ECONNREFUSED.
+ */
+ if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
+ break;
+ }
+ if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+ RES_SET_H_ERRNO(pvt->res, therrno);
+ return (NULL);
+}
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct hostent *rval;
+ struct irs_ho *ho;
+ int therrno = NETDB_INTERNAL;
+ int softerror = 0;
+
+
+ if (init(this) == -1)
+ return (NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ ho = rule->inst->ho;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = 0;
+ rval = (*ho->byaddr)(ho, addr, len, af);
+ if (rval != NULL)
+ return (rval);
+ if (softerror == 0 &&
+ pvt->res->res_h_errno != HOST_NOT_FOUND &&
+ pvt->res->res_h_errno != NETDB_INTERNAL) {
+ softerror = 1;
+ therrno = pvt->res->res_h_errno;
+ }
+
+ if (rule->flags & IRS_CONTINUE)
+ continue;
+ /*
+ * See the comments in ho_byname() explaining
+ * the interpretation of TRY_AGAIN and ECONNREFUSED.
+ */
+ if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
+ break;
+ }
+ if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+ RES_SET_H_ERRNO(pvt->res, therrno);
+ return (NULL);
+}
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *rval;
+ struct irs_ho *ho;
+
+ while (pvt->rule) {
+ ho = pvt->rule->inst->ho;
+ rval = (*ho->next)(ho);
+ if (rval)
+ return (rval);
+ if (!(pvt->rule->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ ho = pvt->rule->inst->ho;
+ (*ho->rewind)(ho);
+ }
+ }
+ return (NULL);
+}
+
+static void
+ho_rewind(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_ho *ho;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ ho = pvt->rule->inst->ho;
+ (*ho->rewind)(ho);
+ }
+}
+
+static void
+ho_minimize(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_ho *ho = rule->inst->ho;
+
+ (*ho->minimize)(ho);
+ }
+}
+
+static struct __res_state *
+ho_res_get(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ ho_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+ho_res_set(struct irs_ho *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_ho *ho = rule->inst->ho;
+
+ (*ho->res_set)(ho, pvt->res, NULL);
+ }
+}
+
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct addrinfo *rval = NULL;
+ struct irs_ho *ho;
+ int therrno = NETDB_INTERNAL;
+ int softerror = 0;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ ho = rule->inst->ho;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = 0;
+ if (ho->addrinfo == NULL) /*%< for safety */
+ continue;
+ rval = (*ho->addrinfo)(ho, name, pai);
+ if (rval != NULL)
+ return (rval);
+ if (softerror == 0 &&
+ pvt->res->res_h_errno != HOST_NOT_FOUND &&
+ pvt->res->res_h_errno != NETDB_INTERNAL) {
+ softerror = 1;
+ therrno = pvt->res->res_h_errno;
+ }
+ if (rule->flags & IRS_CONTINUE)
+ continue;
+ /*
+ * See the comments in ho_byname() explaining
+ * the interpretation of TRY_AGAIN and ECONNREFUSED.
+ */
+ if (pvt->res->res_h_errno != TRY_AGAIN ||
+ errno != ECONNREFUSED)
+ break;
+ }
+ if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+ RES_SET_H_ERRNO(pvt->res, therrno);
+ return (NULL);
+}
+
+static int
+init(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !ho_res_get(this))
+ return (-1);
+
+ if (((pvt->res->options & RES_INIT) == 0U) &&
+ (res_ninit(pvt->res) == -1))
+ return (-1);
+
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/gen_ng.c b/lib/bind/irs/gen_ng.c
new file mode 100644
index 0000000..67f4edd
--- /dev/null
+++ b/lib/bind/irs/gen_ng.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_ng.c,v 1.2.18.1 2005/04/27 05:00:56 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ char * curgroup;
+};
+
+/* Forward */
+
+static void ng_close(struct irs_ng *);
+static int ng_next(struct irs_ng *, const char **,
+ const char **, const char **);
+static int ng_test(struct irs_ng *, const char *,
+ const char *, const char *,
+ const char *);
+static void ng_rewind(struct irs_ng *, const char *);
+static void ng_minimize(struct irs_ng *);
+
+/* Public */
+
+struct irs_ng *
+irs_gen_ng(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_ng *ng;
+ struct pvt *pvt;
+
+ if (!(ng = memget(sizeof *ng))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ng, 0x5e, sizeof *ng);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(ng, sizeof *ng);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->rules = accpvt->map_rules[irs_ng];
+ pvt->rule = pvt->rules;
+ ng->private = pvt;
+ ng->close = ng_close;
+ ng->next = ng_next;
+ ng->test = ng_test;
+ ng->rewind = ng_rewind;
+ ng->minimize = ng_minimize;
+ return (ng);
+}
+
+/* Methods */
+
+static void
+ng_close(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ng_minimize(this);
+ if (pvt->curgroup)
+ free(pvt->curgroup);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user,
+ const char **domain)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_ng *ng;
+
+ while (pvt->rule) {
+ ng = pvt->rule->inst->ng;
+ if ((*ng->next)(ng, host, user, domain) == 1)
+ return (1);
+ if (!(pvt->rule->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ ng = pvt->rule->inst->ng;
+ (*ng->rewind)(ng, pvt->curgroup);
+ }
+ }
+ return (0);
+}
+
+static int
+ng_test(struct irs_ng *this, const char *name,
+ const char *user, const char *host, const char *domain)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct irs_ng *ng;
+ int rval;
+
+ rval = 0;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ ng = rule->inst->ng;
+ rval = (*ng->test)(ng, name, user, host, domain);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static void
+ng_rewind(struct irs_ng *this, const char *group) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_ng *ng;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ if (pvt->curgroup)
+ free(pvt->curgroup);
+ pvt->curgroup = strdup(group);
+ ng = pvt->rule->inst->ng;
+ (*ng->rewind)(ng, pvt->curgroup);
+ }
+}
+
+static void
+ng_minimize(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_ng *ng = rule->inst->ng;
+
+ (*ng->minimize)(ng);
+ }
+}
+
+/*! \file */
diff --git a/lib/bind/irs/gen_nw.c b/lib/bind/irs/gen_nw.c
new file mode 100644
index 0000000..8452f3f
--- /dev/null
+++ b/lib/bind/irs/gen_nw.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_nw.c,v 1.3.18.1 2005/04/27 05:00:56 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward */
+
+static void nw_close(struct irs_nw*);
+static struct nwent * nw_next(struct irs_nw *);
+static struct nwent * nw_byname(struct irs_nw *, const char *, int);
+static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int);
+static void nw_rewind(struct irs_nw *);
+static void nw_minimize(struct irs_nw *);
+static struct __res_state * nw_res_get(struct irs_nw *this);
+static void nw_res_set(struct irs_nw *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+
+static int init(struct irs_nw *this);
+
+/* Public */
+
+struct irs_nw *
+irs_gen_nw(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_nw *nw;
+ struct pvt *pvt;
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(nw = memget(sizeof *nw))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(nw, 0x5e, sizeof *nw);
+ pvt->rules = accpvt->map_rules[irs_nw];
+ pvt->rule = pvt->rules;
+ nw->private = pvt;
+ nw->close = nw_close;
+ nw->next = nw_next;
+ nw->byname = nw_byname;
+ nw->byaddr = nw_byaddr;
+ nw->rewind = nw_rewind;
+ nw->minimize = nw_minimize;
+ nw->res_get = nw_res_get;
+ nw->res_set = nw_res_set;
+ return (nw);
+}
+
+/* Methods */
+
+static void
+nw_close(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ nw_minimize(this);
+
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct nwent *rval;
+ struct irs_nw *nw;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ while (pvt->rule) {
+ nw = pvt->rule->inst->nw;
+ rval = (*nw->next)(nw);
+ if (rval)
+ return (rval);
+ if (!(pvt->rules->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ nw = pvt->rule->inst->nw;
+ (*nw->rewind)(nw);
+ }
+ }
+ return (NULL);
+}
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int type) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct nwent *rval;
+ struct irs_nw *nw;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ nw = rule->inst->nw;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ rval = (*nw->byname)(nw, name, type);
+ if (rval != NULL)
+ return (rval);
+ if (pvt->res->res_h_errno != TRY_AGAIN &&
+ !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (NULL);
+}
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int length, int type) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct nwent *rval;
+ struct irs_nw *nw;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ nw = rule->inst->nw;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ rval = (*nw->byaddr)(nw, net, length, type);
+ if (rval != NULL)
+ return (rval);
+ if (pvt->res->res_h_errno != TRY_AGAIN &&
+ !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (NULL);
+}
+
+static void
+nw_rewind(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_nw *nw;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ nw = pvt->rule->inst->nw;
+ (*nw->rewind)(nw);
+ }
+}
+
+static void
+nw_minimize(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_nw *nw = rule->inst->nw;
+
+ (*nw->minimize)(nw);
+ }
+}
+
+static struct __res_state *
+nw_res_get(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ nw_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+nw_res_set(struct irs_nw *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_nw *nw = rule->inst->nw;
+
+ (*nw->res_set)(nw, pvt->res, NULL);
+ }
+}
+
+static int
+init(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !nw_res_get(this))
+ return (-1);
+ if (((pvt->res->options & RES_INIT) == 0U) &&
+ res_ninit(pvt->res) == -1)
+ return (-1);
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/gen_p.h b/lib/bind/irs/gen_p.h
new file mode 100644
index 0000000..a0a312d
--- /dev/null
+++ b/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.2.18.1 2005/04/27 05:00:56 sra Exp $
+ */
+
+/*! \file
+ * Notes:
+ * We hope to create a complete set of thread-safe entry points someday,
+ * which will mean a set of getXbyY() functions that take as an argument
+ * a pointer to the map class, which will have a pointer to the private
+ * data, which will be used preferentially to the static variables that
+ * are necessary to support the "classic" interface. This "classic"
+ * interface will then be reimplemented as stubs on top of the thread
+ * safe modules, and will keep the map class pointers as their only
+ * static data. HOWEVER, we are not there yet. So while we will call
+ * the just-barely-converted map class methods with map class pointers,
+ * right now they probably all still use statics. We're not fooling
+ * anybody, and we're not trying to (yet).
+ */
+
+#ifndef _GEN_P_H_INCLUDED
+#define _GEN_P_H_INCLUDED
+
+/*%
+ * These are the access methods.
+ */
+enum irs_acc_id {
+ irs_lcl, /*%< Local. */
+ irs_dns, /*%< DNS or Hesiod. */
+ irs_nis, /*%< Sun NIS ("YP"). */
+ irs_irp, /*%< IR protocol. */
+ irs_nacc
+};
+
+/*%
+ * These are the map types.
+ */
+enum irs_map_id {
+ irs_gr, /*%< "group" */
+ irs_pw, /*%< "passwd" */
+ irs_sv, /*%< "services" */
+ irs_pr, /*%< "protocols" */
+ irs_ho, /*%< "hosts" */
+ irs_nw, /*%< "networks" */
+ irs_ng, /*%< "netgroup" */
+ irs_nmap
+};
+
+/*%
+ * This is an accessor instance.
+ */
+struct irs_inst {
+ struct irs_acc *acc;
+ struct irs_gr * gr;
+ struct irs_pw * pw;
+ struct irs_sv * sv;
+ struct irs_pr * pr;
+ struct irs_ho * ho;
+ struct irs_nw * nw;
+ struct irs_ng * ng;
+};
+
+/*%
+ * This is a search rule for some map type.
+ */
+struct irs_rule {
+ struct irs_rule * next;
+ struct irs_inst * inst;
+ int flags;
+};
+#define IRS_MERGE 0x0001 /*%< Don't stop if acc. has data? */
+#define IRS_CONTINUE 0x0002 /*%< Don't stop if acc. has no data? */
+/*
+ * This is the private data for a search access class.
+ */
+struct gen_p {
+ char * options;
+ struct irs_rule * map_rules[(int)irs_nmap];
+ struct irs_inst accessors[(int)irs_nacc];
+ struct __res_state * res;
+ void (*free_res) __P((void *));
+};
+
+/*
+ * Externs.
+ */
+
+extern struct irs_acc * irs_gen_acc __P((const char *, const char *conf_file));
+extern struct irs_gr * irs_gen_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_gen_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_gen_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_gen_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_gen_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_gen_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_gen_ng __P((struct irs_acc *));
+
+#endif /*_IRS_P_H_INCLUDED*/
diff --git a/lib/bind/irs/gen_pr.c b/lib/bind/irs/gen_pr.c
new file mode 100644
index 0000000..5c9d69c
--- /dev/null
+++ b/lib/bind/irs/gen_pr.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_pr.c,v 1.2.18.1 2005/04/27 05:00:56 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward */
+
+static void pr_close(struct irs_pr*);
+static struct protoent * pr_next(struct irs_pr *);
+static struct protoent * pr_byname(struct irs_pr *, const char *);
+static struct protoent * pr_bynumber(struct irs_pr *, int);
+static void pr_rewind(struct irs_pr *);
+static void pr_minimize(struct irs_pr *);
+static struct __res_state * pr_res_get(struct irs_pr *);
+static void pr_res_set(struct irs_pr *,
+ struct __res_state *,
+ void (*)(void *));
+
+/* Public */
+
+struct irs_pr *
+irs_gen_pr(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_pr *pr;
+ struct pvt *pvt;
+
+ if (!(pr = memget(sizeof *pr))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pr, 0x5e, sizeof *pr);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(pr, sizeof *pr);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->rules = accpvt->map_rules[irs_pr];
+ pvt->rule = pvt->rules;
+ pr->private = pvt;
+ pr->close = pr_close;
+ pr->next = pr_next;
+ pr->byname = pr_byname;
+ pr->bynumber = pr_bynumber;
+ pr->rewind = pr_rewind;
+ pr->minimize = pr_minimize;
+ pr->res_get = pr_res_get;
+ pr->res_set = pr_res_set;
+ return (pr);
+}
+
+/* Methods */
+
+static void
+pr_close(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct protoent *rval;
+ struct irs_pr *pr;
+
+ while (pvt->rule) {
+ pr = pvt->rule->inst->pr;
+ rval = (*pr->next)(pr);
+ if (rval)
+ return (rval);
+ if (!(pvt->rules->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ pr = pvt->rule->inst->pr;
+ (*pr->rewind)(pr);
+ }
+ }
+ return (NULL);
+}
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct protoent *rval;
+ struct irs_pr *pr;
+
+ rval = NULL;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ pr = rule->inst->pr;
+ rval = (*pr->byname)(pr, name);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct protoent *rval;
+ struct irs_pr *pr;
+
+ rval = NULL;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ pr = rule->inst->pr;
+ rval = (*pr->bynumber)(pr, proto);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static void
+pr_rewind(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_pr *pr;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ pr = pvt->rule->inst->pr;
+ (*pr->rewind)(pr);
+ }
+}
+
+static void
+pr_minimize(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_pr *pr = rule->inst->pr;
+
+ (*pr->minimize)(pr);
+ }
+}
+
+static struct __res_state *
+pr_res_get(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ pr_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+pr_res_set(struct irs_pr *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_pr *pr = rule->inst->pr;
+
+ if (pr->res_set)
+ (*pr->res_set)(pr, pvt->res, NULL);
+ }
+}
+
+/*! \file */
diff --git a/lib/bind/irs/gen_pw.c b/lib/bind/irs/gen_pw.c
new file mode 100644
index 0000000..80d9b5d
--- /dev/null
+++ b/lib/bind/irs/gen_pw.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_pw.c,v 1.2.18.1 2005/04/27 05:00:57 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <errno.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward */
+
+static void pw_close(struct irs_pw *);
+static struct passwd * pw_next(struct irs_pw *);
+static struct passwd * pw_byname(struct irs_pw *, const char *);
+static struct passwd * pw_byuid(struct irs_pw *, uid_t);
+static void pw_rewind(struct irs_pw *);
+static void pw_minimize(struct irs_pw *);
+static struct __res_state * pw_res_get(struct irs_pw *);
+static void pw_res_set(struct irs_pw *,
+ struct __res_state *,
+ void (*)(void *));
+
+/* Public */
+
+struct irs_pw *
+irs_gen_pw(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_pw *pw;
+ struct pvt *pvt;
+
+ if (!(pw = memget(sizeof *pw))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pw, 0x5e, sizeof *pw);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(pw, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->rules = accpvt->map_rules[irs_pw];
+ pvt->rule = pvt->rules;
+ pw->private = pvt;
+ pw->close = pw_close;
+ pw->next = pw_next;
+ pw->byname = pw_byname;
+ pw->byuid = pw_byuid;
+ pw->rewind = pw_rewind;
+ pw->minimize = pw_minimize;
+ pw->res_get = pw_res_get;
+ pw->res_set = pw_res_set;
+ return (pw);
+}
+
+/* Methods */
+
+static void
+pw_close(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct passwd *
+pw_next(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct passwd *rval;
+ struct irs_pw *pw;
+
+ while (pvt->rule) {
+ pw = pvt->rule->inst->pw;
+ rval = (*pw->next)(pw);
+ if (rval)
+ return (rval);
+ if (!(pvt->rule->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ pw = pvt->rule->inst->pw;
+ (*pw->rewind)(pw);
+ }
+ }
+ return (NULL);
+}
+
+static void
+pw_rewind(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_pw *pw;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ pw = pvt->rule->inst->pw;
+ (*pw->rewind)(pw);
+ }
+}
+
+static struct passwd *
+pw_byname(struct irs_pw *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct passwd *rval;
+ struct irs_pw *pw;
+
+ rval = NULL;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ pw = rule->inst->pw;
+ rval = (*pw->byname)(pw, name);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static struct passwd *
+pw_byuid(struct irs_pw *this, uid_t uid) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct passwd *rval;
+ struct irs_pw *pw;
+
+ rval = NULL;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ pw = rule->inst->pw;
+ rval = (*pw->byuid)(pw, uid);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static void
+pw_minimize(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_pw *pw = rule->inst->pw;
+
+ (*pw->minimize)(pw);
+ }
+}
+
+static struct __res_state *
+pw_res_get(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ pw_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+pw_res_set(struct irs_pw *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_pw *pw = rule->inst->pw;
+
+ if (pw->res_set)
+ (*pw->res_set)(pw, pvt->res, NULL);
+ }
+}
+
+#endif /* WANT_IRS_PW */
+/*! \file */
diff --git a/lib/bind/irs/gen_sv.c b/lib/bind/irs/gen_sv.c
new file mode 100644
index 0000000..66f0ab7
--- /dev/null
+++ b/lib/bind/irs/gen_sv.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_sv.c,v 1.2.18.1 2005/04/27 05:00:57 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward */
+
+static void sv_close(struct irs_sv*);
+static struct servent * sv_next(struct irs_sv *);
+static struct servent * sv_byname(struct irs_sv *, const char *,
+ const char *);
+static struct servent * sv_byport(struct irs_sv *, int, const char *);
+static void sv_rewind(struct irs_sv *);
+static void sv_minimize(struct irs_sv *);
+static struct __res_state * sv_res_get(struct irs_sv *);
+static void sv_res_set(struct irs_sv *,
+ struct __res_state *,
+ void (*)(void *));
+
+/* Public */
+
+struct irs_sv *
+irs_gen_sv(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_sv *sv;
+ struct pvt *pvt;
+
+ if (!(sv = memget(sizeof *sv))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(sv, 0x5e, sizeof *sv);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(sv, sizeof *sv);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->rules = accpvt->map_rules[irs_sv];
+ pvt->rule = pvt->rules;
+ sv->private = pvt;
+ sv->close = sv_close;
+ sv->next = sv_next;
+ sv->byname = sv_byname;
+ sv->byport = sv_byport;
+ sv->rewind = sv_rewind;
+ sv->minimize = sv_minimize;
+ sv->res_get = sv_res_get;
+ sv->res_set = sv_res_set;
+ return (sv);
+}
+
+/* Methods */
+
+static void
+sv_close(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct servent *rval;
+ struct irs_sv *sv;
+
+ while (pvt->rule) {
+ sv = pvt->rule->inst->sv;
+ rval = (*sv->next)(sv);
+ if (rval)
+ return (rval);
+ if (!(pvt->rule->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ sv = pvt->rule->inst->sv;
+ (*sv->rewind)(sv);
+ }
+ }
+ return (NULL);
+}
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct servent *rval;
+ struct irs_sv *sv;
+
+ rval = NULL;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ sv = rule->inst->sv;
+ rval = (*sv->byname)(sv, name, proto);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct servent *rval;
+ struct irs_sv *sv;
+
+ rval = NULL;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ sv = rule->inst->sv;
+ rval = (*sv->byport)(sv, port, proto);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static void
+sv_rewind(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_sv *sv;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ sv = pvt->rule->inst->sv;
+ (*sv->rewind)(sv);
+ }
+}
+
+static void
+sv_minimize(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_sv *sv = rule->inst->sv;
+
+ (*sv->minimize)(sv);
+ }
+}
+
+static struct __res_state *
+sv_res_get(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ sv_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+sv_res_set(struct irs_sv *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_sv *sv = rule->inst->sv;
+
+ if (sv->res_set)
+ (*sv->res_set)(sv, pvt->res, NULL);
+ }
+}
+
+/*! \file */
diff --git a/lib/bind/irs/getaddrinfo.c b/lib/bind/irs/getaddrinfo.c
new file mode 100644
index 0000000..1839ba4
--- /dev/null
+++ b/lib/bind/irs/getaddrinfo.c
@@ -0,0 +1,1253 @@
+/* $KAME: getaddrinfo.c,v 1.14 2001/01/06 09:41:15 jinmei Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*! \file
+ * Issues to be discussed:
+ *\li Thread safe-ness must be checked.
+ *\li Return values. There are nonstandard return values defined and used
+ * in the source code. This is because RFC2553 is silent about which error
+ * code must be returned for which situation.
+ *\li IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2
+ * says to use inet_aton() to convert IPv4 numeric to binary (allows
+ * classful form as a result).
+ * current code - disallow classful form for IPv4 (due to use of inet_pton).
+ *\li freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
+ * invalid.
+ * current code - SEGV on freeaddrinfo(NULL)
+ * Note:
+ *\li We use getipnodebyname() just for thread-safeness. There's no intent
+ * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
+ * getipnodebyname().
+ *\li The code filters out AFs that are not supported by the kernel,
+ * when globbing NULL hostname (to loopback, or wildcard). Is it the right
+ * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
+ * in ai_flags?
+ *\li (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
+ * (1) what should we do against numeric hostname (2) what should we do
+ * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
+ * non-loopback address configured? global address configured?
+ * \par Additional Issue:
+ * To avoid search order issue, we have a big amount of code duplicate
+ * from gethnamaddr.c and some other places. The issues that there's no
+ * lower layer function to lookup "IPv4 or IPv6" record. Calling
+ * gethostbyname2 from getaddrinfo will end up in wrong search order, as
+ * follows:
+ * \li The code makes use of following calls when asked to resolver with
+ * ai_family = PF_UNSPEC:
+ *\code getipnodebyname(host, AF_INET6);
+ * getipnodebyname(host, AF_INET);
+ *\endcode
+ * \li This will result in the following queries if the node is configure to
+ * prefer /etc/hosts than DNS:
+ *\code
+ * lookup /etc/hosts for IPv6 address
+ * lookup DNS for IPv6 address
+ * lookup /etc/hosts for IPv4 address
+ * lookup DNS for IPv4 address
+ *\endcode
+ * which may not meet people's requirement.
+ * \li The right thing to happen is to have underlying layer which does
+ * PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
+ * This would result in a bit of code duplicate with _dns_ghbyname() and
+ * friends.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <stdarg.h>
+
+#include <irs.h>
+#include <isc/assertions.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO 0
+
+static const char in_addrany[] = { 0, 0, 0, 0 };
+static const char in6_addrany[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+static const char in_loopback[] = { 127, 0, 0, 1 };
+static const char in6_loopback[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+};
+
+static const struct afd {
+ int a_af;
+ int a_addrlen;
+ int a_socklen;
+ int a_off;
+ const char *a_addrany;
+ const char *a_loopback;
+ int a_scoped;
+} afdl [] = {
+ {PF_INET6, sizeof(struct in6_addr),
+ sizeof(struct sockaddr_in6),
+ offsetof(struct sockaddr_in6, sin6_addr),
+ in6_addrany, in6_loopback, 1},
+ {PF_INET, sizeof(struct in_addr),
+ sizeof(struct sockaddr_in),
+ offsetof(struct sockaddr_in, sin_addr),
+ in_addrany, in_loopback, 0},
+ {0, 0, 0, 0, NULL, NULL, 0},
+};
+
+struct explore {
+ int e_af;
+ int e_socktype;
+ int e_protocol;
+ const char *e_protostr;
+ int e_wild;
+#define WILD_AF(ex) ((ex)->e_wild & 0x01)
+#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
+#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
+};
+
+static const struct explore explore[] = {
+#if 0
+ { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
+#endif
+ { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+ { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+ { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
+ { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+ { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+ { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
+ { -1, 0, 0, NULL, 0 },
+};
+
+#define PTON_MAX 16
+
+static int str_isnumber __P((const char *));
+static int explore_fqdn __P((const struct addrinfo *, const char *,
+ const char *, struct addrinfo **));
+static int explore_copy __P((const struct addrinfo *, const struct addrinfo *,
+ struct addrinfo **));
+static int explore_null __P((const struct addrinfo *,
+ const char *, struct addrinfo **));
+static int explore_numeric __P((const struct addrinfo *, const char *,
+ const char *, struct addrinfo **));
+static int explore_numeric_scope __P((const struct addrinfo *, const char *,
+ const char *, struct addrinfo **));
+static int get_canonname __P((const struct addrinfo *,
+ struct addrinfo *, const char *));
+static struct addrinfo *get_ai __P((const struct addrinfo *,
+ const struct afd *, const char *));
+static struct addrinfo *copy_ai __P((const struct addrinfo *));
+static int get_portmatch __P((const struct addrinfo *, const char *));
+static int get_port __P((const struct addrinfo *, const char *, int));
+static const struct afd *find_afd __P((int));
+static int addrconfig __P((int));
+static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *,
+ u_int32_t *scopeidp));
+static struct net_data *init __P((void));
+
+struct addrinfo *hostent2addrinfo __P((struct hostent *,
+ const struct addrinfo *));
+struct addrinfo *addr2addrinfo __P((const struct addrinfo *,
+ const char *));
+
+#if 0
+static const char *ai_errlist[] = {
+ "Success",
+ "Address family for hostname not supported", /*%< EAI_ADDRFAMILY */
+ "Temporary failure in name resolution", /*%< EAI_AGAIN */
+ "Invalid value for ai_flags", /*%< EAI_BADFLAGS */
+ "Non-recoverable failure in name resolution", /*%< EAI_FAIL */
+ "ai_family not supported", /*%< EAI_FAMILY */
+ "Memory allocation failure", /*%< EAI_MEMORY */
+ "No address associated with hostname", /*%< EAI_NODATA */
+ "hostname nor servname provided, or not known", /*%< EAI_NONAME */
+ "servname not supported for ai_socktype", /*%< EAI_SERVICE */
+ "ai_socktype not supported", /*%< EAI_SOCKTYPE */
+ "System error returned in errno", /*%< EAI_SYSTEM */
+ "Invalid value for hints", /*%< EAI_BADHINTS */
+ "Resolved protocol is unknown", /*%< EAI_PROTOCOL */
+ "Unknown error", /*%< EAI_MAX */
+};
+#endif
+
+/* XXX macros that make external reference is BAD. */
+
+#define GET_AI(ai, afd, addr) \
+do { \
+ /* external reference: pai, error, and label free */ \
+ (ai) = get_ai(pai, (afd), (addr)); \
+ if ((ai) == NULL) { \
+ error = EAI_MEMORY; \
+ goto free; \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define GET_PORT(ai, serv) \
+do { \
+ /* external reference: error and label free */ \
+ error = get_port((ai), (serv), 0); \
+ if (error != 0) \
+ goto free; \
+} while (/*CONSTCOND*/0)
+
+#define GET_CANONNAME(ai, str) \
+do { \
+ /* external reference: pai, error and label free */ \
+ error = get_canonname(pai, (ai), (str)); \
+ if (error != 0) \
+ goto free; \
+} while (/*CONSTCOND*/0)
+
+#ifndef SOLARIS2
+#define SETERROR(err) \
+do { \
+ /* external reference: error, and label bad */ \
+ error = (err); \
+ goto bad; \
+ /*NOTREACHED*/ \
+} while (/*CONSTCOND*/0)
+#else
+#define SETERROR(err) \
+do { \
+ /* external reference: error, and label bad */ \
+ error = (err); \
+ if (error == error) \
+ goto bad; \
+} while (/*CONSTCOND*/0)
+#endif
+
+
+#define MATCH_FAMILY(x, y, w) \
+ ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
+#define MATCH(x, y, w) \
+ ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
+
+#if 0 /*%< bind8 has its own version */
+char *
+gai_strerror(ecode)
+ int ecode;
+{
+ if (ecode < 0 || ecode > EAI_MAX)
+ ecode = EAI_MAX;
+ return ai_errlist[ecode];
+}
+#endif
+
+void
+freeaddrinfo(ai)
+ struct addrinfo *ai;
+{
+ struct addrinfo *next;
+
+ do {
+ next = ai->ai_next;
+ if (ai->ai_canonname)
+ free(ai->ai_canonname);
+ /* no need to free(ai->ai_addr) */
+ free(ai);
+ ai = next;
+ } while (ai);
+}
+
+static int
+str_isnumber(p)
+ const char *p;
+{
+ char *ep;
+
+ if (*p == '\0')
+ return NO;
+ ep = NULL;
+ errno = 0;
+ (void)strtoul(p, &ep, 10);
+ if (errno == 0 && ep && *ep == '\0')
+ return YES;
+ else
+ return NO;
+}
+
+int
+getaddrinfo(hostname, servname, hints, res)
+ const char *hostname, *servname;
+ const struct addrinfo *hints;
+ struct addrinfo **res;
+{
+ struct addrinfo sentinel;
+ struct addrinfo *cur;
+ int error = 0;
+ struct addrinfo ai, ai0, *afai = NULL;
+ struct addrinfo *pai;
+ const struct explore *ex;
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+ pai = &ai;
+ pai->ai_flags = 0;
+ pai->ai_family = PF_UNSPEC;
+ pai->ai_socktype = ANY;
+ pai->ai_protocol = ANY;
+#if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9)
+ /*
+ * clear _ai_pad to preserve binary
+ * compatibility with previously compiled 64-bit
+ * applications in a pre-SUSv3 environment by
+ * guaranteeing the upper 32-bits are empty.
+ */
+ pai->_ai_pad = 0;
+#endif
+ pai->ai_addrlen = 0;
+ pai->ai_canonname = NULL;
+ pai->ai_addr = NULL;
+ pai->ai_next = NULL;
+
+ if (hostname == NULL && servname == NULL)
+ return EAI_NONAME;
+ if (hints) {
+ /* error check for hints */
+ if (hints->ai_addrlen || hints->ai_canonname ||
+ hints->ai_addr || hints->ai_next)
+ SETERROR(EAI_BADHINTS); /*%< xxx */
+ if (hints->ai_flags & ~AI_MASK)
+ SETERROR(EAI_BADFLAGS);
+ switch (hints->ai_family) {
+ case PF_UNSPEC:
+ case PF_INET:
+ case PF_INET6:
+ break;
+ default:
+ SETERROR(EAI_FAMILY);
+ }
+ memcpy(pai, hints, sizeof(*pai));
+
+#if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9)
+ /*
+ * We need to clear _ai_pad to preserve binary
+ * compatibility. See prior comment.
+ */
+ pai->_ai_pad = 0;
+#endif
+ /*
+ * if both socktype/protocol are specified, check if they
+ * are meaningful combination.
+ */
+ if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
+ for (ex = explore; ex->e_af >= 0; ex++) {
+ if (pai->ai_family != ex->e_af)
+ continue;
+ if (ex->e_socktype == ANY)
+ continue;
+ if (ex->e_protocol == ANY)
+ continue;
+ if (pai->ai_socktype == ex->e_socktype &&
+ pai->ai_protocol != ex->e_protocol) {
+ SETERROR(EAI_BADHINTS);
+ }
+ }
+ }
+ }
+
+ /*
+ * post-2553: AI_ALL and AI_V4MAPPED are effective only against
+ * AF_INET6 query. They needs to be ignored if specified in other
+ * occassions.
+ */
+ switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
+ case AI_V4MAPPED:
+ case AI_ALL | AI_V4MAPPED:
+ if (pai->ai_family != AF_INET6)
+ pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
+ break;
+ case AI_ALL:
+#if 1
+ /* illegal */
+ SETERROR(EAI_BADFLAGS);
+#else
+ pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
+ break;
+#endif
+ }
+
+ /*
+ * check for special cases. (1) numeric servname is disallowed if
+ * socktype/protocol are left unspecified. (2) servname is disallowed
+ * for raw and other inet{,6} sockets.
+ */
+ if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
+#ifdef PF_INET6
+ || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
+#endif
+ ) {
+ ai0 = *pai; /* backup *pai */
+
+ if (pai->ai_family == PF_UNSPEC) {
+#ifdef PF_INET6
+ pai->ai_family = PF_INET6;
+#else
+ pai->ai_family = PF_INET;
+#endif
+ }
+ error = get_portmatch(pai, servname);
+ if (error)
+ SETERROR(error);
+
+ *pai = ai0;
+ }
+
+ ai0 = *pai;
+
+ /* NULL hostname, or numeric hostname */
+ for (ex = explore; ex->e_af >= 0; ex++) {
+ *pai = ai0;
+
+ if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
+ continue;
+ if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
+ continue;
+ if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
+ continue;
+
+ if (pai->ai_family == PF_UNSPEC)
+ pai->ai_family = ex->e_af;
+ if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
+ pai->ai_socktype = ex->e_socktype;
+ if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
+ pai->ai_protocol = ex->e_protocol;
+
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ continue;
+
+ if (hostname == NULL) {
+ /*
+ * filter out AFs that are not supported by the kernel
+ * XXX errno?
+ */
+ if (!addrconfig(pai->ai_family))
+ continue;
+ error = explore_null(pai, servname, &cur->ai_next);
+ } else
+ error = explore_numeric_scope(pai, hostname, servname,
+ &cur->ai_next);
+
+ if (error)
+ goto free;
+
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+
+ /*
+ * XXX
+ * If numreic representation of AF1 can be interpreted as FQDN
+ * representation of AF2, we need to think again about the code below.
+ */
+ if (sentinel.ai_next)
+ goto good;
+
+ if (pai->ai_flags & AI_NUMERICHOST)
+ SETERROR(EAI_NONAME);
+ if (hostname == NULL)
+ SETERROR(EAI_NONAME);
+
+ /*
+ * hostname as alphabetical name.
+ * We'll make sure that
+ * - if returning addrinfo list is empty, return non-zero error
+ * value (already known one or EAI_NONAME).
+ * - otherwise,
+ * + if we haven't had any errors, return 0 (i.e. success).
+ * + if we've had an error, free the list and return the error.
+ * without any assumption on the behavior of explore_fqdn().
+ */
+
+ /* first, try to query DNS for all possible address families. */
+ *pai = ai0;
+ error = explore_fqdn(pai, hostname, servname, &afai);
+ if (error) {
+ if (afai != NULL)
+ freeaddrinfo(afai);
+ goto free;
+ }
+ if (afai == NULL) {
+ error = EAI_NONAME; /*%< we've had no errors. */
+ goto free;
+ }
+
+ /*
+ * we would like to prefer AF_INET6 than AF_INET, so we'll make an
+ * outer loop by AFs.
+ */
+ for (ex = explore; ex->e_af >= 0; ex++) {
+ *pai = ai0;
+
+ if (pai->ai_family == PF_UNSPEC)
+ pai->ai_family = ex->e_af;
+
+ if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
+ continue;
+ if (!MATCH(pai->ai_socktype, ex->e_socktype,
+ WILD_SOCKTYPE(ex))) {
+ continue;
+ }
+ if (!MATCH(pai->ai_protocol, ex->e_protocol,
+ WILD_PROTOCOL(ex))) {
+ continue;
+ }
+
+#ifdef AI_ADDRCONFIG
+ /*
+ * If AI_ADDRCONFIG is specified, check if we are
+ * expected to return the address family or not.
+ */
+ if ((pai->ai_flags & AI_ADDRCONFIG) != 0 &&
+ !addrconfig(pai->ai_family))
+ continue;
+#endif
+
+ if (pai->ai_family == PF_UNSPEC)
+ pai->ai_family = ex->e_af;
+ if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
+ pai->ai_socktype = ex->e_socktype;
+ if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
+ pai->ai_protocol = ex->e_protocol;
+
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ continue;
+
+ if ((error = explore_copy(pai, afai, &cur->ai_next)) != 0) {
+ freeaddrinfo(afai);
+ goto free;
+ }
+
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+
+ freeaddrinfo(afai); /*%< afai must not be NULL at this point. */
+
+ if (sentinel.ai_next) {
+good:
+ *res = sentinel.ai_next;
+ return(SUCCESS);
+ } else {
+ /*
+ * All the process succeeded, but we've had an empty list.
+ * This can happen if the given hints do not match our
+ * candidates.
+ */
+ error = EAI_NONAME;
+ }
+
+free:
+bad:
+ if (sentinel.ai_next)
+ freeaddrinfo(sentinel.ai_next);
+ *res = NULL;
+ return(error);
+}
+
+/*%
+ * FQDN hostname, DNS lookup
+ */
+static int
+explore_fqdn(pai, hostname, servname, res)
+ const struct addrinfo *pai;
+ const char *hostname;
+ const char *servname;
+ struct addrinfo **res;
+{
+ struct addrinfo *result;
+ struct addrinfo *cur;
+ struct net_data *net_data = init();
+ struct irs_ho *ho;
+ int error = 0;
+ char tmp[NS_MAXDNAME];
+ const char *cp;
+
+ INSIST(res != NULL && *res == NULL);
+
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ return(0);
+
+ if (!net_data || !(ho = net_data->ho))
+ return(0);
+#if 0 /*%< XXX (notyet) */
+ if (net_data->ho_stayopen && net_data->ho_last &&
+ net_data->ho_last->h_addrtype == af) {
+ if (ns_samename(name, net_data->ho_last->h_name) == 1)
+ return (net_data->ho_last);
+ for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++)
+ if (ns_samename(name, *hap) == 1)
+ return (net_data->ho_last);
+ }
+#endif
+ if (!strchr(hostname, '.') &&
+ (cp = res_hostalias(net_data->res, hostname,
+ tmp, sizeof(tmp))))
+ hostname = cp;
+ result = (*ho->addrinfo)(ho, hostname, pai);
+ if (!net_data->ho_stayopen) {
+ (*ho->minimize)(ho);
+ }
+ if (result == NULL) {
+ int e = h_errno;
+
+ switch(e) {
+ case NETDB_INTERNAL:
+ error = EAI_SYSTEM;
+ break;
+ case TRY_AGAIN:
+ error = EAI_AGAIN;
+ break;
+ case NO_RECOVERY:
+ error = EAI_FAIL;
+ break;
+ case HOST_NOT_FOUND:
+ case NO_DATA:
+ error = EAI_NONAME;
+ break;
+ default:
+ case NETDB_SUCCESS: /*%< should be impossible... */
+ error = EAI_NONAME;
+ break;
+ }
+ goto free;
+ }
+
+ for (cur = result; cur; cur = cur->ai_next) {
+ GET_PORT(cur, servname); /*%< XXX: redundant lookups... */
+ /* canonname should already be filled. */
+ }
+
+ *res = result;
+
+ return(0);
+
+free:
+ if (result)
+ freeaddrinfo(result);
+ return error;
+}
+
+static int
+explore_copy(pai, src0, res)
+ const struct addrinfo *pai; /*%< seed */
+ const struct addrinfo *src0; /*%< source */
+ struct addrinfo **res;
+{
+ int error;
+ struct addrinfo sentinel, *cur;
+ const struct addrinfo *src;
+
+ error = 0;
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+
+ for (src = src0; src != NULL; src = src->ai_next) {
+ if (src->ai_family != pai->ai_family)
+ continue;
+
+ cur->ai_next = copy_ai(src);
+ if (!cur->ai_next) {
+ error = EAI_MEMORY;
+ goto fail;
+ }
+
+ cur->ai_next->ai_socktype = pai->ai_socktype;
+ cur->ai_next->ai_protocol = pai->ai_protocol;
+ cur = cur->ai_next;
+ }
+
+ *res = sentinel.ai_next;
+ return 0;
+
+fail:
+ freeaddrinfo(sentinel.ai_next);
+ return error;
+}
+
+/*%
+ * hostname == NULL.
+ * passive socket -> anyaddr (0.0.0.0 or ::)
+ * non-passive socket -> localhost (127.0.0.1 or ::1)
+ */
+static int
+explore_null(pai, servname, res)
+ const struct addrinfo *pai;
+ const char *servname;
+ struct addrinfo **res;
+{
+ const struct afd *afd;
+ struct addrinfo *cur;
+ struct addrinfo sentinel;
+ int error;
+
+ *res = NULL;
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return 0;
+
+ if (pai->ai_flags & AI_PASSIVE) {
+ GET_AI(cur->ai_next, afd, afd->a_addrany);
+ /* xxx meaningless?
+ * GET_CANONNAME(cur->ai_next, "anyaddr");
+ */
+ GET_PORT(cur->ai_next, servname);
+ } else {
+ GET_AI(cur->ai_next, afd, afd->a_loopback);
+ /* xxx meaningless?
+ * GET_CANONNAME(cur->ai_next, "localhost");
+ */
+ GET_PORT(cur->ai_next, servname);
+ }
+ cur = cur->ai_next;
+
+ *res = sentinel.ai_next;
+ return 0;
+
+free:
+ if (sentinel.ai_next)
+ freeaddrinfo(sentinel.ai_next);
+ return error;
+}
+
+/*%
+ * numeric hostname
+ */
+static int
+explore_numeric(pai, hostname, servname, res)
+ const struct addrinfo *pai;
+ const char *hostname;
+ const char *servname;
+ struct addrinfo **res;
+{
+ const struct afd *afd;
+ struct addrinfo *cur;
+ struct addrinfo sentinel;
+ int error;
+ char pton[PTON_MAX];
+
+ *res = NULL;
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return 0;
+
+ switch (afd->a_af) {
+#if 0 /*X/Open spec*/
+ case AF_INET:
+ if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
+ if (pai->ai_family == afd->a_af ||
+ pai->ai_family == PF_UNSPEC /*?*/) {
+ GET_AI(cur->ai_next, afd, pton);
+ GET_PORT(cur->ai_next, servname);
+ while (cur->ai_next)
+ cur = cur->ai_next;
+ } else
+ SETERROR(EAI_FAMILY); /*xxx*/
+ }
+ break;
+#endif
+ default:
+ if (inet_pton(afd->a_af, hostname, pton) == 1) {
+ if (pai->ai_family == afd->a_af ||
+ pai->ai_family == PF_UNSPEC /*?*/) {
+ GET_AI(cur->ai_next, afd, pton);
+ GET_PORT(cur->ai_next, servname);
+ while (cur->ai_next)
+ cur = cur->ai_next;
+ } else
+ SETERROR(EAI_FAMILY); /*xxx*/
+ }
+ break;
+ }
+
+ *res = sentinel.ai_next;
+ return 0;
+
+free:
+bad:
+ if (sentinel.ai_next)
+ freeaddrinfo(sentinel.ai_next);
+ return error;
+}
+
+/*%
+ * numeric hostname with scope
+ */
+static int
+explore_numeric_scope(pai, hostname, servname, res)
+ const struct addrinfo *pai;
+ const char *hostname;
+ const char *servname;
+ struct addrinfo **res;
+{
+#ifndef SCOPE_DELIMITER
+ return explore_numeric(pai, hostname, servname, res);
+#else
+ const struct afd *afd;
+ struct addrinfo *cur;
+ int error;
+ char *cp, *hostname2 = NULL, *scope, *addr;
+ struct sockaddr_in6 *sin6;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return 0;
+
+ if (!afd->a_scoped)
+ return explore_numeric(pai, hostname, servname, res);
+
+ cp = strchr(hostname, SCOPE_DELIMITER);
+ if (cp == NULL)
+ return explore_numeric(pai, hostname, servname, res);
+
+ /*
+ * Handle special case of <scoped_address><delimiter><scope id>
+ */
+ hostname2 = strdup(hostname);
+ if (hostname2 == NULL)
+ return EAI_MEMORY;
+ /* terminate at the delimiter */
+ hostname2[cp - hostname] = '\0';
+ addr = hostname2;
+ scope = cp + 1;
+
+ error = explore_numeric(pai, addr, servname, res);
+ if (error == 0) {
+ u_int32_t scopeid = 0;
+
+ for (cur = *res; cur; cur = cur->ai_next) {
+ if (cur->ai_family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
+ if (!ip6_str2scopeid(scope, sin6, &scopeid)) {
+ free(hostname2);
+ return(EAI_NONAME); /*%< XXX: is return OK? */
+ }
+#ifdef HAVE_SIN6_SCOPE_ID
+ sin6->sin6_scope_id = scopeid;
+#endif
+ }
+ }
+
+ free(hostname2);
+
+ return error;
+#endif
+}
+
+static int
+get_canonname(pai, ai, str)
+ const struct addrinfo *pai;
+ struct addrinfo *ai;
+ const char *str;
+{
+ if ((pai->ai_flags & AI_CANONNAME) != 0) {
+ ai->ai_canonname = (char *)malloc(strlen(str) + 1);
+ if (ai->ai_canonname == NULL)
+ return EAI_MEMORY;
+ strcpy(ai->ai_canonname, str);
+ }
+ return 0;
+}
+
+static struct addrinfo *
+get_ai(pai, afd, addr)
+ const struct addrinfo *pai;
+ const struct afd *afd;
+ const char *addr;
+{
+ char *p;
+ struct addrinfo *ai;
+
+ ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
+ + (afd->a_socklen));
+ if (ai == NULL)
+ return NULL;
+
+ memcpy(ai, pai, sizeof(struct addrinfo));
+ ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
+ memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
+#ifdef HAVE_SA_LEN
+ ai->ai_addr->sa_len = afd->a_socklen;
+#endif
+ ai->ai_addrlen = afd->a_socklen;
+ ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
+ p = (char *)(void *)(ai->ai_addr);
+ memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
+ return ai;
+}
+
+/* XXX need to malloc() the same way we do from other functions! */
+static struct addrinfo *
+copy_ai(pai)
+ const struct addrinfo *pai;
+{
+ struct addrinfo *ai;
+ size_t l;
+
+ l = sizeof(*ai) + pai->ai_addrlen;
+ if ((ai = (struct addrinfo *)malloc(l)) == NULL)
+ return NULL;
+ memset(ai, 0, l);
+ memcpy(ai, pai, sizeof(*ai));
+ ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
+ memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen);
+
+ if (pai->ai_canonname) {
+ l = strlen(pai->ai_canonname) + 1;
+ if ((ai->ai_canonname = malloc(l)) == NULL) {
+ free(ai);
+ return NULL;
+ }
+ strcpy(ai->ai_canonname, pai->ai_canonname); /* (checked) */
+ } else {
+ /* just to make sure */
+ ai->ai_canonname = NULL;
+ }
+
+ ai->ai_next = NULL;
+
+ return ai;
+}
+
+static int
+get_portmatch(const struct addrinfo *ai, const char *servname) {
+
+ /* get_port does not touch first argument. when matchonly == 1. */
+ /* LINTED const cast */
+ return get_port((const struct addrinfo *)ai, servname, 1);
+}
+
+static int
+get_port(const struct addrinfo *ai, const char *servname, int matchonly) {
+ const char *proto;
+ struct servent *sp;
+ int port;
+ int allownumeric;
+
+ if (servname == NULL)
+ return 0;
+ switch (ai->ai_family) {
+ case AF_INET:
+#ifdef AF_INET6
+ case AF_INET6:
+#endif
+ break;
+ default:
+ return 0;
+ }
+
+ switch (ai->ai_socktype) {
+ case SOCK_RAW:
+ return EAI_SERVICE;
+ case SOCK_DGRAM:
+ case SOCK_STREAM:
+ allownumeric = 1;
+ break;
+ case ANY:
+ switch (ai->ai_family) {
+ case AF_INET:
+#ifdef AF_INET6
+ case AF_INET6:
+#endif
+ allownumeric = 1;
+ break;
+ default:
+ allownumeric = 0;
+ break;
+ }
+ break;
+ default:
+ return EAI_SOCKTYPE;
+ }
+
+ if (str_isnumber(servname)) {
+ if (!allownumeric)
+ return EAI_SERVICE;
+ port = atoi(servname);
+ if (port < 0 || port > 65535)
+ return EAI_SERVICE;
+ port = htons(port);
+ } else {
+ switch (ai->ai_socktype) {
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ case SOCK_STREAM:
+ proto = "tcp";
+ break;
+ default:
+ proto = NULL;
+ break;
+ }
+
+ if ((sp = getservbyname(servname, proto)) == NULL)
+ return EAI_SERVICE;
+ port = sp->s_port;
+ }
+
+ if (!matchonly) {
+ switch (ai->ai_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)(void *)
+ ai->ai_addr)->sin_port = port;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)(void *)
+ ai->ai_addr)->sin6_port = port;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static const struct afd *
+find_afd(af)
+ int af;
+{
+ const struct afd *afd;
+
+ if (af == PF_UNSPEC)
+ return NULL;
+ for (afd = afdl; afd->a_af; afd++) {
+ if (afd->a_af == af)
+ return afd;
+ }
+ return NULL;
+}
+
+/*%
+ * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend
+ * will take care of it.
+ * the semantics of AI_ADDRCONFIG is not defined well. we are not sure
+ * if the code is right or not.
+ */
+static int
+addrconfig(af)
+ int af;
+{
+ int s;
+
+ /* XXX errno */
+ s = socket(af, SOCK_DGRAM, 0);
+ if (s < 0) {
+ if (errno != EMFILE)
+ return 0;
+ } else
+ close(s);
+ return 1;
+}
+
+/* convert a string to a scope identifier. XXX: IPv6 specific */
+static int
+ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6,
+ u_int32_t *scopeidp)
+{
+ u_int32_t scopeid;
+ u_long lscopeid;
+ struct in6_addr *a6 = &sin6->sin6_addr;
+ char *ep;
+
+ /* empty scopeid portion is invalid */
+ if (*scope == '\0')
+ return (0);
+
+#ifdef USE_IFNAMELINKID
+ if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
+ IN6_IS_ADDR_MC_NODELOCAL(a6)) {
+ /*
+ * Using interface names as link indices can be allowed
+ * only when we can assume a one-to-one mappings between
+ * links and interfaces. See comments in getnameinfo.c.
+ */
+ scopeid = if_nametoindex(scope);
+ if (scopeid == 0)
+ goto trynumeric;
+ *scopeidp = scopeid;
+ return (1);
+ }
+#endif
+
+ /* still unclear about literal, allow numeric only - placeholder */
+ if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
+ goto trynumeric;
+ if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
+ goto trynumeric;
+ else
+ goto trynumeric; /*%< global */
+ /* try to convert to a numeric id as a last resort */
+trynumeric:
+ errno = 0;
+ lscopeid = strtoul(scope, &ep, 10);
+ scopeid = lscopeid & 0xffffffff;
+ if (errno == 0 && ep && *ep == '\0' && scopeid == lscopeid) {
+ *scopeidp = scopeid;
+ return (1);
+ } else
+ return (0);
+}
+
+struct addrinfo *
+hostent2addrinfo(hp, pai)
+ struct hostent *hp;
+ const struct addrinfo *pai;
+{
+ int i, af, error = 0;
+ char **aplist = NULL, *ap;
+ struct addrinfo sentinel, *cur;
+ const struct afd *afd;
+
+ af = hp->h_addrtype;
+ if (pai->ai_family != AF_UNSPEC && af != pai->ai_family)
+ return(NULL);
+
+ afd = find_afd(af);
+ if (afd == NULL)
+ return(NULL);
+
+ aplist = hp->h_addr_list;
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ for (i = 0; (ap = aplist[i]) != NULL; i++) {
+#if 0 /*%< the trick seems too much */
+ af = hp->h_addr_list;
+ if (af == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
+ af = AF_INET;
+ ap = ap + sizeof(struct in6_addr)
+ - sizeof(struct in_addr);
+ }
+ afd = find_afd(af);
+ if (afd == NULL)
+ continue;
+#endif /* 0 */
+
+ GET_AI(cur->ai_next, afd, ap);
+
+ /* GET_PORT(cur->ai_next, servname); */
+ if ((pai->ai_flags & AI_CANONNAME) != 0) {
+ /*
+ * RFC2553 says that ai_canonname will be set only for
+ * the first element. we do it for all the elements,
+ * just for convenience.
+ */
+ GET_CANONNAME(cur->ai_next, hp->h_name);
+ }
+ while (cur->ai_next) /*%< no need to loop, actually. */
+ cur = cur->ai_next;
+ continue;
+
+ free:
+ if (cur->ai_next)
+ freeaddrinfo(cur->ai_next);
+ cur->ai_next = NULL;
+ /* continue, without tht pointer CUR advanced. */
+ }
+
+ return(sentinel.ai_next);
+}
+
+struct addrinfo *
+addr2addrinfo(pai, cp)
+ const struct addrinfo *pai;
+ const char *cp;
+{
+ const struct afd *afd;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return(NULL);
+
+ return(get_ai(pai, afd, cp));
+}
+
+static struct net_data *
+init()
+{
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->ho) {
+ net_data->ho = (*net_data->irs->ho_map)(net_data->irs);
+ if (!net_data->ho || !net_data->res) {
+error:
+ errno = EIO;
+ if (net_data && net_data->res)
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+
+ (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL);
+ }
+
+ return (net_data);
+}
diff --git a/lib/bind/irs/getgrent.c b/lib/bind/irs/getgrent.c
new file mode 100644
index 0000000..fe91ab3
--- /dev/null
+++ b/lib/bind/irs/getgrent.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getgrent.c,v 1.4.18.1 2005/04/27 05:00:57 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(WANT_IRS_GR) || defined(__BIND_NOSTATIC)
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <grp.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data *init(void);
+void endgrent(void);
+
+/* Public */
+
+struct group *
+getgrent() {
+ struct net_data *net_data = init();
+
+ return (getgrent_p(net_data));
+}
+
+struct group *
+getgrnam(const char *name) {
+ struct net_data *net_data = init();
+
+ return (getgrnam_p(name, net_data));
+}
+
+struct group *
+getgrgid(gid_t gid) {
+ struct net_data *net_data = init();
+
+ return (getgrgid_p(gid, net_data));
+}
+
+int
+setgroupent(int stayopen) {
+ struct net_data *net_data = init();
+
+ return (setgroupent_p(stayopen, net_data));
+}
+
+#ifdef SETGRENT_VOID
+void
+setgrent(void) {
+ struct net_data *net_data = init();
+
+ setgrent_p(net_data);
+}
+#else
+int
+setgrent(void) {
+ struct net_data *net_data = init();
+
+ return (setgrent_p(net_data));
+}
+#endif /* SETGRENT_VOID */
+
+void
+endgrent() {
+ struct net_data *net_data = init();
+
+ endgrent_p(net_data);
+}
+
+int
+getgrouplist(GETGROUPLIST_ARGS) {
+ struct net_data *net_data = init();
+
+ return (getgrouplist_p(name, basegid, groups, ngroups, net_data));
+}
+
+/* Shared private. */
+
+struct group *
+getgrent_p(struct net_data *net_data) {
+ struct irs_gr *gr;
+
+ if (!net_data || !(gr = net_data->gr))
+ return (NULL);
+ net_data->gr_last = (*gr->next)(gr);
+ return (net_data->gr_last);
+}
+
+struct group *
+getgrnam_p(const char *name, struct net_data *net_data) {
+ struct irs_gr *gr;
+
+ if (!net_data || !(gr = net_data->gr))
+ return (NULL);
+ if (net_data->gr_stayopen && net_data->gr_last &&
+ !strcmp(net_data->gr_last->gr_name, name))
+ return (net_data->gr_last);
+ net_data->gr_last = (*gr->byname)(gr, name);
+ if (!net_data->gr_stayopen)
+ endgrent();
+ return (net_data->gr_last);
+}
+
+struct group *
+getgrgid_p(gid_t gid, struct net_data *net_data) {
+ struct irs_gr *gr;
+
+ if (!net_data || !(gr = net_data->gr))
+ return (NULL);
+ if (net_data->gr_stayopen && net_data->gr_last &&
+ (gid_t)net_data->gr_last->gr_gid == gid)
+ return (net_data->gr_last);
+ net_data->gr_last = (*gr->bygid)(gr, gid);
+ if (!net_data->gr_stayopen)
+ endgrent();
+ return (net_data->gr_last);
+}
+
+int
+setgroupent_p(int stayopen, struct net_data *net_data) {
+ struct irs_gr *gr;
+
+ if (!net_data || !(gr = net_data->gr))
+ return (0);
+ (*gr->rewind)(gr);
+ net_data->gr_stayopen = (stayopen != 0);
+ if (stayopen == 0)
+ net_data_minimize(net_data);
+ return (1);
+}
+
+#ifdef SETGRENT_VOID
+void
+setgrent_p(struct net_data *net_data) {
+ (void)setgroupent_p(0, net_data);
+}
+#else
+int
+setgrent_p(struct net_data *net_data) {
+ return (setgroupent_p(0, net_data));
+}
+#endif /* SETGRENT_VOID */
+
+void
+endgrent_p(struct net_data *net_data) {
+ struct irs_gr *gr;
+
+ if ((net_data != NULL) && ((gr = net_data->gr) != NULL))
+ (*gr->minimize)(gr);
+}
+
+int
+getgrouplist_p(const char *name, gid_t basegid, gid_t *groups, int *ngroups,
+ struct net_data *net_data) {
+ struct irs_gr *gr;
+
+ if (!net_data || !(gr = net_data->gr)) {
+ *ngroups = 0;
+ return (-1);
+ }
+ return ((*gr->list)(gr, name, basegid, groups, ngroups));
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->gr) {
+ net_data->gr = (*net_data->irs->gr_map)(net_data->irs);
+
+ if (!net_data->gr || !net_data->res) {
+ error:
+ errno = EIO;
+ return (NULL);
+ }
+ (*net_data->gr->res_set)(net_data->gr, net_data->res,
+ NULL);
+ }
+
+ return (net_data);
+}
+
+#endif /* WANT_IRS_GR */
+/*! \file */
diff --git a/lib/bind/irs/getgrent_r.c b/lib/bind/irs/getgrent_r.c
new file mode 100644
index 0000000..1f7d94d
--- /dev/null
+++ b/lib/bind/irs/getgrent_r.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: getgrent_r.c,v 1.6.18.1 2005/04/27 05:00:57 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS) || !defined(WANT_IRS_PW)
+ static int getgrent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#if (defined(POSIX_GETGRNAM_R) || defined(POSIX_GETGRGID_R)) && \
+ defined(_POSIX_PTHREAD_SEMANTICS)
+ /* turn off solaris remapping in <grp.h> */
+#define _UNIX95
+#undef _POSIX_PTHREAD_SEMANTICS
+#include <grp.h>
+#define _POSIX_PTHREAD_SEMANTICS 1
+#else
+#include <grp.h>
+#endif
+#include <sys/param.h>
+#include <port_after.h>
+
+#ifdef GROUP_R_RETURN
+
+static int
+copy_group(struct group *, struct group *, char *buf, int buflen);
+
+/* POSIX 1003.1c */
+#ifdef POSIX_GETGRNAM_R
+int
+__posix_getgrnam_r(const char *name, struct group *gptr,
+ char *buf, int buflen, struct group **result) {
+#else
+int
+getgrnam_r(const char *name, struct group *gptr,
+ char *buf, size_t buflen, struct group **result) {
+#endif
+ struct group *ge = getgrnam(name);
+ int res;
+
+ if (ge == NULL) {
+ *result = NULL;
+ return (0);
+ }
+
+ res = copy_group(ge, gptr, buf, buflen);
+ *result = res ? NULL : gptr;
+ return (res);
+}
+
+#ifdef POSIX_GETGRNAM_R
+struct group *
+getgrnam_r(const char *name, struct group *gptr,
+ char *buf, int buflen) {
+ struct group *ge = getgrnam(name);
+ int res;
+
+ if (ge == NULL)
+ return (NULL);
+ res = copy_group(ge, gptr, buf, buflen);
+ return (res ? NULL : gptr);
+}
+#endif /* POSIX_GETGRNAM_R */
+
+/* POSIX 1003.1c */
+#ifdef POSIX_GETGRGID_R
+int
+__posix_getgrgid_r(gid_t gid, struct group *gptr,
+ char *buf, int buflen, struct group **result) {
+#else /* POSIX_GETGRGID_R */
+int
+getgrgid_r(gid_t gid, struct group *gptr,
+ char *buf, size_t buflen, struct group **result) {
+#endif /* POSIX_GETGRGID_R */
+ struct group *ge = getgrgid(gid);
+ int res;
+
+ if (ge == NULL) {
+ *result = NULL;
+ return (0);
+ }
+
+ res = copy_group(ge, gptr, buf, buflen);
+ *result = res ? NULL : gptr;
+ return (res);
+}
+
+#ifdef POSIX_GETGRGID_R
+struct group *
+getgrgid_r(gid_t gid, struct group *gptr,
+ char *buf, int buflen) {
+ struct group *ge = getgrgid(gid);
+ int res;
+
+ if (ge == NULL)
+ return (NULL);
+
+ res = copy_group(ge, gptr, buf, buflen);
+ return (res ? NULL : gptr);
+}
+#endif
+
+/*%
+ * These assume a single context is in operation per thread.
+ * If this is not the case we will need to call irs directly
+ * rather than through the base functions.
+ */
+
+GROUP_R_RETURN
+getgrent_r(struct group *gptr, GROUP_R_ARGS) {
+ struct group *ge = getgrent();
+ int res;
+
+ if (ge == NULL) {
+ return (GROUP_R_BAD);
+ }
+
+ res = copy_group(ge, gptr, buf, buflen);
+ return (res ? GROUP_R_BAD : GROUP_R_OK);
+}
+
+GROUP_R_SET_RETURN
+setgrent_r(GROUP_R_ENT_ARGS) {
+
+ setgrent();
+#ifdef GROUP_R_SET_RESULT
+ return (GROUP_R_SET_RESULT);
+#endif
+}
+
+GROUP_R_END_RETURN
+endgrent_r(GROUP_R_ENT_ARGS) {
+
+ endgrent();
+ GROUP_R_END_RESULT(GROUP_R_OK);
+}
+
+
+#if 0
+ /* XXX irs does not have a fgetgrent() */
+GROUP_R_RETURN
+fgetgrent_r(FILE *f, struct group *gptr, GROUP_R_ARGS) {
+ struct group *ge = fgetgrent(f);
+ int res;
+
+ if (ge == NULL)
+ return (GROUP_R_BAD);
+
+ res = copy_group(ge, gptr, buf, buflen);
+ return (res ? GROUP_R_BAD : GROUP_R_OK);
+}
+#endif
+
+/* Private */
+
+static int
+copy_group(struct group *ge, struct group *gptr, char *buf, int buflen) {
+ char *cp;
+ int i, n;
+ int numptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ numptr = 1; /*%< NULL ptr */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; ge->gr_mem[i]; i++, numptr++) {
+ len += strlen(ge->gr_mem[i]) + 1;
+ }
+ len += strlen(ge->gr_name) + 1;
+ len += strlen(ge->gr_passwd) + 1;
+ len += numptr * sizeof(char*);
+
+ if (len > buflen) {
+ errno = ERANGE;
+ return (ERANGE);
+ }
+
+ /* copy group id */
+ gptr->gr_gid = ge->gr_gid;
+
+ cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+ /* copy official name */
+ n = strlen(ge->gr_name) + 1;
+ strcpy(cp, ge->gr_name);
+ gptr->gr_name = cp;
+ cp += n;
+
+ /* copy member list */
+ gptr->gr_mem = (char **)ALIGN(buf);
+ for (i = 0 ; ge->gr_mem[i]; i++) {
+ n = strlen(ge->gr_mem[i]) + 1;
+ strcpy(cp, ge->gr_mem[i]);
+ gptr->gr_mem[i] = cp;
+ cp += n;
+ }
+ gptr->gr_mem[i] = NULL;
+
+ /* copy password */
+ n = strlen(ge->gr_passwd) + 1;
+ strcpy(cp, ge->gr_passwd);
+ gptr->gr_passwd = cp;
+ cp += n;
+
+ return (0);
+}
+#else /* GROUP_R_RETURN */
+ static int getgrent_r_unknown_system = 0;
+#endif /* GROUP_R_RETURN */
+#endif /* !def(_REENTRANT) || !def(DO_PTHREADS) || !def(WANT_IRS_PW) */
+/*! \file */
diff --git a/lib/bind/irs/gethostent.c b/lib/bind/irs/gethostent.c
new file mode 100644
index 0000000..23aaa30
--- /dev/null
+++ b/lib/bind/irs/gethostent.c
@@ -0,0 +1,1070 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gethostent.c,v 1.6.18.2 2006/01/10 05:09:08 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "irs_data.h"
+
+/* Definitions */
+
+struct pvt {
+ char * aliases[1];
+ char * addrs[2];
+ char addr[NS_IN6ADDRSZ];
+ char name[NS_MAXDNAME + 1];
+ struct hostent host;
+};
+
+/* Forward */
+
+static struct net_data *init(void);
+static void freepvt(struct net_data *);
+static struct hostent *fakeaddr(const char *, int, struct net_data *);
+
+
+/* Public */
+
+struct hostent *
+gethostbyname(const char *name) {
+ struct net_data *net_data = init();
+
+ return (gethostbyname_p(name, net_data));
+}
+
+struct hostent *
+gethostbyname2(const char *name, int af) {
+ struct net_data *net_data = init();
+
+ return (gethostbyname2_p(name, af, net_data));
+}
+
+struct hostent *
+gethostbyaddr(const char *addr, int len, int af) {
+ struct net_data *net_data = init();
+
+ return (gethostbyaddr_p(addr, len, af, net_data));
+}
+
+struct hostent *
+gethostent() {
+ struct net_data *net_data = init();
+
+ return (gethostent_p(net_data));
+}
+
+void
+sethostent(int stayopen) {
+ struct net_data *net_data = init();
+ sethostent_p(stayopen, net_data);
+}
+
+
+void
+endhostent() {
+ struct net_data *net_data = init();
+ endhostent_p(net_data);
+}
+
+/* Shared private. */
+
+struct hostent *
+gethostbyname_p(const char *name, struct net_data *net_data) {
+ struct hostent *hp;
+
+ if (!net_data)
+ return (NULL);
+
+ if (net_data->res->options & RES_USE_INET6) {
+ hp = gethostbyname2_p(name, AF_INET6, net_data);
+ if (hp)
+ return (hp);
+ }
+ return (gethostbyname2_p(name, AF_INET, net_data));
+}
+
+struct hostent *
+gethostbyname2_p(const char *name, int af, struct net_data *net_data) {
+ struct irs_ho *ho;
+ char tmp[NS_MAXDNAME];
+ struct hostent *hp;
+ const char *cp;
+ char **hap;
+
+ if (!net_data || !(ho = net_data->ho))
+ return (NULL);
+ if (net_data->ho_stayopen && net_data->ho_last &&
+ net_data->ho_last->h_addrtype == af) {
+ if (ns_samename(name, net_data->ho_last->h_name) == 1)
+ return (net_data->ho_last);
+ for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++)
+ if (ns_samename(name, *hap) == 1)
+ return (net_data->ho_last);
+ }
+ if (!strchr(name, '.') && (cp = res_hostalias(net_data->res, name,
+ tmp, sizeof tmp)))
+ name = cp;
+ if ((hp = fakeaddr(name, af, net_data)) != NULL)
+ return (hp);
+ net_data->ho_last = (*ho->byname2)(ho, name, af);
+ if (!net_data->ho_stayopen)
+ endhostent();
+ return (net_data->ho_last);
+}
+
+struct hostent *
+gethostbyaddr_p(const char *addr, int len, int af, struct net_data *net_data) {
+ struct irs_ho *ho;
+ char **hap;
+
+ if (!net_data || !(ho = net_data->ho))
+ return (NULL);
+ if (net_data->ho_stayopen && net_data->ho_last &&
+ net_data->ho_last->h_length == len)
+ for (hap = net_data->ho_last->h_addr_list;
+ hap && *hap;
+ hap++)
+ if (!memcmp(addr, *hap, len))
+ return (net_data->ho_last);
+ net_data->ho_last = (*ho->byaddr)(ho, addr, len, af);
+ if (!net_data->ho_stayopen)
+ endhostent();
+ return (net_data->ho_last);
+}
+
+
+struct hostent *
+gethostent_p(struct net_data *net_data) {
+ struct irs_ho *ho;
+ struct hostent *hp;
+
+ if (!net_data || !(ho = net_data->ho))
+ return (NULL);
+ while ((hp = (*ho->next)(ho)) != NULL &&
+ hp->h_addrtype == AF_INET6 &&
+ (net_data->res->options & RES_USE_INET6) == 0U)
+ continue;
+ net_data->ho_last = hp;
+ return (net_data->ho_last);
+}
+
+
+void
+sethostent_p(int stayopen, struct net_data *net_data) {
+ struct irs_ho *ho;
+
+ if (!net_data || !(ho = net_data->ho))
+ return;
+ freepvt(net_data);
+ (*ho->rewind)(ho);
+ net_data->ho_stayopen = (stayopen != 0);
+ if (stayopen == 0)
+ net_data_minimize(net_data);
+}
+
+void
+endhostent_p(struct net_data *net_data) {
+ struct irs_ho *ho;
+
+ if ((net_data != NULL) && ((ho = net_data->ho) != NULL))
+ (*ho->minimize)(ho);
+}
+
+#ifndef IN6_IS_ADDR_V4COMPAT
+static const unsigned char in6addr_compat[12] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+#define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \
+ ((x)->s6_addr[12] != 0 || \
+ (x)->s6_addr[13] != 0 || \
+ (x)->s6_addr[14] != 0 || \
+ ((x)->s6_addr[15] != 0 && \
+ (x)->s6_addr[15] != 1)))
+#endif
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12))
+#endif
+
+static const unsigned char in6addr_mapped[12] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
+
+static int scan_interfaces(int *, int *);
+static struct hostent *copyandmerge(struct hostent *, struct hostent *, int, int *);
+
+/*%
+ * Public functions
+ */
+
+/*%
+ * AI_V4MAPPED + AF_INET6
+ * If no IPv6 address then a query for IPv4 and map returned values.
+ *
+ * AI_ALL + AI_V4MAPPED + AF_INET6
+ * Return IPv6 and IPv4 mapped.
+ *
+ * AI_ADDRCONFIG
+ * Only return IPv6 / IPv4 address if there is an interface of that
+ * type active.
+ */
+
+struct hostent *
+getipnodebyname(const char *name, int af, int flags, int *error_num) {
+ int have_v4 = 1, have_v6 = 1;
+ struct in_addr in4;
+ struct in6_addr in6;
+ struct hostent he, *he1 = NULL, *he2 = NULL, *he3;
+ int v4 = 0, v6 = 0;
+ struct net_data *net_data = init();
+ u_long options;
+ int tmp_err;
+
+ if (net_data == NULL) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ /* If we care about active interfaces then check. */
+ if ((flags & AI_ADDRCONFIG) != 0)
+ if (scan_interfaces(&have_v4, &have_v6) == -1) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ /* Check for literal address. */
+ if ((v4 = inet_pton(AF_INET, name, &in4)) != 1)
+ v6 = inet_pton(AF_INET6, name, &in6);
+
+ /* Impossible combination? */
+
+ if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) ||
+ (af == AF_INET && v6 == 1) ||
+ (have_v4 == 0 && v4 == 1) ||
+ (have_v6 == 0 && v6 == 1) ||
+ (have_v4 == 0 && af == AF_INET) ||
+ (have_v6 == 0 && af == AF_INET6)) {
+ *error_num = HOST_NOT_FOUND;
+ return (NULL);
+ }
+
+ /* Literal address? */
+ if (v4 == 1 || v6 == 1) {
+ char *addr_list[2];
+ char *aliases[1];
+
+ DE_CONST(name, he.h_name);
+ he.h_addr_list = addr_list;
+ he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6;
+ he.h_addr_list[1] = NULL;
+ he.h_aliases = aliases;
+ he.h_aliases[0] = NULL;
+ he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ;
+ he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6;
+ return (copyandmerge(&he, NULL, af, error_num));
+ }
+
+ options = net_data->res->options;
+ net_data->res->options &= ~RES_USE_INET6;
+
+ tmp_err = NO_RECOVERY;
+ if (have_v6 && af == AF_INET6) {
+ he2 = gethostbyname2_p(name, AF_INET6, net_data);
+ if (he2 != NULL) {
+ he1 = copyandmerge(he2, NULL, af, error_num);
+ if (he1 == NULL)
+ return (NULL);
+ he2 = NULL;
+ } else {
+ tmp_err = net_data->res->res_h_errno;
+ }
+ }
+
+ if (have_v4 &&
+ ((af == AF_INET) ||
+ (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
+ (he1 == NULL || (flags & AI_ALL) != 0)))) {
+ he2 = gethostbyname2_p(name, AF_INET, net_data);
+ if (he1 == NULL && he2 == NULL) {
+ *error_num = net_data->res->res_h_errno;
+ return (NULL);
+ }
+ } else
+ *error_num = tmp_err;
+
+ net_data->res->options = options;
+
+ he3 = copyandmerge(he1, he2, af, error_num);
+
+ if (he1 != NULL)
+ freehostent(he1);
+ return (he3);
+}
+
+struct hostent *
+getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
+ struct hostent *he1, *he2;
+ struct net_data *net_data = init();
+
+ /* Sanity Checks. */
+ if (src == NULL) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ switch (af) {
+ case AF_INET:
+ if (len != (size_t)INADDRSZ) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+ break;
+ case AF_INET6:
+ if (len != (size_t)IN6ADDRSZ) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+ break;
+ default:
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ /*
+ * Lookup IPv4 and IPv4 mapped/compatible addresses
+ */
+ if ((af == AF_INET6 &&
+ IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) ||
+ (af == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) ||
+ (af == AF_INET)) {
+ const char *cp = src;
+
+ if (af == AF_INET6)
+ cp += 12;
+ he1 = gethostbyaddr_p(cp, 4, AF_INET, net_data);
+ if (he1 == NULL) {
+ *error_num = net_data->res->res_h_errno;
+ return (NULL);
+ }
+ he2 = copyandmerge(he1, NULL, af, error_num);
+ if (he2 == NULL)
+ return (NULL);
+ /*
+ * Restore original address if mapped/compatible.
+ */
+ if (af == AF_INET6)
+ memcpy(he1->h_addr, src, len);
+ return (he2);
+ }
+
+ /*
+ * Lookup IPv6 address.
+ */
+ if (memcmp((const struct in6_addr *)src, &in6addr_any, 16) == 0) {
+ *error_num = HOST_NOT_FOUND;
+ return (NULL);
+ }
+
+ he1 = gethostbyaddr_p(src, 16, AF_INET6, net_data);
+ if (he1 == NULL) {
+ *error_num = net_data->res->res_h_errno;
+ return (NULL);
+ }
+ return (copyandmerge(he1, NULL, af, error_num));
+}
+
+void
+freehostent(struct hostent *he) {
+ char **cpp;
+ int names = 1;
+ int addresses = 1;
+
+ memput(he->h_name, strlen(he->h_name) + 1);
+
+ cpp = he->h_addr_list;
+ while (*cpp != NULL) {
+ memput(*cpp, (he->h_addrtype == AF_INET) ?
+ INADDRSZ : IN6ADDRSZ);
+ *cpp = NULL;
+ cpp++;
+ addresses++;
+ }
+
+ cpp = he->h_aliases;
+ while (*cpp != NULL) {
+ memput(*cpp, strlen(*cpp) + 1);
+ cpp++;
+ names++;
+ }
+
+ memput(he->h_aliases, sizeof(char *) * (names));
+ memput(he->h_addr_list, sizeof(char *) * (addresses));
+ memput(he, sizeof *he);
+}
+
+/*%
+ * Private
+ */
+
+/*%
+ * Scan the interface table and set have_v4 and have_v6 depending
+ * upon whether there are IPv4 and IPv6 interface addresses.
+ *
+ * Returns:
+ * 0 on success
+ * -1 on failure.
+ */
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
+ !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
+
+#ifdef __hpux
+#define lifc_len iflc_len
+#define lifc_buf iflc_buf
+#define lifc_req iflc_req
+#define LIFCONF if_laddrconf
+#else
+#define SETFAMILYFLAGS
+#define LIFCONF lifconf
+#endif
+
+#ifdef __hpux
+#define lifr_addr iflr_addr
+#define lifr_name iflr_name
+#define lifr_dstaddr iflr_dstaddr
+#define lifr_flags iflr_flags
+#define ss_family sa_family
+#define LIFREQ if_laddrreq
+#else
+#define LIFREQ lifreq
+#endif
+
+static void
+scan_interfaces6(int *have_v4, int *have_v6) {
+ struct LIFCONF lifc;
+ struct LIFREQ lifreq;
+ struct in_addr in4;
+ struct in6_addr in6;
+ char *buf = NULL, *cp, *cplim;
+ static unsigned int bufsiz = 4095;
+ int s, cpsize, n;
+
+ /* Get interface list from system. */
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
+ goto cleanup;
+
+ /*
+ * Grow buffer until large enough to contain all interface
+ * descriptions.
+ */
+ for (;;) {
+ buf = memget(bufsiz);
+ if (buf == NULL)
+ goto cleanup;
+#ifdef SETFAMILYFLAGS
+ lifc.lifc_family = AF_UNSPEC; /*%< request all families */
+ lifc.lifc_flags = 0;
+#endif
+ lifc.lifc_len = bufsiz;
+ lifc.lifc_buf = buf;
+ if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
+ /*
+ * Some OS's just return what will fit rather
+ * than set EINVAL if the buffer is too small
+ * to fit all the interfaces in. If
+ * lifc.lifc_len is too near to the end of the
+ * buffer we will grow it just in case and
+ * retry.
+ */
+ if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
+ break;
+ }
+ if ((n == -1) && errno != EINVAL)
+ goto cleanup;
+
+ if (bufsiz > 1000000)
+ goto cleanup;
+
+ memput(buf, bufsiz);
+ bufsiz += 4096;
+ }
+
+ /* Parse system's interface list. */
+ cplim = buf + lifc.lifc_len; /*%< skip over if's with big ifr_addr's */
+ for (cp = buf;
+ (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
+ cp += cpsize) {
+ memcpy(&lifreq, cp, sizeof lifreq);
+#ifdef HAVE_SA_LEN
+#ifdef FIX_ZERO_SA_LEN
+ if (lifreq.lifr_addr.sa_len == 0)
+ lifreq.lifr_addr.sa_len = 16;
+#endif
+#ifdef HAVE_MINIMUM_IFREQ
+ cpsize = sizeof lifreq;
+ if (lifreq.lifr_addr.sa_len > sizeof (struct sockaddr))
+ cpsize += (int)lifreq.lifr_addr.sa_len -
+ (int)(sizeof (struct sockaddr));
+#else
+ cpsize = sizeof lifreq.lifr_name + lifreq.lifr_addr.sa_len;
+#endif /* HAVE_MINIMUM_IFREQ */
+#elif defined SIOCGIFCONF_ADDR
+ cpsize = sizeof lifreq;
+#else
+ cpsize = sizeof lifreq.lifr_name;
+ /* XXX maybe this should be a hard error? */
+ if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
+ continue;
+#endif
+ switch (lifreq.lifr_addr.ss_family) {
+ case AF_INET:
+ if (*have_v4 == 0) {
+ memcpy(&in4,
+ &((struct sockaddr_in *)
+ &lifreq.lifr_addr)->sin_addr,
+ sizeof in4);
+ if (in4.s_addr == INADDR_ANY)
+ break;
+ n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
+ if (n < 0)
+ break;
+ if ((lifreq.lifr_flags & IFF_UP) == 0)
+ break;
+ *have_v4 = 1;
+ }
+ break;
+ case AF_INET6:
+ if (*have_v6 == 0) {
+ memcpy(&in6,
+ &((struct sockaddr_in6 *)
+ &lifreq.lifr_addr)->sin6_addr, sizeof in6);
+ if (memcmp(&in6, &in6addr_any, sizeof in6) == 0)
+ break;
+ n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
+ if (n < 0)
+ break;
+ if ((lifreq.lifr_flags & IFF_UP) == 0)
+ break;
+ *have_v6 = 1;
+ }
+ break;
+ }
+ }
+ if (buf != NULL)
+ memput(buf, bufsiz);
+ close(s);
+ /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
+ return;
+ cleanup:
+ if (buf != NULL)
+ memput(buf, bufsiz);
+ if (s != -1)
+ close(s);
+ /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
+ return;
+}
+#endif
+
+#if ( defined(__linux__) || defined(__linux) || defined(LINUX) )
+#ifndef IF_NAMESIZE
+# ifdef IFNAMSIZ
+# define IF_NAMESIZE IFNAMSIZ
+# else
+# define IF_NAMESIZE 16
+# endif
+#endif
+static void
+scan_linux6(int *have_v6) {
+ FILE *proc = NULL;
+ char address[33];
+ char name[IF_NAMESIZE+1];
+ int ifindex, prefix, flag3, flag4;
+
+ proc = fopen("/proc/net/if_inet6", "r");
+ if (proc == NULL)
+ return;
+
+ if (fscanf(proc, "%32[a-f0-9] %x %x %x %x %16s\n",
+ address, &ifindex, &prefix, &flag3, &flag4, name) == 6)
+ *have_v6 = 1;
+ fclose(proc);
+ return;
+}
+#endif
+
+static int
+scan_interfaces(int *have_v4, int *have_v6) {
+ struct ifconf ifc;
+ union {
+ char _pad[256]; /*%< leave space for IPv6 addresses */
+ struct ifreq ifreq;
+ } u;
+ struct in_addr in4;
+ struct in6_addr in6;
+ char *buf = NULL, *cp, *cplim;
+ static unsigned int bufsiz = 4095;
+ int s, n;
+ size_t cpsize;
+
+ /* Set to zero. Used as loop terminators below. */
+ *have_v4 = *have_v6 = 0;
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
+ !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
+ /*
+ * Try to scan the interfaces using IPv6 ioctls().
+ */
+ scan_interfaces6(have_v4, have_v6);
+ if (*have_v4 != 0 && *have_v6 != 0)
+ return (0);
+#endif
+#ifdef __linux
+ scan_linux6(have_v6);
+#endif
+
+ /* Get interface list from system. */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ goto err_ret;
+
+ /*
+ * Grow buffer until large enough to contain all interface
+ * descriptions.
+ */
+ for (;;) {
+ buf = memget(bufsiz);
+ if (buf == NULL)
+ goto err_ret;
+ ifc.ifc_len = bufsiz;
+ ifc.ifc_buf = buf;
+#ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
+ /*
+ * This is a fix for IRIX OS in which the call to ioctl with
+ * the flag SIOCGIFCONF may not return an entry for all the
+ * interfaces like most flavors of Unix.
+ */
+ if (emul_ioctl(&ifc) >= 0)
+ break;
+#else
+ if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
+ /*
+ * Some OS's just return what will fit rather
+ * than set EINVAL if the buffer is too small
+ * to fit all the interfaces in. If
+ * ifc.ifc_len is too near to the end of the
+ * buffer we will grow it just in case and
+ * retry.
+ */
+ if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz)
+ break;
+ }
+#endif
+ if ((n == -1) && errno != EINVAL)
+ goto err_ret;
+
+ if (bufsiz > 1000000)
+ goto err_ret;
+
+ memput(buf, bufsiz);
+ bufsiz += 4096;
+ }
+
+ /* Parse system's interface list. */
+ cplim = buf + ifc.ifc_len; /*%< skip over if's with big ifr_addr's */
+ for (cp = buf;
+ (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
+ cp += cpsize) {
+ memcpy(&u.ifreq, cp, sizeof u.ifreq);
+#ifdef HAVE_SA_LEN
+#ifdef FIX_ZERO_SA_LEN
+ if (u.ifreq.ifr_addr.sa_len == 0)
+ u.ifreq.ifr_addr.sa_len = 16;
+#endif
+#ifdef HAVE_MINIMUM_IFREQ
+ cpsize = sizeof u.ifreq;
+ if (u.ifreq.ifr_addr.sa_len > sizeof (struct sockaddr))
+ cpsize += (int)u.ifreq.ifr_addr.sa_len -
+ (int)(sizeof (struct sockaddr));
+#else
+ cpsize = sizeof u.ifreq.ifr_name + u.ifreq.ifr_addr.sa_len;
+#endif /* HAVE_MINIMUM_IFREQ */
+ if (cpsize > sizeof u.ifreq && cpsize <= sizeof u)
+ memcpy(&u.ifreq, cp, cpsize);
+#elif defined SIOCGIFCONF_ADDR
+ cpsize = sizeof u.ifreq;
+#else
+ cpsize = sizeof u.ifreq.ifr_name;
+ /* XXX maybe this should be a hard error? */
+ if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0)
+ continue;
+#endif
+ switch (u.ifreq.ifr_addr.sa_family) {
+ case AF_INET:
+ if (*have_v4 == 0) {
+ memcpy(&in4,
+ &((struct sockaddr_in *)
+ &u.ifreq.ifr_addr)->sin_addr,
+ sizeof in4);
+ if (in4.s_addr == INADDR_ANY)
+ break;
+ n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
+ if (n < 0)
+ break;
+ if ((u.ifreq.ifr_flags & IFF_UP) == 0)
+ break;
+ *have_v4 = 1;
+ }
+ break;
+ case AF_INET6:
+ if (*have_v6 == 0) {
+ memcpy(&in6,
+ &((struct sockaddr_in6 *)
+ &u.ifreq.ifr_addr)->sin6_addr,
+ sizeof in6);
+ if (memcmp(&in6, &in6addr_any, sizeof in6) == 0)
+ break;
+ n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
+ if (n < 0)
+ break;
+ if ((u.ifreq.ifr_flags & IFF_UP) == 0)
+ break;
+ *have_v6 = 1;
+ }
+ break;
+ }
+ }
+ if (buf != NULL)
+ memput(buf, bufsiz);
+ close(s);
+ /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
+ return (0);
+ err_ret:
+ if (buf != NULL)
+ memput(buf, bufsiz);
+ if (s != -1)
+ close(s);
+ /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
+ return (-1);
+}
+
+static struct hostent *
+copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num) {
+ struct hostent *he = NULL;
+ int addresses = 1; /*%< NULL terminator */
+ int names = 1; /*%< NULL terminator */
+ int len = 0;
+ char **cpp, **npp;
+
+ /*
+ * Work out array sizes;
+ */
+ if (he1 != NULL) {
+ cpp = he1->h_addr_list;
+ while (*cpp != NULL) {
+ addresses++;
+ cpp++;
+ }
+ cpp = he1->h_aliases;
+ while (*cpp != NULL) {
+ names++;
+ cpp++;
+ }
+ }
+
+ if (he2 != NULL) {
+ cpp = he2->h_addr_list;
+ while (*cpp != NULL) {
+ addresses++;
+ cpp++;
+ }
+ if (he1 == NULL) {
+ cpp = he2->h_aliases;
+ while (*cpp != NULL) {
+ names++;
+ cpp++;
+ }
+ }
+ }
+
+ if (addresses == 1) {
+ *error_num = NO_ADDRESS;
+ return (NULL);
+ }
+
+ he = memget(sizeof *he);
+ if (he == NULL)
+ goto no_recovery;
+
+ he->h_addr_list = memget(sizeof(char *) * (addresses));
+ if (he->h_addr_list == NULL)
+ goto cleanup0;
+ memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
+
+ /* copy addresses */
+ npp = he->h_addr_list;
+ if (he1 != NULL) {
+ cpp = he1->h_addr_list;
+ while (*cpp != NULL) {
+ *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ if (*npp == NULL)
+ goto cleanup1;
+ /* convert to mapped if required */
+ if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
+ memcpy(*npp, in6addr_mapped,
+ sizeof in6addr_mapped);
+ memcpy(*npp + sizeof in6addr_mapped, *cpp,
+ INADDRSZ);
+ } else {
+ memcpy(*npp, *cpp,
+ (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ }
+ cpp++;
+ npp++;
+ }
+ }
+
+ if (he2 != NULL) {
+ cpp = he2->h_addr_list;
+ while (*cpp != NULL) {
+ *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ if (*npp == NULL)
+ goto cleanup1;
+ /* convert to mapped if required */
+ if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
+ memcpy(*npp, in6addr_mapped,
+ sizeof in6addr_mapped);
+ memcpy(*npp + sizeof in6addr_mapped, *cpp,
+ INADDRSZ);
+ } else {
+ memcpy(*npp, *cpp,
+ (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ }
+ cpp++;
+ npp++;
+ }
+ }
+
+ he->h_aliases = memget(sizeof(char *) * (names));
+ if (he->h_aliases == NULL)
+ goto cleanup1;
+ memset(he->h_aliases, 0, sizeof(char *) * (names));
+
+ /* copy aliases */
+ npp = he->h_aliases;
+ cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases;
+ while (*cpp != NULL) {
+ len = strlen (*cpp) + 1;
+ *npp = memget(len);
+ if (*npp == NULL)
+ goto cleanup2;
+ strcpy(*npp, *cpp);
+ npp++;
+ cpp++;
+ }
+
+ /* copy hostname */
+ he->h_name = memget(strlen((he1 != NULL) ?
+ he1->h_name : he2->h_name) + 1);
+ if (he->h_name == NULL)
+ goto cleanup2;
+ strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name);
+
+ /* set address type and length */
+ he->h_addrtype = af;
+ he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
+ return(he);
+
+ cleanup2:
+ cpp = he->h_aliases;
+ while (*cpp != NULL) {
+ memput(*cpp, strlen(*cpp) + 1);
+ cpp++;
+ }
+ memput(he->h_aliases, sizeof(char *) * (names));
+
+ cleanup1:
+ cpp = he->h_addr_list;
+ while (*cpp != NULL) {
+ memput(*cpp, (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ *cpp = NULL;
+ cpp++;
+ }
+ memput(he->h_addr_list, sizeof(char *) * (addresses));
+
+ cleanup0:
+ memput(he, sizeof *he);
+
+ no_recovery:
+ *error_num = NO_RECOVERY;
+ return (NULL);
+}
+
+static struct net_data *
+init() {
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->ho) {
+ net_data->ho = (*net_data->irs->ho_map)(net_data->irs);
+ if (!net_data->ho || !net_data->res) {
+ error:
+ errno = EIO;
+ if (net_data && net_data->res)
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+
+ (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL);
+ }
+
+ return (net_data);
+}
+
+static void
+freepvt(struct net_data *net_data) {
+ if (net_data->ho_data) {
+ free(net_data->ho_data);
+ net_data->ho_data = NULL;
+ }
+}
+
+static struct hostent *
+fakeaddr(const char *name, int af, struct net_data *net_data) {
+ struct pvt *pvt;
+
+ freepvt(net_data);
+ net_data->ho_data = malloc(sizeof (struct pvt));
+ if (!net_data->ho_data) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ pvt = net_data->ho_data;
+#ifndef __bsdi__
+ /*
+ * Unlike its forebear(inet_aton), our friendly inet_pton() is strict
+ * in its interpretation of its input, and it will only return "1" if
+ * the input string is a formally valid(and thus unambiguous with
+ * respect to host names) internet address specification for this AF.
+ *
+ * This means "telnet 0xdeadbeef" and "telnet 127.1" are dead now.
+ */
+ if (inet_pton(af, name, pvt->addr) != 1) {
+#else
+ /* BSDI XXX
+ * We put this back to inet_aton -- we really want the old behavior
+ * Long live 127.1...
+ */
+ if ((af != AF_INET ||
+ inet_aton(name, (struct in_addr *)pvt->addr) != 1) &&
+ inet_pton(af, name, pvt->addr) != 1) {
+#endif
+ RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ strncpy(pvt->name, name, NS_MAXDNAME);
+ pvt->name[NS_MAXDNAME] = '\0';
+ if (af == AF_INET && (net_data->res->options & RES_USE_INET6) != 0U) {
+ map_v4v6_address(pvt->addr, pvt->addr);
+ af = AF_INET6;
+ }
+ pvt->host.h_addrtype = af;
+ switch(af) {
+ case AF_INET:
+ pvt->host.h_length = NS_INADDRSZ;
+ break;
+ case AF_INET6:
+ pvt->host.h_length = NS_IN6ADDRSZ;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ pvt->host.h_name = pvt->name;
+ pvt->host.h_aliases = pvt->aliases;
+ pvt->aliases[0] = NULL;
+ pvt->addrs[0] = (char *)pvt->addr;
+ pvt->addrs[1] = NULL;
+ pvt->host.h_addr_list = pvt->addrs;
+ RES_SET_H_ERRNO(net_data->res, NETDB_SUCCESS);
+ return (&pvt->host);
+}
+
+#ifdef grot /*%< for future use in gethostbyaddr(), for "SUNSECURITY" */
+ struct hostent *rhp;
+ char **haddr;
+ u_long old_options;
+ char hname2[MAXDNAME+1];
+
+ if (af == AF_INET) {
+ /*
+ * turn off search as the name should be absolute,
+ * 'localhost' should be matched by defnames
+ */
+ strncpy(hname2, hp->h_name, MAXDNAME);
+ hname2[MAXDNAME] = '\0';
+ old_options = net_data->res->options;
+ net_data->res->options &= ~RES_DNSRCH;
+ net_data->res->options |= RES_DEFNAMES;
+ if (!(rhp = gethostbyname(hname2))) {
+ net_data->res->options = old_options;
+ RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ net_data->res->options = old_options;
+ for (haddr = rhp->h_addr_list; *haddr; haddr++)
+ if (!memcmp(*haddr, addr, INADDRSZ))
+ break;
+ if (!*haddr) {
+ RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ }
+#endif /* grot */
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/lib/bind/irs/gethostent_r.c b/lib/bind/irs/gethostent_r.c
new file mode 100644
index 0000000..96d2a57
--- /dev/null
+++ b/lib/bind/irs/gethostent_r.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: gethostent_r.c,v 1.5.18.4 2005/09/03 12:45:14 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+ static int gethostent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <port_after.h>
+
+#ifdef HOST_R_RETURN
+
+static HOST_R_RETURN
+copy_hostent(struct hostent *, struct hostent *, HOST_R_COPY_ARGS);
+
+HOST_R_RETURN
+gethostbyname_r(const char *name, struct hostent *hptr, HOST_R_ARGS) {
+ struct hostent *he = gethostbyname(name);
+#ifdef HOST_R_SETANSWER
+ int n = 0;
+#endif
+
+#ifdef HOST_R_ERRNO
+ HOST_R_ERRNO;
+#endif
+
+#ifdef HOST_R_SETANSWER
+ if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = hptr;
+
+ return (n);
+#else
+ if (he == NULL)
+ return (HOST_R_BAD);
+
+ return (copy_hostent(he, hptr, HOST_R_COPY));
+#endif
+}
+
+HOST_R_RETURN
+gethostbyaddr_r(const char *addr, int len, int type,
+ struct hostent *hptr, HOST_R_ARGS) {
+ struct hostent *he = gethostbyaddr(addr, len, type);
+#ifdef HOST_R_SETANSWER
+ int n = 0;
+#endif
+
+#ifdef HOST_R_ERRNO
+ HOST_R_ERRNO;
+#endif
+
+#ifdef HOST_R_SETANSWER
+ if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = hptr;
+
+ return (n);
+#else
+ if (he == NULL)
+ return (HOST_R_BAD);
+
+ return (copy_hostent(he, hptr, HOST_R_COPY));
+#endif
+}
+
+/*%
+ * These assume a single context is in operation per thread.
+ * If this is not the case we will need to call irs directly
+ * rather than through the base functions.
+ */
+
+HOST_R_RETURN
+gethostent_r(struct hostent *hptr, HOST_R_ARGS) {
+ struct hostent *he = gethostent();
+#ifdef HOST_R_SETANSWER
+ int n = 0;
+#endif
+
+#ifdef HOST_R_ERRNO
+ HOST_R_ERRNO;
+#endif
+
+#ifdef HOST_R_SETANSWER
+ if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = hptr;
+
+ return (n);
+#else
+ if (he == NULL)
+ return (HOST_R_BAD);
+
+ return (copy_hostent(he, hptr, HOST_R_COPY));
+#endif
+}
+
+HOST_R_SET_RETURN
+#ifdef HOST_R_ENT_ARGS
+sethostent_r(int stay_open, HOST_R_ENT_ARGS)
+#else
+sethostent_r(int stay_open)
+#endif
+{
+#ifdef HOST_R_ENT_ARGS
+ UNUSED(hdptr);
+#endif
+ sethostent(stay_open);
+#ifdef HOST_R_SET_RESULT
+ return (HOST_R_SET_RESULT);
+#endif
+}
+
+HOST_R_END_RETURN
+#ifdef HOST_R_ENT_ARGS
+endhostent_r(HOST_R_ENT_ARGS)
+#else
+endhostent_r(void)
+#endif
+{
+#ifdef HOST_R_ENT_ARGS
+ UNUSED(hdptr);
+#endif
+ endhostent();
+ HOST_R_END_RESULT(HOST_R_OK);
+}
+
+/* Private */
+
+#ifndef HOSTENT_DATA
+static HOST_R_RETURN
+copy_hostent(struct hostent *he, struct hostent *hptr, HOST_R_COPY_ARGS) {
+ char *cp;
+ char **ptr;
+ int i, n;
+ int nptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ nptr = 2; /*%< NULL ptrs */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; he->h_addr_list[i]; i++, nptr++) {
+ len += he->h_length;
+ }
+ for (i = 0; he->h_aliases[i]; i++, nptr++) {
+ len += strlen(he->h_aliases[i]) + 1;
+ }
+ len += strlen(he->h_name) + 1;
+ len += nptr * sizeof(char*);
+
+ if (len > buflen) {
+ errno = ERANGE;
+ return (HOST_R_BAD);
+ }
+
+ /* copy address size and type */
+ hptr->h_addrtype = he->h_addrtype;
+ n = hptr->h_length = he->h_length;
+
+ ptr = (char **)ALIGN(buf);
+ cp = (char *)ALIGN(buf) + nptr * sizeof(char *);
+
+ /* copy address list */
+ hptr->h_addr_list = ptr;
+ for (i = 0; he->h_addr_list[i]; i++ , ptr++) {
+ memcpy(cp, he->h_addr_list[i], n);
+ hptr->h_addr_list[i] = cp;
+ cp += n;
+ }
+ hptr->h_addr_list[i] = NULL;
+ ptr++;
+
+ /* copy official name */
+ n = strlen(he->h_name) + 1;
+ strcpy(cp, he->h_name);
+ hptr->h_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ hptr->h_aliases = ptr;
+ for (i = 0 ; he->h_aliases[i]; i++) {
+ n = strlen(he->h_aliases[i]) + 1;
+ strcpy(cp, he->h_aliases[i]);
+ hptr->h_aliases[i] = cp;
+ cp += n;
+ }
+ hptr->h_aliases[i] = NULL;
+
+ return (HOST_R_OK);
+}
+#else /* !HOSTENT_DATA */
+static int
+copy_hostent(struct hostent *he, struct hostent *hptr, HOST_R_COPY_ARGS) {
+ char *cp, *eob;
+ int i, n;
+
+ /* copy address size and type */
+ hptr->h_addrtype = he->h_addrtype;
+ n = hptr->h_length = he->h_length;
+
+ /* copy up to first 35 addresses */
+ i = 0;
+ cp = hdptr->hostbuf;
+ eob = hdptr->hostbuf + sizeof(hdptr->hostbuf);
+ hptr->h_addr_list = hdptr->h_addr_ptrs;
+ while (he->h_addr_list[i] && i < (_MAXADDRS)) {
+ if (n < (eob - cp)) {
+ memcpy(cp, he->h_addr_list[i], n);
+ hptr->h_addr_list[i] = cp;
+ cp += n;
+ } else {
+ break;
+ }
+ i++;
+ }
+ hptr->h_addr_list[i] = NULL;
+
+ /* copy official name */
+ if ((n = strlen(he->h_name) + 1) < (eob - cp)) {
+ strcpy(cp, he->h_name);
+ hptr->h_name = cp;
+ cp += n;
+ } else {
+ return (-1);
+ }
+
+ /* copy aliases */
+ i = 0;
+ hptr->h_aliases = hdptr->host_aliases;
+ while (he->h_aliases[i] && i < (_MAXALIASES-1)) {
+ if ((n = strlen(he->h_aliases[i]) + 1) < (eob - cp)) {
+ strcpy(cp, he->h_aliases[i]);
+ hptr->h_aliases[i] = cp;
+ cp += n;
+ } else {
+ break;
+ }
+ i++;
+ }
+ hptr->h_aliases[i] = NULL;
+
+ return (HOST_R_OK);
+}
+#endif /* !HOSTENT_DATA */
+#else /* HOST_R_RETURN */
+ static int gethostent_r_unknown_system = 0;
+#endif /* HOST_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
+/*! \file */
diff --git a/lib/bind/irs/getnameinfo.c b/lib/bind/irs/getnameinfo.c
new file mode 100644
index 0000000..89c8230
--- /dev/null
+++ b/lib/bind/irs/getnameinfo.c
@@ -0,0 +1,334 @@
+/*
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked
+ */
+
+#if ( defined(__linux__) || defined(__linux) || defined(LINUX) )
+#ifndef IF_NAMESIZE
+# ifdef IFNAMSIZ
+# define IF_NAMESIZE IFNAMSIZ
+# else
+# define IF_NAMESIZE 16
+# endif
+#endif
+#endif
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by WIDE Project and
+ * its contributors.
+ * 4. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <port_before.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <stddef.h>
+
+#include <port_after.h>
+
+/*%
+ * 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 <numeric-addr><delim><scopeid> */
+ memcpy(host + numaddrlen + 1, scopebuf,
+ scopelen);
+ host[numaddrlen] = SCOPE_DELIMITER;
+ host[numaddrlen + 1 + scopelen] = '\0';
+ }
+#endif
+
+ return 0;
+}
+
+#ifdef HAVE_SIN6_SCOPE_ID
+/* ARGSUSED */
+static int
+ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf,
+ size_t bufsiz, int flags)
+{
+#ifdef USE_IFNAMELINKID
+ unsigned int ifindex = (unsigned int)sa6->sin6_scope_id;
+ const struct in6_addr *a6 = &sa6->sin6_addr;
+#endif
+ char tmp[64];
+
+#ifdef NI_NUMERICSCOPE
+ if (flags & NI_NUMERICSCOPE) {
+ sprintf(tmp, "%u", sa6->sin6_scope_id);
+ if (bufsiz != 0U) {
+ strncpy(buf, tmp, bufsiz - 1);
+ buf[bufsiz - 1] = '\0';
+ }
+ return(strlen(tmp));
+ }
+#endif
+
+#ifdef USE_IFNAMELINKID
+ /*
+ * For a link-local address, convert the index to an interface
+ * name, assuming a one-to-one mapping between links and interfaces.
+ * Note, however, that this assumption is stronger than the
+ * specification of the scoped address architecture; the
+ * specficication says that more than one interfaces can belong to
+ * a single link.
+ */
+
+ /* if_indextoname() does not take buffer size. not a good api... */
+ if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) &&
+ bufsiz >= IF_NAMESIZE) {
+ char *p = if_indextoname(ifindex, buf);
+ if (p) {
+ return(strlen(p));
+ }
+ }
+#endif
+
+ /* last resort */
+ sprintf(tmp, "%u", sa6->sin6_scope_id);
+ if (bufsiz != 0U) {
+ strncpy(buf, tmp, bufsiz - 1);
+ buf[bufsiz - 1] = '\0';
+ }
+ return(strlen(tmp));
+}
+#endif
+
+/*! \file */
diff --git a/lib/bind/irs/getnetent.c b/lib/bind/irs/getnetent.c
new file mode 100644
index 0000000..5f7d233
--- /dev/null
+++ b/lib/bind/irs/getnetent.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getnetent.c,v 1.6.18.1 2005/04/27 05:00:58 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "irs_data.h"
+
+/* Definitions */
+
+struct pvt {
+ struct netent netent;
+ char * aliases[1];
+ char name[MAXDNAME + 1];
+};
+
+/* Forward */
+
+static struct net_data *init(void);
+static struct netent *nw_to_net(struct nwent *, struct net_data *);
+static void freepvt(struct net_data *);
+static struct netent *fakeaddr(const char *, int af, struct net_data *);
+
+/* Portability */
+
+#ifndef INADDR_NONE
+# define INADDR_NONE 0xffffffff
+#endif
+
+/* Public */
+
+struct netent *
+getnetent() {
+ struct net_data *net_data = init();
+
+ return (getnetent_p(net_data));
+}
+
+struct netent *
+getnetbyname(const char *name) {
+ struct net_data *net_data = init();
+
+ return (getnetbyname_p(name, net_data));
+}
+
+struct netent *
+getnetbyaddr(unsigned long net, int type) {
+ struct net_data *net_data = init();
+
+ return (getnetbyaddr_p(net, type, net_data));
+}
+
+void
+setnetent(int stayopen) {
+ struct net_data *net_data = init();
+
+ setnetent_p(stayopen, net_data);
+}
+
+
+void
+endnetent() {
+ struct net_data *net_data = init();
+
+ endnetent_p(net_data);
+}
+
+/* Shared private. */
+
+struct netent *
+getnetent_p(struct net_data *net_data) {
+ struct irs_nw *nw;
+
+ if (!net_data || !(nw = net_data->nw))
+ return (NULL);
+ net_data->nww_last = (*nw->next)(nw);
+ net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
+ return (net_data->nw_last);
+}
+
+struct netent *
+getnetbyname_p(const char *name, struct net_data *net_data) {
+ struct irs_nw *nw;
+ struct netent *np;
+ char **nap;
+
+ if (!net_data || !(nw = net_data->nw))
+ return (NULL);
+ if (net_data->nw_stayopen && net_data->nw_last) {
+ if (!strcmp(net_data->nw_last->n_name, name))
+ return (net_data->nw_last);
+ for (nap = net_data->nw_last->n_aliases; nap && *nap; nap++)
+ if (!strcmp(name, *nap))
+ return (net_data->nw_last);
+ }
+ if ((np = fakeaddr(name, AF_INET, net_data)) != NULL)
+ return (np);
+ net_data->nww_last = (*nw->byname)(nw, name, AF_INET);
+ net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
+ if (!net_data->nw_stayopen)
+ endnetent();
+ return (net_data->nw_last);
+}
+
+struct netent *
+getnetbyaddr_p(unsigned long net, int type, struct net_data *net_data) {
+ struct irs_nw *nw;
+ u_char addr[4];
+ int bits;
+
+ if (!net_data || !(nw = net_data->nw))
+ return (NULL);
+ if (net_data->nw_stayopen && net_data->nw_last)
+ if (type == net_data->nw_last->n_addrtype &&
+ net == net_data->nw_last->n_net)
+ return (net_data->nw_last);
+
+ /* cannonize net(host order) */
+ if (net < 256UL) {
+ net <<= 24;
+ bits = 8;
+ } else if (net < 65536UL) {
+ net <<= 16;
+ bits = 16;
+ } else if (net < 16777216UL) {
+ net <<= 8;
+ bits = 24;
+ } else
+ bits = 32;
+
+ /* convert to net order */
+ addr[0] = (0xFF000000 & net) >> 24;
+ addr[1] = (0x00FF0000 & net) >> 16;
+ addr[2] = (0x0000FF00 & net) >> 8;
+ addr[3] = (0x000000FF & net);
+
+ /* reduce bits to as close to natural number as possible */
+ if ((bits == 32) && (addr[0] < 224) && (addr[3] == 0)) {
+ if ((addr[0] < 192) && (addr[2] == 0)) {
+ if ((addr[0] < 128) && (addr[1] == 0))
+ bits = 8;
+ else
+ bits = 16;
+ } else {
+ bits = 24;
+ }
+ }
+
+ net_data->nww_last = (*nw->byaddr)(nw, addr, bits, AF_INET);
+ net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
+ if (!net_data->nw_stayopen)
+ endnetent();
+ return (net_data->nw_last);
+}
+
+
+
+
+void
+setnetent_p(int stayopen, struct net_data *net_data) {
+ struct irs_nw *nw;
+
+ if (!net_data || !(nw = net_data->nw))
+ return;
+ freepvt(net_data);
+ (*nw->rewind)(nw);
+ net_data->nw_stayopen = (stayopen != 0);
+ if (stayopen == 0)
+ net_data_minimize(net_data);
+}
+
+void
+endnetent_p(struct net_data *net_data) {
+ struct irs_nw *nw;
+
+ if ((net_data != NULL) && ((nw = net_data->nw) != NULL))
+ (*nw->minimize)(nw);
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->nw) {
+ net_data->nw = (*net_data->irs->nw_map)(net_data->irs);
+
+ if (!net_data->nw || !net_data->res) {
+ error:
+ errno = EIO;
+ return (NULL);
+ }
+ (*net_data->nw->res_set)(net_data->nw, net_data->res, NULL);
+ }
+
+ return (net_data);
+}
+
+static void
+freepvt(struct net_data *net_data) {
+ if (net_data->nw_data) {
+ free(net_data->nw_data);
+ net_data->nw_data = NULL;
+ }
+}
+
+static struct netent *
+fakeaddr(const char *name, int af, struct net_data *net_data) {
+ struct pvt *pvt;
+ const char *cp;
+ u_long tmp;
+
+ if (af != AF_INET) {
+ /* XXX should support IPv6 some day */
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ if (!isascii((unsigned char)(name[0])) ||
+ !isdigit((unsigned char)(name[0])))
+ return (NULL);
+ for (cp = name; *cp; ++cp)
+ if (!isascii(*cp) || (!isdigit((unsigned char)*cp) && *cp != '.'))
+ return (NULL);
+ if (*--cp == '.')
+ return (NULL);
+
+ /* All-numeric, no dot at the end. */
+
+ tmp = inet_network(name);
+ if (tmp == INADDR_NONE) {
+ RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+
+ /* Valid network number specified.
+ * Fake up a netent as if we'd actually
+ * done a lookup.
+ */
+ freepvt(net_data);
+ net_data->nw_data = malloc(sizeof (struct pvt));
+ if (!net_data->nw_data) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ pvt = net_data->nw_data;
+
+ strncpy(pvt->name, name, MAXDNAME);
+ pvt->name[MAXDNAME] = '\0';
+ pvt->netent.n_name = pvt->name;
+ pvt->netent.n_addrtype = AF_INET;
+ pvt->netent.n_aliases = pvt->aliases;
+ pvt->aliases[0] = NULL;
+ pvt->netent.n_net = tmp;
+
+ return (&pvt->netent);
+}
+
+static struct netent *
+nw_to_net(struct nwent *nwent, struct net_data *net_data) {
+ struct pvt *pvt;
+ u_long addr = 0;
+ int i;
+ int msbyte;
+
+ if (!nwent || nwent->n_addrtype != AF_INET)
+ return (NULL);
+ freepvt(net_data);
+ net_data->nw_data = malloc(sizeof (struct pvt));
+ if (!net_data->nw_data) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ pvt = net_data->nw_data;
+ pvt->netent.n_name = nwent->n_name;
+ pvt->netent.n_aliases = nwent->n_aliases;
+ pvt->netent.n_addrtype = nwent->n_addrtype;
+
+/*%
+ * What this code does: Converts net addresses from network to host form.
+ *
+ * msbyte: the index of the most significant byte in the n_addr array.
+ *
+ * Shift bytes in significant order into addr. When all signicant
+ * bytes are in, zero out bits in the LSB that are not part of the network.
+ */
+ msbyte = nwent->n_length / 8 +
+ ((nwent->n_length % 8) != 0 ? 1 : 0) - 1;
+ for (i = 0; i <= msbyte; i++)
+ addr = (addr << 8) | ((unsigned char *)nwent->n_addr)[i];
+ i = (32 - nwent->n_length) % 8;
+ if (i != 0)
+ addr &= ~((1 << (i + 1)) - 1);
+ pvt->netent.n_net = addr;
+ return (&pvt->netent);
+}
+
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/lib/bind/irs/getnetent_r.c b/lib/bind/irs/getnetent_r.c
new file mode 100644
index 0000000..7e56ddc
--- /dev/null
+++ b/lib/bind/irs/getnetent_r.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: getnetent_r.c,v 1.4.18.2 2005/09/03 12:45:14 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+ static int getnetent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <port_after.h>
+
+#ifdef NET_R_RETURN
+
+static NET_R_RETURN
+copy_netent(struct netent *, struct netent *, NET_R_COPY_ARGS);
+
+NET_R_RETURN
+getnetbyname_r(const char *name, struct netent *nptr, NET_R_ARGS) {
+ struct netent *ne = getnetbyname(name);
+#ifdef NET_R_SETANSWER
+ int n = 0;
+
+ if (ne == NULL || (n = copy_netent(ne, nptr, NET_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = ne;
+ if (ne == NULL)
+ *h_errnop = h_errno;
+ return (n);
+#else
+ if (ne == NULL)
+ return (NET_R_BAD);
+
+ return (copy_netent(ne, nptr, NET_R_COPY));
+#endif
+}
+
+#ifndef GETNETBYADDR_ADDR_T
+#define GETNETBYADDR_ADDR_T long
+#endif
+NET_R_RETURN
+getnetbyaddr_r(GETNETBYADDR_ADDR_T addr, int type, struct netent *nptr, NET_R_ARGS) {
+ struct netent *ne = getnetbyaddr(addr, type);
+#ifdef NET_R_SETANSWER
+ int n = 0;
+
+ if (ne == NULL || (n = copy_netent(ne, nptr, NET_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = ne;
+ if (ne == NULL)
+ *h_errnop = h_errno;
+ return (n);
+#else
+
+ if (ne == NULL)
+ return (NET_R_BAD);
+
+ return (copy_netent(ne, nptr, NET_R_COPY));
+#endif
+}
+
+/*%
+ * These assume a single context is in operation per thread.
+ * If this is not the case we will need to call irs directly
+ * rather than through the base functions.
+ */
+
+NET_R_RETURN
+getnetent_r(struct netent *nptr, NET_R_ARGS) {
+ struct netent *ne = getnetent();
+#ifdef NET_R_SETANSWER
+ int n = 0;
+
+ if (ne == NULL || (n = copy_netent(ne, nptr, NET_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = ne;
+ if (ne == NULL)
+ *h_errnop = h_errno;
+ return (n);
+#else
+
+ if (ne == NULL)
+ return (NET_R_BAD);
+
+ return (copy_netent(ne, nptr, NET_R_COPY));
+#endif
+}
+
+NET_R_SET_RETURN
+#ifdef NET_R_ENT_ARGS
+setnetent_r(int stay_open, NET_R_ENT_ARGS)
+#else
+setnetent_r(int stay_open)
+#endif
+{
+#ifdef NET_R_ENT_ARGS
+ UNUSED(ndptr);
+#endif
+ setnetent(stay_open);
+#ifdef NET_R_SET_RESULT
+ return (NET_R_SET_RESULT);
+#endif
+}
+
+NET_R_END_RETURN
+#ifdef NET_R_ENT_ARGS
+endnetent_r(NET_R_ENT_ARGS)
+#else
+endnetent_r()
+#endif
+{
+#ifdef NET_R_ENT_ARGS
+ UNUSED(ndptr);
+#endif
+ endnetent();
+ NET_R_END_RESULT(NET_R_OK);
+}
+
+/* Private */
+
+#ifndef NETENT_DATA
+static NET_R_RETURN
+copy_netent(struct netent *ne, struct netent *nptr, NET_R_COPY_ARGS) {
+ char *cp;
+ int i, n;
+ int numptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ numptr = 1; /*%< NULL ptr */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; ne->n_aliases[i]; i++, numptr++) {
+ len += strlen(ne->n_aliases[i]) + 1;
+ }
+ len += strlen(ne->n_name) + 1;
+ len += numptr * sizeof(char*);
+
+ if (len > (int)buflen) {
+ errno = ERANGE;
+ return (NET_R_BAD);
+ }
+
+ /* copy net value and type */
+ nptr->n_addrtype = ne->n_addrtype;
+ nptr->n_net = ne->n_net;
+
+ cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+ /* copy official name */
+ n = strlen(ne->n_name) + 1;
+ strcpy(cp, ne->n_name);
+ nptr->n_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ nptr->n_aliases = (char **)ALIGN(buf);
+ for (i = 0 ; ne->n_aliases[i]; i++) {
+ n = strlen(ne->n_aliases[i]) + 1;
+ strcpy(cp, ne->n_aliases[i]);
+ nptr->n_aliases[i] = cp;
+ cp += n;
+ }
+ nptr->n_aliases[i] = NULL;
+
+ return (NET_R_OK);
+}
+#else /* !NETENT_DATA */
+static int
+copy_netent(struct netent *ne, struct netent *nptr, NET_R_COPY_ARGS) {
+ char *cp, *eob;
+ int i, n;
+
+ /* copy net value and type */
+ nptr->n_addrtype = ne->n_addrtype;
+ nptr->n_net = ne->n_net;
+
+ /* copy official name */
+ cp = ndptr->line;
+ eob = ndptr->line + sizeof(ndptr->line);
+ if ((n = strlen(ne->n_name) + 1) < (eob - cp)) {
+ strcpy(cp, ne->n_name);
+ nptr->n_name = cp;
+ cp += n;
+ } else {
+ return (-1);
+ }
+
+ /* copy aliases */
+ i = 0;
+ nptr->n_aliases = ndptr->net_aliases;
+ while (ne->n_aliases[i] && i < (_MAXALIASES-1)) {
+ if ((n = strlen(ne->n_aliases[i]) + 1) < (eob - cp)) {
+ strcpy(cp, ne->n_aliases[i]);
+ nptr->n_aliases[i] = cp;
+ cp += n;
+ } else {
+ break;
+ }
+ i++;
+ }
+ nptr->n_aliases[i] = NULL;
+
+ return (NET_R_OK);
+}
+#endif /* !NETENT_DATA */
+#else /* NET_R_RETURN */
+ static int getnetent_r_unknown_system = 0;
+#endif /* NET_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
+/*! \file */
diff --git a/lib/bind/irs/getnetgrent.c b/lib/bind/irs/getnetgrent.c
new file mode 100644
index 0000000..a11fa08
--- /dev/null
+++ b/lib/bind/irs/getnetgrent.c
@@ -0,0 +1,158 @@
+/*
+ * 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.3.18.1 2005/04/27 05:00:58 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+
+#include <irs.h>
+
+#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*/
+
+/*! \file */
diff --git a/lib/bind/irs/getnetgrent_r.c b/lib/bind/irs/getnetgrent_r.c
new file mode 100644
index 0000000..261d9b7
--- /dev/null
+++ b/lib/bind/irs/getnetgrent_r.c
@@ -0,0 +1,178 @@
+/*
+ * 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.7.18.4 2005/09/03 12:45:15 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+ static int getnetgrent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <port_after.h>
+
+#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;
+#if defined(NGR_R_ENT_ARGS) && !defined(NGR_R_PRIVATE)
+ UNUSED(buf);
+ UNUSED(buflen);
+#endif
+
+ 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
+{
+#if defined(NGR_R_ENT_ARGS) && !defined(NGR_R_PRIVATE)
+ UNUSED(buf);
+ UNUSED(buflen);
+#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) */
+/*! \file */
diff --git a/lib/bind/irs/getprotoent.c b/lib/bind/irs/getprotoent.c
new file mode 100644
index 0000000..9e3d775
--- /dev/null
+++ b/lib/bind/irs/getprotoent.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getprotoent.c,v 1.3.18.1 2005/04/27 05:00:58 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data *init(void);
+
+/* Public */
+
+struct protoent *
+getprotoent() {
+ struct net_data *net_data = init();
+
+ return (getprotoent_p(net_data));
+}
+
+struct protoent *
+getprotobyname(const char *name) {
+ struct net_data *net_data = init();
+
+ return (getprotobyname_p(name, net_data));
+}
+
+struct protoent *
+getprotobynumber(int proto) {
+ struct net_data *net_data = init();
+
+ return (getprotobynumber_p(proto, net_data));
+}
+
+void
+setprotoent(int stayopen) {
+ struct net_data *net_data = init();
+
+ setprotoent_p(stayopen, net_data);
+}
+
+void
+endprotoent() {
+ struct net_data *net_data = init();
+
+ endprotoent_p(net_data);
+}
+
+/* Shared private. */
+
+struct protoent *
+getprotoent_p(struct net_data *net_data) {
+ struct irs_pr *pr;
+
+ if (!net_data || !(pr = net_data->pr))
+ return (NULL);
+ net_data->pr_last = (*pr->next)(pr);
+ return (net_data->pr_last);
+}
+
+struct protoent *
+getprotobyname_p(const char *name, struct net_data *net_data) {
+ struct irs_pr *pr;
+ char **pap;
+
+ if (!net_data || !(pr = net_data->pr))
+ return (NULL);
+ if (net_data->pr_stayopen && net_data->pr_last) {
+ if (!strcmp(net_data->pr_last->p_name, name))
+ return (net_data->pr_last);
+ for (pap = net_data->pr_last->p_aliases; pap && *pap; pap++)
+ if (!strcmp(name, *pap))
+ return (net_data->pr_last);
+ }
+ net_data->pr_last = (*pr->byname)(pr, name);
+ if (!net_data->pr_stayopen)
+ endprotoent();
+ return (net_data->pr_last);
+}
+
+struct protoent *
+getprotobynumber_p(int proto, struct net_data *net_data) {
+ struct irs_pr *pr;
+
+ if (!net_data || !(pr = net_data->pr))
+ return (NULL);
+ if (net_data->pr_stayopen && net_data->pr_last)
+ if (net_data->pr_last->p_proto == proto)
+ return (net_data->pr_last);
+ net_data->pr_last = (*pr->bynumber)(pr, proto);
+ if (!net_data->pr_stayopen)
+ endprotoent();
+ return (net_data->pr_last);
+}
+
+void
+setprotoent_p(int stayopen, struct net_data *net_data) {
+ struct irs_pr *pr;
+
+ if (!net_data || !(pr = net_data->pr))
+ return;
+ (*pr->rewind)(pr);
+ net_data->pr_stayopen = (stayopen != 0);
+ if (stayopen == 0)
+ net_data_minimize(net_data);
+}
+
+void
+endprotoent_p(struct net_data *net_data) {
+ struct irs_pr *pr;
+
+ if ((net_data != NULL) && ((pr = net_data->pr) != NULL))
+ (*pr->minimize)(pr);
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->pr) {
+ net_data->pr = (*net_data->irs->pr_map)(net_data->irs);
+
+ if (!net_data->pr || !net_data->res) {
+ error:
+ errno = EIO;
+ return (NULL);
+ }
+ (*net_data->pr->res_set)(net_data->pr, net_data->res, NULL);
+ }
+
+ return (net_data);
+}
+
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/lib/bind/irs/getprotoent_r.c b/lib/bind/irs/getprotoent_r.c
new file mode 100644
index 0000000..00b1572
--- /dev/null
+++ b/lib/bind/irs/getprotoent_r.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: getprotoent_r.c,v 1.4.18.2 2006/08/01 01:19:12 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+ static int getprotoent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <port_after.h>
+
+#ifdef PROTO_R_RETURN
+
+static PROTO_R_RETURN
+copy_protoent(struct protoent *, struct protoent *, PROTO_R_COPY_ARGS);
+
+PROTO_R_RETURN
+getprotobyname_r(const char *name, struct protoent *pptr, PROTO_R_ARGS) {
+ struct protoent *pe = getprotobyname(name);
+#ifdef PROTO_R_SETANSWER
+ int n = 0;
+
+ if (pe == NULL || (n = copy_protoent(pe, pptr, PROTO_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = pptr;
+
+ return (n);
+#else
+ if (pe == NULL)
+ return (PROTO_R_BAD);
+
+ return (copy_protoent(pe, pptr, PROTO_R_COPY));
+#endif
+}
+
+PROTO_R_RETURN
+getprotobynumber_r(int proto, struct protoent *pptr, PROTO_R_ARGS) {
+ struct protoent *pe = getprotobynumber(proto);
+#ifdef PROTO_R_SETANSWER
+ int n = 0;
+
+ if (pe == NULL || (n = copy_protoent(pe, pptr, PROTO_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = pptr;
+
+ return (n);
+#else
+ if (pe == NULL)
+ return (PROTO_R_BAD);
+
+ return (copy_protoent(pe, pptr, PROTO_R_COPY));
+#endif
+}
+
+/*%
+ * These assume a single context is in operation per thread.
+ * If this is not the case we will need to call irs directly
+ * rather than through the base functions.
+ */
+
+PROTO_R_RETURN
+getprotoent_r(struct protoent *pptr, PROTO_R_ARGS) {
+ struct protoent *pe = getprotoent();
+#ifdef PROTO_R_SETANSWER
+ int n = 0;
+
+ if (pe == NULL || (n = copy_protoent(pe, pptr, PROTO_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = pptr;
+
+ return (n);
+#else
+ if (pe == NULL)
+ return (PROTO_R_BAD);
+
+ return (copy_protoent(pe, pptr, PROTO_R_COPY));
+#endif
+}
+
+PROTO_R_SET_RETURN
+#ifdef PROTO_R_ENT_ARGS
+setprotoent_r(int stay_open, PROTO_R_ENT_ARGS)
+#else
+setprotoent_r(int stay_open)
+#endif
+{
+#ifdef PROTO_R_ENT_UNUSED
+ PROTO_R_ENT_UNUSED;
+#endif
+ setprotoent(stay_open);
+#ifdef PROTO_R_SET_RESULT
+ return (PROTO_R_SET_RESULT);
+#endif
+}
+
+PROTO_R_END_RETURN
+#ifdef PROTO_R_ENT_ARGS
+endprotoent_r(PROTO_R_ENT_ARGS)
+#else
+endprotoent_r()
+#endif
+{
+#ifdef PROTO_R_ENT_UNUSED
+ PROTO_R_ENT_UNUSED;
+#endif
+ endprotoent();
+ PROTO_R_END_RESULT(PROTO_R_OK);
+}
+
+/* Private */
+
+#ifndef PROTOENT_DATA
+static PROTO_R_RETURN
+copy_protoent(struct protoent *pe, struct protoent *pptr, PROTO_R_COPY_ARGS) {
+ char *cp;
+ int i, n;
+ int numptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ numptr = 1; /*%< NULL ptr */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; pe->p_aliases[i]; i++, numptr++) {
+ len += strlen(pe->p_aliases[i]) + 1;
+ }
+ len += strlen(pe->p_name) + 1;
+ len += numptr * sizeof(char*);
+
+ if (len > (int)buflen) {
+ errno = ERANGE;
+ return (PROTO_R_BAD);
+ }
+
+ /* copy protocol value*/
+ pptr->p_proto = pe->p_proto;
+
+ cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+ /* copy official name */
+ n = strlen(pe->p_name) + 1;
+ strcpy(cp, pe->p_name);
+ pptr->p_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ pptr->p_aliases = (char **)ALIGN(buf);
+ for (i = 0 ; pe->p_aliases[i]; i++) {
+ n = strlen(pe->p_aliases[i]) + 1;
+ strcpy(cp, pe->p_aliases[i]);
+ pptr->p_aliases[i] = cp;
+ cp += n;
+ }
+ pptr->p_aliases[i] = NULL;
+
+ return (PROTO_R_OK);
+}
+#else /* !PROTOENT_DATA */
+static int
+copy_protoent(struct protoent *pe, struct protoent *pptr, PROTO_R_COPY_ARGS) {
+ char *cp, *eob;
+ int i, n;
+
+ /* copy protocol value */
+ pptr->p_proto = pe->p_proto;
+
+ /* copy official name */
+ cp = pdptr->line;
+ eob = pdptr->line + sizeof(pdptr->line);
+ if ((n = strlen(pe->p_name) + 1) < (eob - cp)) {
+ strcpy(cp, pe->p_name);
+ pptr->p_name = cp;
+ cp += n;
+ } else {
+ return (-1);
+ }
+
+ /* copy aliases */
+ i = 0;
+ pptr->p_aliases = pdptr->proto_aliases;
+ while (pe->p_aliases[i] && i < (_MAXALIASES-1)) {
+ if ((n = strlen(pe->p_aliases[i]) + 1) < (eob - cp)) {
+ strcpy(cp, pe->p_aliases[i]);
+ pptr->p_aliases[i] = cp;
+ cp += n;
+ } else {
+ break;
+ }
+ i++;
+ }
+ pptr->p_aliases[i] = NULL;
+
+ return (PROTO_R_OK);
+}
+#endif /* PROTOENT_DATA */
+#else /* PROTO_R_RETURN */
+ static int getprotoent_r_unknown_system = 0;
+#endif /* PROTO_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
+/*! \file */
diff --git a/lib/bind/irs/getpwent.c b/lib/bind/irs/getpwent.c
new file mode 100644
index 0000000..86f1d03
--- /dev/null
+++ b/lib/bind/irs/getpwent.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getpwent.c,v 1.2.18.1 2005/04/27 05:00:59 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(WANT_IRS_PW) || defined(__BIND_NOSTATIC)
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <pwd.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data * init(void);
+
+/* Public */
+
+struct passwd *
+getpwent(void) {
+ struct net_data *net_data = init();
+
+ return (getpwent_p(net_data));
+}
+
+struct passwd *
+getpwnam(const char *name) {
+ struct net_data *net_data = init();
+
+ return (getpwnam_p(name, net_data));
+}
+
+struct passwd *
+getpwuid(uid_t uid) {
+ struct net_data *net_data = init();
+
+ return (getpwuid_p(uid, net_data));
+}
+
+int
+setpassent(int stayopen) {
+ struct net_data *net_data = init();
+
+ return (setpassent_p(stayopen, net_data));
+}
+
+#ifdef SETPWENT_VOID
+void
+setpwent() {
+ struct net_data *net_data = init();
+
+ setpwent_p(net_data);
+}
+#else
+int
+setpwent() {
+ struct net_data *net_data = init();
+
+ return (setpwent_p(net_data));
+}
+#endif
+
+void
+endpwent() {
+ struct net_data *net_data = init();
+
+ endpwent_p(net_data);
+}
+
+/* Shared private. */
+
+struct passwd *
+getpwent_p(struct net_data *net_data) {
+ struct irs_pw *pw;
+
+ if (!net_data || !(pw = net_data->pw))
+ return (NULL);
+ net_data->pw_last = (*pw->next)(pw);
+ return (net_data->pw_last);
+}
+
+struct passwd *
+getpwnam_p(const char *name, struct net_data *net_data) {
+ struct irs_pw *pw;
+
+ if (!net_data || !(pw = net_data->pw))
+ return (NULL);
+ if (net_data->pw_stayopen && net_data->pw_last &&
+ !strcmp(net_data->pw_last->pw_name, name))
+ return (net_data->pw_last);
+ net_data->pw_last = (*pw->byname)(pw, name);
+ if (!net_data->pw_stayopen)
+ endpwent();
+ return (net_data->pw_last);
+}
+
+struct passwd *
+getpwuid_p(uid_t uid, struct net_data *net_data) {
+ struct irs_pw *pw;
+
+ if (!net_data || !(pw = net_data->pw))
+ return (NULL);
+ if (net_data->pw_stayopen && net_data->pw_last &&
+ net_data->pw_last->pw_uid == uid)
+ return (net_data->pw_last);
+ net_data->pw_last = (*pw->byuid)(pw, uid);
+ if (!net_data->pw_stayopen)
+ endpwent();
+ return (net_data->pw_last);
+}
+
+int
+setpassent_p(int stayopen, struct net_data *net_data) {
+ struct irs_pw *pw;
+
+ if (!net_data || !(pw = net_data->pw))
+ return (0);
+ (*pw->rewind)(pw);
+ net_data->pw_stayopen = (stayopen != 0);
+ if (stayopen == 0)
+ net_data_minimize(net_data);
+ return (1);
+}
+
+#ifdef SETPWENT_VOID
+void
+setpwent_p(struct net_data *net_data) {
+ (void) setpassent_p(0, net_data);
+}
+#else
+int
+setpwent_p(struct net_data *net_data) {
+ return (setpassent_p(0, net_data));
+}
+#endif
+
+void
+endpwent_p(struct net_data *net_data) {
+ struct irs_pw *pw;
+
+ if ((net_data != NULL) && ((pw = net_data->pw) != NULL))
+ (*pw->minimize)(pw);
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+ struct net_data *net_data;
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->pw) {
+ net_data->pw = (*net_data->irs->pw_map)(net_data->irs);
+
+ if (!net_data->pw || !net_data->res) {
+ error:
+ errno = EIO;
+ return (NULL);
+ }
+ (*net_data->pw->res_set)(net_data->pw, net_data->res, NULL);
+ }
+
+ return (net_data);
+}
+
+#endif /* WANT_IRS_PW */
+/*! \file */
diff --git a/lib/bind/irs/getpwent_r.c b/lib/bind/irs/getpwent_r.c
new file mode 100644
index 0000000..212d016
--- /dev/null
+++ b/lib/bind/irs/getpwent_r.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: getpwent_r.c,v 1.6.18.2 2005/04/27 05:00:59 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS) || !defined(WANT_IRS_PW)
+ static int getpwent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#if (defined(POSIX_GETPWNAM_R) || defined(POSIX_GETPWUID_R))
+#if defined(_POSIX_PTHREAD_SEMANTICS)
+ /* turn off solaris remapping in <grp.h> */
+#undef _POSIX_PTHREAD_SEMANTICS
+#include <pwd.h>
+#define _POSIX_PTHREAD_SEMANTICS 1
+#else
+#define _UNIX95 1
+#include <pwd.h>
+#endif
+#else
+#include <pwd.h>
+#endif
+#include <port_after.h>
+
+#ifdef PASS_R_RETURN
+
+static int
+copy_passwd(struct passwd *, struct passwd *, char *buf, int buflen);
+
+/* POSIX 1003.1c */
+#ifdef POSIX_GETPWNAM_R
+int
+__posix_getpwnam_r(const char *login, struct passwd *pwptr,
+ char *buf, size_t buflen, struct passwd **result) {
+#else
+int
+getpwnam_r(const char *login, struct passwd *pwptr,
+ char *buf, size_t buflen, struct passwd **result) {
+#endif
+ struct passwd *pw = getpwnam(login);
+ int res;
+
+ if (pw == NULL) {
+ *result = NULL;
+ return (0);
+ }
+
+ res = copy_passwd(pw, pwptr, buf, buflen);
+ *result = res ? NULL : pwptr;
+ return (res);
+}
+
+#ifdef POSIX_GETPWNAM_R
+struct passwd *
+getpwnam_r(const char *login, struct passwd *pwptr, char *buf, int buflen) {
+ struct passwd *pw = getpwnam(login);
+ int res;
+
+ if (pw == NULL)
+ return (NULL);
+
+ res = copy_passwd(pw, pwptr, buf, buflen);
+ return (res ? NULL : pwptr);
+}
+#endif
+
+/* POSIX 1003.1c */
+#ifdef POSIX_GETPWUID_R
+int
+__posix_getpwuid_r(uid_t uid, struct passwd *pwptr,
+ char *buf, int buflen, struct passwd **result) {
+#else
+int
+getpwuid_r(uid_t uid, struct passwd *pwptr,
+ char *buf, size_t buflen, struct passwd **result) {
+#endif
+ struct passwd *pw = getpwuid(uid);
+ int res;
+
+ if (pw == NULL) {
+ *result = NULL;
+ return (0);
+ }
+
+ res = copy_passwd(pw, pwptr, buf, buflen);
+ *result = res ? NULL : pwptr;
+ return (res);
+}
+
+#ifdef POSIX_GETPWUID_R
+struct passwd *
+getpwuid_r(uid_t uid, struct passwd *pwptr, char *buf, int buflen) {
+ struct passwd *pw = getpwuid(uid);
+ int res;
+
+ if (pw == NULL)
+ return (NULL);
+
+ res = copy_passwd(pw, pwptr, buf, buflen);
+ return (res ? NULL : pwptr);
+}
+#endif
+
+/*%
+ * These assume a single context is in operation per thread.
+ * If this is not the case we will need to call irs directly
+ * rather than through the base functions.
+ */
+
+PASS_R_RETURN
+getpwent_r(struct passwd *pwptr, PASS_R_ARGS) {
+ struct passwd *pw = getpwent();
+ int res = 0;
+
+ if (pw == NULL)
+ return (PASS_R_BAD);
+
+ res = copy_passwd(pw, pwptr, buf, buflen);
+ return (res ? PASS_R_BAD : PASS_R_OK);
+}
+
+PASS_R_SET_RETURN
+#ifdef PASS_R_ENT_ARGS
+setpassent_r(int stayopen, PASS_R_ENT_ARGS)
+#else
+setpassent_r(int stayopen)
+#endif
+{
+
+ setpassent(stayopen);
+#ifdef PASS_R_SET_RESULT
+ return (PASS_R_SET_RESULT);
+#endif
+}
+
+PASS_R_SET_RETURN
+#ifdef PASS_R_ENT_ARGS
+setpwent_r(PASS_R_ENT_ARGS)
+#else
+setpwent_r(void)
+#endif
+{
+
+ setpwent();
+#ifdef PASS_R_SET_RESULT
+ return (PASS_R_SET_RESULT);
+#endif
+}
+
+PASS_R_END_RETURN
+#ifdef PASS_R_ENT_ARGS
+endpwent_r(PASS_R_ENT_ARGS)
+#else
+endpwent_r(void)
+#endif
+{
+
+ endpwent();
+ PASS_R_END_RESULT(PASS_R_OK);
+}
+
+
+#ifdef HAS_FGETPWENT
+PASS_R_RETURN
+fgetpwent_r(FILE *f, struct passwd *pwptr, PASS_R_COPY_ARGS) {
+ struct passwd *pw = fgetpwent(f);
+ int res = 0;
+
+ if (pw == NULL)
+ return (PASS_R_BAD);
+
+ res = copy_passwd(pw, pwptr, PASS_R_COPY);
+ return (res ? PASS_R_BAD : PASS_R_OK );
+}
+#endif
+
+/* Private */
+
+static int
+copy_passwd(struct passwd *pw, struct passwd *pwptr, char *buf, int buflen) {
+ char *cp;
+ int n;
+ int len;
+
+ /* Find out the amount of space required to store the answer. */
+ len = strlen(pw->pw_name) + 1;
+ len += strlen(pw->pw_passwd) + 1;
+#ifdef HAVE_PW_CLASS
+ len += strlen(pw->pw_class) + 1;
+#endif
+ len += strlen(pw->pw_gecos) + 1;
+ len += strlen(pw->pw_dir) + 1;
+ len += strlen(pw->pw_shell) + 1;
+
+ if (len > buflen) {
+ errno = ERANGE;
+ return (ERANGE);
+ }
+
+ /* copy fixed atomic values*/
+ pwptr->pw_uid = pw->pw_uid;
+ pwptr->pw_gid = pw->pw_gid;
+#ifdef HAVE_PW_CHANGE
+ pwptr->pw_change = pw->pw_change;
+#endif
+#ifdef HAVE_PW_EXPIRE
+ pwptr->pw_expire = pw->pw_expire;
+#endif
+
+ cp = buf;
+
+ /* copy official name */
+ n = strlen(pw->pw_name) + 1;
+ strcpy(cp, pw->pw_name);
+ pwptr->pw_name = cp;
+ cp += n;
+
+ /* copy password */
+ n = strlen(pw->pw_passwd) + 1;
+ strcpy(cp, pw->pw_passwd);
+ pwptr->pw_passwd = cp;
+ cp += n;
+
+#ifdef HAVE_PW_CLASS
+ /* copy class */
+ n = strlen(pw->pw_class) + 1;
+ strcpy(cp, pw->pw_class);
+ pwptr->pw_class = cp;
+ cp += n;
+#endif
+
+ /* copy gecos */
+ n = strlen(pw->pw_gecos) + 1;
+ strcpy(cp, pw->pw_gecos);
+ pwptr->pw_gecos = cp;
+ cp += n;
+
+ /* copy directory */
+ n = strlen(pw->pw_dir) + 1;
+ strcpy(cp, pw->pw_dir);
+ pwptr->pw_dir = cp;
+ cp += n;
+
+ /* copy login shell */
+ n = strlen(pw->pw_shell) + 1;
+ strcpy(cp, pw->pw_shell);
+ pwptr->pw_shell = cp;
+ cp += n;
+
+ return (0);
+}
+#else /* PASS_R_RETURN */
+ static int getpwent_r_unknown_system = 0;
+#endif /* PASS_R_RETURN */
+#endif /* !def(_REENTRANT) || !def(DO_PTHREADS) || !def(WANT_IRS_PW) */
+/*! \file */
diff --git a/lib/bind/irs/getservent.c b/lib/bind/irs/getservent.c
new file mode 100644
index 0000000..92ed18b
--- /dev/null
+++ b/lib/bind/irs/getservent.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getservent.c,v 1.3.18.1 2005/04/27 05:00:59 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data *init(void);
+
+/* Public */
+
+struct servent *
+getservent(void) {
+ struct net_data *net_data = init();
+
+ return (getservent_p(net_data));
+}
+
+struct servent *
+getservbyname(const char *name, const char *proto) {
+ struct net_data *net_data = init();
+
+ return (getservbyname_p(name, proto, net_data));
+}
+
+struct servent *
+getservbyport(int port, const char *proto) {
+ struct net_data *net_data = init();
+
+ return (getservbyport_p(port, proto, net_data));
+}
+
+void
+setservent(int stayopen) {
+ struct net_data *net_data = init();
+
+ setservent_p(stayopen, net_data);
+}
+
+void
+endservent() {
+ struct net_data *net_data = init();
+
+ endservent_p(net_data);
+}
+
+/* Shared private. */
+
+struct servent *
+getservent_p(struct net_data *net_data) {
+ struct irs_sv *sv;
+
+ if (!net_data || !(sv = net_data->sv))
+ return (NULL);
+ net_data->sv_last = (*sv->next)(sv);
+ return (net_data->sv_last);
+}
+
+struct servent *
+getservbyname_p(const char *name, const char *proto,
+ struct net_data *net_data) {
+ struct irs_sv *sv;
+ char **sap;
+
+ if (!net_data || !(sv = net_data->sv))
+ return (NULL);
+ if (net_data->sv_stayopen && net_data->sv_last)
+ if (!proto || !strcmp(net_data->sv_last->s_proto, proto)) {
+ if (!strcmp(net_data->sv_last->s_name, name))
+ return (net_data->sv_last);
+ for (sap = net_data->sv_last->s_aliases;
+ sap && *sap; sap++)
+ if (!strcmp(name, *sap))
+ return (net_data->sv_last);
+ }
+ net_data->sv_last = (*sv->byname)(sv, name, proto);
+ if (!net_data->sv_stayopen)
+ endservent();
+ return (net_data->sv_last);
+}
+
+struct servent *
+getservbyport_p(int port, const char *proto, struct net_data *net_data) {
+ struct irs_sv *sv;
+
+ if (!net_data || !(sv = net_data->sv))
+ return (NULL);
+ if (net_data->sv_stayopen && net_data->sv_last)
+ if (port == net_data->sv_last->s_port &&
+ ( !proto ||
+ !strcmp(net_data->sv_last->s_proto, proto)))
+ return (net_data->sv_last);
+ net_data->sv_last = (*sv->byport)(sv, port, proto);
+ return (net_data->sv_last);
+}
+
+void
+setservent_p(int stayopen, struct net_data *net_data) {
+ struct irs_sv *sv;
+
+ if (!net_data || !(sv = net_data->sv))
+ return;
+ (*sv->rewind)(sv);
+ net_data->sv_stayopen = (stayopen != 0);
+ if (stayopen == 0)
+ net_data_minimize(net_data);
+}
+
+void
+endservent_p(struct net_data *net_data) {
+ struct irs_sv *sv;
+
+ if ((net_data != NULL) && ((sv = net_data->sv) != NULL))
+ (*sv->minimize)(sv);
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->sv) {
+ net_data->sv = (*net_data->irs->sv_map)(net_data->irs);
+
+ if (!net_data->sv || !net_data->res) {
+ error:
+ errno = EIO;
+ return (NULL);
+ }
+ (*net_data->sv->res_set)(net_data->sv, net_data->res, NULL);
+ }
+
+ return (net_data);
+}
+
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/lib/bind/irs/getservent_r.c b/lib/bind/irs/getservent_r.c
new file mode 100644
index 0000000..12c2b9b
--- /dev/null
+++ b/lib/bind/irs/getservent_r.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: getservent_r.c,v 1.4.18.2 2006/08/01 01:19:12 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+ static int getservent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <port_after.h>
+
+#ifdef SERV_R_RETURN
+
+static SERV_R_RETURN
+copy_servent(struct servent *, struct servent *, SERV_R_COPY_ARGS);
+
+SERV_R_RETURN
+getservbyname_r(const char *name, const char *proto,
+ struct servent *sptr, SERV_R_ARGS) {
+ struct servent *se = getservbyname(name, proto);
+#ifdef SERV_R_SETANSWER
+ int n = 0;
+
+ if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = sptr;
+
+ return (n);
+#else
+ if (se == NULL)
+ return (SERV_R_BAD);
+
+ return (copy_servent(se, sptr, SERV_R_COPY));
+#endif
+}
+
+SERV_R_RETURN
+getservbyport_r(int port, const char *proto,
+ struct servent *sptr, SERV_R_ARGS) {
+ struct servent *se = getservbyport(port, proto);
+#ifdef SERV_R_SETANSWER
+ int n = 0;
+
+ if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = sptr;
+
+ return (n);
+#else
+ if (se == NULL)
+ return (SERV_R_BAD);
+
+ return (copy_servent(se, sptr, SERV_R_COPY));
+#endif
+}
+
+/*%
+ * These assume a single context is in operation per thread.
+ * If this is not the case we will need to call irs directly
+ * rather than through the base functions.
+ */
+
+SERV_R_RETURN
+getservent_r(struct servent *sptr, SERV_R_ARGS) {
+ struct servent *se = getservent();
+#ifdef SERV_R_SETANSWER
+ int n = 0;
+
+ if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = sptr;
+
+ return (n);
+#else
+ if (se == NULL)
+ return (SERV_R_BAD);
+
+ return (copy_servent(se, sptr, SERV_R_COPY));
+#endif
+}
+
+SERV_R_SET_RETURN
+#ifdef SERV_R_ENT_ARGS
+setservent_r(int stay_open, SERV_R_ENT_ARGS)
+#else
+setservent_r(int stay_open)
+#endif
+{
+#ifdef SERV_R_ENT_UNUSED
+ SERV_R_ENT_UNUSED;
+#endif
+ setservent(stay_open);
+#ifdef SERV_R_SET_RESULT
+ return (SERV_R_SET_RESULT);
+#endif
+}
+
+SERV_R_END_RETURN
+#ifdef SERV_R_ENT_ARGS
+endservent_r(SERV_R_ENT_ARGS)
+#else
+endservent_r()
+#endif
+{
+#ifdef SERV_R_ENT_UNUSED
+ SERV_R_ENT_UNUSED;
+#endif
+ endservent();
+ SERV_R_END_RESULT(SERV_R_OK);
+}
+
+/* Private */
+
+#ifndef SERVENT_DATA
+static SERV_R_RETURN
+copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) {
+ char *cp;
+ int i, n;
+ int numptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ numptr = 1; /*%< NULL ptr */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; se->s_aliases[i]; i++, numptr++) {
+ len += strlen(se->s_aliases[i]) + 1;
+ }
+ len += strlen(se->s_name) + 1;
+ len += strlen(se->s_proto) + 1;
+ len += numptr * sizeof(char*);
+
+ if (len > (int)buflen) {
+ errno = ERANGE;
+ return (SERV_R_BAD);
+ }
+
+ /* copy port value */
+ sptr->s_port = se->s_port;
+
+ cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+ /* copy official name */
+ n = strlen(se->s_name) + 1;
+ strcpy(cp, se->s_name);
+ sptr->s_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ sptr->s_aliases = (char **)ALIGN(buf);
+ for (i = 0 ; se->s_aliases[i]; i++) {
+ n = strlen(se->s_aliases[i]) + 1;
+ strcpy(cp, se->s_aliases[i]);
+ sptr->s_aliases[i] = cp;
+ cp += n;
+ }
+ sptr->s_aliases[i] = NULL;
+
+ /* copy proto */
+ n = strlen(se->s_proto) + 1;
+ strcpy(cp, se->s_proto);
+ sptr->s_proto = cp;
+ cp += n;
+
+ return (SERV_R_OK);
+}
+#else /* !SERVENT_DATA */
+static int
+copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) {
+ char *cp, *eob;
+ int i, n;
+
+ /* copy port value */
+ sptr->s_port = se->s_port;
+
+ /* copy official name */
+ cp = sdptr->line;
+ eob = sdptr->line + sizeof(sdptr->line);
+ if ((n = strlen(se->s_name) + 1) < (eob - cp)) {
+ strcpy(cp, se->s_name);
+ sptr->s_name = cp;
+ cp += n;
+ } else {
+ return (-1);
+ }
+
+ /* copy aliases */
+ i = 0;
+ sptr->s_aliases = sdptr->serv_aliases;
+ while (se->s_aliases[i] && i < (_MAXALIASES-1)) {
+ if ((n = strlen(se->s_aliases[i]) + 1) < (eob - cp)) {
+ strcpy(cp, se->s_aliases[i]);
+ sptr->s_aliases[i] = cp;
+ cp += n;
+ } else {
+ break;
+ }
+ i++;
+ }
+ sptr->s_aliases[i] = NULL;
+
+ /* copy proto */
+ if ((n = strlen(se->s_proto) + 1) < (eob - cp)) {
+ strcpy(cp, se->s_proto);
+ sptr->s_proto = cp;
+ cp += n;
+ } else {
+ return (-1);
+ }
+
+ return (SERV_R_OK);
+}
+#endif /* !SERVENT_DATA */
+#else /*SERV_R_RETURN */
+ static int getservent_r_unknown_system = 0;
+#endif /*SERV_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
+/*! \file */
diff --git a/lib/bind/irs/hesiod.c b/lib/bind/irs/hesiod.c
new file mode 100644
index 0000000..5abb57c
--- /dev/null
+++ b/lib/bind/irs/hesiod.c
@@ -0,0 +1,505 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: hesiod.c,v 1.4.18.3 2005/07/28 07:38:08 marka Exp $";
+#endif
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*! \file
+ * \brief
+ * hesiod.c --- the core portion of the hesiod resolver.
+ *
+ * This file is derived from the hesiod library from Project Athena;
+ * It has been extensively rewritten by Theodore Ts'o to have a more
+ * thread-safe interface.
+ * \author
+ * This file is primarily maintained by &lt;tytso@mit.edu&gt; and &lt;ghudson@mit.edu&gt;.
+ */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#include "pathnames.h"
+#include "hesiod.h"
+#include "hesiod_p.h"
+
+/* Forward */
+
+int hesiod_init(void **context);
+void hesiod_end(void *context);
+char * hesiod_to_bind(void *context, const char *name,
+ const char *type);
+char ** hesiod_resolve(void *context, const char *name,
+ const char *type);
+void hesiod_free_list(void *context, char **list);
+
+static int parse_config_file(struct hesiod_p *ctx, const char *filename);
+static char ** get_txt_records(struct hesiod_p *ctx, int class,
+ const char *name);
+static int init(struct hesiod_p *ctx);
+
+/* Public */
+
+/*%
+ * This function is called to initialize a hesiod_p.
+ */
+int
+hesiod_init(void **context) {
+ struct hesiod_p *ctx;
+ char *cp;
+
+ ctx = malloc(sizeof(struct hesiod_p));
+ if (ctx == 0) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ memset(ctx, 0, sizeof (*ctx));
+
+ if (parse_config_file(ctx, _PATH_HESIOD_CONF) < 0) {
+#ifdef DEF_RHS
+ /*
+ * Use compiled in defaults.
+ */
+ ctx->LHS = malloc(strlen(DEF_LHS) + 1);
+ ctx->RHS = malloc(strlen(DEF_RHS) + 1);
+ if (ctx->LHS == NULL || ctx->RHS == NULL) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ strcpy(ctx->LHS, DEF_LHS); /* (checked) */
+ strcpy(ctx->RHS, DEF_RHS); /* (checked) */
+#else
+ goto cleanup;
+#endif
+ }
+ /*
+ * The default RHS can be overridden by an environment
+ * variable.
+ */
+ if ((cp = getenv("HES_DOMAIN")) != NULL) {
+ size_t RHSlen = strlen(cp) + 2;
+ if (ctx->RHS)
+ free(ctx->RHS);
+ ctx->RHS = malloc(RHSlen);
+ if (!ctx->RHS) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ if (cp[0] == '.') {
+ strcpy(ctx->RHS, cp); /* (checked) */
+ } else {
+ strcpy(ctx->RHS, "."); /* (checked) */
+ strcat(ctx->RHS, cp); /* (checked) */
+ }
+ }
+
+ /*
+ * If there is no default hesiod realm set, we return an
+ * error.
+ */
+ if (!ctx->RHS) {
+ errno = ENOEXEC;
+ goto cleanup;
+ }
+
+#if 0
+ if (res_ninit(ctx->res) < 0)
+ goto cleanup;
+#endif
+
+ *context = ctx;
+ return (0);
+
+ cleanup:
+ hesiod_end(ctx);
+ return (-1);
+}
+
+/*%
+ * This function deallocates the hesiod_p
+ */
+void
+hesiod_end(void *context) {
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ int save_errno = errno;
+
+ if (ctx->res)
+ res_nclose(ctx->res);
+ if (ctx->RHS)
+ free(ctx->RHS);
+ if (ctx->LHS)
+ free(ctx->LHS);
+ if (ctx->res && ctx->free_res)
+ (*ctx->free_res)(ctx->res);
+ free(ctx);
+ errno = save_errno;
+}
+
+/*%
+ * This function takes a hesiod (name, type) and returns a DNS
+ * name which is to be resolved.
+ */
+char *
+hesiod_to_bind(void *context, const char *name, const char *type) {
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char *bindname;
+ char **rhs_list = NULL;
+ const char *RHS, *cp;
+
+ /* Decide what our RHS is, and set cp to the end of the actual name. */
+ if ((cp = strchr(name, '@')) != NULL) {
+ if (strchr(cp + 1, '.'))
+ RHS = cp + 1;
+ else if ((rhs_list = hesiod_resolve(context, cp + 1,
+ "rhs-extension")) != NULL)
+ RHS = *rhs_list;
+ else {
+ errno = ENOENT;
+ return (NULL);
+ }
+ } else {
+ RHS = ctx->RHS;
+ cp = name + strlen(name);
+ }
+
+ /*
+ * Allocate the space we need, including up to three periods and
+ * the terminating NUL.
+ */
+ if ((bindname = malloc((cp - name) + strlen(type) + strlen(RHS) +
+ (ctx->LHS ? strlen(ctx->LHS) : 0) + 4)) == NULL) {
+ errno = ENOMEM;
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+ return NULL;
+ }
+
+ /* Now put together the DNS name. */
+ memcpy(bindname, name, cp - name);
+ bindname[cp - name] = '\0';
+ strcat(bindname, ".");
+ strcat(bindname, type);
+ if (ctx->LHS) {
+ if (ctx->LHS[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, ctx->LHS);
+ }
+ if (RHS[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, RHS);
+
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+
+ return (bindname);
+}
+
+/*%
+ * This is the core function. Given a hesiod (name, type), it
+ * returns an array of strings returned by the resolver.
+ */
+char **
+hesiod_resolve(void *context, const char *name, const char *type) {
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char *bindname = hesiod_to_bind(context, name, type);
+ char **retvec;
+
+ if (bindname == NULL)
+ return (NULL);
+ if (init(ctx) == -1) {
+ free(bindname);
+ return (NULL);
+ }
+
+ if ((retvec = get_txt_records(ctx, C_IN, bindname))) {
+ free(bindname);
+ return (retvec);
+ }
+
+ if (errno != ENOENT)
+ return (NULL);
+
+ retvec = get_txt_records(ctx, C_HS, bindname);
+ free(bindname);
+ return (retvec);
+}
+
+void
+hesiod_free_list(void *context, char **list) {
+ char **p;
+
+ UNUSED(context);
+
+ for (p = list; *p; p++)
+ free(*p);
+ free(list);
+}
+
+/*%
+ * This function parses the /etc/hesiod.conf file
+ */
+static int
+parse_config_file(struct hesiod_p *ctx, const char *filename) {
+ char *key, *data, *cp, **cpp;
+ char buf[MAXDNAME+7];
+ FILE *fp;
+
+ /*
+ * Clear the existing configuration variable, just in case
+ * they're set.
+ */
+ if (ctx->RHS)
+ free(ctx->RHS);
+ if (ctx->LHS)
+ free(ctx->LHS);
+ ctx->RHS = ctx->LHS = 0;
+
+ /*
+ * Now open and parse the file...
+ */
+ if (!(fp = fopen(filename, "r")))
+ return (-1);
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ cp = buf;
+ if (*cp == '#' || *cp == '\n' || *cp == '\r')
+ continue;
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+ key = cp;
+ while(*cp != ' ' && *cp != '\t' && *cp != '=')
+ cp++;
+ *cp++ = '\0';
+
+ while(*cp == ' ' || *cp == '\t' || *cp == '=')
+ cp++;
+ data = cp;
+ while(*cp != ' ' && *cp != '\n' && *cp != '\r')
+ cp++;
+ *cp++ = '\0';
+
+ if (strcmp(key, "lhs") == 0)
+ cpp = &ctx->LHS;
+ else if (strcmp(key, "rhs") == 0)
+ cpp = &ctx->RHS;
+ else
+ continue;
+
+ *cpp = malloc(strlen(data) + 1);
+ if (!*cpp) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ strcpy(*cpp, data);
+ }
+ fclose(fp);
+ return (0);
+
+ cleanup:
+ fclose(fp);
+ if (ctx->RHS)
+ free(ctx->RHS);
+ if (ctx->LHS)
+ free(ctx->LHS);
+ ctx->RHS = ctx->LHS = 0;
+ return (-1);
+}
+
+/*%
+ * Given a DNS class and a DNS name, do a lookup for TXT records, and
+ * return a list of them.
+ */
+static char **
+get_txt_records(struct hesiod_p *ctx, int class, const char *name) {
+ struct {
+ int type; /*%< RR type */
+ int class; /*%< RR class */
+ int dlen; /*%< len of data section */
+ u_char *data; /*%< pointer to data */
+ } rr;
+ HEADER *hp;
+ u_char qbuf[MAX_HESRESP], abuf[MAX_HESRESP];
+ u_char *cp, *erdata, *eom;
+ char *dst, *edst, **list;
+ int ancount, qdcount;
+ int i, j, n, skip;
+
+ /*
+ * Construct the query and send it.
+ */
+ n = res_nmkquery(ctx->res, QUERY, name, class, T_TXT, NULL, 0,
+ NULL, qbuf, MAX_HESRESP);
+ if (n < 0) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+ n = res_nsend(ctx->res, qbuf, n, abuf, MAX_HESRESP);
+ if (n < 0) {
+ errno = ECONNREFUSED;
+ return (NULL);
+ }
+ if (n < HFIXEDSZ) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+
+ /*
+ * OK, parse the result.
+ */
+ hp = (HEADER *) abuf;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ cp = abuf + sizeof(HEADER);
+ eom = abuf + n;
+
+ /* Skip query, trying to get to the answer section which follows. */
+ for (i = 0; i < qdcount; i++) {
+ skip = dn_skipname(cp, eom);
+ if (skip < 0 || cp + skip + QFIXEDSZ > eom) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+ cp += skip + QFIXEDSZ;
+ }
+
+ list = malloc((ancount + 1) * sizeof(char *));
+ if (!list) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ j = 0;
+ for (i = 0; i < ancount; i++) {
+ skip = dn_skipname(cp, eom);
+ if (skip < 0) {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ cp += skip;
+ if (cp + 3 * INT16SZ + INT32SZ > eom) {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ rr.type = ns_get16(cp);
+ cp += INT16SZ;
+ rr.class = ns_get16(cp);
+ cp += INT16SZ + INT32SZ; /*%< skip the ttl, too */
+ rr.dlen = ns_get16(cp);
+ cp += INT16SZ;
+ if (cp + rr.dlen > eom) {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ rr.data = cp;
+ cp += rr.dlen;
+ if (rr.class != class || rr.type != T_TXT)
+ continue;
+ if (!(list[j] = malloc(rr.dlen)))
+ goto cleanup;
+ dst = list[j++];
+ edst = dst + rr.dlen;
+ erdata = rr.data + rr.dlen;
+ cp = rr.data;
+ while (cp < erdata) {
+ n = (unsigned char) *cp++;
+ if (cp + n > eom || dst + n > edst) {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ memcpy(dst, cp, n);
+ cp += n;
+ dst += n;
+ }
+ if (cp != erdata) {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ *dst = '\0';
+ }
+ list[j] = NULL;
+ if (j == 0) {
+ errno = ENOENT;
+ goto cleanup;
+ }
+ return (list);
+
+ cleanup:
+ for (i = 0; i < j; i++)
+ free(list[i]);
+ free(list);
+ return (NULL);
+}
+
+struct __res_state *
+__hesiod_res_get(void *context) {
+ struct hesiod_p *ctx = context;
+
+ if (!ctx->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (res == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ __hesiod_res_set(ctx, res, free);
+ }
+
+ return (ctx->res);
+}
+
+void
+__hesiod_res_set(void *context, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct hesiod_p *ctx = context;
+
+ if (ctx->res && ctx->free_res) {
+ res_nclose(ctx->res);
+ (*ctx->free_res)(ctx->res);
+ }
+
+ ctx->res = res;
+ ctx->free_res = free_res;
+}
+
+static int
+init(struct hesiod_p *ctx) {
+
+ if (!ctx->res && !__hesiod_res_get(ctx))
+ return (-1);
+
+ if (((ctx->res->options & RES_INIT) == 0U) &&
+ (res_ninit(ctx->res) == -1))
+ return (-1);
+
+ return (0);
+}
diff --git a/lib/bind/irs/hesiod_p.h b/lib/bind/irs/hesiod_p.h
new file mode 100644
index 0000000..f42f84a
--- /dev/null
+++ b/lib/bind/irs/hesiod_p.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: hesiod_p.h,v 1.2.18.1 2005/04/27 05:00:59 sra Exp $
+ */
+
+#ifndef _HESIOD_P_H_INCLUDED
+#define _HESIOD_P_H_INCLUDED
+
+/** \file
+ * \brief
+ * hesiod_p.h -- private definitions for the hesiod library.
+ *
+ * \author
+ * This file is primarily maintained by tytso@mit.edu and ghudson@mit.edu.
+ */
+
+#define DEF_RHS ".Athena.MIT.EDU" /*%< Defaults if HESIOD_CONF */
+#define DEF_LHS ".ns" /*%< file is not */
+ /*%< present. */
+struct hesiod_p {
+ char * LHS; /*%< normally ".ns" */
+ char * RHS; /*%< AKA the default hesiod domain */
+ struct __res_state * res; /*%< resolver context */
+ void (*free_res)(void *);
+ void (*res_set)(struct hesiod_p *, struct __res_state *,
+ void (*)(void *));
+ struct __res_state * (*res_get)(struct hesiod_p *);
+};
+
+#define MAX_HESRESP 1024
+
+#endif /*_HESIOD_P_H_INCLUDED*/
diff --git a/lib/bind/irs/irp.c b/lib/bind/irs/irp.c
new file mode 100644
index 0000000..85a053d
--- /dev/null
+++ b/lib/bind/irs/irp.c
@@ -0,0 +1,582 @@
+/*
+ * 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.6.18.3 2006/03/10 00:20:08 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+#include <irp.h>
+
+#include "irs_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Forward. */
+
+static void irp_close(struct irs_acc *);
+
+#define LINEINCR 128
+
+#if !defined(SUN_LEN)
+#define SUN_LEN(su) \
+ (sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path))
+#endif
+
+
+/* Public */
+
+
+/* send errors to syslog if true. */
+int irp_log_errors = 1;
+
+/*%
+ * This module handles the irp module connection to irpd.
+ *
+ * The client expects a synchronous interface to functions like
+ * getpwnam(3), so we can't use the ctl_* i/o library on this end of
+ * the wire (it's used in the server).
+ */
+
+/*%
+ * irs_acc *irs_irp_acc(const char *options);
+ *
+ * Initialize the irp module.
+ */
+struct irs_acc *
+irs_irp_acc(const char *options) {
+ struct irs_acc *acc;
+ struct irp_p *irp;
+
+ UNUSED(options);
+
+ if (!(acc = memget(sizeof *acc))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(acc, 0x5e, sizeof *acc);
+ if (!(irp = memget(sizeof *irp))) {
+ errno = ENOMEM;
+ free(acc);
+ return (NULL);
+ }
+ irp->inlast = 0;
+ irp->incurr = 0;
+ irp->fdCxn = -1;
+ acc->private = irp;
+
+#ifdef WANT_IRS_GR
+ acc->gr_map = irs_irp_gr;
+#else
+ acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+ acc->pw_map = irs_irp_pw;
+#else
+ acc->pw_map = NULL;
+#endif
+ acc->sv_map = irs_irp_sv;
+ acc->pr_map = irs_irp_pr;
+ acc->ho_map = irs_irp_ho;
+ acc->nw_map = irs_irp_nw;
+ acc->ng_map = irs_irp_ng;
+ acc->close = irp_close;
+ return (acc);
+}
+
+
+int
+irs_irp_connection_setup(struct irp_p *cxndata, int *warned) {
+ if (irs_irp_is_connected(cxndata)) {
+ return (0);
+ } else if (irs_irp_connect(cxndata) != 0) {
+ if (warned != NULL && !*warned) {
+ syslog(LOG_ERR, "irpd connection failed: %m\n");
+ (*warned)++;
+ }
+
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*%
+ * int irs_irp_connect(void);
+ *
+ * Sets up the connection to the remote irpd server.
+ *
+ * Returns:
+ *
+ * 0 on success, -1 on failure.
+ *
+ */
+int
+irs_irp_connect(struct irp_p *pvt) {
+ int flags;
+ struct sockaddr *addr;
+ struct sockaddr_in iaddr;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un uaddr;
+#endif
+ long ipaddr;
+ const char *irphost;
+ int code;
+ char text[256];
+ int socklen = 0;
+
+ if (pvt->fdCxn != -1) {
+ perror("fd != 1");
+ return (-1);
+ }
+
+#ifndef NO_SOCKADDR_UN
+ memset(&uaddr, 0, sizeof uaddr);
+#endif
+ memset(&iaddr, 0, sizeof iaddr);
+
+ irphost = getenv(IRPD_HOST_ENV);
+ if (irphost == NULL) {
+ irphost = "127.0.0.1";
+ }
+
+#ifndef NO_SOCKADDR_UN
+ if (irphost[0] == '/') {
+ addr = (struct sockaddr *)&uaddr;
+ strncpy(uaddr.sun_path, irphost, sizeof uaddr.sun_path);
+ uaddr.sun_family = AF_UNIX;
+ socklen = SUN_LEN(&uaddr);
+#ifdef HAVE_SA_LEN
+ uaddr.sun_len = socklen;
+#endif
+ } else
+#endif
+ {
+ if (inet_pton(AF_INET, irphost, &ipaddr) != 1) {
+ errno = EADDRNOTAVAIL;
+ perror("inet_pton");
+ return (-1);
+ }
+
+ addr = (struct sockaddr *)&iaddr;
+ socklen = sizeof iaddr;
+#ifdef HAVE_SA_LEN
+ iaddr.sin_len = socklen;
+#endif
+ iaddr.sin_family = AF_INET;
+ iaddr.sin_port = htons(IRPD_PORT);
+ iaddr.sin_addr.s_addr = ipaddr;
+ }
+
+
+ pvt->fdCxn = socket(addr->sa_family, SOCK_STREAM, PF_UNSPEC);
+ if (pvt->fdCxn < 0) {
+ perror("socket");
+ return (-1);
+ }
+
+ if (connect(pvt->fdCxn, addr, socklen) != 0) {
+ perror("connect");
+ return (-1);
+ }
+
+ flags = fcntl(pvt->fdCxn, F_GETFL, 0);
+ if (flags < 0) {
+ close(pvt->fdCxn);
+ perror("close");
+ return (-1);
+ }
+
+#if 0
+ flags |= O_NONBLOCK;
+ if (fcntl(pvt->fdCxn, F_SETFL, flags) < 0) {
+ close(pvt->fdCxn);
+ perror("fcntl");
+ return (-1);
+ }
+#endif
+
+ code = irs_irp_read_response(pvt, text, sizeof text);
+ if (code != IRPD_WELCOME_CODE) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "Connection failed: %s", text);
+ }
+ irs_irp_disconnect(pvt);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*%
+ * int irs_irp_is_connected(struct irp_p *pvt);
+ *
+ * Returns:
+ *
+ * Non-zero if streams are setup to remote.
+ *
+ */
+
+int
+irs_irp_is_connected(struct irp_p *pvt) {
+ return (pvt->fdCxn >= 0);
+}
+
+/*%
+ * void
+ * irs_irp_disconnect(struct irp_p *pvt);
+ *
+ * Closes streams to remote.
+ */
+
+void
+irs_irp_disconnect(struct irp_p *pvt) {
+ if (pvt->fdCxn != -1) {
+ close(pvt->fdCxn);
+ pvt->fdCxn = -1;
+ }
+}
+
+
+
+int
+irs_irp_read_line(struct irp_p *pvt, char *buffer, int len) {
+ char *realstart = &pvt->inbuffer[0];
+ char *p, *start, *end;
+ int spare;
+ int i;
+ int buffpos = 0;
+ int left = len - 1;
+
+ while (left > 0) {
+ start = p = &pvt->inbuffer[pvt->incurr];
+ end = &pvt->inbuffer[pvt->inlast];
+
+ while (p != end && *p != '\n')
+ p++;
+
+ if (p == end) {
+ /* Found no newline so shift data down if necessary
+ * and append new data to buffer
+ */
+ if (start > realstart) {
+ memmove(realstart, start, end - start);
+ pvt->inlast = end - start;
+ start = realstart;
+ pvt->incurr = 0;
+ end = &pvt->inbuffer[pvt->inlast];
+ }
+
+ spare = sizeof (pvt->inbuffer) - pvt->inlast;
+
+ p = end;
+ i = read(pvt->fdCxn, end, spare);
+ if (i < 0) {
+ close(pvt->fdCxn);
+ pvt->fdCxn = -1;
+ return (buffpos > 0 ? buffpos : -1);
+ } else if (i == 0) {
+ return (buffpos);
+ }
+
+ end += i;
+ pvt->inlast += i;
+
+ while (p != end && *p != '\n')
+ p++;
+ }
+
+ if (p == end) {
+ /* full buffer and still no newline */
+ i = sizeof pvt->inbuffer;
+ } else {
+ /* include newline */
+ i = p - start + 1;
+ }
+
+ if (i > left)
+ i = left;
+ memcpy(buffer + buffpos, start, i);
+ pvt->incurr += i;
+ buffpos += i;
+ buffer[buffpos] = '\0';
+
+ if (p != end) {
+ left = 0;
+ } else {
+ left -= i;
+ }
+ }
+
+#if 0
+ fprintf(stderr, "read line: %s\n", buffer);
+#endif
+ return (buffpos);
+}
+
+/*%
+ * int irp_read_response(struct irp_p *pvt);
+ *
+ * Returns:
+ *
+ * The number found at the beginning of the line read from
+ * FP. 0 on failure(0 is not a legal response code). The
+ * rest of the line is discarded.
+ *
+ */
+
+int
+irs_irp_read_response(struct irp_p *pvt, char *text, size_t textlen) {
+ char line[1024];
+ int code;
+ char *p;
+
+ if (irs_irp_read_line(pvt, line, sizeof line) <= 0) {
+ return (0);
+ }
+
+ p = strchr(line, '\n');
+ if (p == NULL) {
+ return (0);
+ }
+
+ if (sscanf(line, "%d", &code) != 1) {
+ code = 0;
+ } else if (text != NULL && textlen > 0U) {
+ p = line;
+ while (isspace((unsigned char)*p)) p++;
+ while (isdigit((unsigned char)*p)) p++;
+ while (isspace((unsigned char)*p)) p++;
+ strncpy(text, p, textlen - 1);
+ p[textlen - 1] = '\0';
+ }
+
+ return (code);
+}
+
+/*%
+ * char *irp_read_body(struct irp_p *pvt, size_t *size);
+ *
+ * Read in the body of a response. Terminated by a line with
+ * just a dot on it. Lines should be terminated with a CR-LF
+ * sequence, but we're nt piccky if the CR is missing.
+ * No leading dot escaping is done as the protcol doesn't
+ * use leading dots anywhere.
+ *
+ * Returns:
+ *
+ * Pointer to null-terminated buffer allocated by memget.
+ * *SIZE is set to the length of the buffer.
+ *
+ */
+
+char *
+irs_irp_read_body(struct irp_p *pvt, size_t *size) {
+ char line[1024];
+ u_int linelen;
+ size_t len = LINEINCR;
+ char *buffer = memget(len);
+ int idx = 0;
+
+ if (buffer == NULL)
+ return (NULL);
+
+ for (;;) {
+ if (irs_irp_read_line(pvt, line, sizeof line) <= 0 ||
+ strchr(line, '\n') == NULL)
+ goto death;
+
+ linelen = strlen(line);
+
+ if (line[linelen - 1] != '\n')
+ goto death;
+
+ /* We're not strict about missing \r. Should we be?? */
+ if (linelen > 2 && line[linelen - 2] == '\r') {
+ line[linelen - 2] = '\n';
+ line[linelen - 1] = '\0';
+ linelen--;
+ }
+
+ if (linelen == 2 && line[0] == '.') {
+ *size = len;
+ buffer[idx] = '\0';
+
+ return (buffer);
+ }
+
+ if (linelen > (len - (idx + 1))) {
+ char *p = memget(len + LINEINCR);
+
+ if (p == NULL)
+ goto death;
+ memcpy(p, buffer, len);
+ memput(buffer, len);
+ buffer = p;
+ len += LINEINCR;
+ }
+
+ memcpy(buffer + idx, line, linelen);
+ idx += linelen;
+ }
+ death:
+ memput(buffer, len);
+ return (NULL);
+}
+
+/*%
+ * int irs_irp_get_full_response(struct irp_p *pvt, int *code,
+ * char **body, size_t *bodylen);
+ *
+ * Gets the response to a command. If the response indicates
+ * there's a body to follow(code % 10 == 1), then the
+ * body buffer is allcoated with memget and stored in
+ * *BODY. The length of the allocated body buffer is stored
+ * in *BODY. The caller must give the body buffer back to
+ * memput when done. The results code is stored in *CODE.
+ *
+ * Returns:
+ *
+ * 0 if a result was read. -1 on some sort of failure.
+ *
+ */
+
+int
+irs_irp_get_full_response(struct irp_p *pvt, int *code, char *text,
+ size_t textlen, char **body, size_t *bodylen) {
+ int result = irs_irp_read_response(pvt, text, textlen);
+
+ *body = NULL;
+
+ if (result == 0) {
+ return (-1);
+ }
+
+ *code = result;
+
+ /* Code that matches 2xx is a good result code.
+ * Code that matches xx1 means there's a response body coming.
+ */
+ if ((result / 100) == 2 && (result % 10) == 1) {
+ *body = irs_irp_read_body(pvt, bodylen);
+ if (*body == NULL) {
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+/*%
+ * int irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...);
+ *
+ * Sends command to remote connected via the PVT
+ * structure. FMT and args after it are fprintf-like
+ * arguments for formatting.
+ *
+ * Returns:
+ *
+ * 0 on success, -1 on failure.
+ */
+
+int
+irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...) {
+ va_list ap;
+ char buffer[1024];
+ int pos = 0;
+ int i, todo;
+
+
+ if (pvt->fdCxn < 0) {
+ return (-1);
+ }
+
+ va_start(ap, fmt);
+ 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);
+}
+
+
+
+
+/*! \file */
diff --git a/lib/bind/irs/irp_gr.c b/lib/bind/irs/irp_gr.c
new file mode 100644
index 0000000..bdab3da
--- /dev/null
+++ b/lib/bind/irs/irp_gr.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright(c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irp_gr.c,v 1.3.18.1 2005/04/27 05:01:00 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <syslog.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+
+/* Types. */
+
+/*! \file
+ * \brief
+ * Module for the getnetgrent(3) family to use when connected to a
+ * remote irp daemon.
+ * \brief
+ * See irpd.c for justification of caching done here.
+ *
+ */
+
+struct pvt {
+ struct irp_p *girpdata; /*%< global IRP data */
+ int warned;
+ struct group group;
+};
+
+/* Forward. */
+
+static void gr_close(struct irs_gr *);
+static struct group * gr_next(struct irs_gr *);
+static struct group * gr_byname(struct irs_gr *, const char *);
+static struct group * gr_bygid(struct irs_gr *, gid_t);
+static void gr_rewind(struct irs_gr *);
+static void gr_minimize(struct irs_gr *);
+
+/* Private */
+static void free_group(struct group *gr);
+
+
+/* Public. */
+
+/*%
+ * Initialize the group sub-module.
+ *
+ */
+
+struct irs_gr *
+irs_irp_gr(struct irs_acc *this) {
+ struct irs_gr *gr;
+ struct pvt *pvt;
+
+ if (!(gr = memget(sizeof *gr))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(gr, 0x0, sizeof *gr);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(gr, sizeof *gr);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0x0, sizeof *pvt);
+ pvt->girpdata = this->private;
+
+ gr->private = pvt;
+ gr->close = gr_close;
+ gr->next = gr_next;
+ gr->byname = gr_byname;
+ gr->bygid = gr_bygid;
+ gr->rewind = gr_rewind;
+ gr->list = make_group_list;
+ gr->minimize = gr_minimize;
+ return (gr);
+}
+
+/* Methods. */
+
+/*%
+ * Close the sub-module.
+ *
+ */
+
+static void
+gr_close(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ gr_minimize(this);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+/*%
+ * Gets the next group out of the cached data and returns it.
+ *
+ */
+
+static struct group *
+gr_next(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct group *gr = &pvt->group;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getgrent") != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "getgrent failed: %s", text);
+ }
+ return (NULL);
+ }
+
+ if (code == IRPD_GETGROUP_OK) {
+ free_group(gr);
+ if (irp_unmarshall_gr(gr, body) != 0) {
+ gr = NULL;
+ }
+ } else {
+ gr = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (gr);
+}
+
+/*%
+ * Gets a group by name from irpd and returns it.
+ *
+ */
+
+static struct group *
+gr_byname(struct irs_gr *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct group *gr = &pvt->group;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+
+ if (gr->gr_name != NULL && strcmp(name, gr->gr_name) == 0) {
+ return (gr);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getgrnam %s", name) != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETGROUP_OK) {
+ free_group(gr);
+ if (irp_unmarshall_gr(gr, body) != 0) {
+ gr = NULL;
+ }
+ } else {
+ gr = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (gr);
+}
+
+/*%
+ * Gets a group by gid from irpd and returns it.
+ *
+ */
+
+static struct group *
+gr_bygid(struct irs_gr *this, gid_t gid) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct group *gr = &pvt->group;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (gr->gr_name != NULL && (gid_t)gr->gr_gid == gid) {
+ return (gr);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getgrgid %d", gid) != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETGROUP_OK) {
+ free_group(gr);
+ if (irp_unmarshall_gr(gr, body) != 0) {
+ gr = NULL;
+ }
+ } else {
+ gr = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (gr);
+}
+
+/*%
+ * void gr_rewind(struct irs_gr *this)
+ *
+ */
+
+static void
+gr_rewind(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "setgrent") != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETGROUP_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "setgrent failed: %s", text);
+ }
+ }
+
+ return;
+}
+
+/*%
+ * Frees up cached data and disconnects(if necessary) from the remote.
+ *
+ */
+
+static void
+gr_minimize(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ free_group(&pvt->group);
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+/* Private. */
+
+/*%
+ * static void free_group(struct group *gr);
+ *
+ * Deallocate all the memory irp_unmarshall_gr allocated.
+ *
+ */
+
+static void
+free_group(struct group *gr) {
+ char **p;
+
+ if (gr == NULL)
+ return;
+
+ if (gr->gr_name != NULL)
+ free(gr->gr_name);
+
+ if (gr->gr_passwd != NULL)
+ free(gr->gr_passwd);
+
+ for (p = gr->gr_mem ; p != NULL && *p != NULL ; p++)
+ free(*p);
+
+ if (gr->gr_mem)
+ free(gr->gr_mem);
+
+ if (p != NULL)
+ free(p);
+}
+
+
+#endif /* WANT_IRS_GR */
+/*! \file */
diff --git a/lib/bind/irs/irp_ho.c b/lib/bind/irs/irp_ho.c
new file mode 100644
index 0000000..d71285e
--- /dev/null
+++ b/lib/bind/irs/irp_ho.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996,1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irp_ho.c,v 1.2.18.1 2005/04/27 05:01:00 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/irpmarshall.h>
+#include <isc/memcluster.h>
+
+#include "irs_p.h"
+#include "dns_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Definitions. */
+
+#define MAXALIASES 35
+#define MAXADDRS 35
+#define Max(a,b) ((a) > (b) ? (a) : (b))
+
+
+struct pvt {
+ struct irp_p *girpdata;
+ int warned;
+ struct hostent host;
+};
+
+/* Forward. */
+
+static void ho_close(struct irs_ho *this);
+static struct hostent * ho_byname(struct irs_ho *this, const char *name);
+static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
+ int af);
+static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ int len, int af);
+static struct hostent * ho_next(struct irs_ho *this);
+static void ho_rewind(struct irs_ho *this);
+static void ho_minimize(struct irs_ho *this);
+
+static void free_host(struct hostent *ho);
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+ const struct addrinfo *pai);
+
+/* Public. */
+
+/*%
+ * struct irs_ho * irs_irp_ho(struct irs_acc *this)
+ *
+ * Notes:
+ *
+ * Initializes the irp_ho module.
+ *
+ */
+
+struct irs_ho *
+irs_irp_ho(struct irs_acc *this) {
+ struct irs_ho *ho;
+ struct pvt *pvt;
+
+ if (!(ho = memget(sizeof *ho))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ho, 0x0, sizeof *ho);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(ho, sizeof *ho);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->girpdata = this->private;
+
+ ho->private = pvt;
+ ho->close = ho_close;
+ ho->byname = ho_byname;
+ ho->byname2 = ho_byname2;
+ ho->byaddr = ho_byaddr;
+ ho->next = ho_next;
+ ho->rewind = ho_rewind;
+ ho->minimize = ho_minimize;
+ ho->addrinfo = ho_addrinfo;
+
+ return (ho);
+}
+
+/* Methods. */
+
+/*%
+ * Closes down the module.
+ *
+ */
+
+static void
+ho_close(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ho_minimize(this);
+
+ free_host(&pvt->host);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+
+
+/*
+ * struct hostent * ho_byname(struct irs_ho *this, const char *name)
+ *
+ */
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+ return (ho_byname2(this, name, AF_INET));
+}
+
+
+
+
+
+/*
+ * struct hostent * ho_byname2(struct irs_ho *this, const char *name, int af)
+ *
+ */
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *ho = &pvt->host;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (ho->h_name != NULL &&
+ strcmp(name, ho->h_name) == 0 &&
+ af == ho->h_addrtype) {
+ return (ho);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "gethostbyname2 %s %s",
+ name, ADDR_T_STR(af)) != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETHOST_OK) {
+ free_host(ho);
+ if (irp_unmarshall_ho(ho, body) != 0) {
+ ho = NULL;
+ }
+ } else {
+ ho = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (ho);
+}
+
+
+
+/*
+ * struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ * int len, int af)
+ *
+ */
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *ho = &pvt->host;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ char **p;
+ char paddr[MAXPADDRSIZE];
+ char text[256];
+
+ if (ho->h_name != NULL &&
+ af == ho->h_addrtype &&
+ len == ho->h_length) {
+ for (p = ho->h_addr_list ; *p != NULL ; p++) {
+ if (memcmp(*p, addr, len) == 0)
+ return (ho);
+ }
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (inet_ntop(af, addr, paddr, sizeof paddr) == NULL) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "gethostbyaddr %s %s",
+ paddr, ADDR_T_STR(af)) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETHOST_OK) {
+ free_host(ho);
+ if (irp_unmarshall_ho(ho, body) != 0) {
+ ho = NULL;
+ }
+ } else {
+ ho = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (ho);
+}
+
+/*%
+ * The implementation for gethostent(3). The first time it's
+ * called all the data is pulled from the remote(i.e. what
+ * the maximum number of gethostent(3) calls would return)
+ * and that data is cached.
+ *
+ */
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *ho = &pvt->host;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "gethostent") != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETHOST_OK) {
+ free_host(ho);
+ if (irp_unmarshall_ho(ho, body) != 0) {
+ ho = NULL;
+ }
+ } else {
+ ho = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (ho);
+}
+
+/*%
+ * void ho_rewind(struct irs_ho *this)
+ *
+ */
+
+static void
+ho_rewind(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "sethostent") != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETHOST_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "sethostent failed: %s", text);
+ }
+ }
+
+ return;
+}
+
+/*%
+ * void ho_minimize(struct irs_ho *this)
+ *
+ */
+
+static void
+ho_minimize(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ free_host(&pvt->host);
+
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+/*%
+ * void free_host(struct hostent *ho)
+ *
+ */
+
+static void
+free_host(struct hostent *ho) {
+ char **p;
+
+ if (ho == NULL) {
+ return;
+ }
+
+ if (ho->h_name != NULL)
+ free(ho->h_name);
+
+ if (ho->h_aliases != NULL) {
+ for (p = ho->h_aliases ; *p != NULL ; p++)
+ free(*p);
+ free(ho->h_aliases);
+ }
+
+ if (ho->h_addr_list != NULL) {
+ for (p = ho->h_addr_list ; *p != NULL ; p++)
+ free(*p);
+ free(ho->h_addr_list);
+ }
+}
+
+/* dummy */
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+ UNUSED(this);
+ UNUSED(name);
+ UNUSED(pai);
+ return(NULL);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/irp_ng.c b/lib/bind/irs/irp_ng.c
new file mode 100644
index 0000000..e0aa468
--- /dev/null
+++ b/lib/bind/irs/irp_ng.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: irp_ng.c,v 1.2.18.2 2006/12/07 04:53:02 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "irs_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Definitions */
+
+struct pvt {
+ struct irp_p *girpdata;
+ int warned;
+};
+
+
+/* Forward */
+
+static void ng_rewind(struct irs_ng *, const char*);
+static void ng_close(struct irs_ng *);
+static int ng_next(struct irs_ng *, const char **, const char **,
+ const char **);
+static int ng_test(struct irs_ng *, const char *,
+ const char *, const char *,
+ const char *);
+static void ng_minimize(struct irs_ng *);
+
+
+/* Public */
+
+/*%
+ * Intialize the irp netgroup module.
+ *
+ */
+
+struct irs_ng *
+irs_irp_ng(struct irs_acc *this) {
+ struct irs_ng *ng;
+ struct pvt *pvt;
+
+ if (!(ng = memget(sizeof *ng))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ng, 0x5e, sizeof *ng);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(ng, sizeof *ng);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->girpdata = this->private;
+
+ ng->private = pvt;
+ ng->close = ng_close;
+ ng->next = ng_next;
+ ng->test = ng_test;
+ ng->rewind = ng_rewind;
+ ng->minimize = ng_minimize;
+ return (ng);
+}
+
+/* Methods */
+
+
+
+/*
+ * void ng_close(struct irs_ng *this)
+ *
+ */
+
+static void
+ng_close(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ng_minimize(this);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+
+
+
+/*
+ * void ng_rewind(struct irs_ng *this, const char *group)
+ *
+ *
+ */
+
+static void
+ng_rewind(struct irs_ng *this, const char *group) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata,
+ "setnetgrent %s", group) != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETNETGR_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "setnetgrent(%s) failed: %s",
+ group, text);
+ }
+ }
+
+ return;
+}
+
+/*
+ * Get the next netgroup item from the cache.
+ *
+ */
+
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user,
+ const char **domain)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ int code;
+ char *body = NULL;
+ size_t bodylen;
+ int rval = 0;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (0);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getnetgrent") != 0)
+ return (0);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (0);
+ }
+
+ if (code == IRPD_GETNETGR_OK) {
+ if (irp_unmarshall_ng(host, user, domain, body) == 0) {
+ rval = 1;
+ }
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (rval);
+}
+
+/*
+ * Search for a match in a netgroup.
+ *
+ */
+
+static int
+ng_test(struct irs_ng *this, const char *name,
+ const char *host, const char *user, const char *domain)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *body = NULL;
+ size_t bodylen = 0;
+ int code;
+ char text[256];
+ int rval = 0;
+
+ UNUSED(name);
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (0);
+ }
+
+ if (irp_marshall_ng(host, user, domain, &body, &bodylen) != 0) {
+ return (0);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "innetgr %s", body) == 0) {
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code == IRPD_GETNETGR_MATCHES) {
+ rval = 1;
+ }
+ }
+
+ memput(body, bodylen);
+
+ return (rval);
+}
+
+
+
+
+/*
+ * void ng_minimize(struct irs_ng *this)
+ *
+ */
+
+static void
+ng_minimize(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+
+
+
+/* Private */
+
+
+/*! \file */
diff --git a/lib/bind/irs/irp_nw.c b/lib/bind/irs/irp_nw.c
new file mode 100644
index 0000000..b285120
--- /dev/null
+++ b/lib/bind/irs/irp_nw.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996,1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irp_nw.c,v 1.2.18.2 2006/03/10 00:20:08 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#if 0
+
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/irpmarshall.h>
+
+#include <isc/memcluster.h>
+#include <isc/misc.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+#define MAXALIASES 35
+#define MAXADDRSIZE 4
+
+struct pvt {
+ struct irp_p *girpdata;
+ int warned;
+ struct nwent net;
+};
+
+/* Forward */
+
+static void nw_close(struct irs_nw *);
+static struct nwent * nw_byname(struct irs_nw *, const char *, int);
+static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int);
+static struct nwent * nw_next(struct irs_nw *);
+static void nw_rewind(struct irs_nw *);
+static void nw_minimize(struct irs_nw *);
+
+static void free_nw(struct nwent *nw);
+
+
+/* Public */
+
+/*%
+ * struct irs_nw * irs_irp_nw(struct irs_acc *this)
+ *
+ */
+
+struct irs_nw *
+irs_irp_nw(struct irs_acc *this) {
+ struct irs_nw *nw;
+ struct pvt *pvt;
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+
+ if (!(nw = memget(sizeof *nw))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(nw, 0x0, sizeof *nw);
+ pvt->girpdata = this->private;
+
+ nw->private = pvt;
+ nw->close = nw_close;
+ nw->byname = nw_byname;
+ nw->byaddr = nw_byaddr;
+ nw->next = nw_next;
+ nw->rewind = nw_rewind;
+ nw->minimize = nw_minimize;
+ return (nw);
+}
+
+/* Methods */
+
+/*%
+ * void nw_close(struct irs_nw *this)
+ *
+ */
+
+static void
+nw_close(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ nw_minimize(this);
+
+ free_nw(&pvt->net);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+/*%
+ * struct nwent * nw_byaddr(struct irs_nw *this, void *net,
+ * int length, int type)
+ *
+ */
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int length, int type) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct nwent *nw = &pvt->net;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ char paddr[24]; /*%< bigenough for ip4 w/ cidr spec. */
+ char text[256];
+
+ if (inet_net_ntop(type, net, length, paddr, sizeof paddr) == NULL) {
+ return (NULL);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getnetbyaddr %s %s",
+ paddr, ADDR_T_STR(type)) != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETNET_OK) {
+ free_nw(nw);
+ if (irp_unmarshall_nw(nw, body) != 0) {
+ nw = NULL;
+ }
+ } else {
+ nw = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (nw);
+}
+
+/*%
+ * struct nwent * nw_byname(struct irs_nw *this, const char *name, int type)
+ *
+ */
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int type) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct nwent *nw = &pvt->net;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (nw->n_name != NULL &&
+ strcmp(name, nw->n_name) == 0 &&
+ nw->n_addrtype == type) {
+ return (nw);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getnetbyname %s", name) != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETNET_OK) {
+ free_nw(nw);
+ if (irp_unmarshall_nw(nw, body) != 0) {
+ nw = NULL;
+ }
+ } else {
+ nw = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (nw);
+}
+
+/*%
+ * void nw_rewind(struct irs_nw *this)
+ *
+ */
+
+static void
+nw_rewind(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "setnetent") != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETNET_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "setnetent failed: %s", text);
+ }
+ }
+
+ return;
+}
+
+/*%
+ * Prepares the cache if necessary and returns the first, or
+ * next item from it.
+ */
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct nwent *nw = &pvt->net;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getnetent") != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETNET_OK) {
+ free_nw(nw);
+ if (irp_unmarshall_nw(nw, body) != 0) {
+ nw = NULL;
+ }
+ } else {
+ nw = NULL;
+ }
+
+ if (body != NULL)
+ memput(body, bodylen);
+ return (nw);
+}
+
+/*%
+ * void nw_minimize(struct irs_nw *this)
+ *
+ */
+
+static void
+nw_minimize(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+
+
+
+/* private. */
+
+/*%
+ * deallocate all the memory irp_unmarshall_pw allocated.
+ *
+ */
+
+static void
+free_nw(struct nwent *nw) {
+ char **p;
+
+ if (nw == NULL)
+ return;
+
+ if (nw->n_name != NULL)
+ free(nw->n_name);
+
+ if (nw->n_aliases != NULL) {
+ for (p = nw->n_aliases ; *p != NULL ; p++) {
+ free(*p);
+ }
+ free(nw->n_aliases);
+ }
+
+ if (nw->n_addr != NULL)
+ free(nw->n_addr);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/irp_p.h b/lib/bind/irs/irp_p.h
new file mode 100644
index 0000000..21d31cc
--- /dev/null
+++ b/lib/bind/irs/irp_p.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irp_p.h,v 1.4.18.1 2005/04/27 05:01:00 sra Exp $
+ */
+
+#ifndef _IRP_P_H_INCLUDED
+#define _IRP_P_H_INCLUDED
+
+#include <stdio.h>
+
+struct irp_p {
+ char inbuffer[1024];
+ int inlast; /*%< index of one past the last char in buffer */
+ int incurr; /*%< index of the next char to be read from buffer */
+ int fdCxn;
+};
+
+/*
+ * Externs.
+ */
+
+extern struct irs_acc * irs_irp_acc __P((const char *));
+extern struct irs_gr * irs_irp_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_irp_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_irp_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_irp_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_irp_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_irp_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_irp_ng __P((struct irs_acc *));
+
+int irs_irp_connect(struct irp_p *pvt);
+int irs_irp_is_connected(struct irp_p *pvt);
+void irs_irp_disconnect(struct irp_p *pvt);
+int irs_irp_read_response(struct irp_p *pvt, char *text, size_t textlen);
+char *irs_irp_read_body(struct irp_p *pvt, size_t *size);
+int irs_irp_get_full_response(struct irp_p *pvt, int *code,
+ char *text, size_t textlen,
+ char **body, size_t *bodylen);
+
+extern int irp_log_errors;
+
+#endif
+
+/*! \file */
diff --git a/lib/bind/irs/irp_pr.c b/lib/bind/irs/irp_pr.c
new file mode 100644
index 0000000..00e69ab
--- /dev/null
+++ b/lib/bind/irs/irp_pr.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irp_pr.c,v 1.2.18.1 2005/04/27 05:01:01 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+
+#define MAXALIASES 35
+
+/* Types */
+
+struct pvt {
+ struct irp_p *girpdata;
+ int warned;
+ struct protoent proto;
+};
+
+/* Forward */
+
+static void pr_close(struct irs_pr *);
+static struct protoent * pr_next(struct irs_pr *);
+static struct protoent * pr_byname(struct irs_pr *, const char *);
+static struct protoent * pr_bynumber(struct irs_pr *, int);
+static void pr_rewind(struct irs_pr *);
+static void pr_minimize(struct irs_pr *);
+
+static void free_proto(struct protoent *pr);
+
+/* Public */
+
+/*%
+ * struct irs_pr * irs_irp_pr(struct irs_acc *this)
+ *
+ */
+
+struct irs_pr *
+irs_irp_pr(struct irs_acc *this) {
+ struct irs_pr *pr;
+ struct pvt *pvt;
+
+ if (!(pr = memget(sizeof *pr))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pr, 0x0, sizeof *pr);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(pr, sizeof *pr);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->girpdata = this->private;
+
+ pr->private = pvt;
+ pr->close = pr_close;
+ pr->byname = pr_byname;
+ pr->bynumber = pr_bynumber;
+ pr->next = pr_next;
+ pr->rewind = pr_rewind;
+ pr->minimize = pr_minimize;
+ return (pr);
+}
+
+/* Methods */
+
+/*%
+ * void pr_close(struct irs_pr *this)
+ *
+ */
+
+static void
+pr_close(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ pr_minimize(this);
+
+ free_proto(&pvt->proto);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+/*%
+ * struct protoent * pr_byname(struct irs_pr *this, const char *name)
+ *
+ */
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct protoent *pr = &pvt->proto;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ int i;
+ char text[256];
+
+ if (pr->p_name != NULL && strcmp(name, pr->p_name) == 0) {
+ return (pr);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ i = irs_irp_send_command(pvt->girpdata, "getprotobyname %s", name);
+ if (i != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETPROTO_OK) {
+ free_proto(pr);
+ if (irp_unmarshall_pr(pr, body) != 0) {
+ pr = NULL;
+ }
+ } else {
+ pr = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (pr);
+}
+
+/*%
+ * struct protoent * pr_bynumber(struct irs_pr *this, int proto)
+ *
+ */
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct protoent *pr = &pvt->proto;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ int i;
+ char text[256];
+
+ if (pr->p_name != NULL && proto == pr->p_proto) {
+ return (pr);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ i = irs_irp_send_command(pvt->girpdata, "getprotobynumber %d", proto);
+ if (i != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETPROTO_OK) {
+ free_proto(pr);
+ if (irp_unmarshall_pr(pr, body) != 0) {
+ pr = NULL;
+ }
+ } else {
+ pr = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (pr);
+}
+
+/*%
+ * void pr_rewind(struct irs_pr *this)
+ *
+ */
+
+static void
+pr_rewind(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "setprotoent") != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETPROTO_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "setprotoent failed: %s", text);
+ }
+ }
+
+ return;
+}
+
+/*%
+ * Prepares the cache if necessary and returns the next item in it.
+ *
+ */
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct protoent *pr = &pvt->proto;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getprotoent") != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETPROTO_OK) {
+ free_proto(pr);
+ if (irp_unmarshall_pr(pr, body) != 0) {
+ pr = NULL;
+ }
+ } else {
+ pr = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (pr);
+}
+
+/*%
+ * void pr_minimize(struct irs_pr *this)
+ *
+ */
+
+static void
+pr_minimize(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+/*%
+ * Deallocate all the memory irp_unmarshall_pr allocated.
+ *
+ */
+
+static void
+free_proto(struct protoent *pr) {
+ char **p;
+
+ if (pr == NULL)
+ return;
+
+ if (pr->p_name != NULL)
+ free(pr->p_name);
+
+ for (p = pr->p_aliases ; p != NULL && *p != NULL ; p++)
+ free(*p);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/irp_pw.c b/lib/bind/irs/irp_pw.c
new file mode 100644
index 0000000..a326375
--- /dev/null
+++ b/lib/bind/irs/irp_pw.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irp_pw.c,v 1.3.18.1 2005/04/27 05:01:01 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Extern */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <syslog.h>
+#include <sys/param.h>
+
+#include <db.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <utmp.h>
+#include <unistd.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "irp_p.h"
+
+
+/* Types */
+
+struct pvt {
+ struct irp_p *girpdata; /*%< global IRP data */
+ int warned;
+ struct passwd passwd; /*%< password structure */
+};
+
+/* Forward */
+
+static void pw_close(struct irs_pw *);
+static struct passwd * pw_next(struct irs_pw *);
+static struct passwd * pw_byname(struct irs_pw *, const char *);
+static struct passwd * pw_byuid(struct irs_pw *, uid_t);
+static void pw_rewind(struct irs_pw *);
+static void pw_minimize(struct irs_pw *);
+
+static void free_passwd(struct passwd *pw);
+
+/* Public */
+struct irs_pw *
+irs_irp_pw(struct irs_acc *this) {
+ struct irs_pw *pw;
+ struct pvt *pvt;
+
+ if (!(pw = memget(sizeof *pw))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pw, 0, sizeof *pw);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(pw, sizeof *pw);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->girpdata = this->private;
+
+ pw->private = pvt;
+ pw->close = pw_close;
+ pw->next = pw_next;
+ pw->byname = pw_byname;
+ pw->byuid = pw_byuid;
+ pw->rewind = pw_rewind;
+ pw->minimize = pw_minimize;
+
+ return (pw);
+}
+
+/* Methods */
+
+/*%
+ * void pw_close(struct irs_pw *this)
+ *
+ */
+
+static void
+pw_close(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ pw_minimize(this);
+
+ free_passwd(&pvt->passwd);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+/*%
+ * struct passwd * pw_next(struct irs_pw *this)
+ *
+ */
+
+static struct passwd *
+pw_next(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct passwd *pw = &pvt->passwd;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getpwent") != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETUSER_OK) {
+ free_passwd(pw);
+ if (irp_unmarshall_pw(pw, body) != 0) {
+ pw = NULL;
+ }
+ } else {
+ pw = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (pw);
+}
+
+/*%
+ * struct passwd * pw_byname(struct irs_pw *this, const char *name)
+ *
+ */
+
+static struct passwd *
+pw_byname(struct irs_pw *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct passwd *pw = &pvt->passwd;
+ char *body = NULL;
+ char text[256];
+ size_t bodylen;
+ int code;
+
+ if (pw->pw_name != NULL && strcmp(name, pw->pw_name) == 0) {
+ return (pw);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getpwnam %s", name) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETUSER_OK) {
+ free_passwd(pw);
+ if (irp_unmarshall_pw(pw, body) != 0) {
+ pw = NULL;
+ }
+ } else {
+ pw = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (pw);
+}
+
+/*%
+ * struct passwd * pw_byuid(struct irs_pw *this, uid_t uid)
+ *
+ */
+
+static struct passwd *
+pw_byuid(struct irs_pw *this, uid_t uid) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *body;
+ char text[256];
+ size_t bodylen;
+ int code;
+ struct passwd *pw = &pvt->passwd;
+
+ if (pw->pw_name != NULL && pw->pw_uid == uid) {
+ return (pw);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getpwuid %d", uid) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETUSER_OK) {
+ free_passwd(pw);
+ if (irp_unmarshall_pw(pw, body) != 0) {
+ pw = NULL;
+ }
+ } else {
+ pw = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (pw);
+}
+
+/*%
+ * void pw_rewind(struct irs_pw *this)
+ *
+ */
+
+static void
+pw_rewind(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "setpwent") != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETUSER_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "setpwent failed: %s", text);
+ }
+ }
+
+ return;
+}
+
+/*%
+ * void pw_minimize(struct irs_pw *this)
+ *
+ */
+
+static void
+pw_minimize(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+
+/* Private. */
+
+/*%
+ * Deallocate all the memory irp_unmarshall_pw allocated.
+ *
+ */
+
+static void
+free_passwd(struct passwd *pw) {
+ if (pw == NULL)
+ return;
+
+ if (pw->pw_name != NULL)
+ free(pw->pw_name);
+
+ if (pw->pw_passwd != NULL)
+ free(pw->pw_passwd);
+
+#ifdef HAVE_PW_CLASS
+ if (pw->pw_class != NULL)
+ free(pw->pw_class);
+#endif
+
+ if (pw->pw_gecos != NULL)
+ free(pw->pw_gecos);
+
+ if (pw->pw_dir != NULL)
+ free(pw->pw_dir);
+
+ if (pw->pw_shell != NULL)
+ free(pw->pw_shell);
+}
+
+#endif /* WANT_IRS_PW */
+/*! \file */
diff --git a/lib/bind/irs/irp_sv.c b/lib/bind/irs/irp_sv.c
new file mode 100644
index 0000000..22ea980
--- /dev/null
+++ b/lib/bind/irs/irp_sv.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996,1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irp_sv.c,v 1.2.18.1 2005/04/27 05:01:01 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifdef IRS_LCL_SV_DB
+#include <db.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/irpmarshall.h>
+#include <isc/memcluster.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Types */
+
+struct pvt {
+ struct irp_p *girpdata;
+ int warned;
+ struct servent service;
+};
+
+/* Forward */
+
+static void sv_close(struct irs_sv*);
+static struct servent * sv_next(struct irs_sv *);
+static struct servent * sv_byname(struct irs_sv *, const char *,
+ const char *);
+static struct servent * sv_byport(struct irs_sv *, int, const char *);
+static void sv_rewind(struct irs_sv *);
+static void sv_minimize(struct irs_sv *);
+
+static void free_service(struct servent *sv);
+
+
+
+/* Public */
+
+/*%
+ * struct irs_sv * irs_irp_sv(struct irs_acc *this)
+ *
+ */
+
+struct irs_sv *
+irs_irp_sv(struct irs_acc *this) {
+ struct irs_sv *sv;
+ struct pvt *pvt;
+
+ if ((sv = memget(sizeof *sv)) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(sv, 0x0, sizeof *sv);
+
+ if ((pvt = memget(sizeof *pvt)) == NULL) {
+ memput(sv, sizeof *sv);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->girpdata = this->private;
+
+ sv->private = pvt;
+ sv->close = sv_close;
+ sv->next = sv_next;
+ sv->byname = sv_byname;
+ sv->byport = sv_byport;
+ sv->rewind = sv_rewind;
+ sv->minimize = sv_minimize;
+
+ return (sv);
+}
+
+/* Methods */
+
+/*%
+ * void sv_close(struct irs_sv *this)
+ *
+ */
+
+static void
+sv_close(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ sv_minimize(this);
+
+ free_service(&pvt->service);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+/*%
+ * Fills the cache if necessary and returns the next item from it.
+ *
+ */
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct servent *sv = &pvt->service;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getservent") != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETSERVICE_OK) {
+ free_service(sv);
+ if (irp_unmarshall_sv(sv, body) != 0) {
+ sv = NULL;
+ }
+ } else {
+ sv = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (sv);
+}
+
+/*%
+ * struct servent * sv_byname(struct irs_sv *this, const char *name,
+ * const char *proto)
+ *
+ */
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct servent *sv = &pvt->service;
+ char *body;
+ char text[256];
+ size_t bodylen;
+ int code;
+
+ if (sv->s_name != NULL &&
+ strcmp(name, sv->s_name) == 0 &&
+ strcasecmp(proto, sv->s_proto) == 0) {
+ return (sv);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getservbyname %s %s",
+ name, proto) != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETSERVICE_OK) {
+ free_service(sv);
+ if (irp_unmarshall_sv(sv, body) != 0) {
+ sv = NULL;
+ }
+ } else {
+ sv = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (sv);
+}
+
+/*%
+ * struct servent * sv_byport(struct irs_sv *this, int port,
+ * const char *proto)
+ *
+ */
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct servent *sv = &pvt->service;
+ char *body;
+ size_t bodylen;
+ char text[256];
+ int code;
+
+ if (sv->s_name != NULL &&
+ port == sv->s_port &&
+ strcasecmp(proto, sv->s_proto) == 0) {
+ return (sv);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getservbyport %d %s",
+ ntohs((short)port), proto) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETSERVICE_OK) {
+ free_service(sv);
+ if (irp_unmarshall_sv(sv, body) != 0) {
+ sv = NULL;
+ }
+ } else {
+ sv = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (sv);
+}
+
+/*%
+ * void sv_rewind(struct irs_sv *this)
+ *
+ */
+
+static void
+sv_rewind(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "setservent") != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETSERVICE_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "setservent failed: %s", text);
+ }
+ }
+
+ return;
+}
+
+/*%
+ * void sv_minimize(struct irs_sv *this)
+ *
+ */
+
+static void
+sv_minimize(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+
+
+
+
+
+static void
+free_service(struct servent *sv) {
+ char **p;
+
+ if (sv == NULL) {
+ return;
+ }
+
+ if (sv->s_name != NULL) {
+ free(sv->s_name);
+ }
+
+ for (p = sv->s_aliases ; p != NULL && *p != NULL ; p++) {
+ free(*p);
+ }
+
+ if (sv->s_proto != NULL) {
+ free(sv->s_proto);
+ }
+}
+
+
+
+/*! \file */
diff --git a/lib/bind/irs/irpmarshall.c b/lib/bind/irs/irpmarshall.c
new file mode 100644
index 0000000..8c34fa2
--- /dev/null
+++ b/lib/bind/irs/irpmarshall.c
@@ -0,0 +1,2301 @@
+/*
+ * Copyright(c) 1989, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irpmarshall.c,v 1.5.18.2 2006/03/10 00:20:08 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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <utmp.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "port_after.h"
+
+
+#ifndef HAVE_STRNDUP
+static char *strndup(const char *str, size_t len);
+#endif
+
+static char **splitarray(const char *buffer, const char *buffend, char delim);
+static int joinarray(char * const * argv, char *buffer, char delim);
+static char *getfield(char **res, size_t reslen, char **buffer, char delim);
+static size_t joinlength(char * const *argv);
+static void free_array(char **argv, size_t entries);
+
+#define ADDR_T_STR(x) (x == AF_INET ? "AF_INET" :\
+ (x == AF_INET6 ? "AF_INET6" : "UNKNOWN"))
+
+#define MAXPADDRSIZE (sizeof "255.255.255.255" + 1)
+
+static char COMMA = ',';
+
+static const char *COMMASTR = ",";
+static const char *COLONSTR = ":";
+
+
+
+/* See big comment at bottom of irpmarshall.h for description. */
+
+
+#ifdef WANT_IRS_PW
+/* +++++++++++++++++++++++++ struct passwd +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on sucess, -1 on failure.
+ *
+ */
+
+int
+irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len) {
+ size_t need = 1 ; /*%< for null byte */
+ char pwUid[24];
+ char pwGid[24];
+ char pwChange[24];
+ char pwExpire[24];
+ const char *pwClass;
+ const char *fieldsep = COLONSTR;
+
+ if (pw == NULL || len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sprintf(pwUid, "%ld", (long)pw->pw_uid);
+ sprintf(pwGid, "%ld", (long)pw->pw_gid);
+
+#ifdef HAVE_PW_CHANGE
+ sprintf(pwChange, "%ld", (long)pw->pw_change);
+#else
+ pwChange[0] = '0';
+ pwChange[1] = '\0';
+#endif
+
+#ifdef HAVE_PW_EXPIRE
+ sprintf(pwExpire, "%ld", (long)pw->pw_expire);
+#else
+ pwExpire[0] = '0';
+ pwExpire[1] = '\0';
+#endif
+
+#ifdef HAVE_PW_CLASS
+ pwClass = pw->pw_class;
+#else
+ pwClass = "";
+#endif
+
+ need += strlen(pw->pw_name) + 1; /*%< one for fieldsep */
+ need += strlen(pw->pw_passwd) + 1;
+ need += strlen(pwUid) + 1;
+ need += strlen(pwGid) + 1;
+ need += strlen(pwClass) + 1;
+ need += strlen(pwChange) + 1;
+ need += strlen(pwExpire) + 1;
+ need += strlen(pw->pw_gecos) + 1;
+ need += strlen(pw->pw_dir) + 1;
+ need += strlen(pw->pw_shell) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, pw->pw_name); strcat(*buffer, fieldsep);
+ strcat(*buffer, pw->pw_passwd); strcat(*buffer, fieldsep);
+ strcat(*buffer, pwUid); strcat(*buffer, fieldsep);
+ strcat(*buffer, pwGid); strcat(*buffer, fieldsep);
+ strcat(*buffer, pwClass); strcat(*buffer, fieldsep);
+ strcat(*buffer, pwChange); strcat(*buffer, fieldsep);
+ strcat(*buffer, pwExpire); strcat(*buffer, fieldsep);
+ strcat(*buffer, pw->pw_gecos); strcat(*buffer, fieldsep);
+ strcat(*buffer, pw->pw_dir); strcat(*buffer, fieldsep);
+ strcat(*buffer, pw->pw_shell); strcat(*buffer, fieldsep);
+
+ return (0);
+}
+
+/*%
+ * int irp_unmarshall_pw(struct passwd *pw, char *buffer)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure
+ *
+ */
+
+int
+irp_unmarshall_pw(struct passwd *pw, char *buffer) {
+ char *name, *pass, *class, *gecos, *dir, *shell;
+ uid_t pwuid;
+ gid_t pwgid;
+ time_t pwchange;
+ time_t pwexpire;
+ char *p;
+ long t;
+ char tmpbuf[24];
+ char *tb = &tmpbuf[0];
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ name = pass = class = gecos = dir = shell = NULL;
+ p = buffer;
+
+ /* pw_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
+ goto error;
+ }
+
+ /* pw_passwd field */
+ pass = NULL;
+ if (getfield(&pass, 0, &p, fieldsep) == NULL) { /*%< field can be empty */
+ goto error;
+ }
+
+
+ /* pw_uid field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ pwuid = (uid_t)t;
+ if ((long) pwuid != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+
+ /* pw_gid field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ pwgid = (gid_t)t;
+ if ((long)pwgid != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+
+ /* pw_class field */
+ class = NULL;
+ if (getfield(&class, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+
+
+ /* pw_change field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ pwchange = (time_t)t;
+ if ((long)pwchange != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+
+ /* pw_expire field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ pwexpire = (time_t)t;
+ if ((long) pwexpire != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+
+ /* pw_gecos field */
+ gecos = NULL;
+ if (getfield(&gecos, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+
+
+ /* pw_dir field */
+ dir = NULL;
+ if (getfield(&dir, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+
+
+ /* pw_shell field */
+ shell = NULL;
+ if (getfield(&shell, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+
+
+ pw->pw_name = name;
+ pw->pw_passwd = pass;
+ pw->pw_uid = pwuid;
+ pw->pw_gid = pwgid;
+ pw->pw_gecos = gecos;
+ pw->pw_dir = dir;
+ pw->pw_shell = shell;
+
+#ifdef HAVE_PW_CHANGE
+ pw->pw_change = pwchange;
+#endif
+#ifdef HAVE_PW_CLASS
+ pw->pw_class = class;
+#endif
+#ifdef HAVE_PW_EXPIRE
+ pw->pw_expire = pwexpire;
+#endif
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ if (pass != NULL) free(pass);
+ if (gecos != NULL) free(gecos);
+ if (dir != NULL) free(dir);
+ if (shell != NULL) free(shell);
+
+ return (-1);
+}
+
+/* ------------------------- struct passwd ------------------------- */
+#endif /* WANT_IRS_PW */
+/* +++++++++++++++++++++++++ struct group +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_gr(const struct group *gr, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h.
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure
+ */
+
+int
+irp_marshall_gr(const struct group *gr, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char grGid[24];
+ const char *fieldsep = COLONSTR;
+
+ if (gr == NULL || len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sprintf(grGid, "%ld", (long)gr->gr_gid);
+
+ need += strlen(gr->gr_name) + 1;
+#ifndef MISSING_GR_PASSWD
+ need += strlen(gr->gr_passwd) + 1;
+#else
+ need++;
+#endif
+ need += strlen(grGid) + 1;
+ need += joinlength(gr->gr_mem) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, gr->gr_name); strcat(*buffer, fieldsep);
+#ifndef MISSING_GR_PASSWD
+ strcat(*buffer, gr->gr_passwd);
+#endif
+ strcat(*buffer, fieldsep);
+ strcat(*buffer, grGid); strcat(*buffer, fieldsep);
+ joinarray(gr->gr_mem, *buffer, COMMA) ; strcat(*buffer, fieldsep);
+
+ return (0);
+}
+
+/*%
+ * int irp_unmarshall_gr(struct group *gr, char *buffer)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_gr(struct group *gr, char *buffer) {
+ char *p, *q;
+ gid_t grgid;
+ long t;
+ char *name = NULL;
+ char *pass = NULL;
+ char **members = NULL;
+ char tmpbuf[24];
+ char *tb;
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ if (gr == NULL || buffer == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ p = buffer;
+
+ /* gr_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* gr_passwd field */
+ pass = NULL;
+ if (getfield(&pass, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+
+ /* gr_gid field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ grgid = (gid_t)t;
+ if ((long) grgid != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+ /* gr_mem field. Member names are separated by commas */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ members = splitarray(p, q, COMMA);
+ if (members == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ gr->gr_name = name;
+#ifndef MISSING_GR_PASSWD
+ gr->gr_passwd = pass;
+#endif
+ gr->gr_gid = grgid;
+ gr->gr_mem = members;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ if (pass != NULL) free(pass);
+
+ return (-1);
+}
+
+
+/* ------------------------- struct group ------------------------- */
+
+
+
+
+/* +++++++++++++++++++++++++ struct servent +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char svPort[24];
+ const char *fieldsep = COLONSTR;
+ short realport;
+
+ if (sv == NULL || len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* the int s_port field is actually a short in network order. We
+ want host order to make the marshalled data look correct */
+ realport = ntohs((short)sv->s_port);
+ sprintf(svPort, "%d", realport);
+
+ need += strlen(sv->s_name) + 1;
+ need += joinlength(sv->s_aliases) + 1;
+ need += strlen(svPort) + 1;
+ need += strlen(sv->s_proto) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, sv->s_name); strcat(*buffer, fieldsep);
+ joinarray(sv->s_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
+ strcat(*buffer, svPort); strcat(*buffer, fieldsep);
+ strcat(*buffer, sv->s_proto); strcat(*buffer, fieldsep);
+
+ return (0);
+}
+
+/*%
+ * int irp_unmarshall_sv(struct servent *sv, char *buffer)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_sv(struct servent *sv, char *buffer) {
+ char *p, *q;
+ short svport;
+ long t;
+ char *name = NULL;
+ char *proto = NULL;
+ char **aliases = NULL;
+ char tmpbuf[24];
+ char *tb;
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ if (sv == NULL || buffer == NULL)
+ return (-1);
+
+ p = buffer;
+
+
+ /* s_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* s_aliases field */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ aliases = splitarray(p, q, COMMA);
+ if (aliases == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ /* s_port field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ svport = (short)t;
+ if ((long) svport != t) { /*%< value must have been too big. */
+ goto error;
+ }
+ svport = htons(svport);
+
+ /* s_proto field */
+ proto = NULL;
+ if (getfield(&proto, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+ sv->s_name = name;
+ sv->s_aliases = aliases;
+ sv->s_port = svport;
+ sv->s_proto = proto;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ if (proto != NULL) free(proto);
+ free_array(aliases, 0);
+
+ return (-1);
+}
+
+
+/* ------------------------- struct servent ------------------------- */
+
+/* +++++++++++++++++++++++++ struct protoent +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char prProto[24];
+ const char *fieldsep = COLONSTR;
+
+ if (pr == NULL || len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sprintf(prProto, "%d", (int)pr->p_proto);
+
+ need += strlen(pr->p_name) + 1;
+ need += joinlength(pr->p_aliases) + 1;
+ need += strlen(prProto) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, pr->p_name); strcat(*buffer, fieldsep);
+ joinarray(pr->p_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
+ strcat(*buffer, prProto); strcat(*buffer, fieldsep);
+
+ return (0);
+
+}
+
+/*%
+ * int irp_unmarshall_pr(struct protoent *pr, char *buffer)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure
+ *
+ */
+
+int irp_unmarshall_pr(struct protoent *pr, char *buffer) {
+ char *p, *q;
+ int prproto;
+ long t;
+ char *name = NULL;
+ char **aliases = NULL;
+ char tmpbuf[24];
+ char *tb;
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ if (pr == NULL || buffer == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ p = buffer;
+
+ /* p_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* p_aliases field */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ aliases = splitarray(p, q, COMMA);
+ if (aliases == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ /* p_proto field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ prproto = (int)t;
+ if ((long) prproto != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+ pr->p_name = name;
+ pr->p_aliases = aliases;
+ pr->p_proto = prproto;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ free_array(aliases, 0);
+
+ return (-1);
+}
+
+/* ------------------------- struct protoent ------------------------- */
+
+
+
+/* +++++++++++++++++++++++++ struct hostent +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h.
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char hoaddrtype[24];
+ char holength[24];
+ char **av;
+ char *p;
+ int addrlen;
+ int malloced = 0;
+ size_t remlen;
+ const char *fieldsep = "@";
+
+ if (ho == NULL || len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch(ho->h_addrtype) {
+ case AF_INET:
+ strcpy(hoaddrtype, "AF_INET");
+ break;
+
+ case AF_INET6:
+ strcpy(hoaddrtype, "AF_INET6");
+ break;
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sprintf(holength, "%d", ho->h_length);
+
+ need += strlen(ho->h_name) + 1;
+ need += joinlength(ho->h_aliases) + 1;
+ need += strlen(hoaddrtype) + 1;
+ need += strlen(holength) + 1;
+
+ /* we determine an upper bound on the string length needed, not an
+ exact length. */
+ addrlen = (ho->h_addrtype == AF_INET ? 16 : 46) ; /*%< XX other AF's?? */
+ for (av = ho->h_addr_list; av != NULL && *av != NULL ; av++)
+ need += addrlen;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ malloced = 1;
+ }
+
+ strcpy(*buffer, ho->h_name); strcat(*buffer, fieldsep);
+ joinarray(ho->h_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
+ strcat(*buffer, hoaddrtype); strcat(*buffer, fieldsep);
+ strcat(*buffer, holength); strcat(*buffer, fieldsep);
+
+ p = *buffer + strlen(*buffer);
+ remlen = need - strlen(*buffer);
+ for (av = ho->h_addr_list ; av != NULL && *av != NULL ; av++) {
+ if (inet_ntop(ho->h_addrtype, *av, p, remlen) == NULL) {
+ goto error;
+ }
+ if (*(av + 1) != NULL)
+ strcat(p, COMMASTR);
+ remlen -= strlen(p);
+ p += strlen(p);
+ }
+ strcat(*buffer, fieldsep);
+
+ return (0);
+
+ error:
+ if (malloced) {
+ memput(*buffer, need);
+ }
+
+ return (-1);
+}
+
+/*%
+ * int irp_unmarshall_ho(struct hostent *ho, char *buffer)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h.
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_ho(struct hostent *ho, char *buffer) {
+ char *p, *q, *r;
+ int hoaddrtype;
+ int holength;
+ long t;
+ char *name;
+ char **aliases = NULL;
+ char **hohaddrlist = NULL;
+ size_t hoaddrsize;
+ char tmpbuf[24];
+ char *tb;
+ char **alist;
+ int addrcount;
+ char fieldsep = '@';
+ int myerrno = EINVAL;
+
+ if (ho == NULL || buffer == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ p = buffer;
+
+ /* h_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* h_aliases field */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ aliases = splitarray(p, q, COMMA);
+ if (aliases == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ /* h_addrtype field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ if (strcmp(tmpbuf, "AF_INET") == 0)
+ hoaddrtype = AF_INET;
+ else if (strcmp(tmpbuf, "AF_INET6") == 0)
+ hoaddrtype = AF_INET6;
+ else
+ goto error;
+
+
+ /* h_length field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ holength = (int)t;
+ if ((long) holength != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+ /* h_addr_list field */
+ q = strchr(p, fieldsep);
+ if (q == NULL)
+ goto error;
+
+ /* count how many addresss are in there */
+ if (q > p + 1) {
+ for (addrcount = 1, r = p ; r != q ; r++) {
+ if (*r == COMMA)
+ addrcount++;
+ }
+ } else {
+ addrcount = 0;
+ }
+
+ hoaddrsize = (addrcount + 1) * sizeof (char *);
+ hohaddrlist = malloc(hoaddrsize);
+ if (hohaddrlist == NULL) {
+ myerrno = ENOMEM;
+ goto error;
+ }
+
+ memset(hohaddrlist, 0x0, hoaddrsize);
+
+ alist = hohaddrlist;
+ for (t = 0, r = p ; r != q ; p = r + 1, t++) {
+ char saved;
+ while (r != q && *r != COMMA) r++;
+ saved = *r;
+ *r = 0x0;
+
+ alist[t] = malloc(hoaddrtype == AF_INET ? 4 : 16);
+ if (alist[t] == NULL) {
+ myerrno = ENOMEM;
+ goto error;
+ }
+
+ if (inet_pton(hoaddrtype, p, alist[t]) == -1)
+ goto error;
+ *r = saved;
+ }
+ alist[t] = NULL;
+
+ ho->h_name = name;
+ ho->h_aliases = aliases;
+ ho->h_addrtype = hoaddrtype;
+ ho->h_length = holength;
+ ho->h_addr_list = hohaddrlist;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ free_array(hohaddrlist, 0);
+ free_array(aliases, 0);
+
+ return (-1);
+}
+
+/* ------------------------- struct hostent------------------------- */
+
+
+
+/* +++++++++++++++++++++++++ struct netgrp +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_ng(const char *host, const char *user,
+ * const char *domain, char *buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See note for irp_marshall_ng_start
+ *
+ * return: \li
+ *
+ * 0 on success, 0 on failure.
+ *
+ */
+
+int
+irp_marshall_ng(const char *host, const char *user, const char *domain,
+ char **buffer, size_t *len) {
+ size_t need = 1; /*%< for nul byte */
+ const char *fieldsep = ",";
+
+ if (len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ need += 4; /*%< two parens and two commas */
+ need += (host == NULL ? 0 : strlen(host));
+ need += (user == NULL ? 0 : strlen(user));
+ need += (domain == NULL ? 0 : strlen(domain));
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ } else if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ (*buffer)[0] = '(';
+ (*buffer)[1] = '\0';
+
+ if (host != NULL)
+ strcat(*buffer, host);
+ strcat(*buffer, fieldsep);
+
+ if (user != NULL)
+ strcat(*buffer, user);
+ strcat(*buffer, fieldsep);
+
+ if (domain != NULL)
+ strcat(*buffer, domain);
+ strcat(*buffer, ")");
+
+ return (0);
+}
+
+
+
+/* ---------- */
+
+/*%
+ * int irp_unmarshall_ng(const char **host, const char **user,
+ * const char **domain, char *buffer)
+ *
+ * notes: \li
+ *
+ * Unpacks the BUFFER into 3 character arrays it allocates and assigns
+ * to *HOST, *USER and *DOMAIN. If any field of the value is empty,
+ * then the corresponding paramater value will be set to NULL.
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ */
+
+int
+irp_unmarshall_ng(const char **hostp, const char **userp, const char **domainp,
+ char *buffer)
+{
+ char *p, *q;
+ char fieldsep = ',';
+ int myerrno = EINVAL;
+ char *host, *user, *domain;
+
+ if (userp == NULL || hostp == NULL ||
+ domainp == NULL || buffer == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ host = user = domain = NULL;
+
+ p = buffer;
+ while (isspace((unsigned char)*p)) {
+ p++;
+ }
+ if (*p != '(') {
+ goto error;
+ }
+
+ q = p + 1;
+ while (*q && *q != fieldsep)
+ q++;
+ if (!*q) {
+ goto error;
+ } else if (q > p + 1) {
+ host = strndup(p, q - p);
+ }
+
+ p = q + 1;
+ if (!*p) {
+ goto error;
+ } else if (*p != fieldsep) {
+ q = p + 1;
+ while (*q && *q != fieldsep)
+ q++;
+ if (!*q) {
+ goto error;
+ }
+ user = strndup(p, q - p);
+ } else {
+ p++;
+ }
+
+ if (!*p) {
+ goto error;
+ } else if (*p != ')') {
+ q = p + 1;
+ while (*q && *q != ')')
+ q++;
+ if (!*q) {
+ goto error;
+ }
+ domain = strndup(p, q - p);
+ }
+ *hostp = host;
+ *userp = user;
+ *domainp = domain;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (host != NULL) free(host);
+ if (user != NULL) free(user);
+
+ return (-1);
+}
+
+/* ------------------------- struct netgrp ------------------------- */
+
+
+
+
+/* +++++++++++++++++++++++++ struct nwent +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See at top.
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char nAddrType[24];
+ char nNet[MAXPADDRSIZE];
+ const char *fieldsep = COLONSTR;
+
+ if (ne == NULL || len == NULL) {
+ return (-1);
+ }
+
+ strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype));
+
+ if (inet_net_ntop(ne->n_addrtype, ne->n_addr, ne->n_length,
+ nNet, sizeof nNet) == NULL) {
+ return (-1);
+ }
+
+
+ need += strlen(ne->n_name) + 1;
+ need += joinlength(ne->n_aliases) + 1;
+ need += strlen(nAddrType) + 1;
+ need += strlen(nNet) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, ne->n_name); strcat(*buffer, fieldsep);
+ joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep);
+ strcat(*buffer, nAddrType); strcat(*buffer, fieldsep);
+ strcat(*buffer, nNet); strcat(*buffer, fieldsep);
+
+ return (0);
+}
+
+/*%
+ * int irp_unmarshall_nw(struct nwent *ne, char *buffer)
+ *
+ * notes: \li
+ *
+ * See note up top.
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_nw(struct nwent *ne, char *buffer) {
+ char *p, *q;
+ int naddrtype;
+ long nnet;
+ int bits;
+ char *name = NULL;
+ char **aliases = NULL;
+ char tmpbuf[24];
+ char *tb;
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ if (ne == NULL || buffer == NULL) {
+ goto error;
+ }
+
+ p = buffer;
+
+ /* n_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* n_aliases field. Aliases are separated by commas */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ aliases = splitarray(p, q, COMMA);
+ if (aliases == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ /* h_addrtype field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ if (strcmp(tmpbuf, "AF_INET") == 0)
+ naddrtype = AF_INET;
+ else if (strcmp(tmpbuf, "AF_INET6") == 0)
+ naddrtype = AF_INET6;
+ else
+ goto error;
+
+
+ /* n_net field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ nnet = 0;
+ bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet);
+ if (bits < 0) {
+ goto error;
+ }
+
+ /* nnet = ntohl(nnet); */ /* keep in network order for nwent */
+
+ ne->n_name = name;
+ ne->n_aliases = aliases;
+ ne->n_addrtype = naddrtype;
+ ne->n_length = bits;
+ ne->n_addr = malloc(sizeof nnet);
+ if (ne->n_addr == NULL) {
+ goto error;
+ }
+
+ memcpy(ne->n_addr, &nnet, sizeof nnet);
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ free_array(aliases, 0);
+
+ return (-1);
+}
+
+
+/* ------------------------- struct nwent ------------------------- */
+
+
+/* +++++++++++++++++++++++++ struct netent +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_ne(struct netent *ne, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See at top.
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_marshall_ne(struct netent *ne, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char nAddrType[24];
+ char nNet[MAXPADDRSIZE];
+ const char *fieldsep = COLONSTR;
+ long nval;
+
+ if (ne == NULL || len == NULL) {
+ return (-1);
+ }
+
+ strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype));
+
+ nval = htonl(ne->n_net);
+ if (inet_ntop(ne->n_addrtype, &nval, nNet, sizeof nNet) == NULL) {
+ return (-1);
+ }
+
+ need += strlen(ne->n_name) + 1;
+ need += joinlength(ne->n_aliases) + 1;
+ need += strlen(nAddrType) + 1;
+ need += strlen(nNet) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, ne->n_name); strcat(*buffer, fieldsep);
+ joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep);
+ strcat(*buffer, nAddrType); strcat(*buffer, fieldsep);
+ strcat(*buffer, nNet); strcat(*buffer, fieldsep);
+
+ return (0);
+}
+
+/*%
+ * int irp_unmarshall_ne(struct netent *ne, char *buffer)
+ *
+ * notes: \li
+ *
+ * See note up top.
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_ne(struct netent *ne, char *buffer) {
+ char *p, *q;
+ int naddrtype;
+ long nnet;
+ int bits;
+ char *name = NULL;
+ char **aliases = NULL;
+ char tmpbuf[24];
+ char *tb;
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ if (ne == NULL || buffer == NULL) {
+ goto error;
+ }
+
+ p = buffer;
+
+ /* n_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* n_aliases field. Aliases are separated by commas */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ aliases = splitarray(p, q, COMMA);
+ if (aliases == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ /* h_addrtype field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ if (strcmp(tmpbuf, "AF_INET") == 0)
+ naddrtype = AF_INET;
+ else if (strcmp(tmpbuf, "AF_INET6") == 0)
+ naddrtype = AF_INET6;
+ else
+ goto error;
+
+
+ /* n_net field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet);
+ if (bits < 0) {
+ goto error;
+ }
+ nnet = ntohl(nnet);
+
+ ne->n_name = name;
+ ne->n_aliases = aliases;
+ ne->n_addrtype = naddrtype;
+ ne->n_net = nnet;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ free_array(aliases, 0);
+
+ return (-1);
+}
+
+
+/* ------------------------- struct netent ------------------------- */
+
+
+/* =========================================================================== */
+
+/*%
+ * static char ** splitarray(const char *buffer, const char *buffend, char delim)
+ *
+ * notes: \li
+ *
+ * Split a delim separated astring. Not allowed
+ * to have two delims next to each other. BUFFER points to begining of
+ * string, BUFFEND points to one past the end of the string
+ * (i.e. points at where the null byte would be if null
+ * terminated).
+ *
+ * return: \li
+ *
+ * Returns a malloced array of pointers, each pointer pointing to a
+ * malloced string. If BUFEER is an empty string, then return values is
+ * array of 1 pointer that is NULL. Returns NULL on failure.
+ *
+ */
+
+static char **
+splitarray(const char *buffer, const char *buffend, char delim) {
+ const char *p, *q;
+ int count = 0;
+ char **arr = NULL;
+ char **aptr;
+
+ if (buffend < buffer)
+ return (NULL);
+ else if (buffend > buffer && *buffer == delim)
+ return (NULL);
+ else if (buffend > buffer && *(buffend - 1) == delim)
+ return (NULL);
+
+ /* count the number of field and make sure none are empty */
+ if (buffend > buffer + 1) {
+ for (count = 1, q = buffer ; q != buffend ; q++) {
+ if (*q == delim) {
+ if (q > buffer && (*(q - 1) == delim)) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ count++;
+ }
+ }
+ }
+
+ if (count > 0) {
+ count++ ; /*%< for NULL at end */
+ aptr = arr = malloc(count * sizeof (char *));
+ if (aptr == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ memset(arr, 0x0, count * sizeof (char *));
+ for (p = buffer ; p < buffend ; p++) {
+ for (q = p ; *q != delim && q != buffend ; q++)
+ /* nothing */;
+ *aptr = strndup(p, q - p);
+
+ p = q;
+ aptr++;
+ }
+ *aptr = NULL;
+ } else {
+ arr = malloc(sizeof (char *));
+ if (arr == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ *arr = NULL;
+ }
+
+ return (arr);
+}
+
+/*%
+ * static size_t joinlength(char * const *argv)
+ *
+ * return: \li
+ *
+ * the number of bytes in all the arrays pointed at
+ * by argv, including their null bytes(which will usually be turned
+ * into commas).
+ *
+ *
+ */
+
+static size_t
+joinlength(char * const *argv) {
+ int len = 0;
+
+ while (argv && *argv) {
+ len += (strlen(*argv) + 1);
+ argv++;
+ }
+
+ return (len);
+}
+
+/*%
+ * int joinarray(char * const *argv, char *buffer, char delim)
+ *
+ * notes: \li
+ *
+ * Copy all the ARGV strings into the end of BUFFER
+ * separating them with DELIM. BUFFER is assumed to have
+ * enough space to hold everything and to be already null-terminated.
+ *
+ * return: \li
+ *
+ * 0 unless argv or buffer is NULL.
+ *
+ *
+ */
+
+static int
+joinarray(char * const *argv, char *buffer, char delim) {
+ char * const *p;
+ char sep[2];
+
+ if (argv == NULL || buffer == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sep[0] = delim;
+ sep[1] = 0x0;
+
+ for (p = argv ; *p != NULL ; p++) {
+ strcat(buffer, *p);
+ if (*(p + 1) != NULL) {
+ strcat(buffer, sep);
+ }
+ }
+
+ return (0);
+}
+
+/*%
+ * static char * getfield(char **res, size_t reslen, char **ptr, char delim)
+ *
+ * notes: \li
+ *
+ * Stores in *RES, which is a buffer of length RESLEN, a
+ * copy of the bytes from *PTR up to and including the first
+ * instance of DELIM. If *RES is NULL, then it will be
+ * assigned a malloced buffer to hold the copy. *PTR is
+ * modified to point at the found delimiter.
+ *
+ * return: \li
+ *
+ * If there was no delimiter, then NULL is returned,
+ * otherewise *RES is returned.
+ *
+ */
+
+static char *
+getfield(char **res, size_t reslen, char **ptr, char delim) {
+ char *q;
+
+ if (res == NULL || ptr == NULL || *ptr == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ q = strchr(*ptr, delim);
+
+ if (q == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ } else {
+ if (*res == NULL) {
+ *res = strndup(*ptr, q - *ptr);
+ } else {
+ if ((size_t)(q - *ptr + 1) > reslen) { /*%< to big for res */
+ errno = EINVAL;
+ return (NULL);
+ } else {
+ strncpy(*res, *ptr, q - *ptr);
+ (*res)[q - *ptr] = 0x0;
+ }
+ }
+ *ptr = q + 1;
+ }
+
+ return (*res);
+}
+
+
+
+
+
+#ifndef HAVE_STRNDUP
+/*
+ * static char * strndup(const char *str, size_t len)
+ *
+ * notes: \li
+ *
+ * like strdup, except do len bytes instead of the whole string. Always
+ * null-terminates.
+ *
+ * return: \li
+ *
+ * The newly malloced string.
+ *
+ */
+
+static char *
+strndup(const char *str, size_t len) {
+ char *p = malloc(len + 1);
+
+ if (p == NULL)
+ return (NULL);
+ strncpy(p, str, len);
+ p[len] = 0x0;
+ return (p);
+}
+#endif
+
+#if WANT_MAIN
+
+/*%
+ * static int strcmp_nws(const char *a, const char *b)
+ *
+ * notes: \li
+ *
+ * do a strcmp, except uneven lengths of whitespace compare the same
+ *
+ * return: \li
+ *
+ */
+
+static int
+strcmp_nws(const char *a, const char *b) {
+ while (*a && *b) {
+ if (isspace(*a) && isspace(*b)) {
+ do {
+ a++;
+ } while (isspace(*a));
+ do {
+ b++;
+ } while (isspace(*b));
+ }
+ if (*a < *b)
+ return (-1);
+ else if (*a > *b)
+ return (1);
+
+ a++;
+ b++;;
+ }
+
+ if (*a == *b)
+ return (0);
+ else if (*a > *b)
+ return (1);
+ else
+ return (-1);
+}
+
+#endif
+
+/*%
+ * static void free_array(char **argv, size_t entries)
+ *
+ * notes: \li
+ *
+ * Free argv and each of the pointers inside it. The end of
+ * the array is when a NULL pointer is found inside. If
+ * entries is > 0, then NULL pointers inside the array do
+ * not indicate the end of the array.
+ *
+ */
+
+static void
+free_array(char **argv, size_t entries) {
+ char **p = argv;
+ int useEntries = (entries > 0U);
+
+ if (argv == NULL)
+ return;
+
+ while ((useEntries && entries > 0U) || *p) {
+ if (*p)
+ free(*p);
+ p++;
+ if (useEntries)
+ entries--;
+ }
+ free(argv);
+}
+
+
+
+
+
+/* ************************************************** */
+
+#if WANT_MAIN
+
+/*% takes an option to indicate what sort of marshalling(read the code) and
+ an argument. If the argument looks like a marshalled buffer(has a ':'
+ embedded) then it's unmarshalled and the remarshalled and the new string
+ is compared to the old one.
+*/
+
+int
+main(int argc, char **argv) {
+ char buffer[1024];
+ char *b = &buffer[0];
+ size_t len = sizeof buffer;
+ char option;
+
+ if (argc < 2 || argv[1][0] != '-')
+ exit(1);
+
+ option = argv[1][1];
+ argv++;
+ argc--;
+
+
+#if 0
+ {
+ char buff[10];
+ char *p = argv[1], *q = &buff[0];
+
+ while (getfield(&q, sizeof buff, &p, ':') != NULL) {
+ printf("field: \"%s\"\n", q);
+ p++;
+ }
+ printf("p is now \"%s\"\n", p);
+ }
+#endif
+
+#if 0
+ {
+ char **x = splitarray(argv[1], argv[1] + strlen(argv[1]),
+ argv[2][0]);
+ char **p;
+
+ if (x == NULL)
+ printf("split failed\n");
+
+ for (p = x ; p != NULL && *p != NULL ; p++) {
+ printf("\"%s\"\n", *p);
+ }
+ }
+#endif
+
+#if 1
+ switch(option) {
+ case 'n': {
+ struct nwent ne;
+ int i;
+
+ if (strchr(argv[1], ':') != NULL) {
+ if (irp_unmarshall_nw(&ne, argv[1]) != 0) {
+ printf("Unmarhsalling failed\n");
+ exit(1);
+ }
+
+ printf("Name: \"%s\"\n", ne.n_name);
+ printf("Aliases:");
+ for (i = 0 ; ne.n_aliases[i] != NULL ; i++)
+ printf("\n\t\"%s\"", ne.n_aliases[i]);
+ printf("\nAddrtype: %s\n", ADDR_T_STR(ne.n_addrtype));
+ inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length,
+ buffer, sizeof buffer);
+ printf("Net: \"%s\"\n", buffer);
+ *((long*)ne.n_addr) = htonl(*((long*)ne.n_addr));
+ inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length,
+ buffer, sizeof buffer);
+ printf("Corrected Net: \"%s\"\n", buffer);
+ } else {
+ struct netent *np1 = getnetbyname(argv[1]);
+ ne.n_name = np1->n_name;
+ ne.n_aliases = np1->n_aliases;
+ ne.n_addrtype = np1->n_addrtype;
+ ne.n_addr = &np1->n_net;
+ ne.n_length = (IN_CLASSA(np1->n_net) ?
+ 8 :
+ (IN_CLASSB(np1->n_net) ?
+ 16 :
+ (IN_CLASSC(np1->n_net) ?
+ 24 : -1)));
+ np1->n_net = htonl(np1->n_net);
+ if (irp_marshall_nw(&ne, &b, &len) != 0) {
+ printf("Marshalling failed\n");
+ }
+ printf("%s\n", b);
+ }
+ break;
+ }
+
+
+ case 'r': {
+ char **hosts, **users, **domains;
+ size_t entries;
+ int i;
+ char *buff;
+ size_t size;
+ char *ngname;
+
+ if (strchr(argv[1], '(') != NULL) {
+ if (irp_unmarshall_ng(&ngname, &entries,
+ &hosts, &users, &domains,
+ argv[1]) != 0) {
+ printf("unmarshall failed\n");
+ exit(1);
+ }
+
+#define STRVAL(x) (x == NULL ? "*" : x)
+
+ printf("%s {\n", ngname);
+ for (i = 0 ; i < entries ; i++)
+ printf("\t\"%s\" : \"%s\" : \"%s\"\n",
+ STRVAL(hosts[i]),
+ STRVAL(users[i]),
+ STRVAL(domains[i]));
+ printf("}\n\n\n");
+
+
+ irp_marshall_ng_start(ngname, NULL, &size);
+ for (i = 0 ; i < entries ; i++)
+ irp_marshall_ng_next(hosts[i], users[i],
+ domains[i], NULL, &size);
+ irp_marshall_ng_end(NULL, &size);
+
+ buff = malloc(size);
+
+ irp_marshall_ng_start(ngname, buff, &size);
+ for (i = 0 ; i < entries ; i++) {
+ if (irp_marshall_ng_next(hosts[i], users[i],
+ domains[i], buff,
+ &size) != 0)
+ printf("next marshalling failed.\n");
+ }
+ irp_marshall_ng_end(buff, &size);
+
+ if (strcmp_nws(argv[1], buff) != 0) {
+ printf("compare failed:\n\t%s\n\t%s\n",
+ buffer, argv[1]);
+ } else {
+ printf("compare ok\n");
+ }
+ } else {
+ char *h, *u, *d, *buff;
+ size_t size;
+
+ /* run through two times. First to figure out how
+ much of a buffer we need. Second to do the
+ actual marshalling */
+
+ setnetgrent(argv[1]);
+ irp_marshall_ng_start(argv[1], NULL, &size);
+ while (getnetgrent(&h, &u, &d) == 1)
+ irp_marshall_ng_next(h, u, d, NULL, &size);
+ irp_marshall_ng_end(NULL, &size);
+ endnetgrent(argv[1]);
+
+ buff = malloc(size);
+
+ setnetgrent(argv[1]);
+ if (irp_marshall_ng_start(argv[1], buff, &size) != 0)
+ printf("Marshalling start failed\n");
+
+ while (getnetgrent(&h, &u, &d) == 1) {
+ if (irp_marshall_ng_next(h, u, d, buff, &size)
+ != 0) {
+ printf("Marshalling failed\n");
+ }
+ }
+
+ irp_marshall_ng_end(buff, &size);
+ endnetgrent();
+
+ printf("success: %s\n", buff);
+ }
+ break;
+ }
+
+
+
+ case 'h': {
+ struct hostent he, *hp;
+ int i;
+
+
+ if (strchr(argv[1], '@') != NULL) {
+ if (irp_unmarshall_ho(&he, argv[1]) != 0) {
+ printf("unmarshall failed\n");
+ exit(1);
+ }
+
+ printf("Host: \"%s\"\nAliases:", he.h_name);
+ for (i = 0 ; he.h_aliases[i] != NULL ; i++)
+ printf("\n\t\t\"%s\"", he.h_aliases[i]);
+ printf("\nAddr Type: \"%s\"\n",
+ ADDR_T_STR(he.h_addrtype));
+ printf("Length: %d\nAddresses:", he.h_length);
+ for (i = 0 ; he.h_addr_list[i] != 0 ; i++) {
+ inet_ntop(he.h_addrtype, he.h_addr_list[i],
+ buffer, sizeof buffer);
+ printf("\n\t\"%s\"\n", buffer);
+ }
+ printf("\n\n");
+
+ irp_marshall_ho(&he, &b, &len);
+ if (strcmp(argv[1], buffer) != 0) {
+ printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+ buffer, argv[1]);
+ } else {
+ printf("compare ok\n");
+ }
+ } else {
+ if ((hp = gethostbyname(argv[1])) == NULL) {
+ perror("gethostbyname");
+ printf("\"%s\"\n", argv[1]);
+ exit(1);
+ }
+
+ if (irp_marshall_ho(hp, &b, &len) != 0) {
+ printf("irp_marshall_ho failed\n");
+ exit(1);
+ }
+
+ printf("success: \"%s\"\n", buffer);
+ }
+ break;
+ }
+
+
+ case 's': {
+ struct servent *sv;
+ struct servent sv1;
+
+ if (strchr(argv[1], ':') != NULL) {
+ sv = &sv1;
+ memset(sv, 0xef, sizeof (struct servent));
+ if (irp_unmarshall_sv(sv, argv[1]) != 0) {
+ printf("unmarshall failed\n");
+
+ }
+
+ irp_marshall_sv(sv, &b, &len);
+ if (strcmp(argv[1], buffer) != 0) {
+ printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+ buffer, argv[1]);
+ } else {
+ printf("compare ok\n");
+ }
+ } else {
+ if ((sv = getservbyname(argv[1], argv[2])) == NULL) {
+ perror("getservent");
+ exit(1);
+ }
+
+ if (irp_marshall_sv(sv, &b, &len) != 0) {
+ printf("irp_marshall_sv failed\n");
+ exit(1);
+ }
+
+ printf("success: \"%s\"\n", buffer);
+ }
+ break;
+ }
+
+ case 'g': {
+ struct group *gr;
+ struct group gr1;
+
+ if (strchr(argv[1], ':') != NULL) {
+ gr = &gr1;
+ memset(gr, 0xef, sizeof (struct group));
+ if (irp_unmarshall_gr(gr, argv[1]) != 0) {
+ printf("unmarshall failed\n");
+
+ }
+
+ irp_marshall_gr(gr, &b, &len);
+ if (strcmp(argv[1], buffer) != 0) {
+ printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+ buffer, argv[1]);
+ } else {
+ printf("compare ok\n");
+ }
+ } else {
+ if ((gr = getgrnam(argv[1])) == NULL) {
+ perror("getgrnam");
+ exit(1);
+ }
+
+ if (irp_marshall_gr(gr, &b, &len) != 0) {
+ printf("irp_marshall_gr failed\n");
+ exit(1);
+ }
+
+ printf("success: \"%s\"\n", buffer);
+ }
+ break;
+ }
+
+
+ case 'p': {
+ struct passwd *pw;
+ struct passwd pw1;
+
+ if (strchr(argv[1], ':') != NULL) {
+ pw = &pw1;
+ memset(pw, 0xef, sizeof (*pw));
+ if (irp_unmarshall_pw(pw, argv[1]) != 0) {
+ printf("unmarshall failed\n");
+ exit(1);
+ }
+
+ printf("User: \"%s\"\nPasswd: \"%s\"\nUid: %ld\nGid: %ld\n",
+ pw->pw_name, pw->pw_passwd, (long)pw->pw_uid,
+ (long)pw->pw_gid);
+ printf("Class: \"%s\"\nChange: %ld\nGecos: \"%s\"\n",
+ pw->pw_class, (long)pw->pw_change, pw->pw_gecos);
+ printf("Shell: \"%s\"\nDirectory: \"%s\"\n",
+ pw->pw_shell, pw->pw_dir);
+
+ pw = getpwnam(pw->pw_name);
+ irp_marshall_pw(pw, &b, &len);
+ if (strcmp(argv[1], buffer) != 0) {
+ printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+ buffer, argv[1]);
+ } else {
+ printf("compare ok\n");
+ }
+ } else {
+ if ((pw = getpwnam(argv[1])) == NULL) {
+ perror("getpwnam");
+ exit(1);
+ }
+
+ if (irp_marshall_pw(pw, &b, &len) != 0) {
+ printf("irp_marshall_pw failed\n");
+ exit(1);
+ }
+
+ printf("success: \"%s\"\n", buffer);
+ }
+ break;
+ }
+
+ default:
+ printf("Wrong option: %c\n", option);
+ break;
+ }
+
+#endif
+
+ return (0);
+}
+
+#endif
+
+/*! \file */
diff --git a/lib/bind/irs/irs_data.c b/lib/bind/irs/irs_data.c
new file mode 100644
index 0000000..ed94614
--- /dev/null
+++ b/lib/bind/irs/irs_data.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: irs_data.c,v 1.7.18.5 2007/08/27 03:34:24 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#ifndef __BIND_NOSTATIC
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <isc/memcluster.h>
+
+#ifdef DO_PTHREADS
+#include <pthread.h>
+#endif
+
+#include <irs.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+#undef _res
+#if !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
+#undef h_errno
+extern int h_errno;
+#endif
+
+extern struct __res_state _res;
+
+#ifdef DO_PTHREADS
+static pthread_key_t key;
+static int once = 0;
+#else
+static struct net_data *net_data;
+#endif
+
+void
+irs_destroy(void) {
+#ifndef DO_PTHREADS
+ if (net_data != NULL)
+ net_data_destroy(net_data);
+ net_data = NULL;
+#endif
+}
+
+void
+net_data_destroy(void *p) {
+ struct net_data *net_data = p;
+
+ res_ndestroy(net_data->res);
+ if (net_data->gr != NULL) {
+ (*net_data->gr->close)(net_data->gr);
+ net_data->gr = NULL;
+ }
+ if (net_data->pw != NULL) {
+ (*net_data->pw->close)(net_data->pw);
+ net_data->pw = NULL;
+ }
+ if (net_data->sv != NULL) {
+ (*net_data->sv->close)(net_data->sv);
+ net_data->sv = NULL;
+ }
+ if (net_data->pr != NULL) {
+ (*net_data->pr->close)(net_data->pr);
+ net_data->pr = NULL;
+ }
+ if (net_data->ho != NULL) {
+ (*net_data->ho->close)(net_data->ho);
+ net_data->ho = NULL;
+ }
+ if (net_data->nw != NULL) {
+ (*net_data->nw->close)(net_data->nw);
+ net_data->nw = NULL;
+ }
+ if (net_data->ng != NULL) {
+ (*net_data->ng->close)(net_data->ng);
+ net_data->ng = NULL;
+ }
+ if (net_data->ho_data != NULL) {
+ free(net_data->ho_data);
+ net_data->ho_data = NULL;
+ }
+ if (net_data->nw_data != NULL) {
+ free(net_data->nw_data);
+ net_data->nw_data = NULL;
+ }
+
+ (*net_data->irs->close)(net_data->irs);
+ memput(net_data, sizeof *net_data);
+}
+
+/*%
+ * applications that need a specific config file other than
+ * _PATH_IRS_CONF should call net_data_init directly rather than letting
+ * the various wrapper functions make the first call. - brister
+ */
+
+struct net_data *
+net_data_init(const char *conf_file) {
+#ifdef DO_PTHREADS
+#ifndef LIBBIND_MUTEX_INITIALIZER
+#define LIBBIND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#endif
+ static pthread_mutex_t keylock = LIBBIND_MUTEX_INITIALIZER;
+ struct net_data *net_data;
+
+ if (!once) {
+ if (pthread_mutex_lock(&keylock) != 0)
+ return (NULL);
+ if (!once) {
+ if (pthread_key_create(&key, net_data_destroy) != 0) {
+ (void)pthread_mutex_unlock(&keylock);
+ return (NULL);
+ }
+ once = 1;
+ }
+ if (pthread_mutex_unlock(&keylock) != 0)
+ return (NULL);
+ }
+ net_data = pthread_getspecific(key);
+#endif
+
+ if (net_data == NULL) {
+ net_data = net_data_create(conf_file);
+ if (net_data == NULL)
+ return (NULL);
+#ifdef DO_PTHREADS
+ if (pthread_setspecific(key, net_data) != 0) {
+ net_data_destroy(net_data);
+ return (NULL);
+ }
+#endif
+ }
+
+ return (net_data);
+}
+
+struct net_data *
+net_data_create(const char *conf_file) {
+ struct net_data *net_data;
+
+ net_data = memget(sizeof (struct net_data));
+ if (net_data == NULL)
+ return (NULL);
+ memset(net_data, 0, sizeof (struct net_data));
+
+ if ((net_data->irs = irs_gen_acc("", conf_file)) == NULL) {
+ memput(net_data, sizeof (struct net_data));
+ return (NULL);
+ }
+#ifndef DO_PTHREADS
+ (*net_data->irs->res_set)(net_data->irs, &_res, NULL);
+#endif
+
+ net_data->res = (*net_data->irs->res_get)(net_data->irs);
+ if (net_data->res == NULL) {
+ (*net_data->irs->close)(net_data->irs);
+ memput(net_data, sizeof (struct net_data));
+ return (NULL);
+ }
+
+ if ((net_data->res->options & RES_INIT) == 0U &&
+ res_ninit(net_data->res) == -1) {
+ (*net_data->irs->close)(net_data->irs);
+ memput(net_data, sizeof (struct net_data));
+ return (NULL);
+ }
+
+ return (net_data);
+}
+
+void
+net_data_minimize(struct net_data *net_data) {
+ res_nclose(net_data->res);
+}
+
+#ifdef _REENTRANT
+struct __res_state *
+__res_state(void) {
+ /* NULL param here means use the default config file. */
+ struct net_data *net_data = net_data_init(NULL);
+ if (net_data && net_data->res)
+ return (net_data->res);
+
+ return (&_res);
+}
+#else
+#ifdef __linux
+struct __res_state *
+__res_state(void) {
+ return (&_res);
+}
+#endif
+#endif
+
+int *
+__h_errno(void) {
+ /* NULL param here means use the default config file. */
+ struct net_data *net_data = net_data_init(NULL);
+ if (net_data && net_data->res)
+ return (&net_data->res->res_h_errno);
+#if !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
+ return(&_res.res_h_errno);
+#else
+ return (&h_errno);
+#endif
+}
+
+void
+__h_errno_set(struct __res_state *res, int err) {
+
+
+#if (__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
+ res->res_h_errno = err;
+#else
+ h_errno = res->res_h_errno = err;
+#endif
+}
+
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/lib/bind/irs/irs_data.h b/lib/bind/irs/irs_data.h
new file mode 100644
index 0000000..c1ee3dd
--- /dev/null
+++ b/lib/bind/irs/irs_data.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irs_data.h,v 1.2.18.1 2005/04/27 05:01:01 sra Exp $
+ */
+
+#ifndef __BIND_NOSTATIC
+
+#define net_data_init __net_data_init
+
+struct net_data {
+ struct irs_acc * irs;
+
+ struct irs_gr * gr;
+ struct irs_pw * pw;
+ struct irs_sv * sv;
+ struct irs_pr * pr;
+ struct irs_ho * ho;
+ struct irs_nw * nw;
+ struct irs_ng * ng;
+
+ struct group * gr_last;
+ struct passwd * pw_last;
+ struct servent * sv_last;
+ struct protoent * pr_last;
+ struct netent * nw_last; /*%< should have been ne_last */
+ struct nwent * nww_last;
+ struct hostent * ho_last;
+
+ unsigned int gr_stayopen :1;
+ unsigned int pw_stayopen :1;
+ unsigned int sv_stayopen :1;
+ unsigned int pr_stayopen :1;
+ unsigned int ho_stayopen :1;
+ unsigned int nw_stayopen :1;
+
+ void * nw_data;
+ void * ho_data;
+
+ struct __res_state * res; /*%< for gethostent.c */
+};
+
+extern struct net_data * net_data_init(const char *conf_file);
+extern void net_data_minimize(struct net_data *);
+
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/lib/bind/irs/irs_p.h b/lib/bind/irs/irs_p.h
new file mode 100644
index 0000000..bc1817b
--- /dev/null
+++ b/lib/bind/irs/irs_p.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irs_p.h,v 1.2.18.1 2005/04/27 05:01:01 sra Exp $
+ */
+
+#ifndef _IRS_P_H_INCLUDED
+#define _IRS_P_H_INCLUDED
+
+#include <stdio.h>
+
+#include "pathnames.h"
+
+#define IRS_SV_MAXALIASES 35
+
+struct lcl_sv {
+ FILE * fp;
+ char line[BUFSIZ+1];
+ struct servent serv;
+ char * serv_aliases[IRS_SV_MAXALIASES];
+};
+
+#define irs_nul_ng __irs_nul_ng
+#define map_v4v6_address __map_v4v6_address
+#define make_group_list __make_group_list
+#define irs_lclsv_fnxt __irs_lclsv_fnxt
+
+extern void map_v4v6_address(const char *src, char *dst);
+extern int make_group_list(struct irs_gr *, const char *,
+ gid_t, gid_t *, int *);
+extern struct irs_ng * irs_nul_ng(struct irs_acc *);
+extern struct servent * irs_lclsv_fnxt(struct lcl_sv *);
+
+#endif
+
+/*! \file */
diff --git a/lib/bind/irs/lcl.c b/lib/bind/irs/lcl.c
new file mode 100644
index 0000000..930c87e
--- /dev/null
+++ b/lib/bind/irs/lcl.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: lcl.c,v 1.3.18.1 2005/04/27 05:01:02 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+/* Forward. */
+
+static void lcl_close(struct irs_acc *);
+static struct __res_state * lcl_res_get(struct irs_acc *);
+static void lcl_res_set(struct irs_acc *, struct __res_state *,
+ void (*)(void *));
+
+/* Public */
+
+struct irs_acc *
+irs_lcl_acc(const char *options) {
+ struct irs_acc *acc;
+ struct lcl_p *lcl;
+
+ UNUSED(options);
+
+ if (!(acc = memget(sizeof *acc))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(acc, 0x5e, sizeof *acc);
+ if (!(lcl = memget(sizeof *lcl))) {
+ errno = ENOMEM;
+ free(acc);
+ return (NULL);
+ }
+ memset(lcl, 0x5e, sizeof *lcl);
+ lcl->res = NULL;
+ lcl->free_res = NULL;
+ acc->private = lcl;
+#ifdef WANT_IRS_GR
+ acc->gr_map = irs_lcl_gr;
+#else
+ acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+ acc->pw_map = irs_lcl_pw;
+#else
+ acc->pw_map = NULL;
+#endif
+ acc->sv_map = irs_lcl_sv;
+ acc->pr_map = irs_lcl_pr;
+ acc->ho_map = irs_lcl_ho;
+ acc->nw_map = irs_lcl_nw;
+ acc->ng_map = irs_lcl_ng;
+ acc->res_get = lcl_res_get;
+ acc->res_set = lcl_res_set;
+ acc->close = lcl_close;
+ return (acc);
+}
+
+/* Methods */
+static struct __res_state *
+lcl_res_get(struct irs_acc *this) {
+ struct lcl_p *lcl = (struct lcl_p *)this->private;
+
+ if (lcl->res == NULL) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (res == NULL)
+ return (NULL);
+ memset(res, 0, sizeof *res);
+ lcl_res_set(this, res, free);
+ }
+
+ if ((lcl->res->options & RES_INIT) == 0U &&
+ res_ninit(lcl->res) < 0)
+ return (NULL);
+
+ return (lcl->res);
+}
+
+static void
+lcl_res_set(struct irs_acc *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct lcl_p *lcl = (struct lcl_p *)this->private;
+
+ if (lcl->res && lcl->free_res) {
+ res_nclose(lcl->res);
+ (*lcl->free_res)(lcl->res);
+ }
+
+ lcl->res = res;
+ lcl->free_res = free_res;
+}
+
+static void
+lcl_close(struct irs_acc *this) {
+ struct lcl_p *lcl = (struct lcl_p *)this->private;
+
+ if (lcl) {
+ if (lcl->free_res)
+ (*lcl->free_res)(lcl->res);
+ memput(lcl, sizeof *lcl);
+ }
+ memput(this, sizeof *this);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/lcl_gr.c b/lib/bind/irs/lcl_gr.c
new file mode 100644
index 0000000..f17410c
--- /dev/null
+++ b/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.2.18.1 2005/04/27 05:01:02 sra Exp $";
+/* from getgrent.c 8.2 (Berkeley) 3/21/94"; */
+/* from BSDI Id: getgrent.c,v 2.8 1996/05/28 18:15:14 bostic Exp $ */
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+
+/* Types. */
+
+struct pvt {
+ FILE * fp;
+ /*%<
+ * Need space to store the entries read from the group file.
+ * The members list also needs space per member, and the
+ * strings making up the user names must be allocated
+ * somewhere. Rather than doing lots of small allocations,
+ * we keep one buffer and resize it as needed.
+ */
+ struct group group;
+ size_t nmemb; /*%< Malloc'd max index of gr_mem[]. */
+ char * membuf;
+ size_t membufsize;
+};
+
+/* Forward. */
+
+static void gr_close(struct irs_gr *);
+static struct group * gr_next(struct irs_gr *);
+static struct group * gr_byname(struct irs_gr *, const char *);
+static struct group * gr_bygid(struct irs_gr *, gid_t);
+static void gr_rewind(struct irs_gr *);
+static void gr_minimize(struct irs_gr *);
+
+static int grstart(struct pvt *);
+static char * grnext(struct pvt *);
+static struct group * grscan(struct irs_gr *, int, gid_t, const char *);
+
+/* Portability. */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public. */
+
+struct irs_gr *
+irs_lcl_gr(struct irs_acc *this) {
+ struct irs_gr *gr;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(gr = memget(sizeof *gr))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(gr, 0x5e, sizeof *gr);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(gr, sizeof *gr);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ gr->private = pvt;
+ gr->close = gr_close;
+ gr->next = gr_next;
+ gr->byname = gr_byname;
+ gr->bygid = gr_bygid;
+ gr->rewind = gr_rewind;
+ gr->list = make_group_list;
+ gr->minimize = gr_minimize;
+ gr->res_get = NULL;
+ gr->res_set = NULL;
+ return (gr);
+}
+
+/* Methods. */
+
+static void
+gr_close(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp)
+ (void)fclose(pvt->fp);
+ if (pvt->group.gr_mem)
+ free(pvt->group.gr_mem);
+ if (pvt->membuf)
+ free(pvt->membuf);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct group *
+gr_next(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->fp && !grstart(pvt))
+ return (NULL);
+ return (grscan(this, 0, 0, NULL));
+}
+
+static struct group *
+gr_byname(struct irs_gr *this, const char *name) {
+ if (!grstart((struct pvt *)this->private))
+ return (NULL);
+ return (grscan(this, 1, 0, name));
+}
+
+static struct group *
+gr_bygid(struct irs_gr *this, gid_t gid) {
+ if (!grstart((struct pvt *)this->private))
+ return (NULL);
+ return (grscan(this, 1, gid, NULL));
+}
+
+static void
+gr_rewind(struct irs_gr *this) {
+ (void) grstart((struct pvt *)this->private);
+}
+
+static void
+gr_minimize(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp != NULL) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+/* Private. */
+
+static int
+grstart(struct pvt *pvt) {
+ if (pvt->fp) {
+ if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
+ return (1);
+ (void)fclose(pvt->fp);
+ }
+ if (!(pvt->fp = fopen(_PATH_GROUP, "r")))
+ return (0);
+ if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
+ fclose(pvt->fp);
+ return (0);
+ }
+ return (1);
+}
+
+#define INITIAL_NMEMB 30 /*%< about 120 bytes */
+#define INITIAL_BUFSIZ (INITIAL_NMEMB * 8) /*%< about 240 bytes */
+static char *
+grnext(struct pvt *pvt) {
+ char *w, *e;
+ int ch;
+
+ /* Make sure we have a buffer. */
+ if (pvt->membuf == NULL) {
+ pvt->membuf = malloc(INITIAL_BUFSIZ);
+ if (pvt->membuf == NULL) {
+ enomem:
+ errno = ENOMEM;
+ return (NULL);
+ }
+ pvt->membufsize = INITIAL_BUFSIZ;
+ }
+
+ /* Read until EOF or EOL. */
+ w = pvt->membuf;
+ e = pvt->membuf + pvt->membufsize;
+ while ((ch = fgetc(pvt->fp)) != EOF && ch != '\n') {
+ /* Make sure we have room for this character and a \0. */
+ if (w + 1 == e) {
+ size_t o = w - pvt->membuf;
+ size_t n = pvt->membufsize * 2;
+ char *t = realloc(pvt->membuf, n);
+
+ if (t == NULL)
+ goto enomem;
+ pvt->membuf = t;
+ pvt->membufsize = n;
+ w = pvt->membuf + o;
+ e = pvt->membuf + pvt->membufsize;
+ }
+ /* Store it. */
+ *w++ = (char)ch;
+ }
+
+ /* Hitting EOF on the first character really does mean EOF. */
+ if (w == pvt->membuf && ch == EOF) {
+ errno = ENOENT;
+ return (NULL);
+ }
+
+ /* Last line of /etc/group need not end with \n; we don't care. */
+ *w = '\0';
+ return (pvt->membuf);
+}
+
+static struct group *
+grscan(struct irs_gr *this, int search, gid_t gid, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ size_t n;
+ char *bp, **m, *p;
+
+ /* Read lines until we find one that matches our search criteria. */
+ for (;;) {
+ if ((bp = grnext(pvt)) == NULL)
+ return (NULL);
+
+ /* Optimize the usual case of searching for a name. */
+ pvt->group.gr_name = strsep(&bp, ":");
+ if (search && name != NULL &&
+ strcmp(pvt->group.gr_name, name) != 0)
+ continue;
+ if (bp == NULL || *bp == '\0')
+ goto corrupt;
+
+ /* Skip past the password field. */
+ pvt->group.gr_passwd = strsep(&bp, ":");
+ if (bp == NULL || *bp == '\0')
+ goto corrupt;
+
+ /* Checking for a gid. */
+ if ((p = strsep(&bp, ":")) == NULL)
+ continue;
+ /*
+ * Unlike the tests above, the test below is supposed to be
+ * testing 'p' and not 'bp', in case you think it's a typo.
+ */
+ if (p == NULL || *p == '\0') {
+ corrupt:
+ /* warning: corrupted %s file!", _PATH_GROUP */
+ continue;
+ }
+ pvt->group.gr_gid = atoi(p);
+ if (search && name == NULL && (gid_t)pvt->group.gr_gid != gid)
+ continue;
+
+ /* We want this record. */
+ break;
+ }
+
+ /*
+ * Count commas to find out how many members there might be.
+ * Note that commas separate, so if there is one comma there
+ * can be two members (group:*:id:user1,user2). Add another
+ * to account for the NULL terminator. As above, allocate
+ * largest of INITIAL_NMEMB, or 2*n.
+ */
+ n = 1;
+ if (bp != NULL)
+ for (n = 2, p = bp; (p = strpbrk(p, ", ")) != NULL; ++n)
+ p += strspn(p, ", ");
+ if (n > pvt->nmemb || pvt->group.gr_mem == NULL) {
+ if ((n *= 2) < INITIAL_NMEMB)
+ n = INITIAL_NMEMB;
+ if ((m = realloc(pvt->group.gr_mem, n * sizeof *m)) == NULL)
+ return (NULL);
+ pvt->group.gr_mem = m;
+ pvt->nmemb = n;
+ }
+
+ /* Set the name pointers. */
+ for (m = pvt->group.gr_mem; (p = strsep(&bp, ", ")) != NULL;)
+ if (p[0] != '\0')
+ *m++ = p;
+ *m = NULL;
+
+ return (&pvt->group);
+}
+
+#endif /* WANT_IRS_GR */
+/*! \file */
diff --git a/lib/bind/irs/lcl_ho.c b/lib/bind/irs/lcl_ho.c
new file mode 100644
index 0000000..9534ee6
--- /dev/null
+++ b/lib/bind/irs/lcl_ho.c
@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 1985, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* from gethostnamadr.c 8.1 (Berkeley) 6/4/93 */
+/* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_ho.c,v 1.3.18.2 2006/03/10 00:20:08 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "dns_p.h"
+#include "lcl_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+/* Definitions. */
+
+#define MAXALIASES 35
+#define MAXADDRS 35
+#define Max(a,b) ((a) > (b) ? (a) : (b))
+
+#if PACKETSZ > 1024
+#define MAXPACKET PACKETSZ
+#else
+#define MAXPACKET 1024
+#endif
+
+struct pvt {
+ FILE * fp;
+ struct hostent host;
+ char * h_addr_ptrs[MAXADDRS + 1];
+ char * host_aliases[MAXALIASES];
+ char hostbuf[8*1024];
+ u_char host_addr[16]; /*%< IPv4 or IPv6 */
+ struct __res_state *res;
+ void (*free_res)(void *);
+};
+
+typedef union {
+ int32_t al;
+ char ac;
+} align;
+
+static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
+static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+
+/* Forward. */
+
+static void ho_close(struct irs_ho *this);
+static struct hostent * ho_byname(struct irs_ho *this, const char *name);
+static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
+ int af);
+static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ int len, int af);
+static struct hostent * ho_next(struct irs_ho *this);
+static void ho_rewind(struct irs_ho *this);
+static void ho_minimize(struct irs_ho *this);
+static struct __res_state * ho_res_get(struct irs_ho *this);
+static void ho_res_set(struct irs_ho *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+ const struct addrinfo *pai);
+
+static size_t ns_namelen(const char *);
+static int init(struct irs_ho *this);
+
+/* Portability. */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public. */
+
+struct irs_ho *
+irs_lcl_ho(struct irs_acc *this) {
+ struct irs_ho *ho;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(ho = memget(sizeof *ho))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ho, 0x5e, sizeof *ho);
+ ho->private = pvt;
+ ho->close = ho_close;
+ ho->byname = ho_byname;
+ ho->byname2 = ho_byname2;
+ ho->byaddr = ho_byaddr;
+ ho->next = ho_next;
+ ho->rewind = ho_rewind;
+ ho->minimize = ho_minimize;
+ ho->res_get = ho_res_get;
+ ho->res_set = ho_res_set;
+ ho->addrinfo = ho_addrinfo;
+ return (ho);
+}
+
+/* Methods. */
+
+static void
+ho_close(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ho_minimize(this);
+ if (pvt->fp)
+ (void) fclose(pvt->fp);
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (pvt->res->options & RES_USE_INET6) {
+ hp = ho_byname2(this, name, AF_INET6);
+ if (hp)
+ return (hp);
+ }
+ return (ho_byname2(this, name, AF_INET));
+}
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp;
+ char **hap;
+ size_t n;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ ho_rewind(this);
+ n = ns_namelen(name);
+ while ((hp = ho_next(this)) != NULL) {
+ size_t nn;
+
+ if (hp->h_addrtype != af)
+ continue;
+ nn = ns_namelen(hp->h_name);
+ if (strncasecmp(hp->h_name, name, Max(n, nn)) == 0)
+ goto found;
+ for (hap = hp->h_aliases; *hap; hap++) {
+ nn = ns_namelen(*hap);
+ if (strncasecmp(*hap, name, Max(n, nn)) == 0)
+ goto found;
+ }
+ }
+ found:
+ if (!hp) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+ return (hp);
+}
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ const u_char *uaddr = addr;
+ struct hostent *hp;
+ int size;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (af == AF_INET6 && len == IN6ADDRSZ &&
+ (!memcmp(uaddr, mapped, sizeof mapped) ||
+ !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
+ /* Unmap. */
+ addr = (const u_char *)addr + sizeof mapped;
+ uaddr += sizeof mapped;
+ af = AF_INET;
+ len = INADDRSZ;
+ }
+ switch (af) {
+ case AF_INET:
+ size = INADDRSZ;
+ break;
+ case AF_INET6:
+ size = IN6ADDRSZ;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ if (size > len) {
+ errno = EINVAL;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+
+ /*
+ * Do the search.
+ */
+ ho_rewind(this);
+ while ((hp = ho_next(this)) != NULL) {
+ char **hap;
+
+ for (hap = hp->h_addr_list; *hap; hap++) {
+ const u_char *taddr = (const u_char *)*hap;
+ int taf = hp->h_addrtype;
+ int tlen = hp->h_length;
+
+ if (taf == AF_INET6 && tlen == IN6ADDRSZ &&
+ (!memcmp(taddr, mapped, sizeof mapped) ||
+ !memcmp(taddr, tunnelled, sizeof tunnelled))) {
+ /* Unmap. */
+ taddr += sizeof mapped;
+ taf = AF_INET;
+ tlen = INADDRSZ;
+ }
+ if (taf == af && tlen == len &&
+ !memcmp(taddr, uaddr, tlen))
+ goto found;
+ }
+ }
+ found:
+ if (!hp) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+ return (hp);
+}
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *cp, **q, *p;
+ char *bufp, *ndbuf, *dbuf = NULL;
+ int c, af, len, bufsiz, offset;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (!pvt->fp)
+ ho_rewind(this);
+ if (!pvt->fp) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ bufp = pvt->hostbuf;
+ bufsiz = sizeof pvt->hostbuf;
+ offset = 0;
+ again:
+ if (!(p = fgets(bufp + offset, bufsiz - offset, pvt->fp))) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ if (dbuf)
+ free(dbuf);
+ return (NULL);
+ }
+ if (!strchr(p, '\n') && !feof(pvt->fp)) {
+#define GROWBUF 1024
+ /* allocate space for longer line */
+ if (dbuf == NULL) {
+ if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL)
+ strcpy(ndbuf, bufp);
+ } else
+ ndbuf = realloc(dbuf, bufsiz + GROWBUF);
+ if (ndbuf) {
+ dbuf = ndbuf;
+ bufp = dbuf;
+ bufsiz += GROWBUF;
+ offset = strlen(dbuf);
+ } else {
+ /* allocation failed; skip this long line */
+ while ((c = getc(pvt->fp)) != EOF)
+ if (c == '\n')
+ break;
+ if (c != EOF)
+ ungetc(c, pvt->fp);
+ }
+ goto again;
+ }
+
+ p -= offset;
+ offset = 0;
+
+ if (*p == '#')
+ goto again;
+ if ((cp = strpbrk(p, "#\n")) != NULL)
+ *cp = '\0';
+ if (!(cp = strpbrk(p, " \t")))
+ goto again;
+ *cp++ = '\0';
+ if (inet_pton(AF_INET6, p, pvt->host_addr) > 0) {
+ af = AF_INET6;
+ len = IN6ADDRSZ;
+ } else if (inet_aton(p, (struct in_addr *)pvt->host_addr) > 0) {
+ if (pvt->res->options & RES_USE_INET6) {
+ map_v4v6_address((char*)pvt->host_addr,
+ (char*)pvt->host_addr);
+ af = AF_INET6;
+ len = IN6ADDRSZ;
+ } else {
+ af = AF_INET;
+ len = INADDRSZ;
+ }
+ } else {
+ goto again;
+ }
+ pvt->h_addr_ptrs[0] = (char *)pvt->host_addr;
+ pvt->h_addr_ptrs[1] = NULL;
+ pvt->host.h_addr_list = pvt->h_addr_ptrs;
+ pvt->host.h_length = len;
+ pvt->host.h_addrtype = af;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ pvt->host.h_name = cp;
+ q = pvt->host.h_aliases = pvt->host_aliases;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = '\0';
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &pvt->host_aliases[MAXALIASES - 1])
+ *q++ = cp;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = '\0';
+ }
+ *q = NULL;
+ if (dbuf)
+ free(dbuf);
+ RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+ return (&pvt->host);
+}
+
+static void
+ho_rewind(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp) {
+ if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
+ return;
+ (void)fclose(pvt->fp);
+ }
+ if (!(pvt->fp = fopen(_PATH_HOSTS, "r")))
+ return;
+ if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+static void
+ho_minimize(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp != NULL) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+ if (pvt->res)
+ res_nclose(pvt->res);
+}
+
+static struct __res_state *
+ho_res_get(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ ho_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+ho_res_set(struct irs_ho *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+}
+
+struct lcl_res_target {
+ struct lcl_res_target *next;
+ int family;
+};
+
+/* XXX */
+extern struct addrinfo *hostent2addrinfo __P((struct hostent *,
+ const struct addrinfo *pai));
+
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp;
+ struct lcl_res_target q, q2, *p;
+ struct addrinfo sentinel, *cur;
+
+ memset(&q, 0, sizeof(q2));
+ memset(&q2, 0, sizeof(q2));
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ switch(pai->ai_family) {
+ case AF_UNSPEC: /*%< INET6 then INET4 */
+ q.family = AF_INET6;
+ q.next = &q2;
+ q2.family = AF_INET;
+ break;
+ case AF_INET6:
+ q.family = AF_INET6;
+ break;
+ case AF_INET:
+ q.family = AF_INET;
+ break;
+ default:
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /*%< ??? */
+ return(NULL);
+ }
+
+ for (p = &q; p; p = p->next) {
+ struct addrinfo *ai;
+
+ hp = (*this->byname2)(this, name, p->family);
+ if (hp == NULL) {
+ /* byname2 should've set an appropriate error */
+ continue;
+ }
+ if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
+ (hp->h_addr_list[0] == NULL)) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ continue;
+ }
+
+ ai = hostent2addrinfo(hp, pai);
+ if (ai) {
+ cur->ai_next = ai;
+ while (cur->ai_next)
+ cur = cur->ai_next;
+ }
+ }
+
+ if (sentinel.ai_next == NULL)
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+
+ return(sentinel.ai_next);
+}
+
+/* Private. */
+
+static size_t
+ns_namelen(const char *s) {
+ int i;
+
+ for (i = strlen(s); i > 0 && s[i-1] == '.'; i--)
+ (void)NULL;
+ return ((size_t) i);
+}
+
+static int
+init(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !ho_res_get(this))
+ return (-1);
+ if (((pvt->res->options & RES_INIT) == 0U) &&
+ res_ninit(pvt->res) == -1)
+ return (-1);
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/lcl_ng.c b/lib/bind/irs/lcl_ng.c
new file mode 100644
index 0000000..3a9f3fa
--- /dev/null
+++ b/lib/bind/irs/lcl_ng.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: lcl_ng.c,v 1.2.18.1 2005/04/27 05:01:02 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+/* Definitions */
+
+#define NG_HOST 0 /*%< Host name */
+#define NG_USER 1 /*%< User name */
+#define NG_DOM 2 /*%< and Domain name */
+#define LINSIZ 1024 /*%< Length of netgroup file line */
+/*
+ * XXX Warning XXX
+ * This code is a hack-and-slash special. It realy needs to be
+ * rewritten with things like strdup, and realloc in mind.
+ * More reasonable data structures would not be a bad thing.
+ */
+
+/*%
+ * Static Variables and functions used by setnetgrent(), getnetgrent() and
+ * endnetgrent().
+ *
+ * There are two linked lists:
+ * \li linelist is just used by setnetgrent() to parse the net group file via.
+ * parse_netgrp()
+ * \li netgrp is the list of entries for the current netgroup
+ */
+struct linelist {
+ struct linelist *l_next; /*%< Chain ptr. */
+ int l_parsed; /*%< Flag for cycles */
+ char * l_groupname; /*%< Name of netgroup */
+ char * l_line; /*%< Netgroup entrie(s) to be parsed */
+};
+
+struct ng_old_struct {
+ struct ng_old_struct *ng_next; /*%< Chain ptr */
+ char * ng_str[3]; /*%< Field pointers, see below */
+};
+
+struct pvt {
+ FILE *fp;
+ struct linelist *linehead;
+ struct ng_old_struct *nextgrp;
+ struct {
+ struct ng_old_struct *gr;
+ char *grname;
+ } grouphead;
+};
+
+/* Forward */
+
+static void ng_rewind(struct irs_ng *, const char*);
+static void ng_close(struct irs_ng *);
+static int ng_next(struct irs_ng *, const char **,
+ const char **, const char **);
+static int ng_test(struct irs_ng *, const char *,
+ const char *, const char *,
+ const char *);
+static void ng_minimize(struct irs_ng *);
+
+static int parse_netgrp(struct irs_ng *, const char*);
+static struct linelist *read_for_group(struct irs_ng *, const char *);
+static void freelists(struct irs_ng *);
+
+/* Public */
+
+struct irs_ng *
+irs_lcl_ng(struct irs_acc *this) {
+ struct irs_ng *ng;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(ng = memget(sizeof *ng))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ng, 0x5e, sizeof *ng);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(ng, sizeof *ng);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ ng->private = pvt;
+ ng->close = ng_close;
+ ng->next = ng_next;
+ ng->test = ng_test;
+ ng->rewind = ng_rewind;
+ ng->minimize = ng_minimize;
+ return (ng);
+}
+
+/* Methods */
+
+static void
+ng_close(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp != NULL)
+ fclose(pvt->fp);
+ freelists(this);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+/*%
+ * Parse the netgroup file looking for the netgroup and build the list
+ * of netgrp structures. Let parse_netgrp() and read_for_group() do
+ * most of the work.
+ */
+static void
+ng_rewind(struct irs_ng *this, const char *group) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp != NULL && fseek(pvt->fp, SEEK_CUR, 0L) == -1) {
+ fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+
+ if (pvt->fp == NULL || pvt->grouphead.gr == NULL ||
+ strcmp(group, pvt->grouphead.grname)) {
+ freelists(this);
+ if (pvt->fp != NULL)
+ fclose(pvt->fp);
+ pvt->fp = fopen(_PATH_NETGROUP, "r");
+ if (pvt->fp != NULL) {
+ if (parse_netgrp(this, group))
+ freelists(this);
+ if (!(pvt->grouphead.grname = strdup(group)))
+ freelists(this);
+ fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+ }
+ pvt->nextgrp = pvt->grouphead.gr;
+}
+
+/*%
+ * Get the next netgroup off the list.
+ */
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user,
+ const char **domain)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->nextgrp) {
+ *host = pvt->nextgrp->ng_str[NG_HOST];
+ *user = pvt->nextgrp->ng_str[NG_USER];
+ *domain = pvt->nextgrp->ng_str[NG_DOM];
+ pvt->nextgrp = pvt->nextgrp->ng_next;
+ return (1);
+ }
+ return (0);
+}
+
+/*%
+ * Search for a match in a netgroup.
+ */
+static int
+ng_test(struct irs_ng *this, const char *name,
+ const char *host, const char *user, const char *domain)
+{
+ const char *ng_host, *ng_user, *ng_domain;
+
+ ng_rewind(this, name);
+ while (ng_next(this, &ng_host, &ng_user, &ng_domain))
+ if ((host == NULL || ng_host == NULL ||
+ !strcmp(host, ng_host)) &&
+ (user == NULL || ng_user == NULL ||
+ !strcmp(user, ng_user)) &&
+ (domain == NULL || ng_domain == NULL ||
+ !strcmp(domain, ng_domain))) {
+ freelists(this);
+ return (1);
+ }
+ freelists(this);
+ return (0);
+}
+
+static void
+ng_minimize(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp != NULL) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+/* Private */
+
+/*%
+ * endnetgrent() - cleanup
+ */
+static void
+freelists(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct linelist *lp, *olp;
+ struct ng_old_struct *gp, *ogp;
+
+ lp = pvt->linehead;
+ while (lp) {
+ olp = lp;
+ lp = lp->l_next;
+ free(olp->l_groupname);
+ free(olp->l_line);
+ free((char *)olp);
+ }
+ pvt->linehead = NULL;
+ if (pvt->grouphead.grname) {
+ free(pvt->grouphead.grname);
+ pvt->grouphead.grname = NULL;
+ }
+ gp = pvt->grouphead.gr;
+ while (gp) {
+ ogp = gp;
+ gp = gp->ng_next;
+ if (ogp->ng_str[NG_HOST])
+ free(ogp->ng_str[NG_HOST]);
+ if (ogp->ng_str[NG_USER])
+ free(ogp->ng_str[NG_USER]);
+ if (ogp->ng_str[NG_DOM])
+ free(ogp->ng_str[NG_DOM]);
+ free((char *)ogp);
+ }
+ pvt->grouphead.gr = NULL;
+}
+
+/*%
+ * Parse the netgroup file setting up the linked lists.
+ */
+static int
+parse_netgrp(struct irs_ng *this, const char *group) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *spos, *epos;
+ int len, strpos;
+ char *pos, *gpos;
+ struct ng_old_struct *grp;
+ struct linelist *lp = pvt->linehead;
+
+ /*
+ * First, see if the line has already been read in.
+ */
+ while (lp) {
+ if (!strcmp(group, lp->l_groupname))
+ break;
+ lp = lp->l_next;
+ }
+ if (lp == NULL &&
+ (lp = read_for_group(this, group)) == NULL)
+ return (1);
+ if (lp->l_parsed) {
+ /*fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);*/
+ return (1);
+ } else
+ lp->l_parsed = 1;
+ pos = lp->l_line;
+ while (*pos != '\0') {
+ if (*pos == '(') {
+ if (!(grp = malloc(sizeof (struct ng_old_struct)))) {
+ freelists(this);
+ errno = ENOMEM;
+ return (1);
+ }
+ memset(grp, 0, sizeof (struct ng_old_struct));
+ grp->ng_next = pvt->grouphead.gr;
+ pvt->grouphead.gr = grp;
+ pos++;
+ gpos = strsep(&pos, ")");
+ for (strpos = 0; strpos < 3; strpos++) {
+ if ((spos = strsep(&gpos, ","))) {
+ while (*spos == ' ' || *spos == '\t')
+ spos++;
+ if ((epos = strpbrk(spos, " \t"))) {
+ *epos = '\0';
+ len = epos - spos;
+ } else
+ len = strlen(spos);
+ if (len > 0) {
+ if(!(grp->ng_str[strpos]
+ = (char *)
+ malloc(len + 1))) {
+ freelists(this);
+ return (1);
+ }
+ memcpy(grp->ng_str[strpos],
+ spos,
+ len + 1);
+ }
+ } else
+ goto errout;
+ }
+ } else {
+ spos = strsep(&pos, ", \t");
+ if (spos != NULL && parse_netgrp(this, spos)) {
+ freelists(this);
+ return (1);
+ }
+ }
+ if (pos == NULL)
+ break;
+ while (*pos == ' ' || *pos == ',' || *pos == '\t')
+ pos++;
+ }
+ return (0);
+ errout:
+ /*fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname,
+ spos);*/
+ return (1);
+}
+
+/*%
+ * Read the netgroup file and save lines until the line for the netgroup
+ * is found. Return 1 if eof is encountered.
+ */
+static struct linelist *
+read_for_group(struct irs_ng *this, const char *group) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *pos, *spos, *linep = NULL, *olinep;
+ int len, olen, cont;
+ struct linelist *lp;
+ char line[LINSIZ + 1];
+
+ while (fgets(line, LINSIZ, pvt->fp) != NULL) {
+ pos = line;
+ if (*pos == '#')
+ continue;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ spos = pos;
+ while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
+ *pos != '\0')
+ pos++;
+ len = pos - spos;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos != '\n' && *pos != '\0') {
+ if (!(lp = malloc(sizeof (*lp)))) {
+ freelists(this);
+ return (NULL);
+ }
+ lp->l_parsed = 0;
+ if (!(lp->l_groupname = malloc(len + 1))) {
+ free(lp);
+ freelists(this);
+ return (NULL);
+ }
+ memcpy(lp->l_groupname, spos, len);
+ *(lp->l_groupname + len) = '\0';
+ len = strlen(pos);
+ olen = 0;
+ olinep = NULL;
+
+ /*
+ * Loop around handling line continuations.
+ */
+ do {
+ if (*(pos + len - 1) == '\n')
+ len--;
+ if (*(pos + len - 1) == '\\') {
+ len--;
+ cont = 1;
+ } else
+ cont = 0;
+ if (len > 0) {
+ if (!(linep = malloc(olen + len + 1))){
+ if (olen > 0)
+ free(olinep);
+ free(lp->l_groupname);
+ free(lp);
+ freelists(this);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ if (olen > 0) {
+ memcpy(linep, olinep, olen);
+ free(olinep);
+ }
+ memcpy(linep + olen, pos, len);
+ olen += len;
+ *(linep + olen) = '\0';
+ olinep = linep;
+ }
+ if (cont) {
+ if (fgets(line, LINSIZ, pvt->fp)) {
+ pos = line;
+ len = strlen(pos);
+ } else
+ cont = 0;
+ }
+ } while (cont);
+ lp->l_line = linep;
+ lp->l_next = pvt->linehead;
+ pvt->linehead = lp;
+
+ /*
+ * If this is the one we wanted, we are done.
+ */
+ if (!strcmp(lp->l_groupname, group))
+ return (lp);
+ }
+ }
+ return (NULL);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/lcl_nw.c b/lib/bind/irs/lcl_nw.c
new file mode 100644
index 0000000..2804946
--- /dev/null
+++ b/lib/bind/irs/lcl_nw.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_nw.c,v 1.3.18.1 2005/04/27 05:01:02 sra Exp $";
+/* from getgrent.c 8.2 (Berkeley) 3/21/94"; */
+/* from BSDI Id: getgrent.c,v 2.8 1996/05/28 18:15:14 bostic Exp $ */
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include <isc/misc.h>
+#include "irs_p.h"
+#include "lcl_p.h"
+
+#define MAXALIASES 35
+#define MAXADDRSIZE 4
+
+struct pvt {
+ FILE * fp;
+ char line[BUFSIZ+1];
+ struct nwent net;
+ char * aliases[MAXALIASES];
+ char addr[MAXADDRSIZE];
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward */
+
+static void nw_close(struct irs_nw *);
+static struct nwent * nw_byname(struct irs_nw *, const char *, int);
+static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int);
+static struct nwent * nw_next(struct irs_nw *);
+static void nw_rewind(struct irs_nw *);
+static void nw_minimize(struct irs_nw *);
+static struct __res_state * nw_res_get(struct irs_nw *this);
+static void nw_res_set(struct irs_nw *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+
+static int init(struct irs_nw *this);
+
+/* Portability. */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public */
+
+struct irs_nw *
+irs_lcl_nw(struct irs_acc *this) {
+ struct irs_nw *nw;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(nw = memget(sizeof *nw))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(nw, 0x5e, sizeof *nw);
+ nw->private = pvt;
+ nw->close = nw_close;
+ nw->byname = nw_byname;
+ nw->byaddr = nw_byaddr;
+ nw->next = nw_next;
+ nw->rewind = nw_rewind;
+ nw->minimize = nw_minimize;
+ nw->res_get = nw_res_get;
+ nw->res_set = nw_res_set;
+ return (nw);
+}
+
+/* Methods */
+
+static void
+nw_close(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ nw_minimize(this);
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ if (pvt->fp)
+ (void)fclose(pvt->fp);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int length, int type) {
+ struct nwent *p;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ nw_rewind(this);
+ while ((p = nw_next(this)) != NULL)
+ if (p->n_addrtype == type && p->n_length == length)
+ if (bitncmp(p->n_addr, net, length) == 0)
+ break;
+ return (p);
+}
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int type) {
+ struct nwent *p;
+ char **ap;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ nw_rewind(this);
+ while ((p = nw_next(this)) != NULL) {
+ if (ns_samename(p->n_name, name) == 1 &&
+ p->n_addrtype == type)
+ break;
+ for (ap = p->n_aliases; *ap; ap++)
+ if ((ns_samename(*ap, name) == 1) &&
+ (p->n_addrtype == type))
+ goto found;
+ }
+ found:
+ return (p);
+}
+
+static void
+nw_rewind(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp) {
+ if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
+ return;
+ (void)fclose(pvt->fp);
+ }
+ if (!(pvt->fp = fopen(_PATH_NETWORKS, "r")))
+ return;
+ if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct nwent *ret = NULL;
+ char *p, *cp, **q;
+ char *bufp, *ndbuf, *dbuf = NULL;
+ int c, bufsiz, offset = 0;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ if (pvt->fp == NULL)
+ nw_rewind(this);
+ if (pvt->fp == NULL) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ bufp = pvt->line;
+ bufsiz = sizeof(pvt->line);
+
+ again:
+ p = fgets(bufp + offset, bufsiz - offset, pvt->fp);
+ if (p == NULL)
+ goto cleanup;
+ if (!strchr(p, '\n') && !feof(pvt->fp)) {
+#define GROWBUF 1024
+ /* allocate space for longer line */
+ if (dbuf == NULL) {
+ if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL)
+ strcpy(ndbuf, bufp);
+ } else
+ ndbuf = realloc(dbuf, bufsiz + GROWBUF);
+ if (ndbuf) {
+ dbuf = ndbuf;
+ bufp = dbuf;
+ bufsiz += GROWBUF;
+ offset = strlen(dbuf);
+ } else {
+ /* allocation failed; skip this long line */
+ while ((c = getc(pvt->fp)) != EOF)
+ if (c == '\n')
+ break;
+ if (c != EOF)
+ ungetc(c, pvt->fp);
+ }
+ goto again;
+ }
+
+ p -= offset;
+ offset = 0;
+
+ if (*p == '#')
+ goto again;
+
+ cp = strpbrk(p, "#\n");
+ if (cp != NULL)
+ *cp = '\0';
+ pvt->net.n_name = p;
+ cp = strpbrk(p, " \t");
+ if (cp == NULL)
+ goto again;
+ *cp++ = '\0';
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ p = strpbrk(cp, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ pvt->net.n_length = inet_net_pton(AF_INET, cp, pvt->addr,
+ sizeof pvt->addr);
+ if (pvt->net.n_length < 0)
+ goto again;
+ pvt->net.n_addrtype = AF_INET;
+ pvt->net.n_addr = pvt->addr;
+ q = pvt->net.n_aliases = pvt->aliases;
+ if (p != NULL) {
+ cp = p;
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &pvt->aliases[MAXALIASES - 1])
+ *q++ = cp;
+ cp = strpbrk(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+ }
+ *q = NULL;
+ ret = &pvt->net;
+
+ cleanup:
+ if (dbuf)
+ free(dbuf);
+
+ return (ret);
+}
+
+static void
+nw_minimize(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+ if (pvt->fp != NULL) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+static struct __res_state *
+nw_res_get(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ nw_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+nw_res_set(struct irs_nw *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+}
+
+static int
+init(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !nw_res_get(this))
+ return (-1);
+ if (((pvt->res->options & RES_INIT) == 0U) &&
+ res_ninit(pvt->res) == -1)
+ return (-1);
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/bind/irs/lcl_p.h b/lib/bind/irs/lcl_p.h
new file mode 100644
index 0000000..4e6bdc3
--- /dev/null
+++ b/lib/bind/irs/lcl_p.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: lcl_p.h,v 1.2.18.1 2005/04/27 05:01:02 sra Exp $
+ */
+
+/*! \file
+ * \brief
+ * lcl_p.h - private include file for the local accessor functions.
+ */
+
+#ifndef _LCL_P_H_INCLUDED
+#define _LCL_P_H_INCLUDED
+
+/*%
+ * Object state.
+ */
+struct lcl_p {
+ struct __res_state * res;
+ void (*free_res) __P((void *));
+};
+
+/*
+ * Externs.
+ */
+
+extern struct irs_acc * irs_lcl_acc __P((const char *));
+extern struct irs_gr * irs_lcl_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_lcl_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_lcl_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_lcl_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_lcl_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_lcl_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_lcl_ng __P((struct irs_acc *));
+
+#endif /*_LCL_P_H_INCLUDED*/
diff --git a/lib/bind/irs/lcl_pr.c b/lib/bind/irs/lcl_pr.c
new file mode 100644
index 0000000..08c6da9
--- /dev/null
+++ b/lib/bind/irs/lcl_pr.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_pr.c,v 1.2.18.2 2006/03/10 00:20:08 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+#ifndef _PATH_PROTOCOLS
+#define _PATH_PROTOCOLS "/etc/protocols"
+#endif
+#define MAXALIASES 35
+
+/* Types */
+
+struct pvt {
+ FILE * fp;
+ char line[BUFSIZ+1];
+ char * dbuf;
+ struct protoent proto;
+ char * proto_aliases[MAXALIASES];
+};
+
+/* Forward */
+
+static void pr_close(struct irs_pr *);
+static struct protoent * pr_next(struct irs_pr *);
+static struct protoent * pr_byname(struct irs_pr *, const char *);
+static struct protoent * pr_bynumber(struct irs_pr *, int);
+static void pr_rewind(struct irs_pr *);
+static void pr_minimize(struct irs_pr *);
+
+/* Portability. */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public */
+
+struct irs_pr *
+irs_lcl_pr(struct irs_acc *this) {
+ struct irs_pr *pr;
+ struct pvt *pvt;
+
+ if (!(pr = memget(sizeof *pr))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(pr, sizeof *this);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pr->private = pvt;
+ pr->close = pr_close;
+ pr->byname = pr_byname;
+ pr->bynumber = pr_bynumber;
+ pr->next = pr_next;
+ pr->rewind = pr_rewind;
+ pr->minimize = pr_minimize;
+ pr->res_get = NULL;
+ pr->res_set = NULL;
+ return (pr);
+}
+
+/* Methods */
+
+static void
+pr_close(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp)
+ (void) fclose(pvt->fp);
+ if (pvt->dbuf)
+ free(pvt->dbuf);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+
+ struct protoent *p;
+ char **cp;
+
+ pr_rewind(this);
+ while ((p = pr_next(this))) {
+ if (!strcmp(p->p_name, name))
+ goto found;
+ for (cp = p->p_aliases; *cp; cp++)
+ if (!strcmp(*cp, name))
+ goto found;
+ }
+ found:
+ return (p);
+}
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int proto) {
+ struct protoent *p;
+
+ pr_rewind(this);
+ while ((p = pr_next(this)))
+ if (p->p_proto == proto)
+ break;
+ return (p);
+}
+
+static void
+pr_rewind(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp) {
+ if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
+ return;
+ (void)fclose(pvt->fp);
+ }
+ if (!(pvt->fp = fopen(_PATH_PROTOCOLS, "r" )))
+ return;
+ if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *p, *cp, **q;
+ char *bufp, *ndbuf, *dbuf = NULL;
+ int c, bufsiz, offset;
+
+ if (!pvt->fp)
+ pr_rewind(this);
+ if (!pvt->fp)
+ return (NULL);
+ if (pvt->dbuf) {
+ free(pvt->dbuf);
+ pvt->dbuf = NULL;
+ }
+ bufp = pvt->line;
+ bufsiz = BUFSIZ;
+ offset = 0;
+ again:
+ if ((p = fgets(bufp + offset, bufsiz - offset, pvt->fp)) == NULL) {
+ if (dbuf)
+ free(dbuf);
+ return (NULL);
+ }
+ if (!strchr(p, '\n') && !feof(pvt->fp)) {
+#define GROWBUF 1024
+ /* allocate space for longer line */
+ if (dbuf == NULL) {
+ if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL)
+ strcpy(ndbuf, bufp);
+ } else
+ ndbuf = realloc(dbuf, bufsiz + GROWBUF);
+ if (ndbuf) {
+ dbuf = ndbuf;
+ bufp = dbuf;
+ bufsiz += GROWBUF;
+ offset = strlen(dbuf);
+ } else {
+ /* allocation failed; skip this long line */
+ while ((c = getc(pvt->fp)) != EOF)
+ if (c == '\n')
+ break;
+ if (c != EOF)
+ ungetc(c, pvt->fp);
+ }
+ goto again;
+ }
+
+ p -= offset;
+ offset = 0;
+
+ if (*p == '#')
+ goto again;
+ cp = strpbrk(p, "#\n");
+ if (cp != NULL)
+ *cp = '\0';
+ pvt->proto.p_name = p;
+ cp = strpbrk(p, " \t");
+ if (cp == NULL)
+ goto again;
+ *cp++ = '\0';
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ p = strpbrk(cp, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ pvt->proto.p_proto = atoi(cp);
+ q = pvt->proto.p_aliases = pvt->proto_aliases;
+ if (p != NULL) {
+ cp = p;
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &pvt->proto_aliases[MAXALIASES - 1])
+ *q++ = cp;
+ cp = strpbrk(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+ }
+ *q = NULL;
+ pvt->dbuf = dbuf;
+ return (&pvt->proto);
+}
+
+static void
+pr_minimize(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp != NULL) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+/*! \file */
diff --git a/lib/bind/irs/lcl_pw.c b/lib/bind/irs/lcl_pw.c
new file mode 100644
index 0000000..316057b
--- /dev/null
+++ b/lib/bind/irs/lcl_pw.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_pw.c,v 1.2.18.1 2005/04/27 05:01:03 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Extern */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <db.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <utmp.h>
+#include <unistd.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+/*! \file
+ * \brief
+ * The lookup techniques and data extraction code here must be kept
+ * in sync with that in `pwd_mkdb'.
+ */
+
+
+/* Types */
+
+struct pvt {
+ struct passwd passwd; /*%< password structure */
+ DB *pw_db; /*%< password database */
+ int pw_keynum; /*%< key counter */
+ int warned;
+ u_int max;
+ char * line;
+};
+
+/* Forward */
+
+static void pw_close(struct irs_pw *);
+static struct passwd * pw_next(struct irs_pw *);
+static struct passwd * pw_byname(struct irs_pw *, const char *);
+static struct passwd * pw_byuid(struct irs_pw *, uid_t);
+static void pw_rewind(struct irs_pw *);
+static void pw_minimize(struct irs_pw *);
+
+static int initdb(struct pvt *);
+static int hashpw(struct irs_pw *, DBT *);
+
+/* Public */
+struct irs_pw *
+irs_lcl_pw(struct irs_acc *this) {
+ struct irs_pw *pw;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(pw = memget(sizeof *pw))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pw, 0x5e, sizeof *pw);
+ if (!(pvt = memget(sizeof *pvt))) {
+ free(pw);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pw->private = pvt;
+ pw->close = pw_close;
+ pw->next = pw_next;
+ pw->byname = pw_byname;
+ pw->byuid = pw_byuid;
+ pw->rewind = pw_rewind;
+ pw->minimize = pw_minimize;
+ pw->res_get = NULL;
+ pw->res_set = NULL;
+ return (pw);
+}
+
+/* Methods */
+
+static void
+pw_close(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->pw_db) {
+ (void)(pvt->pw_db->close)(pvt->pw_db);
+ pvt->pw_db = NULL;
+ }
+ if (pvt->line)
+ memput(pvt->line, pvt->max);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct passwd *
+pw_next(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ DBT key;
+ char bf[sizeof(pvt->pw_keynum) + 1];
+
+ if (!initdb(pvt))
+ return (NULL);
+
+ ++pvt->pw_keynum;
+ bf[0] = _PW_KEYBYNUM;
+ memcpy(bf + 1, (char *)&pvt->pw_keynum, sizeof(pvt->pw_keynum));
+ key.data = (u_char *)bf;
+ key.size = sizeof(pvt->pw_keynum) + 1;
+ return (hashpw(this, &key) ? &pvt->passwd : NULL);
+}
+
+static struct passwd *
+pw_byname(struct irs_pw *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ DBT key;
+ int len, rval;
+ char bf[UT_NAMESIZE + 1];
+
+ if (!initdb(pvt))
+ return (NULL);
+
+ bf[0] = _PW_KEYBYNAME;
+ len = strlen(name);
+ memcpy(bf + 1, name, MIN(len, UT_NAMESIZE));
+ key.data = (u_char *)bf;
+ key.size = len + 1;
+ rval = hashpw(this, &key);
+
+ return (rval ? &pvt->passwd : NULL);
+}
+
+
+static struct passwd *
+pw_byuid(struct irs_pw *this, uid_t uid) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ DBT key;
+ int keyuid, rval;
+ char bf[sizeof(keyuid) + 1];
+
+ if (!initdb(pvt))
+ return (NULL);
+
+ bf[0] = _PW_KEYBYUID;
+ keyuid = uid;
+ memcpy(bf + 1, &keyuid, sizeof(keyuid));
+ key.data = (u_char *)bf;
+ key.size = sizeof(keyuid) + 1;
+ rval = hashpw(this, &key);
+
+ return (rval ? &pvt->passwd : NULL);
+}
+
+static void
+pw_rewind(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ pvt->pw_keynum = 0;
+}
+
+static void
+pw_minimize(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->pw_db != NULL) {
+ (void) (*pvt->pw_db->close)(pvt->pw_db);
+ pvt->pw_db = NULL;
+ }
+}
+
+/* Private. */
+
+static int
+initdb(struct pvt *pvt) {
+ const char *p;
+
+ if (pvt->pw_db) {
+ if (lseek((*pvt->pw_db->fd)(pvt->pw_db), 0L, SEEK_CUR) >= 0L)
+ return (1);
+ else
+ (void) (*pvt->pw_db->close)(pvt->pw_db);
+ }
+ pvt->pw_db = dbopen((p = _PATH_SMP_DB), O_RDONLY, 0, DB_HASH, NULL);
+ if (!pvt->pw_db)
+ pvt->pw_db = dbopen((p =_PATH_MP_DB), O_RDONLY,
+ 0, DB_HASH, NULL);
+ if (pvt->pw_db)
+ return (1);
+ if (!pvt->warned) {
+ syslog(LOG_ERR, "%s: %m", p);
+ pvt->warned++;
+ }
+ return (0);
+}
+
+static int
+hashpw(struct irs_pw *this, DBT *key) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *p, *t, *l;
+ DBT data;
+
+ if ((pvt->pw_db->get)(pvt->pw_db, key, &data, 0))
+ return (0);
+ p = (char *)data.data;
+ if (data.size > pvt->max) {
+ size_t newlen = pvt->max + 1024;
+ char *p = memget(newlen);
+ if (p == NULL) {
+ return (0);
+ }
+ if (pvt->line != NULL) {
+ memcpy(p, pvt->line, pvt->max);
+ memput(pvt->line, pvt->max);
+ }
+ pvt->max = newlen;
+ pvt->line = p;
+ }
+
+ /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
+ t = pvt->line;
+ l = pvt->line + pvt->max;
+#define EXPAND(e) if ((e = t) == NULL) return (0); else \
+ do if (t >= l) return (0); while ((*t++ = *p++) != '\0')
+#define SCALAR(v) if (t + sizeof v >= l) return (0); else \
+ (memmove(&(v), p, sizeof v), p += sizeof v)
+ EXPAND(pvt->passwd.pw_name);
+ EXPAND(pvt->passwd.pw_passwd);
+ SCALAR(pvt->passwd.pw_uid);
+ SCALAR(pvt->passwd.pw_gid);
+ SCALAR(pvt->passwd.pw_change);
+ EXPAND(pvt->passwd.pw_class);
+ EXPAND(pvt->passwd.pw_gecos);
+ EXPAND(pvt->passwd.pw_dir);
+ EXPAND(pvt->passwd.pw_shell);
+ SCALAR(pvt->passwd.pw_expire);
+ return (1);
+}
+
+#endif /* WANT_IRS_PW */
diff --git a/lib/bind/irs/lcl_sv.c b/lib/bind/irs/lcl_sv.c
new file mode 100644
index 0000000..7675834
--- /dev/null
+++ b/lib/bind/irs/lcl_sv.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_sv.c,v 1.3.18.1 2005/04/27 05:01:03 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#ifdef IRS_LCL_SV_DB
+#include <db.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Types */
+
+struct pvt {
+#ifdef IRS_LCL_SV_DB
+ DB * dbh;
+ int dbf;
+#endif
+ struct lcl_sv sv;
+};
+
+/* Forward */
+
+static void sv_close(struct irs_sv*);
+static struct servent * sv_next(struct irs_sv *);
+static struct servent * sv_byname(struct irs_sv *, const char *,
+ const char *);
+static struct servent * sv_byport(struct irs_sv *, int, const char *);
+static void sv_rewind(struct irs_sv *);
+static void sv_minimize(struct irs_sv *);
+/*global*/ struct servent * irs_lclsv_fnxt(struct lcl_sv *);
+#ifdef IRS_LCL_SV_DB
+static struct servent * sv_db_rec(struct lcl_sv *, DBT *, DBT *);
+#endif
+
+/* Portability */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public */
+
+struct irs_sv *
+irs_lcl_sv(struct irs_acc *this) {
+ struct irs_sv *sv;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if ((sv = memget(sizeof *sv)) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(sv, 0x5e, sizeof *sv);
+ if ((pvt = memget(sizeof *pvt)) == NULL) {
+ memput(sv, sizeof *sv);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ sv->private = pvt;
+ sv->close = sv_close;
+ sv->next = sv_next;
+ sv->byname = sv_byname;
+ sv->byport = sv_byport;
+ sv->rewind = sv_rewind;
+ sv->minimize = sv_minimize;
+ sv->res_get = NULL;
+ sv->res_set = NULL;
+#ifdef IRS_LCL_SV_DB
+ pvt->dbf = R_FIRST;
+#endif
+ return (sv);
+}
+
+/* Methods */
+
+static void
+sv_close(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh != NULL)
+ (*pvt->dbh->close)(pvt->dbh);
+#endif
+ if (pvt->sv.fp)
+ fclose(pvt->sv.fp);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+#ifdef IRS_LCL_SV_DB
+ struct pvt *pvt = (struct pvt *)this->private;
+#endif
+ struct servent *p;
+ char **cp;
+
+ sv_rewind(this);
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh != NULL) {
+ DBT key, data;
+
+ /* Note that (sizeof "/") == 2. */
+ if ((strlen(name) + sizeof "/" + proto ? strlen(proto) : 0)
+ > sizeof pvt->sv.line)
+ goto try_local;
+ key.data = pvt->sv.line;
+ key.size = SPRINTF((pvt->sv.line, "%s/%s", name,
+ proto ? proto : "")) + 1;
+ if (proto != NULL) {
+ if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0)
+ return (NULL);
+ } else if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR)
+ != 0)
+ return (NULL);
+ return (sv_db_rec(&pvt->sv, &key, &data));
+ }
+ try_local:
+#endif
+
+ while ((p = sv_next(this))) {
+ if (strcmp(name, p->s_name) == 0)
+ goto gotname;
+ for (cp = p->s_aliases; *cp; cp++)
+ if (strcmp(name, *cp) == 0)
+ goto gotname;
+ continue;
+ gotname:
+ if (proto == NULL || strcmp(p->s_proto, proto) == 0)
+ break;
+ }
+ return (p);
+}
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+#ifdef IRS_LCL_SV_DB
+ struct pvt *pvt = (struct pvt *)this->private;
+#endif
+ struct servent *p;
+
+ sv_rewind(this);
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh != NULL) {
+ DBT key, data;
+ u_short *ports;
+
+ ports = (u_short *)pvt->sv.line;
+ ports[0] = 0;
+ ports[1] = port;
+ key.data = ports;
+ key.size = sizeof(u_short) * 2;
+ if (proto && *proto) {
+ strncpy((char *)ports + key.size, proto,
+ BUFSIZ - key.size);
+ key.size += strlen((char *)ports + key.size) + 1;
+ if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0)
+ return (NULL);
+ } else {
+ if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR)
+ != 0)
+ return (NULL);
+ }
+ return (sv_db_rec(&pvt->sv, &key, &data));
+ }
+#endif
+ while ((p = sv_next(this))) {
+ if (p->s_port != port)
+ continue;
+ if (proto == NULL || strcmp(p->s_proto, proto) == 0)
+ break;
+ }
+ return (p);
+}
+
+static void
+sv_rewind(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->sv.fp) {
+ if (fseek(pvt->sv.fp, 0L, SEEK_SET) == 0)
+ return;
+ (void)fclose(pvt->sv.fp);
+ pvt->sv.fp = NULL;
+ }
+#ifdef IRS_LCL_SV_DB
+ pvt->dbf = R_FIRST;
+ if (pvt->dbh != NULL)
+ return;
+ pvt->dbh = dbopen(_PATH_SERVICES_DB, O_RDONLY,O_RDONLY,DB_BTREE, NULL);
+ if (pvt->dbh != NULL) {
+ if (fcntl((*pvt->dbh->fd)(pvt->dbh), F_SETFD, 1) < 0) {
+ (*pvt->dbh->close)(pvt->dbh);
+ pvt->dbh = NULL;
+ }
+ return;
+ }
+#endif
+ if ((pvt->sv.fp = fopen(_PATH_SERVICES, "r")) == NULL)
+ return;
+ if (fcntl(fileno(pvt->sv.fp), F_SETFD, 1) < 0) {
+ (void)fclose(pvt->sv.fp);
+ pvt->sv.fp = NULL;
+ }
+}
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh == NULL && pvt->sv.fp == NULL)
+#else
+ if (pvt->sv.fp == NULL)
+#endif
+ sv_rewind(this);
+
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh != NULL) {
+ DBT key, data;
+
+ while ((*pvt->dbh->seq)(pvt->dbh, &key, &data, pvt->dbf) == 0){
+ pvt->dbf = R_NEXT;
+ if (((char *)key.data)[0])
+ continue;
+ return (sv_db_rec(&pvt->sv, &key, &data));
+ }
+ }
+#endif
+
+ if (pvt->sv.fp == NULL)
+ return (NULL);
+ return (irs_lclsv_fnxt(&pvt->sv));
+}
+
+static void
+sv_minimize(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh != NULL) {
+ (*pvt->dbh->close)(pvt->dbh);
+ pvt->dbh = NULL;
+ }
+#endif
+ if (pvt->sv.fp != NULL) {
+ (void)fclose(pvt->sv.fp);
+ pvt->sv.fp = NULL;
+ }
+}
+
+/* Quasipublic. */
+
+struct servent *
+irs_lclsv_fnxt(struct lcl_sv *sv) {
+ char *p, *cp, **q;
+
+ again:
+ if ((p = fgets(sv->line, BUFSIZ, sv->fp)) == NULL)
+ return (NULL);
+ if (*p == '#')
+ goto again;
+ sv->serv.s_name = p;
+ while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
+ ++p;
+ if (*p == '\0' || *p == '#' || *p == '\n')
+ goto again;
+ *p++ = '\0';
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == '\0' || *p == '#' || *p == '\n')
+ goto again;
+ sv->serv.s_port = htons((u_short)strtol(p, &cp, 10));
+ if (cp == p || (*cp != '/' && *cp != ','))
+ goto again;
+ p = cp + 1;
+ sv->serv.s_proto = p;
+
+ q = sv->serv.s_aliases = sv->serv_aliases;
+
+ while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
+ ++p;
+
+ while (*p == ' ' || *p == '\t') {
+ *p++ = '\0';
+ while (*p == ' ' || *p == '\t')
+ ++p;
+ if (*p == '\0' || *p == '#' || *p == '\n')
+ break;
+ if (q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1])
+ *q++ = p;
+ while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
+ ++p;
+ }
+
+ *p = '\0';
+ *q = NULL;
+ return (&sv->serv);
+}
+
+/* Private. */
+
+#ifdef IRS_LCL_SV_DB
+static struct servent *
+sv_db_rec(struct lcl_sv *sv, DBT *key, DBT *data) {
+ char *p, **q;
+ int n;
+
+ p = data->data;
+ p[data->size - 1] = '\0'; /*%< should be, but we depend on it */
+ if (((char *)key->data)[0] == '\0') {
+ if (key->size < sizeof(u_short)*2 || data->size < 2)
+ return (NULL);
+ sv->serv.s_port = ((u_short *)key->data)[1];
+ n = strlen(p) + 1;
+ if ((size_t)n > sizeof(sv->line)) {
+ n = sizeof(sv->line);
+ }
+ memcpy(sv->line, p, n);
+ sv->serv.s_name = sv->line;
+ if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL)
+ *(sv->serv.s_proto)++ = '\0';
+ p += n;
+ data->size -= n;
+ } else {
+ if (data->size < sizeof(u_short) + 1)
+ return (NULL);
+ if (key->size > sizeof(sv->line))
+ key->size = sizeof(sv->line);
+ ((char *)key->data)[key->size - 1] = '\0';
+ memcpy(sv->line, key->data, key->size);
+ sv->serv.s_name = sv->line;
+ if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL)
+ *(sv->serv.s_proto)++ = '\0';
+ sv->serv.s_port = *(u_short *)data->data;
+ p += sizeof(u_short);
+ data->size -= sizeof(u_short);
+ }
+ q = sv->serv.s_aliases = sv->serv_aliases;
+ while (data->size > 0 && q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1]) {
+
+ *q++ = p;
+ n = strlen(p) + 1;
+ data->size -= n;
+ p += n;
+ }
+ *q = NULL;
+ return (&sv->serv);
+}
+#endif
+
+/*! \file */
diff --git a/lib/bind/irs/nis.c b/lib/bind/irs/nis.c
new file mode 100644
index 0000000..62cc267
--- /dev/null
+++ b/lib/bind/irs/nis.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nis.c,v 1.2.18.1 2005/04/27 05:01:03 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifdef WANT_IRS_NIS
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#ifdef T_NULL
+#undef T_NULL /* Silence re-definition warning of T_NULL. */
+#endif
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "nis_p.h"
+
+/* Forward */
+
+static void nis_close(struct irs_acc *);
+static struct __res_state * nis_res_get(struct irs_acc *);
+static void nis_res_set(struct irs_acc *, struct __res_state *,
+ void (*)(void *));
+
+/* Public */
+
+struct irs_acc *
+irs_nis_acc(const char *options) {
+ struct nis_p *nis;
+ struct irs_acc *acc;
+ char *domain;
+
+ UNUSED(options);
+
+ if (yp_get_default_domain(&domain) != 0)
+ return (NULL);
+ if (!(nis = memget(sizeof *nis))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(nis, 0, sizeof *nis);
+ if (!(acc = memget(sizeof *acc))) {
+ memput(nis, sizeof *nis);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(acc, 0x5e, sizeof *acc);
+ acc->private = nis;
+ nis->domain = strdup(domain);
+#ifdef WANT_IRS_GR
+ acc->gr_map = irs_nis_gr;
+#else
+ acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+ acc->pw_map = irs_nis_pw;
+#else
+ acc->pw_map = NULL;
+#endif
+ acc->sv_map = irs_nis_sv;
+ acc->pr_map = irs_nis_pr;
+ acc->ho_map = irs_nis_ho;
+ acc->nw_map = irs_nis_nw;
+ acc->ng_map = irs_nis_ng;
+ acc->res_get = nis_res_get;
+ acc->res_set = nis_res_set;
+ acc->close = nis_close;
+ return (acc);
+}
+
+/* Methods */
+
+static struct __res_state *
+nis_res_get(struct irs_acc *this) {
+ struct nis_p *nis = (struct nis_p *)this->private;
+
+ if (nis->res == NULL) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (res == NULL)
+ return (NULL);
+ memset(res, 0, sizeof *res);
+ nis_res_set(this, res, free);
+ }
+
+ if ((nis->res->options & RES_INIT) == 0 &&
+ res_ninit(nis->res) < 0)
+ return (NULL);
+
+ return (nis->res);
+}
+
+static void
+nis_res_set(struct irs_acc *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct nis_p *nis = (struct nis_p *)this->private;
+
+ if (nis->res && nis->free_res) {
+ res_nclose(nis->res);
+ (*nis->free_res)(nis->res);
+ }
+
+ nis->res = res;
+ nis->free_res = free_res;
+}
+
+static void
+nis_close(struct irs_acc *this) {
+ struct nis_p *nis = (struct nis_p *)this->private;
+
+ if (nis->res && nis->free_res)
+ (*nis->free_res)(nis->res);
+ free(nis->domain);
+ memput(nis, sizeof *nis);
+ memput(this, sizeof *this);
+}
+
+#endif /*WANT_IRS_NIS*/
+
+/*! \file */
diff --git a/lib/bind/irs/nis_gr.c b/lib/bind/irs/nis_gr.c
new file mode 100644
index 0000000..9d4f15d
--- /dev/null
+++ b/lib/bind/irs/nis_gr.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nis_gr.c,v 1.3.18.1 2005/04/27 05:01:03 sra Exp $";
+/* from getgrent.c 8.2 (Berkeley) 3/21/94"; */
+/* from BSDI Id: getgrent.c,v 2.8 1996/05/28 18:15:14 bostic Exp $ */
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(WANT_IRS_GR) || !defined(WANT_IRS_NIS)
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <isc/memcluster.h>
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+struct pvt {
+ int needrewind;
+ char * nis_domain;
+ char * curkey_data;
+ int curkey_len;
+ char * curval_data;
+ int curval_len;
+ /*%<
+ * Need space to store the entries read from the group file.
+ * The members list also needs space per member, and the
+ * strings making up the user names must be allocated
+ * somewhere. Rather than doing lots of small allocations,
+ * we keep one buffer and resize it as needed.
+ */
+ struct group group;
+ size_t nmemb; /*%< Malloc'd max index of gr_mem[]. */
+ char * membuf;
+ size_t membufsize;
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char group_bygid[] = "group.bygid";
+static /*const*/ char group_byname[] = "group.byname";
+
+/* Forward */
+
+static void gr_close(struct irs_gr *);
+static struct group * gr_next(struct irs_gr *);
+static struct group * gr_byname(struct irs_gr *, const char *);
+static struct group * gr_bygid(struct irs_gr *, gid_t);
+static void gr_rewind(struct irs_gr *);
+static void gr_minimize(struct irs_gr *);
+
+static struct group * makegroupent(struct irs_gr *);
+static void nisfree(struct pvt *, enum do_what);
+
+/* Public */
+
+struct irs_gr *
+irs_nis_gr(struct irs_acc *this) {
+ struct irs_gr *gr;
+ struct pvt *pvt;
+
+ if (!(gr = memget(sizeof *gr))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(gr, 0x5e, sizeof *gr);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(gr, sizeof *gr);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->needrewind = 1;
+ pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+ gr->private = pvt;
+ gr->close = gr_close;
+ gr->next = gr_next;
+ gr->byname = gr_byname;
+ gr->bygid = gr_bygid;
+ gr->rewind = gr_rewind;
+ gr->list = make_group_list;
+ gr->minimize = gr_minimize;
+ gr->res_get = NULL;
+ gr->res_set = NULL;
+ return (gr);
+}
+
+/* Methods */
+
+static void
+gr_close(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->group.gr_mem)
+ free(pvt->group.gr_mem);
+ if (pvt->membuf)
+ free(pvt->membuf);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct group *
+gr_next(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct group *rval;
+ int r;
+
+ do {
+ if (pvt->needrewind) {
+ nisfree(pvt, do_all);
+ r = yp_first(pvt->nis_domain, group_byname,
+ &pvt->curkey_data, &pvt->curkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ pvt->needrewind = 0;
+ } else {
+ char *newkey_data;
+ int newkey_len;
+
+ nisfree(pvt, do_val);
+ r = yp_next(pvt->nis_domain, group_byname,
+ pvt->curkey_data, pvt->curkey_len,
+ &newkey_data, &newkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ nisfree(pvt, do_key);
+ pvt->curkey_data = newkey_data;
+ pvt->curkey_len = newkey_len;
+ }
+ if (r != 0) {
+ errno = ENOENT;
+ return (NULL);
+ }
+ rval = makegroupent(this);
+ } while (rval == NULL);
+ return (rval);
+}
+
+static struct group *
+gr_byname(struct irs_gr *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ int r;
+
+ nisfree(pvt, do_val);
+ r = yp_match(pvt->nis_domain, group_byname, name, strlen(name),
+ &pvt->curval_data, &pvt->curval_len);
+ if (r != 0) {
+ errno = ENOENT;
+ return (NULL);
+ }
+ return (makegroupent(this));
+}
+
+static struct group *
+gr_bygid(struct irs_gr *this, gid_t gid) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char tmp[sizeof "4294967295"];
+ int r;
+
+ nisfree(pvt, do_val);
+ (void) sprintf(tmp, "%u", (unsigned int)gid);
+ r = yp_match(pvt->nis_domain, group_bygid, tmp, strlen(tmp),
+ &pvt->curval_data, &pvt->curval_len);
+ if (r != 0) {
+ errno = ENOENT;
+ return (NULL);
+ }
+ return (makegroupent(this));
+}
+
+static void
+gr_rewind(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ pvt->needrewind = 1;
+}
+
+static void
+gr_minimize(struct irs_gr *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+/* Private */
+
+static struct group *
+makegroupent(struct irs_gr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ unsigned int num_members = 0;
+ char *cp, **new;
+ u_long t;
+
+ if (pvt->group.gr_mem) {
+ free(pvt->group.gr_mem);
+ pvt->group.gr_mem = NULL;
+ pvt->nmemb = 0;
+ }
+ if (pvt->membuf)
+ free(pvt->membuf);
+ pvt->membuf = pvt->curval_data;
+ pvt->curval_data = NULL;
+
+ cp = pvt->membuf;
+ pvt->group.gr_name = cp;
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->group.gr_passwd = cp;
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ errno = 0;
+ t = strtoul(cp, NULL, 10);
+ if (errno == ERANGE)
+ goto cleanup;
+ pvt->group.gr_gid = (gid_t) t;
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ cp++;
+
+ if (*cp && cp[strlen(cp)-1] == '\n')
+ cp[strlen(cp)-1] = '\0';
+
+ /*
+ * Parse the members out.
+ */
+ while (*cp) {
+ if (num_members+1 >= pvt->nmemb || pvt->group.gr_mem == NULL) {
+ pvt->nmemb += 10;
+ new = realloc(pvt->group.gr_mem,
+ pvt->nmemb * sizeof(char *));
+ if (new == NULL)
+ goto cleanup;
+ pvt->group.gr_mem = new;
+ }
+ pvt->group.gr_mem[num_members++] = cp;
+ if (!(cp = strchr(cp, ',')))
+ break;
+ *cp++ = '\0';
+ }
+ if (pvt->group.gr_mem == NULL) {
+ pvt->group.gr_mem = malloc(sizeof(char*));
+ if (!pvt->group.gr_mem)
+ goto cleanup;
+ pvt->nmemb = 1;
+ }
+ pvt->group.gr_mem[num_members] = NULL;
+
+ return (&pvt->group);
+
+ cleanup:
+ if (pvt->group.gr_mem) {
+ free(pvt->group.gr_mem);
+ pvt->group.gr_mem = NULL;
+ pvt->nmemb = 0;
+ }
+ if (pvt->membuf) {
+ free(pvt->membuf);
+ pvt->membuf = NULL;
+ }
+ return (NULL);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+ if ((do_what & do_key) && pvt->curkey_data) {
+ free(pvt->curkey_data);
+ pvt->curkey_data = NULL;
+ }
+ if ((do_what & do_val) && pvt->curval_data) {
+ free(pvt->curval_data);
+ pvt->curval_data = NULL;
+ }
+}
+
+#endif /* WANT_IRS_GR && WANT_IRS_NIS */
+/*! \file */
diff --git a/lib/bind/irs/nis_ho.c b/lib/bind/irs/nis_ho.c
new file mode 100644
index 0000000..7524279
--- /dev/null
+++ b/lib/bind/irs/nis_ho.c
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nis_ho.c,v 1.4.18.1 2005/04/27 05:01:03 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_NIS
+static int __bind_irs_nis_unneeded;
+#else
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#ifdef T_NULL
+#undef T_NULL /* Silence re-definition warning of T_NULL. */
+#endif
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+#define MAXALIASES 35
+#define MAXADDRS 35
+
+#if PACKETSZ > 1024
+#define MAXPACKET PACKETSZ
+#else
+#define MAXPACKET 1024
+#endif
+
+struct pvt {
+ int needrewind;
+ char * nis_domain;
+ char * curkey_data;
+ int curkey_len;
+ char * curval_data;
+ int curval_len;
+ struct hostent host;
+ char * h_addr_ptrs[MAXADDRS + 1];
+ char * host_aliases[MAXALIASES + 1];
+ char hostbuf[8*1024];
+ u_char host_addr[16]; /*%< IPv4 or IPv6 */
+ struct __res_state *res;
+ void (*free_res)(void *);
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
+static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+static /*const*/ char hosts_byname[] = "hosts.byname";
+static /*const*/ char hosts_byaddr[] = "hosts.byaddr";
+static /*const*/ char ipnode_byname[] = "ipnode.byname";
+static /*const*/ char ipnode_byaddr[] = "ipnode.byaddr";
+static /*const*/ char yp_multi[] = "YP_MULTI_";
+
+/* Forwards */
+
+static void ho_close(struct irs_ho *this);
+static struct hostent * ho_byname(struct irs_ho *this, const char *name);
+static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
+ int af);
+static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ int len, int af);
+static struct hostent * ho_next(struct irs_ho *this);
+static void ho_rewind(struct irs_ho *this);
+static void ho_minimize(struct irs_ho *this);
+static struct __res_state * ho_res_get(struct irs_ho *this);
+static void ho_res_set(struct irs_ho *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+ const struct addrinfo *pai);
+
+static struct hostent * makehostent(struct irs_ho *this);
+static void nisfree(struct pvt *, enum do_what);
+static int init(struct irs_ho *this);
+
+/* Public */
+
+struct irs_ho *
+irs_nis_ho(struct irs_acc *this) {
+ struct irs_ho *ho;
+ struct pvt *pvt;
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(ho = memget(sizeof *ho))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ho, 0x5e, sizeof *ho);
+ pvt->needrewind = 1;
+ pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+ ho->private = pvt;
+ ho->close = ho_close;
+ ho->byname = ho_byname;
+ ho->byname2 = ho_byname2;
+ ho->byaddr = ho_byaddr;
+ ho->next = ho_next;
+ ho->rewind = ho_rewind;
+ ho->minimize = ho_minimize;
+ ho->res_set = ho_res_set;
+ ho->res_get = ho_res_get;
+ ho->addrinfo = ho_addrinfo;
+ return (ho);
+}
+
+/* Methods */
+
+static void
+ho_close(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ho_minimize(this);
+ nisfree(pvt, do_all);
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (pvt->res->options & RES_USE_INET6) {
+ hp = ho_byname2(this, name, AF_INET6);
+ if (hp)
+ return (hp);
+ }
+ return (ho_byname2(this, name, AF_INET));
+}
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ int r;
+ char *tmp;
+
+ UNUSED(af);
+
+ if (init(this) == -1)
+ return (NULL);
+
+ nisfree(pvt, do_val);
+
+ strcpy(pvt->hostbuf, yp_multi);
+ strncat(pvt->hostbuf, name, sizeof(pvt->hostbuf) - sizeof(yp_multi));
+ pvt->hostbuf[sizeof(pvt->hostbuf) - 1] = '\0';
+ for (r = sizeof(yp_multi) - 1; pvt->hostbuf[r] != '\0'; r++)
+ if (isupper((unsigned char)pvt->hostbuf[r]))
+ tolower(pvt->hostbuf[r]);
+
+ tmp = pvt->hostbuf;
+ r = yp_match(pvt->nis_domain, ipnode_byname, tmp,
+ strlen(tmp), &pvt->curval_data, &pvt->curval_len);
+ if (r != 0) {
+ tmp = pvt->hostbuf + sizeof(yp_multi) - 1;
+ r = yp_match(pvt->nis_domain, ipnode_byname, tmp,
+ strlen(tmp), &pvt->curval_data, &pvt->curval_len);
+ }
+ if (r != 0) {
+ tmp = pvt->hostbuf;
+ r = yp_match(pvt->nis_domain, hosts_byname, tmp,
+ strlen(tmp), &pvt->curval_data, &pvt->curval_len);
+ }
+ if (r != 0) {
+ tmp = pvt->hostbuf + sizeof(yp_multi) - 1;
+ r = yp_match(pvt->nis_domain, hosts_byname, tmp,
+ strlen(tmp), &pvt->curval_data, &pvt->curval_len);
+ }
+ if (r != 0) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ return (makehostent(this));
+}
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+ const u_char *uaddr = addr;
+ int r;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (af == AF_INET6 && len == IN6ADDRSZ &&
+ (!memcmp(uaddr, mapped, sizeof mapped) ||
+ !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
+ /* Unmap. */
+ addr = (const u_char *)addr + sizeof mapped;
+ uaddr += sizeof mapped;
+ af = AF_INET;
+ len = INADDRSZ;
+ }
+ if (inet_ntop(af, uaddr, tmp, sizeof tmp) == NULL) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ nisfree(pvt, do_val);
+ r = yp_match(pvt->nis_domain, ipnode_byaddr, tmp, strlen(tmp),
+ &pvt->curval_data, &pvt->curval_len);
+ if (r != 0)
+ r = yp_match(pvt->nis_domain, hosts_byaddr, tmp, strlen(tmp),
+ &pvt->curval_data, &pvt->curval_len);
+ if (r != 0) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ return (makehostent(this));
+}
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *rval;
+ int r;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ do {
+ if (pvt->needrewind) {
+ nisfree(pvt, do_all);
+ r = yp_first(pvt->nis_domain, hosts_byaddr,
+ &pvt->curkey_data, &pvt->curkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ pvt->needrewind = 0;
+ } else {
+ char *newkey_data;
+ int newkey_len;
+
+ nisfree(pvt, do_val);
+ r = yp_next(pvt->nis_domain, hosts_byaddr,
+ pvt->curkey_data, pvt->curkey_len,
+ &newkey_data, &newkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ nisfree(pvt, do_key);
+ pvt->curkey_data = newkey_data;
+ pvt->curkey_len = newkey_len;
+ }
+ if (r != 0) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ rval = makehostent(this);
+ } while (rval == NULL);
+ return (rval);
+}
+
+static void
+ho_rewind(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ pvt->needrewind = 1;
+}
+
+static void
+ho_minimize(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+}
+
+static struct __res_state *
+ho_res_get(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ ho_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+ho_res_set(struct irs_ho *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+}
+
+struct nis_res_target {
+ struct nis_res_target *next;
+ int family;
+};
+
+/* XXX */
+extern struct addrinfo *hostent2addrinfo __P((struct hostent *,
+ const struct addrinfo *pai));
+
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp;
+ struct nis_res_target q, q2, *p;
+ struct addrinfo sentinel, *cur;
+
+ memset(&q, 0, sizeof(q2));
+ memset(&q2, 0, sizeof(q2));
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ switch(pai->ai_family) {
+ case AF_UNSPEC: /*%< INET6 then INET4 */
+ q.family = AF_INET6;
+ q.next = &q2;
+ q2.family = AF_INET;
+ break;
+ case AF_INET6:
+ q.family = AF_INET6;
+ break;
+ case AF_INET:
+ q.family = AF_INET;
+ break;
+ default:
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /*%< ??? */
+ return(NULL);
+ }
+
+ for (p = &q; p; p = p->next) {
+ struct addrinfo *ai;
+
+ hp = (*this->byname2)(this, name, p->family);
+ if (hp == NULL) {
+ /* byname2 should've set an appropriate error */
+ continue;
+ }
+ if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
+ (hp->h_addr_list[0] == NULL)) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ continue;
+ }
+ ai = hostent2addrinfo(hp, pai);
+ if (ai) {
+ cur->ai_next = ai;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ }
+
+ if (sentinel.ai_next == NULL)
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+
+ return(sentinel.ai_next);
+}
+
+/* Private */
+
+/*%
+ipnodes:
+::1 localhost
+127.0.0.1 localhost
+1.2.3.4 FOO bar
+1.2.6.4 FOO bar
+1.2.6.5 host
+
+ipnodes.byname:
+YP_MULTI_localhost ::1,127.0.0.1 localhost
+YP_MULTI_foo 1.2.3.4,1.2.6.4 FOO bar
+YP_MULTI_bar 1.2.3.4,1.2.6.4 FOO bar
+host 1.2.6.5 host
+
+hosts.byname:
+localhost 127.0.0.1 localhost
+host 1.2.6.5 host
+YP_MULTI_foo 1.2.3.4,1.2.6.4 FOO bar
+YP_MULTI_bar 1.2.3.4,1.2.6.4 FOO bar
+*/
+
+static struct hostent *
+makehostent(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ static const char spaces[] = " \t";
+ char *cp, **q, *p, *comma, *ap;
+ int af = 0, len = 0;
+ int multi = 0;
+ int addr = 0;
+
+ p = pvt->curval_data;
+ if ((cp = strpbrk(p, "#\n")) != NULL)
+ *cp = '\0';
+ if (!(cp = strpbrk(p, spaces)))
+ return (NULL);
+ *cp++ = '\0';
+ ap = pvt->hostbuf;
+ do {
+ if ((comma = strchr(p, ',')) != NULL) {
+ *comma++ = '\0';
+ multi = 1;
+ }
+ if ((ap + IN6ADDRSZ) > (pvt->hostbuf + sizeof(pvt->hostbuf)))
+ break;
+ if ((pvt->res->options & RES_USE_INET6) &&
+ inet_pton(AF_INET6, p, ap) > 0) {
+ af = AF_INET6;
+ len = IN6ADDRSZ;
+ } else if (inet_pton(AF_INET, p, pvt->host_addr) > 0) {
+ if (pvt->res->options & RES_USE_INET6) {
+ map_v4v6_address((char*)pvt->host_addr, ap);
+ af = AF_INET6;
+ len = IN6ADDRSZ;
+ } else {
+ af = AF_INET;
+ len = INADDRSZ;
+ }
+ } else {
+ if (!multi)
+ return (NULL);
+ continue;
+ }
+ if (addr < MAXADDRS) {
+ pvt->h_addr_ptrs[addr++] = ap;
+ pvt->h_addr_ptrs[addr] = NULL;
+ ap += len;
+ }
+ } while ((p = comma) != NULL);
+ if (ap == pvt->hostbuf)
+ return (NULL);
+ pvt->host.h_addr_list = pvt->h_addr_ptrs;
+ pvt->host.h_length = len;
+ pvt->host.h_addrtype = af;
+ cp += strspn(cp, spaces);
+ pvt->host.h_name = cp;
+ q = pvt->host.h_aliases = pvt->host_aliases;
+ if ((cp = strpbrk(cp, spaces)) != NULL)
+ *cp++ = '\0';
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &pvt->host_aliases[MAXALIASES])
+ *q++ = cp;
+ if ((cp = strpbrk(cp, spaces)) != NULL)
+ *cp++ = '\0';
+ }
+ *q = NULL;
+ RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+ return (&pvt->host);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+ if ((do_what & do_key) && pvt->curkey_data) {
+ free(pvt->curkey_data);
+ pvt->curkey_data = NULL;
+ }
+ if ((do_what & do_val) && pvt->curval_data) {
+ free(pvt->curval_data);
+ pvt->curval_data = NULL;
+ }
+}
+
+static int
+init(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !ho_res_get(this))
+ return (-1);
+ if (((pvt->res->options & RES_INIT) == 0) &&
+ res_ninit(pvt->res) == -1)
+ return (-1);
+ return (0);
+}
+#endif /*WANT_IRS_NIS*/
+
+/*! \file */
diff --git a/lib/bind/irs/nis_ng.c b/lib/bind/irs/nis_ng.c
new file mode 100644
index 0000000..f2298b2
--- /dev/null
+++ b/lib/bind/irs/nis_ng.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nis_ng.c,v 1.3.18.1 2005/04/27 05:01:03 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_NIS
+static int __bind_irs_nis_unneeded;
+#else
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <isc/assertions.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#ifdef T_NULL
+#undef T_NULL /* Silence re-definition warning of T_NULL. */
+#endif
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+struct tmpgrp {
+ const char * name;
+ const char * host;
+ const char * user;
+ const char * domain;
+ struct tmpgrp * next;
+};
+
+struct pvt {
+ char * nis_domain;
+ struct tmpgrp * tmp;
+ struct tmpgrp * cur;
+ char * tmpgroup;
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char netgroup_map[] = "netgroup";
+
+/* Forward */
+
+static void ng_close(struct irs_ng *);
+static int ng_next(struct irs_ng *, const char **,
+ const char **, const char **);
+static int ng_test(struct irs_ng *,
+ const char *, const char *,
+ const char *, const char *);
+static void ng_rewind(struct irs_ng *, const char *);
+static void ng_minimize(struct irs_ng *);
+
+static void add_group_to_list(struct pvt *, const char *, int);
+static void add_tuple_to_list(struct pvt *, const char *, char *);
+static void tmpfree(struct pvt *);
+
+/* Public */
+
+struct irs_ng *
+irs_nis_ng(struct irs_acc *this) {
+ struct irs_ng *ng;
+ struct pvt *pvt;
+
+ if (!(ng = memget(sizeof *ng))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ng, 0x5e, sizeof *ng);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(ng, sizeof *ng);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+ ng->private = pvt;
+ ng->close = ng_close;
+ ng->next = ng_next;
+ ng->test = ng_test;
+ ng->rewind = ng_rewind;
+ ng->minimize = ng_minimize;
+ return (ng);
+}
+
+/* Methods */
+
+static void
+ng_close(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ tmpfree(pvt);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user, const char **domain) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->cur)
+ return (0);
+ *host = pvt->cur->host;
+ *user = pvt->cur->user;
+ *domain = pvt->cur->domain;
+ pvt->cur = pvt->cur->next;
+ return (1);
+}
+
+static int
+ng_test(struct irs_ng *this, const char *name,
+ const char *host, const char *user, const char *domain)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct tmpgrp *cur;
+
+ tmpfree(pvt);
+ add_group_to_list(pvt, name, strlen(name));
+ for (cur = pvt->tmp; cur; cur = cur->next) {
+ if ((!host || !cur->host || !strcmp(host, cur->host)) &&
+ (!user || !cur->user || !strcmp(user, cur->user)) &&
+ (!domain || !cur->domain || !strcmp(domain, cur->domain)))
+ break;
+ }
+ tmpfree(pvt);
+ return ((cur == NULL) ? 0 : 1);
+}
+
+static void
+ng_rewind(struct irs_ng *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ /* Either hand back or free the existing list. */
+ if (pvt->tmpgroup) {
+ if (pvt->tmp && !strcmp(pvt->tmpgroup, name))
+ goto reset;
+ tmpfree(pvt);
+ }
+ pvt->tmpgroup = strdup(name);
+ add_group_to_list(pvt, name, strlen(name));
+ reset:
+ pvt->cur = pvt->tmp;
+}
+
+static void
+ng_minimize(struct irs_ng *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+/* Private */
+
+static void
+add_group_to_list(struct pvt *pvt, const char *name, int len) {
+ char *vdata, *cp, *np;
+ struct tmpgrp *tmp;
+ int vlen, r;
+ char *nametmp;
+
+ /* Don't add the same group to the list more than once. */
+ for (tmp = pvt->tmp; tmp; tmp = tmp->next)
+ if (!strcmp(tmp->name, name))
+ return;
+
+ DE_CONST(name, nametmp);
+ r = yp_match(pvt->nis_domain, netgroup_map, nametmp, len,
+ &vdata, &vlen);
+ if (r == 0) {
+ cp = vdata;
+ if (*cp && cp[strlen(cp)-1] == '\n')
+ cp[strlen(cp)-1] = '\0';
+ for ( ; cp; cp = np) {
+ np = strchr(cp, ' ');
+ if (np)
+ *np++ = '\0';
+ if (*cp == '(')
+ add_tuple_to_list(pvt, name, cp);
+ else
+ add_group_to_list(pvt, cp, strlen(cp));
+ }
+ free(vdata);
+ }
+}
+
+static void
+add_tuple_to_list(struct pvt *pvt, const char *name, char *cp) {
+ struct tmpgrp *tmp;
+ char *tp, *np;
+
+ INSIST(*cp++ == '(');
+
+ tmp = malloc(sizeof *tmp + strlen(name) + sizeof '\0' +
+ strlen(cp) - sizeof ')');
+ if (!tmp)
+ return;
+ memset(tmp, 0, sizeof *tmp);
+ tp = ((char *)tmp) + sizeof *tmp;
+
+ /* Name */
+ strcpy(tp, name);
+ tmp->name = tp;
+ tp += strlen(tp) + 1;
+
+ /* Host */
+ if (!(np = strchr(cp, ',')))
+ goto cleanup;
+ *np++ = '\0';
+ strcpy(tp, cp);
+ tmp->host = tp;
+ tp += strlen(tp) + 1;
+ cp = np;
+
+ /* User */
+ if (!(np = strchr(cp, ',')))
+ goto cleanup;
+ *np++ = '\0';
+ strcpy(tp, cp);
+ tmp->user = tp;
+ tp += strlen(tp) + 1;
+ cp = np;
+
+ /* Domain */
+ if (!(np = strchr(cp, ')')))
+ goto cleanup;
+ *np++ = '\0';
+ strcpy(tp, cp);
+ tmp->domain = tp;
+
+ /*
+ * Empty string in file means wildcard, but
+ * NULL string in return value means wildcard.
+ */
+ if (!*tmp->host)
+ tmp->host = NULL;
+ if (!*tmp->user)
+ tmp->user = NULL;
+ if (!*tmp->domain)
+ tmp->domain = NULL;
+
+ /* Add to list (LIFO). */
+ tmp->next = pvt->tmp;
+ pvt->tmp = tmp;
+ return;
+
+ cleanup:
+ free(tmp);
+}
+
+static void
+tmpfree(struct pvt *pvt) {
+ struct tmpgrp *cur, *next;
+
+ if (pvt->tmpgroup) {
+ free(pvt->tmpgroup);
+ pvt->tmpgroup = NULL;
+ }
+ for (cur = pvt->tmp; cur; cur = next) {
+ next = cur->next;
+ free(cur);
+ }
+ pvt->tmp = NULL;
+}
+
+#endif /*WANT_IRS_NIS*/
+
+/*! \file */
diff --git a/lib/bind/irs/nis_nw.c b/lib/bind/irs/nis_nw.c
new file mode 100644
index 0000000..2fb50dc
--- /dev/null
+++ b/lib/bind/irs/nis_nw.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nis_nw.c,v 1.3.18.1 2005/04/27 05:01:03 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_NIS
+static int __bind_irs_nis_unneeded;
+#else
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#ifdef T_NULL
+#undef T_NULL /* Silence re-definition warning of T_NULL. */
+#endif
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+#define MAXALIASES 35
+#define MAXADDRSIZE 4
+
+struct pvt {
+ int needrewind;
+ char * nis_domain;
+ char * curkey_data;
+ int curkey_len;
+ char * curval_data;
+ int curval_len;
+
+ struct nwent nwent;
+ char * nwbuf;
+
+ char * aliases[MAXALIASES + 1];
+ u_char addr[MAXADDRSIZE];
+
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char networks_byname[] = "networks.byname";
+static /*const*/ char networks_byaddr[] = "networks.byaddr";
+
+/* Forward */
+
+static void nw_close(struct irs_nw *);
+static struct nwent * nw_byname(struct irs_nw *, const char *, int);
+static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int);
+static struct nwent * nw_next(struct irs_nw *);
+static void nw_rewind(struct irs_nw *);
+static void nw_minimize(struct irs_nw *);
+static struct __res_state * nw_res_get(struct irs_nw *this);
+static void nw_res_set(struct irs_nw *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+
+static struct nwent * makenwent(struct irs_nw *this);
+static void nisfree(struct pvt *, enum do_what);
+static int init(struct irs_nw *this);
+
+/* Public */
+
+struct irs_nw *
+irs_nis_nw(struct irs_acc *this) {
+ struct irs_nw *nw;
+ struct pvt *pvt;
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(nw = memget(sizeof *nw))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(nw, 0x5e, sizeof *nw);
+ pvt->needrewind = 1;
+ pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+ nw->private = pvt;
+ nw->close = nw_close;
+ nw->byname = nw_byname;
+ nw->byaddr = nw_byaddr;
+ nw->next = nw_next;
+ nw->rewind = nw_rewind;
+ nw->minimize = nw_minimize;
+ nw->res_get = nw_res_get;
+ nw->res_set = nw_res_set;
+ return (nw);
+}
+
+/* Methods */
+
+static void
+nw_close(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ nw_minimize(this);
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ if (pvt->nwbuf)
+ free(pvt->nwbuf);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int length, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char tmp[sizeof "255.255.255.255/32"], *t;
+ int r;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (af != AF_INET) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ nisfree(pvt, do_val);
+ /* Try it with /CIDR first. */
+ if (inet_net_ntop(AF_INET, net, length, tmp, sizeof tmp) == NULL) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ r = yp_match(pvt->nis_domain, networks_byaddr, tmp, strlen(tmp),
+ &pvt->curval_data, &pvt->curval_len);
+ if (r != 0) {
+ /* Give it a shot without the /CIDR. */
+ if ((t = strchr(tmp, '/')) != NULL) {
+ *t = '\0';
+ r = yp_match(pvt->nis_domain, networks_byaddr,
+ tmp, strlen(tmp),
+ &pvt->curval_data, &pvt->curval_len);
+ }
+ if (r != 0) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ }
+ return (makenwent(this));
+}
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ int r;
+ char *tmp;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (af != AF_INET) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ nisfree(pvt, do_val);
+ DE_CONST(name, tmp);
+ r = yp_match(pvt->nis_domain, networks_byname, tmp,
+ strlen(tmp), &pvt->curval_data, &pvt->curval_len);
+ if (r != 0) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ return (makenwent(this));
+}
+
+static void
+nw_rewind(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ pvt->needrewind = 1;
+}
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct nwent *rval;
+ int r;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ do {
+ if (pvt->needrewind) {
+ nisfree(pvt, do_all);
+ r = yp_first(pvt->nis_domain, networks_byaddr,
+ &pvt->curkey_data, &pvt->curkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ pvt->needrewind = 0;
+ } else {
+ char *newkey_data;
+ int newkey_len;
+
+ nisfree(pvt, do_val);
+ r = yp_next(pvt->nis_domain, networks_byaddr,
+ pvt->curkey_data, pvt->curkey_len,
+ &newkey_data, &newkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ nisfree(pvt, do_key);
+ pvt->curkey_data = newkey_data;
+ pvt->curkey_len = newkey_len;
+ }
+ if (r != 0) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ rval = makenwent(this);
+ } while (rval == NULL);
+ return (rval);
+}
+
+static void
+nw_minimize(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+}
+
+static struct __res_state *
+nw_res_get(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ nw_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+nw_res_set(struct irs_nw *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+}
+
+/* Private */
+
+static struct nwent *
+makenwent(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ static const char spaces[] = " \t";
+ char *t, *cp, **ap;
+
+ if (pvt->nwbuf)
+ free(pvt->nwbuf);
+ pvt->nwbuf = pvt->curval_data;
+ pvt->curval_data = NULL;
+
+ if ((cp = strpbrk(pvt->nwbuf, "#\n")) != NULL)
+ *cp = '\0';
+ cp = pvt->nwbuf;
+
+ /* Name */
+ pvt->nwent.n_name = cp;
+ cp += strcspn(cp, spaces);
+ if (!*cp)
+ goto cleanup;
+ *cp++ = '\0';
+ cp += strspn(cp, spaces);
+
+ /* Network */
+ pvt->nwent.n_addrtype = AF_INET;
+ t = cp + strcspn(cp, spaces);
+ if (*t)
+ *t++ = '\0';
+ pvt->nwent.n_length = inet_net_pton(AF_INET, cp,
+ pvt->addr, sizeof pvt->addr);
+ if (pvt->nwent.n_length < 0)
+ goto cleanup;
+ pvt->nwent.n_addr = pvt->addr;
+ cp = t;
+
+ /* Aliases */
+ ap = pvt->nwent.n_aliases = pvt->aliases;
+ while (*cp) {
+ if (ap >= &pvt->aliases[MAXALIASES])
+ break;
+ *ap++ = cp;
+ cp += strcspn(cp, spaces);
+ if (!*cp)
+ break;
+ *cp++ = '\0';
+ cp += strspn(cp, spaces);
+ }
+ *ap = NULL;
+
+ return (&pvt->nwent);
+
+ cleanup:
+ if (pvt->nwbuf) {
+ free(pvt->nwbuf);
+ pvt->nwbuf = NULL;
+ }
+ return (NULL);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+ if ((do_what & do_key) && pvt->curkey_data) {
+ free(pvt->curkey_data);
+ pvt->curkey_data = NULL;
+ }
+ if ((do_what & do_val) && pvt->curval_data) {
+ free(pvt->curval_data);
+ pvt->curval_data = NULL;
+ }
+}
+
+static int
+init(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !nw_res_get(this))
+ return (-1);
+ if (((pvt->res->options & RES_INIT) == 0) &&
+ res_ninit(pvt->res) == -1)
+ return (-1);
+ return (0);
+}
+
+#endif /*WANT_IRS_NIS*/
+
+/*! \file */
diff --git a/lib/bind/irs/nis_p.h b/lib/bind/irs/nis_p.h
new file mode 100644
index 0000000..9e7f26c
--- /dev/null
+++ b/lib/bind/irs/nis_p.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: nis_p.h,v 1.2.18.1 2005/04/27 05:01:04 sra Exp $
+ */
+
+/*! \file
+ * \brief
+ * nis_p.h - private include file for the NIS functions.
+ */
+
+/*%
+ * Object state.
+ */
+struct nis_p {
+ char * domain;
+ struct __res_state * res;
+ void (*free_res) __P((void *));
+};
+
+
+/*
+ * Methods.
+ */
+
+extern struct irs_gr * irs_nis_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_nis_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_nis_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_nis_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_nis_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_nis_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_nis_ng __P((struct irs_acc *));
diff --git a/lib/bind/irs/nis_pr.c b/lib/bind/irs/nis_pr.c
new file mode 100644
index 0000000..58ff84d
--- /dev/null
+++ b/lib/bind/irs/nis_pr.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nis_pr.c,v 1.3.18.1 2005/04/27 05:01:04 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_NIS
+static int __bind_irs_nis_unneeded;
+#else
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#ifdef T_NULL
+#undef T_NULL /* Silence re-definition warning of T_NULL. */
+#endif
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+struct pvt {
+ int needrewind;
+ char * nis_domain;
+ char * curkey_data;
+ int curkey_len;
+ char * curval_data;
+ int curval_len;
+ struct protoent proto;
+ char * prbuf;
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char protocols_byname[] = "protocols.byname";
+static /*const*/ char protocols_bynumber[] = "protocols.bynumber";
+
+/* Forward */
+
+static void pr_close(struct irs_pr *);
+static struct protoent * pr_byname(struct irs_pr *, const char *);
+static struct protoent * pr_bynumber(struct irs_pr *, int);
+static struct protoent * pr_next(struct irs_pr *);
+static void pr_rewind(struct irs_pr *);
+static void pr_minimize(struct irs_pr *);
+
+static struct protoent * makeprotoent(struct irs_pr *this);
+static void nisfree(struct pvt *, enum do_what);
+
+/* Public */
+
+struct irs_pr *
+irs_nis_pr(struct irs_acc *this) {
+ struct irs_pr *pr;
+ struct pvt *pvt;
+
+ if (!(pr = memget(sizeof *pr))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pr, 0x5e, sizeof *pr);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(pr, sizeof *pr);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->needrewind = 1;
+ pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+ pr->private = pvt;
+ pr->byname = pr_byname;
+ pr->bynumber = pr_bynumber;
+ pr->next = pr_next;
+ pr->rewind = pr_rewind;
+ pr->close = pr_close;
+ pr->minimize = pr_minimize;
+ pr->res_get = NULL;
+ pr->res_set = NULL;
+ return (pr);
+}
+
+/* Methods. */
+
+static void
+pr_close(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ nisfree(pvt, do_all);
+ if (pvt->proto.p_aliases)
+ free(pvt->proto.p_aliases);
+ if (pvt->prbuf)
+ free(pvt->prbuf);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ int r;
+ char *tmp;
+
+ nisfree(pvt, do_val);
+ DE_CONST(name, tmp);
+ r = yp_match(pvt->nis_domain, protocols_byname, tmp,
+ strlen(tmp), &pvt->curval_data, &pvt->curval_len);
+ if (r != 0) {
+ errno = ENOENT;
+ return (NULL);
+ }
+ return (makeprotoent(this));
+}
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int num) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char tmp[sizeof "-4294967295"];
+ int r;
+
+ nisfree(pvt, do_val);
+ (void) sprintf(tmp, "%d", num);
+ r = yp_match(pvt->nis_domain, protocols_bynumber, tmp, strlen(tmp),
+ &pvt->curval_data, &pvt->curval_len);
+ if (r != 0) {
+ errno = ENOENT;
+ return (NULL);
+ }
+ return (makeprotoent(this));
+}
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct protoent *rval;
+ int r;
+
+ do {
+ if (pvt->needrewind) {
+ nisfree(pvt, do_all);
+ r = yp_first(pvt->nis_domain, protocols_bynumber,
+ &pvt->curkey_data, &pvt->curkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ pvt->needrewind = 0;
+ } else {
+ char *newkey_data;
+ int newkey_len;
+
+ nisfree(pvt, do_val);
+ r = yp_next(pvt->nis_domain, protocols_bynumber,
+ pvt->curkey_data, pvt->curkey_len,
+ &newkey_data, &newkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ nisfree(pvt, do_key);
+ pvt->curkey_data = newkey_data;
+ pvt->curkey_len = newkey_len;
+ }
+ if (r != 0) {
+ errno = ENOENT;
+ return (NULL);
+ }
+ rval = makeprotoent(this);
+ } while (rval == NULL);
+ return (rval);
+}
+
+static void
+pr_rewind(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ pvt->needrewind = 1;
+}
+
+static void
+pr_minimize(struct irs_pr *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+/* Private */
+
+static struct protoent *
+makeprotoent(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *p, **t;
+ int n, m;
+
+ if (pvt->prbuf)
+ free(pvt->prbuf);
+ pvt->prbuf = pvt->curval_data;
+ pvt->curval_data = NULL;
+
+ for (p = pvt->prbuf; *p && *p != '#';)
+ p++;
+ while (p > pvt->prbuf && isspace((unsigned char)(p[-1])))
+ p--;
+ *p = '\0';
+
+ p = pvt->prbuf;
+ n = m = 0;
+
+ pvt->proto.p_name = p;
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (!*p)
+ return (NULL);
+ *p++ = '\0';
+
+ while (*p && isspace((unsigned char)*p))
+ p++;
+ pvt->proto.p_proto = atoi(p);
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ *p++ = '\0';
+
+ while (*p) {
+ if ((n + 1) >= m || !pvt->proto.p_aliases) {
+ m += 10;
+ t = realloc(pvt->proto.p_aliases,
+ m * sizeof(char *));
+ if (!t) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ pvt->proto.p_aliases = t;
+ }
+ pvt->proto.p_aliases[n++] = p;
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (*p)
+ *p++ = '\0';
+ }
+ if (!pvt->proto.p_aliases)
+ pvt->proto.p_aliases = malloc(sizeof(char *));
+ if (!pvt->proto.p_aliases)
+ goto cleanup;
+ pvt->proto.p_aliases[n] = NULL;
+ return (&pvt->proto);
+
+ cleanup:
+ if (pvt->proto.p_aliases) {
+ free(pvt->proto.p_aliases);
+ pvt->proto.p_aliases = NULL;
+ }
+ if (pvt->prbuf) {
+ free(pvt->prbuf);
+ pvt->prbuf = NULL;
+ }
+ return (NULL);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+ if ((do_what & do_key) && pvt->curkey_data) {
+ free(pvt->curkey_data);
+ pvt->curkey_data = NULL;
+ }
+ if ((do_what & do_val) && pvt->curval_data) {
+ free(pvt->curval_data);
+ pvt->curval_data = NULL;
+ }
+}
+
+#endif /*WANT_IRS_NIS*/
+
+/*! \file */
diff --git a/lib/bind/irs/nis_pw.c b/lib/bind/irs/nis_pw.c
new file mode 100644
index 0000000..02c6b42
--- /dev/null
+++ b/lib/bind/irs/nis_pw.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nis_pw.c,v 1.3.18.1 2005/04/27 05:01:04 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(WANT_IRS_PW) || !defined(WANT_IRS_NIS)
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <isc/memcluster.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+struct pvt {
+ int needrewind;
+ char * nis_domain;
+ char * curkey_data;
+ int curkey_len;
+ char * curval_data;
+ int curval_len;
+ struct passwd passwd;
+ char * pwbuf;
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char passwd_byname[] = "passwd.byname";
+static /*const*/ char passwd_byuid[] = "passwd.byuid";
+
+/* Forward */
+
+static void pw_close(struct irs_pw *);
+static struct passwd * pw_next(struct irs_pw *);
+static struct passwd * pw_byname(struct irs_pw *, const char *);
+static struct passwd * pw_byuid(struct irs_pw *, uid_t);
+static void pw_rewind(struct irs_pw *);
+static void pw_minimize(struct irs_pw *);
+
+static struct passwd * makepasswdent(struct irs_pw *);
+static void nisfree(struct pvt *, enum do_what);
+
+/* Public */
+
+struct irs_pw *
+irs_nis_pw(struct irs_acc *this) {
+ struct irs_pw *pw;
+ struct pvt *pvt;
+
+ if (!(pw = memget(sizeof *pw))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pw, 0x5e, sizeof *pw);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(pw, sizeof *pw);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->needrewind = 1;
+ pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+ pw->private = pvt;
+ pw->close = pw_close;
+ pw->next = pw_next;
+ pw->byname = pw_byname;
+ pw->byuid = pw_byuid;
+ pw->rewind = pw_rewind;
+ pw->minimize = pw_minimize;
+ pw->res_get = NULL;
+ pw->res_set = NULL;
+ return (pw);
+}
+
+/* Methods */
+
+static void
+pw_close(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->pwbuf)
+ free(pvt->pwbuf);
+ nisfree(pvt, do_all);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct passwd *
+pw_next(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct passwd *rval;
+ int r;
+
+ do {
+ if (pvt->needrewind) {
+ nisfree(pvt, do_all);
+ r = yp_first(pvt->nis_domain, passwd_byname,
+ &pvt->curkey_data, &pvt->curkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ pvt->needrewind = 0;
+ } else {
+ char *newkey_data;
+ int newkey_len;
+
+ nisfree(pvt, do_val);
+ r = yp_next(pvt->nis_domain, passwd_byname,
+ pvt->curkey_data, pvt->curkey_len,
+ &newkey_data, &newkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ nisfree(pvt, do_key);
+ pvt->curkey_data = newkey_data;
+ pvt->curkey_len = newkey_len;
+ }
+ if (r != 0) {
+ errno = ENOENT;
+ return (NULL);
+ }
+ rval = makepasswdent(this);
+ } while (rval == NULL);
+ return (rval);
+}
+
+static struct passwd *
+pw_byname(struct irs_pw *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ int r;
+ char *tmp;
+
+ nisfree(pvt, do_val);
+ DE_CONST(name, tmp);
+ r = yp_match(pvt->nis_domain, passwd_byname, tmp, strlen(tmp),
+ &pvt->curval_data, &pvt->curval_len);
+ if (r != 0) {
+ errno = ENOENT;
+ return (NULL);
+ }
+ return (makepasswdent(this));
+}
+
+static struct passwd *
+pw_byuid(struct irs_pw *this, uid_t uid) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char tmp[sizeof "4294967295"];
+ int r;
+
+ nisfree(pvt, do_val);
+ (void) sprintf(tmp, "%u", (unsigned int)uid);
+ r = yp_match(pvt->nis_domain, passwd_byuid, tmp, strlen(tmp),
+ &pvt->curval_data, &pvt->curval_len);
+ if (r != 0) {
+ errno = ENOENT;
+ return (NULL);
+ }
+ return (makepasswdent(this));
+}
+
+static void
+pw_rewind(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ pvt->needrewind = 1;
+}
+
+static void
+pw_minimize(struct irs_pw *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+/* Private */
+
+static struct passwd *
+makepasswdent(struct irs_pw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *cp;
+
+ memset(&pvt->passwd, 0, sizeof pvt->passwd);
+ if (pvt->pwbuf)
+ free(pvt->pwbuf);
+ pvt->pwbuf = pvt->curval_data;
+ pvt->curval_data = NULL;
+
+ cp = pvt->pwbuf;
+ pvt->passwd.pw_name = cp;
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+#ifdef HAS_PW_CLASS
+ pvt->passwd.pw_class = cp; /*%< Needs to point at a \0. */
+#endif
+ *cp++ = '\0';
+
+ pvt->passwd.pw_passwd = cp;
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->passwd.pw_uid = atoi(cp);
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->passwd.pw_gid = atoi(cp);
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->passwd.pw_gecos = cp;
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->passwd.pw_dir = cp;
+ if (!(cp = strchr(cp, ':')))
+ goto cleanup;
+ *cp++ = '\0';
+
+ pvt->passwd.pw_shell = cp;
+
+ if ((cp = strchr(cp, '\n')) != NULL)
+ *cp = '\0';
+
+ return (&pvt->passwd);
+
+ cleanup:
+ free(pvt->pwbuf);
+ pvt->pwbuf = NULL;
+ return (NULL);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+ if ((do_what & do_key) && pvt->curkey_data) {
+ free(pvt->curkey_data);
+ pvt->curkey_data = NULL;
+ }
+ if ((do_what & do_val) && pvt->curval_data) {
+ free(pvt->curval_data);
+ pvt->curval_data = NULL;
+ }
+}
+
+#endif /* WANT_IRS_PW && WANT_IRS_NIS */
+/*! \file */
diff --git a/lib/bind/irs/nis_sv.c b/lib/bind/irs/nis_sv.c
new file mode 100644
index 0000000..dd307f0
--- /dev/null
+++ b/lib/bind/irs/nis_sv.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nis_sv.c,v 1.3.18.1 2005/04/27 05:01:04 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_NIS
+static int __bind_irs_nis_unneeded;
+#else
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <sys/socket.h>
+#ifdef T_NULL
+#undef T_NULL /* Silence re-definition warning of T_NULL. */
+#endif
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+struct pvt {
+ int needrewind;
+ char * nis_domain;
+ char * curkey_data;
+ int curkey_len;
+ char * curval_data;
+ int curval_len;
+ char line[BUFSIZ+1];
+ struct servent serv;
+ char * svbuf;
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char services_byname[] = "services.byname";
+
+/* Forward */
+
+static void sv_close(struct irs_sv*);
+static struct servent * sv_next(struct irs_sv *);
+static struct servent * sv_byname(struct irs_sv *, const char *,
+ const char *);
+static struct servent * sv_byport(struct irs_sv *, int, const char *);
+static void sv_rewind(struct irs_sv *);
+static void sv_minimize(struct irs_sv *);
+
+static struct servent * makeservent(struct irs_sv *this);
+static void nisfree(struct pvt *, enum do_what);
+
+/* Public */
+
+struct irs_sv *
+irs_nis_sv(struct irs_acc *this) {
+ struct irs_sv *sv;
+ struct pvt *pvt;
+
+ if (!(sv = memget(sizeof *sv))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(sv, 0x5e, sizeof *sv);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(sv, sizeof *sv);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->needrewind = 1;
+ pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+ sv->private = pvt;
+ sv->close = sv_close;
+ sv->next = sv_next;
+ sv->byname = sv_byname;
+ sv->byport = sv_byport;
+ sv->rewind = sv_rewind;
+ sv->minimize = sv_minimize;
+ sv->res_get = NULL;
+ sv->res_set = NULL;
+ return (sv);
+}
+
+/* Methods */
+
+static void
+sv_close(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ nisfree(pvt, do_all);
+ if (pvt->serv.s_aliases)
+ free(pvt->serv.s_aliases);
+ if (pvt->svbuf)
+ free(pvt->svbuf);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+ struct servent *serv;
+ char **sap;
+
+ sv_rewind(this);
+ while ((serv = sv_next(this)) != NULL) {
+ if (proto != NULL && strcmp(proto, serv->s_proto))
+ continue;
+ if (!strcmp(name, serv->s_name))
+ break;
+ for (sap = serv->s_aliases; sap && *sap; sap++)
+ if (!strcmp(name, *sap))
+ break;
+ }
+ return (serv);
+}
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+ struct servent *serv;
+
+ sv_rewind(this);
+ while ((serv = sv_next(this)) != NULL) {
+ if (proto != NULL && strcmp(proto, serv->s_proto))
+ continue;
+ if (serv->s_port == port)
+ break;
+ }
+ return (serv);
+}
+
+static void
+sv_rewind(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ pvt->needrewind = 1;
+}
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct servent *rval;
+ int r;
+
+ do {
+ if (pvt->needrewind) {
+ nisfree(pvt, do_all);
+ r = yp_first(pvt->nis_domain, services_byname,
+ &pvt->curkey_data, &pvt->curkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ pvt->needrewind = 0;
+ } else {
+ char *newkey_data;
+ int newkey_len;
+
+ nisfree(pvt, do_val);
+ r = yp_next(pvt->nis_domain, services_byname,
+ pvt->curkey_data, pvt->curkey_len,
+ &newkey_data, &newkey_len,
+ &pvt->curval_data, &pvt->curval_len);
+ nisfree(pvt, do_key);
+ pvt->curkey_data = newkey_data;
+ pvt->curkey_len = newkey_len;
+ }
+ if (r != 0) {
+ errno = ENOENT;
+ return (NULL);
+ }
+ rval = makeservent(this);
+ } while (rval == NULL);
+ return (rval);
+}
+
+static void
+sv_minimize(struct irs_sv *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+/* Private */
+
+static struct servent *
+makeservent(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ static const char spaces[] = " \t";
+ char *p, **t;
+ int n, m;
+
+ if (pvt->svbuf)
+ free(pvt->svbuf);
+ pvt->svbuf = pvt->curval_data;
+ pvt->curval_data = NULL;
+
+ if (pvt->serv.s_aliases) {
+ free(pvt->serv.s_aliases);
+ pvt->serv.s_aliases = NULL;
+ }
+
+ if ((p = strpbrk(pvt->svbuf, "#\n")))
+ *p = '\0';
+
+ p = pvt->svbuf;
+
+ pvt->serv.s_name = p;
+ p += strcspn(p, spaces);
+ if (!*p)
+ goto cleanup;
+ *p++ = '\0';
+ p += strspn(p, spaces);
+
+ pvt->serv.s_port = htons((u_short) atoi(p));
+ pvt->serv.s_proto = NULL;
+
+ while (*p && !isspace((unsigned char)*p))
+ if (*p++ == '/')
+ pvt->serv.s_proto = p;
+ if (!pvt->serv.s_proto)
+ goto cleanup;
+ if (*p) {
+ *p++ = '\0';
+ p += strspn(p, spaces);
+ }
+
+ n = m = 0;
+ while (*p) {
+ if ((n + 1) >= m || !pvt->serv.s_aliases) {
+ m += 10;
+ t = realloc(pvt->serv.s_aliases, m * sizeof(char *));
+ if (!t) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ pvt->serv.s_aliases = t;
+ }
+ pvt->serv.s_aliases[n++] = p;
+ p += strcspn(p, spaces);
+ if (!*p)
+ break;
+ *p++ = '\0';
+ p += strspn(p, spaces);
+ }
+ if (!pvt->serv.s_aliases)
+ pvt->serv.s_aliases = malloc(sizeof(char *));
+ if (!pvt->serv.s_aliases)
+ goto cleanup;
+ pvt->serv.s_aliases[n] = NULL;
+ return (&pvt->serv);
+
+ cleanup:
+ if (pvt->serv.s_aliases) {
+ free(pvt->serv.s_aliases);
+ pvt->serv.s_aliases = NULL;
+ }
+ if (pvt->svbuf) {
+ free(pvt->svbuf);
+ pvt->svbuf = NULL;
+ }
+ return (NULL);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+ if ((do_what & do_key) && pvt->curkey_data) {
+ free(pvt->curkey_data);
+ pvt->curkey_data = NULL;
+ }
+ if ((do_what & do_val) && pvt->curval_data) {
+ free(pvt->curval_data);
+ pvt->curval_data = NULL;
+ }
+}
+
+#endif /*WANT_IRS_NIS*/
+
+/*! \file */
diff --git a/lib/bind/irs/nul_ng.c b/lib/bind/irs/nul_ng.c
new file mode 100644
index 0000000..fa9ec46
--- /dev/null
+++ b/lib/bind/irs/nul_ng.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nul_ng.c,v 1.2.18.1 2005/04/27 05:01:04 sra Exp $";
+#endif
+
+/*! \file
+ * \brief
+ * nul_ng.c - the netgroup accessor null map
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#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/lib/bind/irs/pathnames.h b/lib/bind/irs/pathnames.h
new file mode 100644
index 0000000..c775de2
--- /dev/null
+++ b/lib/bind/irs/pathnames.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: pathnames.h,v 1.2.18.1 2005/04/27 05:01:04 sra Exp $
+ */
+
+#ifndef _PATH_IRS_CONF
+#define _PATH_IRS_CONF "/etc/irs.conf"
+#endif
+
+#ifndef _PATH_NETWORKS
+#define _PATH_NETWORKS "/etc/networks"
+#endif
+
+#ifndef _PATH_GROUP
+#define _PATH_GROUP "/etc/group"
+#endif
+
+#ifndef _PATH_NETGROUP
+#define _PATH_NETGROUP "/etc/netgroup"
+#endif
+
+#ifndef _PATH_SERVICES
+#define _PATH_SERVICES "/etc/services"
+#endif
+
+#ifdef IRS_LCL_SV_DB
+#ifndef _PATH_SERVICES_DB
+#define _PATH_SERVICES_DB _PATH_SERVICES ".db"
+#endif
+#endif
+
+#ifndef _PATH_HESIOD_CONF
+#define _PATH_HESIOD_CONF "/etc/hesiod.conf"
+#endif
+
+/*! \file */
diff --git a/lib/bind/irs/util.c b/lib/bind/irs/util.c
new file mode 100644
index 0000000..5c4cc28
--- /dev/null
+++ b/lib/bind/irs/util.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: util.c,v 1.2.18.1 2005/04/27 05:01:05 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+void
+map_v4v6_address(const char *src, char *dst) {
+ u_char *p = (u_char *)dst;
+ char tmp[NS_INADDRSZ];
+ int i;
+
+ /* Stash a temporary copy so our caller can update in place. */
+ memcpy(tmp, src, NS_INADDRSZ);
+ /* Mark this ipv6 addr as a mapped ipv4. */
+ for (i = 0; i < 10; i++)
+ *p++ = 0x00;
+ *p++ = 0xff;
+ *p++ = 0xff;
+ /* Retrieve the saved copy and we're done. */
+ memcpy((void*)p, tmp, NS_INADDRSZ);
+}
+
+int
+make_group_list(struct irs_gr *this, const char *name,
+ gid_t basegid, gid_t *groups, int *ngroups)
+{
+ struct group *grp;
+ int i, ng;
+ int ret, maxgroups;
+
+ ret = -1;
+ ng = 0;
+ maxgroups = *ngroups;
+ /*
+ * When installing primary group, duplicate it;
+ * the first element of groups is the effective gid
+ * and will be overwritten when a setgid file is executed.
+ */
+ if (ng >= maxgroups)
+ goto done;
+ groups[ng++] = basegid;
+ if (ng >= maxgroups)
+ goto done;
+ groups[ng++] = basegid;
+ /*
+ * Scan the group file to find additional groups.
+ */
+ (*this->rewind)(this);
+ while ((grp = (*this->next)(this)) != NULL) {
+ if ((gid_t)grp->gr_gid == basegid)
+ continue;
+ for (i = 0; grp->gr_mem[i]; i++) {
+ if (!strcmp(grp->gr_mem[i], name)) {
+ if (ng >= maxgroups)
+ goto done;
+ groups[ng++] = grp->gr_gid;
+ break;
+ }
+ }
+ }
+ ret = 0;
+ done:
+ *ngroups = ng;
+ return (ret);
+}
+
+/*! \file */
diff --git a/lib/bind/isc/Makefile.in b/lib/bind/isc/Makefile.in
new file mode 100644
index 0000000..3cbb640
--- /dev/null
+++ b/lib/bind/isc/Makefile.in
@@ -0,0 +1,35 @@
+# 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: Makefile.in,v 1.7 2004/03/05 05:05:38 marka Exp $
+
+srcdir= @srcdir@
+VPATH = @srcdir@
+
+OBJS= assertions.@O@ base64.@O@ bitncmp.@O@ ctl_clnt.@O@ ctl_p.@O@ \
+ ctl_srvr.@O@ ev_connects.@O@ ev_files.@O@ ev_streams.@O@ \
+ ev_timers.@O@ ev_waits.@O@ eventlib.@O@ heap.@O@ hex.@O@ \
+ logging.@O@ memcluster.@O@ movefile.@O@ tree.@O@
+
+SRCS= assertions.c base64.c bitncmp.c ctl_clnt.c ctl_p.c \
+ ctl_srvr.c ev_connects.c ev_files.c ev_streams.c \
+ ev_timers.c ev_waits.c eventlib.c heap.c hex.c logging.c \
+ memcluster.c movefile.c tree.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I${srcdir}/../include
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/isc/assertions.c b/lib/bind/isc/assertions.c
new file mode 100644
index 0000000..c03464d
--- /dev/null
+++ b/lib/bind/isc/assertions.c
@@ -0,0 +1,93 @@
+/*
+ * 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.2.18.1 2005/04/27 05:01:05 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/assertions.h>
+
+#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 */
+}
+
+/*! \file */
diff --git a/lib/bind/isc/assertions.mdoc b/lib/bind/isc/assertions.mdoc
new file mode 100644
index 0000000..4b77e56
--- /dev/null
+++ b/lib/bind/isc/assertions.mdoc
@@ -0,0 +1,138 @@
+.\" $Id: assertions.mdoc,v 1.3 2004/03/09 06:30:06 marka Exp $
+.\"
+.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 1997,1999 by Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd November 17, 1997
+.Dt ASSERTIONS 3
+.Os ISC
+.Sh NAME
+.Nm REQUIRE ,
+.Nm REQUIRE_ERR ,
+.Nm ENSURE ,
+.Nm ENSURE_ERR ,
+.Nm INSIST ,
+.Nm INSIST_ERR ,
+.Nm INVARIANT ,
+.Nm INVARIANT_ERR ,
+.Nm set_assertion_failure_callback
+.Nd assertion system
+.Sh SYNOPSIS
+.Fd #include <isc/assertions.h>
+.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 "<isc/assertions.h>"
+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/lib/bind/isc/base64.c b/lib/bind/isc/base64.c
new file mode 100644
index 0000000..d4bc2ea
--- /dev/null
+++ b/lib/bind/isc/base64.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: base64.c,v 1.3.18.1 2005/04/27 05:01:05 sra Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
+ size_t datalength = 0;
+ u_char input[3];
+ u_char output[4];
+ size_t i;
+
+ while (2U < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0U != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1U)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /*%< Returned value doesn't count \\0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton(src, target, targsize)
+ char const *src;
+ u_char *target;
+ size_t targsize;
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace(ch)) /*%< Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /*%< A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /*%< We got a pad char. */
+ ch = *src++; /*%< Skip it, get next. */
+ switch (state) {
+ case 0: /*%< Invalid = in first position */
+ case 1: /*%< Invalid = in second position */
+ return (-1);
+
+ case 2: /*%< Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /*%< Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /*%< Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
+
+/*! \file */
diff --git a/lib/bind/isc/bitncmp.c b/lib/bind/isc/bitncmp.c
new file mode 100644
index 0000000..8764db1
--- /dev/null
+++ b/lib/bind/isc/bitncmp.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: bitncmp.c,v 1.2.18.1 2005/04/27 05:01:05 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <string.h>
+
+#include "port_after.h"
+
+#include <isc/misc.h>
+
+/*%
+ * 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);
+}
+
+/*! \file */
diff --git a/lib/bind/isc/bitncmp.mdoc b/lib/bind/isc/bitncmp.mdoc
new file mode 100644
index 0000000..7d4646c
--- /dev/null
+++ b/lib/bind/isc/bitncmp.mdoc
@@ -0,0 +1,82 @@
+.\" $Id: bitncmp.mdoc,v 1.3 2004/03/09 06:30:07 marka Exp $
+.\"
+.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 1996,1999 by Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd June 1, 1996
+.Dt BITNCMP 3
+.Os BSD 4
+.Sh NAME
+.Nm bitncmp
+.Nd compare bit masks
+.Sh SYNOPSIS
+.Ft int
+.Fn bitncmp "const void *l" "const void *r" "int n"
+.Sh DESCRIPTION
+The function
+.Fn bitncmp
+compares the
+.Dq Fa n
+most-significant bits of the two masks pointed to by
+.Dq Fa l
+and
+.Dq Fa r ,
+and returns an integer less than, equal to, or greater than 0, according to
+whether or not
+.Dq Fa l
+is lexicographically less than, equal to, or greater than
+.Dq Fa r
+when taken to be unsigned characters (this behaviour is just like that of
+.Xr memcmp 3 ) .
+.Pp
+.Sy NOTE :
+.Fn Bitncmp
+assumes
+.Sy network byte order ;
+this means that the fourth octet of
+.Li 192.5.5.240/28
+.Li 0x11110000 .
+.Sh RETURN VALUES
+.Fn Bitncmp
+returns values in the manner of
+.Xr memcmp 3 :
+.Bd -ragged -offset indent
++1 if
+.Dq Fa 1
+is greater than
+.Dq Fa r ;
+.Pp
+-1 if
+.Dq Fa l
+is less than
+.Dq Fa r ;
+and
+.Pp
+0 if
+.Dq Fa l
+is equal to
+.Dq Fa r ,
+.Ed
+.Pp
+where
+.Dq Fa l
+and
+.Dq Fa r
+are both interpreted as strings of unsigned characters (through bit
+.Dq Fa n . )
+.Sh SEE ALSO
+.Xr memcmp 3 .
+.Sh AUTHOR
+Paul Vixie (ISC).
diff --git a/lib/bind/isc/ctl_clnt.c b/lib/bind/isc/ctl_clnt.c
new file mode 100644
index 0000000..eca8e7f
--- /dev/null
+++ b/lib/bind/isc/ctl_clnt.c
@@ -0,0 +1,617 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_clnt.c,v 1.7.18.2 2007/05/18 06:24:39 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 <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/assertions.h>
+#include <isc/ctl.h>
+#include <isc/eventlib.h>
+#include <isc/list.h>
+#include <isc/memcluster.h>
+
+#include "ctl_p.h"
+
+#include "port_after.h"
+
+/* Constants. */
+
+
+/* Macros. */
+
+#define donefunc_p(ctx) ((ctx).donefunc != NULL)
+#define arpacode_p(line) (isdigit((unsigned char)(line[0])) && \
+ isdigit((unsigned char)(line[1])) && \
+ isdigit((unsigned char)(line[2])))
+#define arpacont_p(line) (line[3] == '-')
+#define arpadone_p(line) (line[3] == ' ' || line[3] == '\t' || \
+ line[3] == '\r' || line[3] == '\0')
+
+/* Types. */
+
+enum state {
+ initializing = 0, connecting, connected, destroyed
+};
+
+struct ctl_tran {
+ LINK(struct ctl_tran) link;
+ LINK(struct ctl_tran) wlink;
+ struct ctl_cctx * ctx;
+ struct ctl_buf outbuf;
+ ctl_clntdone donefunc;
+ void * uap;
+};
+
+struct ctl_cctx {
+ enum state state;
+ evContext ev;
+ int sock;
+ ctl_logfunc logger;
+ ctl_clntdone donefunc;
+ void * uap;
+ evConnID coID;
+ evTimerID tiID;
+ evFileID rdID;
+ evStreamID wrID;
+ struct ctl_buf inbuf;
+ struct timespec timeout;
+ LIST(struct ctl_tran) tran;
+ LIST(struct ctl_tran) wtran;
+};
+
+/* Forward. */
+
+static struct ctl_tran *new_tran(struct ctl_cctx *, ctl_clntdone, void *, int);
+static void start_write(struct ctl_cctx *);
+static void destroy(struct ctl_cctx *, int);
+static void error(struct ctl_cctx *);
+static void new_state(struct ctl_cctx *, enum state);
+static void conn_done(evContext, void *, int,
+ const void *, int,
+ const void *, int);
+static void write_done(evContext, void *, int, int);
+static void start_read(struct ctl_cctx *);
+static void stop_read(struct ctl_cctx *);
+static void readable(evContext, void *, int, int);
+static void start_timer(struct ctl_cctx *);
+static void stop_timer(struct ctl_cctx *);
+static void touch_timer(struct ctl_cctx *);
+static void timer(evContext, void *,
+ struct timespec, struct timespec);
+
+#ifndef HAVE_MEMCHR
+static void *
+memchr(const void *b, int c, size_t len) {
+ const unsigned char *p = b;
+ size_t i;
+
+ for (i = 0; i < len; i++, p++)
+ if (*p == (unsigned char)c)
+ return ((void *)p);
+ return (NULL);
+}
+#endif
+
+/* Private data. */
+
+static const char * const state_names[] = {
+ "initializing", "connecting", "connected", "destroyed"
+};
+
+/* Public. */
+
+/*%
+ * void
+ * ctl_client()
+ * create, condition, and connect to a listener on the control port.
+ */
+struct ctl_cctx *
+ctl_client(evContext lev, const struct sockaddr *cap, size_t cap_len,
+ const struct sockaddr *sap, size_t sap_len,
+ ctl_clntdone donefunc, void *uap,
+ u_int timeout, ctl_logfunc logger)
+{
+ static const char me[] = "ctl_client";
+ static const int on = 1;
+ struct ctl_cctx *ctx;
+ struct sockaddr *captmp;
+
+ if (logger == NULL)
+ logger = ctl_logger;
+ ctx = memget(sizeof *ctx);
+ if (ctx == NULL) {
+ (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
+ goto fatal;
+ }
+ ctx->state = initializing;
+ ctx->ev = lev;
+ ctx->logger = logger;
+ ctx->timeout = evConsTime(timeout, 0);
+ ctx->donefunc = donefunc;
+ ctx->uap = uap;
+ ctx->coID.opaque = NULL;
+ ctx->tiID.opaque = NULL;
+ ctx->rdID.opaque = NULL;
+ ctx->wrID.opaque = NULL;
+ buffer_init(ctx->inbuf);
+ INIT_LIST(ctx->tran);
+ INIT_LIST(ctx->wtran);
+ ctx->sock = socket(sap->sa_family, SOCK_STREAM, PF_UNSPEC);
+ if (ctx->sock > evHighestFD(ctx->ev)) {
+ ctx->sock = -1;
+ errno = ENOTSOCK;
+ }
+ if (ctx->sock < 0) {
+ (*ctx->logger)(ctl_error, "%s: socket: %s",
+ me, strerror(errno));
+ goto fatal;
+ }
+ if (cap != NULL) {
+ if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR,
+ (const char *)&on, sizeof on) != 0) {
+ (*ctx->logger)(ctl_warning,
+ "%s: setsockopt(REUSEADDR): %s",
+ me, strerror(errno));
+ }
+ DE_CONST(cap, captmp);
+ if (bind(ctx->sock, captmp, cap_len) < 0) {
+ (*ctx->logger)(ctl_error, "%s: bind: %s", me,
+ strerror(errno));
+ goto fatal;
+ }
+ }
+ if (evConnect(lev, ctx->sock, (const struct sockaddr *)sap, sap_len,
+ conn_done, ctx, &ctx->coID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: evConnect(fd %d): %s",
+ me, ctx->sock, strerror(errno));
+ fatal:
+ if (ctx != NULL) {
+ if (ctx->sock >= 0)
+ close(ctx->sock);
+ memput(ctx, sizeof *ctx);
+ }
+ return (NULL);
+ }
+ new_state(ctx, connecting);
+ return (ctx);
+}
+
+/*%
+ * void
+ * ctl_endclient(ctx)
+ * close a client and release all of its resources.
+ */
+void
+ctl_endclient(struct ctl_cctx *ctx) {
+ if (ctx->state != destroyed)
+ destroy(ctx, 0);
+ memput(ctx, sizeof *ctx);
+}
+
+/*%
+ * int
+ * ctl_command(ctx, cmd, len, donefunc, uap)
+ * Queue a transaction, which will begin with sending cmd
+ * and complete by calling donefunc with the answer.
+ */
+int
+ctl_command(struct ctl_cctx *ctx, const char *cmd, size_t len,
+ ctl_clntdone donefunc, void *uap)
+{
+ struct ctl_tran *tran;
+ char *pc;
+ unsigned int n;
+
+ switch (ctx->state) {
+ case destroyed:
+ errno = ENOTCONN;
+ return (-1);
+ case connecting:
+ case connected:
+ break;
+ default:
+ abort();
+ }
+ if (len >= (size_t)MAX_LINELEN) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ tran = new_tran(ctx, donefunc, uap, 1);
+ if (tran == NULL)
+ return (-1);
+ if (ctl_bufget(&tran->outbuf, ctx->logger) < 0)
+ return (-1);
+ memcpy(tran->outbuf.text, cmd, len);
+ tran->outbuf.used = len;
+ for (pc = tran->outbuf.text, n = 0; n < tran->outbuf.used; pc++, n++)
+ if (!isascii((unsigned char)*pc) ||
+ !isprint((unsigned char)*pc))
+ *pc = '\040';
+ start_write(ctx);
+ return (0);
+}
+
+/* Private. */
+
+static struct ctl_tran *
+new_tran(struct ctl_cctx *ctx, ctl_clntdone donefunc, void *uap, int w) {
+ struct ctl_tran *new = memget(sizeof *new);
+
+ if (new == NULL)
+ return (NULL);
+ new->ctx = ctx;
+ buffer_init(new->outbuf);
+ new->donefunc = donefunc;
+ new->uap = uap;
+ INIT_LINK(new, link);
+ INIT_LINK(new, wlink);
+ APPEND(ctx->tran, new, link);
+ if (w)
+ APPEND(ctx->wtran, new, wlink);
+ return (new);
+}
+
+static void
+start_write(struct ctl_cctx *ctx) {
+ static const char me[] = "isc/ctl_clnt::start_write";
+ struct ctl_tran *tran;
+ struct iovec iov[2], *iovp = iov;
+ char * tmp;
+
+ REQUIRE(ctx->state == connecting || ctx->state == connected);
+ /* If there is a write in progress, don't try to write more yet. */
+ if (ctx->wrID.opaque != NULL)
+ return;
+ /* If there are no trans, make sure timer is off, and we're done. */
+ if (EMPTY(ctx->wtran)) {
+ if (ctx->tiID.opaque != NULL)
+ stop_timer(ctx);
+ return;
+ }
+ /* Pull it off the head of the write queue. */
+ tran = HEAD(ctx->wtran);
+ UNLINK(ctx->wtran, tran, wlink);
+ /* Since there are some trans, make sure timer is successfully "on". */
+ if (ctx->tiID.opaque != NULL)
+ touch_timer(ctx);
+ else
+ start_timer(ctx);
+ if (ctx->state == destroyed)
+ return;
+ /* Marshall a newline-terminated message and clock it out. */
+ *iovp++ = evConsIovec(tran->outbuf.text, tran->outbuf.used);
+ DE_CONST("\r\n", tmp);
+ *iovp++ = evConsIovec(tmp, 2);
+ if (evWrite(ctx->ev, ctx->sock, iov, iovp - iov,
+ write_done, tran, &ctx->wrID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: evWrite: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+ if (evTimeRW(ctx->ev, ctx->wrID, ctx->tiID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: evTimeRW: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+}
+
+static void
+destroy(struct ctl_cctx *ctx, int notify) {
+ struct ctl_tran *this, *next;
+
+ if (ctx->sock != -1) {
+ (void) close(ctx->sock);
+ ctx->sock = -1;
+ }
+ switch (ctx->state) {
+ case connecting:
+ REQUIRE(ctx->wrID.opaque == NULL);
+ REQUIRE(EMPTY(ctx->tran));
+ /*
+ * This test is nec'y since destroy() can be called from
+ * start_read() while the state is still "connecting".
+ */
+ if (ctx->coID.opaque != NULL) {
+ (void)evCancelConn(ctx->ev, ctx->coID);
+ ctx->coID.opaque = NULL;
+ }
+ break;
+ case connected:
+ REQUIRE(ctx->coID.opaque == NULL);
+ if (ctx->wrID.opaque != NULL) {
+ (void)evCancelRW(ctx->ev, ctx->wrID);
+ ctx->wrID.opaque = NULL;
+ }
+ if (ctx->rdID.opaque != NULL)
+ stop_read(ctx);
+ break;
+ case destroyed:
+ break;
+ default:
+ abort();
+ }
+ if (allocated_p(ctx->inbuf))
+ ctl_bufput(&ctx->inbuf);
+ for (this = HEAD(ctx->tran); this != NULL; this = next) {
+ next = NEXT(this, link);
+ if (allocated_p(this->outbuf))
+ ctl_bufput(&this->outbuf);
+ if (notify && this->donefunc != NULL)
+ (*this->donefunc)(ctx, this->uap, NULL, 0);
+ memput(this, sizeof *this);
+ }
+ if (ctx->tiID.opaque != NULL)
+ stop_timer(ctx);
+ new_state(ctx, destroyed);
+}
+
+static void
+error(struct ctl_cctx *ctx) {
+ REQUIRE(ctx->state != destroyed);
+ destroy(ctx, 1);
+}
+
+static void
+new_state(struct ctl_cctx *ctx, enum state new_state) {
+ static const char me[] = "isc/ctl_clnt::new_state";
+
+ (*ctx->logger)(ctl_debug, "%s: %s -> %s", me,
+ state_names[ctx->state], state_names[new_state]);
+ ctx->state = new_state;
+}
+
+static void
+conn_done(evContext ev, void *uap, int fd,
+ const void *la, int lalen,
+ const void *ra, int ralen)
+{
+ static const char me[] = "isc/ctl_clnt::conn_done";
+ struct ctl_cctx *ctx = uap;
+ struct ctl_tran *tran;
+
+ UNUSED(ev);
+ UNUSED(la);
+ UNUSED(lalen);
+ UNUSED(ra);
+ UNUSED(ralen);
+
+ ctx->coID.opaque = NULL;
+ if (fd < 0) {
+ (*ctx->logger)(ctl_error, "%s: evConnect: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+ new_state(ctx, connected);
+ tran = new_tran(ctx, ctx->donefunc, ctx->uap, 0);
+ if (tran == NULL) {
+ (*ctx->logger)(ctl_error, "%s: new_tran failed: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+ start_read(ctx);
+ if (ctx->state == destroyed) {
+ (*ctx->logger)(ctl_error, "%s: start_read failed: %s",
+ me, strerror(errno));
+ error(ctx);
+ return;
+ }
+}
+
+static void
+write_done(evContext lev, void *uap, int fd, int bytes) {
+ struct ctl_tran *tran = (struct ctl_tran *)uap;
+ struct ctl_cctx *ctx = tran->ctx;
+
+ UNUSED(lev);
+ UNUSED(fd);
+
+ ctx->wrID.opaque = NULL;
+ if (ctx->tiID.opaque != NULL)
+ touch_timer(ctx);
+ ctl_bufput(&tran->outbuf);
+ start_write(ctx);
+ if (bytes < 0)
+ destroy(ctx, 1);
+ else
+ start_read(ctx);
+}
+
+static void
+start_read(struct ctl_cctx *ctx) {
+ static const char me[] = "isc/ctl_clnt::start_read";
+
+ REQUIRE(ctx->state == connecting || ctx->state == connected);
+ REQUIRE(ctx->rdID.opaque == NULL);
+ if (evSelectFD(ctx->ev, ctx->sock, EV_READ, readable, ctx,
+ &ctx->rdID) < 0)
+ {
+ (*ctx->logger)(ctl_error, "%s: evSelect(fd %d): %s", me,
+ ctx->sock, strerror(errno));
+ error(ctx);
+ return;
+ }
+}
+
+static void
+stop_read(struct ctl_cctx *ctx) {
+ REQUIRE(ctx->coID.opaque == NULL);
+ REQUIRE(ctx->rdID.opaque != NULL);
+ (void)evDeselectFD(ctx->ev, ctx->rdID);
+ ctx->rdID.opaque = NULL;
+}
+
+static void
+readable(evContext ev, void *uap, int fd, int evmask) {
+ static const char me[] = "isc/ctl_clnt::readable";
+ struct ctl_cctx *ctx = uap;
+ struct ctl_tran *tran;
+ ssize_t n;
+ char *eos;
+
+ UNUSED(ev);
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(fd >= 0);
+ REQUIRE(evmask == EV_READ);
+ REQUIRE(ctx->state == connected);
+ REQUIRE(!EMPTY(ctx->tran));
+ tran = HEAD(ctx->tran);
+ if (!allocated_p(ctx->inbuf) &&
+ ctl_bufget(&ctx->inbuf, ctx->logger) < 0) {
+ (*ctx->logger)(ctl_error, "%s: can't get an input buffer", me);
+ error(ctx);
+ return;
+ }
+ n = read(ctx->sock, ctx->inbuf.text + ctx->inbuf.used,
+ MAX_LINELEN - ctx->inbuf.used);
+ if (n <= 0) {
+ (*ctx->logger)(ctl_warning, "%s: read: %s", me,
+ (n == 0) ? "Unexpected EOF" : strerror(errno));
+ error(ctx);
+ return;
+ }
+ if (ctx->tiID.opaque != NULL)
+ touch_timer(ctx);
+ ctx->inbuf.used += n;
+ (*ctx->logger)(ctl_debug, "%s: read %d, used %d", me,
+ n, ctx->inbuf.used);
+ again:
+ eos = memchr(ctx->inbuf.text, '\n', ctx->inbuf.used);
+ if (eos != NULL && eos != ctx->inbuf.text && eos[-1] == '\r') {
+ int done = 0;
+
+ eos[-1] = '\0';
+ if (!arpacode_p(ctx->inbuf.text)) {
+ /* XXX Doesn't FTP do this sometimes? Is it legal? */
+ (*ctx->logger)(ctl_error, "%s: no arpa code (%s)", me,
+ ctx->inbuf.text);
+ error(ctx);
+ return;
+ }
+ if (arpadone_p(ctx->inbuf.text))
+ done = 1;
+ else if (arpacont_p(ctx->inbuf.text))
+ done = 0;
+ else {
+ /* XXX Doesn't FTP do this sometimes? Is it legal? */
+ (*ctx->logger)(ctl_error, "%s: no arpa flag (%s)", me,
+ ctx->inbuf.text);
+ error(ctx);
+ return;
+ }
+ (*tran->donefunc)(ctx, tran->uap, ctx->inbuf.text,
+ (done ? 0 : CTL_MORE));
+ ctx->inbuf.used -= ((eos - ctx->inbuf.text) + 1);
+ if (ctx->inbuf.used == 0U)
+ ctl_bufput(&ctx->inbuf);
+ else
+ memmove(ctx->inbuf.text, eos + 1, ctx->inbuf.used);
+ if (done) {
+ UNLINK(ctx->tran, tran, link);
+ memput(tran, sizeof *tran);
+ stop_read(ctx);
+ start_write(ctx);
+ return;
+ }
+ if (allocated_p(ctx->inbuf))
+ goto again;
+ return;
+ }
+ if (ctx->inbuf.used == (size_t)MAX_LINELEN) {
+ (*ctx->logger)(ctl_error, "%s: line too long (%-10s...)", me,
+ ctx->inbuf.text);
+ error(ctx);
+ }
+}
+
+/* Timer related stuff. */
+
+static void
+start_timer(struct ctl_cctx *ctx) {
+ static const char me[] = "isc/ctl_clnt::start_timer";
+
+ REQUIRE(ctx->tiID.opaque == NULL);
+ if (evSetIdleTimer(ctx->ev, timer, ctx, ctx->timeout, &ctx->tiID) < 0){
+ (*ctx->logger)(ctl_error, "%s: evSetIdleTimer: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+}
+
+static void
+stop_timer(struct ctl_cctx *ctx) {
+ static const char me[] = "isc/ctl_clnt::stop_timer";
+
+ REQUIRE(ctx->tiID.opaque != NULL);
+ if (evClearIdleTimer(ctx->ev, ctx->tiID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: evClearIdleTimer: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+ ctx->tiID.opaque = NULL;
+}
+
+static void
+touch_timer(struct ctl_cctx *ctx) {
+ REQUIRE(ctx->tiID.opaque != NULL);
+
+ evTouchIdleTimer(ctx->ev, ctx->tiID);
+}
+
+static void
+timer(evContext ev, void *uap, struct timespec due, struct timespec itv) {
+ static const char me[] = "isc/ctl_clnt::timer";
+ struct ctl_cctx *ctx = uap;
+
+ UNUSED(ev);
+ UNUSED(due);
+ UNUSED(itv);
+
+ ctx->tiID.opaque = NULL;
+ (*ctx->logger)(ctl_error, "%s: timeout after %u seconds while %s", me,
+ ctx->timeout.tv_sec, state_names[ctx->state]);
+ error(ctx);
+}
+
+/*! \file */
diff --git a/lib/bind/isc/ctl_p.c b/lib/bind/isc/ctl_p.c
new file mode 100644
index 0000000..35c2398
--- /dev/null
+++ b/lib/bind/isc/ctl_p.c
@@ -0,0 +1,188 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_p.c,v 1.3.18.1 2005/04/27 05:01:05 sra Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Extern. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <isc/assertions.h>
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+#include <isc/ctl.h>
+
+#include "ctl_p.h"
+
+#include "port_after.h"
+
+/* Constants. */
+
+const char * const ctl_sevnames[] = {
+ "debug", "warning", "error"
+};
+
+/* Public. */
+
+/*%
+ * ctl_logger()
+ * if ctl_startup()'s caller didn't specify a logger, this one
+ * is used. this pollutes stderr with all kinds of trash so it will
+ * probably never be used in real applications.
+ */
+void
+ctl_logger(enum ctl_severity severity, const char *format, ...) {
+ va_list ap;
+ static const char me[] = "ctl_logger";
+
+ fprintf(stderr, "%s(%s): ", me, ctl_sevnames[severity]);
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+int
+ctl_bufget(struct ctl_buf *buf, ctl_logfunc logger) {
+ static const char me[] = "ctl_bufget";
+
+ REQUIRE(!allocated_p(*buf) && buf->used == 0U);
+ buf->text = memget(MAX_LINELEN);
+ if (!allocated_p(*buf)) {
+ (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
+ return (-1);
+ }
+ buf->used = 0;
+ return (0);
+}
+
+void
+ctl_bufput(struct ctl_buf *buf) {
+
+ REQUIRE(allocated_p(*buf));
+ memput(buf->text, MAX_LINELEN);
+ buf->text = NULL;
+ buf->used = 0;
+}
+
+const char *
+ctl_sa_ntop(const struct sockaddr *sa,
+ char *buf, size_t size,
+ ctl_logfunc logger)
+{
+ static const char me[] = "ctl_sa_ntop";
+ static const char punt[] = "[0].-1";
+ char tmp[INET6_ADDRSTRLEN];
+
+ switch (sa->sa_family) {
+ case AF_INET6: {
+ const struct sockaddr_in6 *in6 =
+ (const struct sockaddr_in6 *) sa;
+
+ if (inet_ntop(in6->sin6_family, &in6->sin6_addr, tmp, sizeof tmp)
+ == NULL) {
+ (*logger)(ctl_error, "%s: inet_ntop(%u %04x): %s",
+ me, in6->sin6_family,
+ in6->sin6_port, strerror(errno));
+ return (punt);
+ }
+ if (strlen(tmp) + sizeof "[].65535" > size) {
+ (*logger)(ctl_error, "%s: buffer overflow", me);
+ return (punt);
+ }
+ (void) sprintf(buf, "[%s].%u", tmp, ntohs(in6->sin6_port));
+ return (buf);
+ }
+ case AF_INET: {
+ const struct sockaddr_in *in =
+ (const struct sockaddr_in *) sa;
+
+ if (inet_ntop(in->sin_family, &in->sin_addr, tmp, sizeof tmp)
+ == NULL) {
+ (*logger)(ctl_error, "%s: inet_ntop(%u %04x %08x): %s",
+ me, in->sin_family,
+ in->sin_port, in->sin_addr.s_addr,
+ strerror(errno));
+ return (punt);
+ }
+ if (strlen(tmp) + sizeof "[].65535" > size) {
+ (*logger)(ctl_error, "%s: buffer overflow", me);
+ return (punt);
+ }
+ (void) sprintf(buf, "[%s].%u", tmp, ntohs(in->sin_port));
+ return (buf);
+ }
+#ifndef NO_SOCKADDR_UN
+ case AF_UNIX: {
+ const struct sockaddr_un *un =
+ (const struct sockaddr_un *) sa;
+ unsigned int x = sizeof un->sun_path;
+
+ if (x > size)
+ x = size;
+ strncpy(buf, un->sun_path, x - 1);
+ buf[x - 1] = '\0';
+ return (buf);
+ }
+#endif
+ default:
+ return (punt);
+ }
+}
+
+void
+ctl_sa_copy(const struct sockaddr *src, struct sockaddr *dst) {
+ switch (src->sa_family) {
+ case AF_INET6:
+ *((struct sockaddr_in6 *)dst) =
+ *((const struct sockaddr_in6 *)src);
+ break;
+ case AF_INET:
+ *((struct sockaddr_in *)dst) =
+ *((const struct sockaddr_in *)src);
+ break;
+#ifndef NO_SOCKADDR_UN
+ case AF_UNIX:
+ *((struct sockaddr_un *)dst) =
+ *((const struct sockaddr_un *)src);
+ break;
+#endif
+ default:
+ *dst = *src;
+ break;
+ }
+}
+
+/*! \file */
diff --git a/lib/bind/isc/ctl_p.h b/lib/bind/isc/ctl_p.h
new file mode 100644
index 0000000..18a52ae
--- /dev/null
+++ b/lib/bind/isc/ctl_p.h
@@ -0,0 +1,28 @@
+struct ctl_buf {
+ char * text;
+ size_t used;
+};
+
+#define MAX_LINELEN 990 /*%< Like SMTP. */
+#ifndef NO_SOCKADDR_UN
+#define MAX_NTOP PATH_MAX
+#else
+#define MAX_NTOP (sizeof "[255.255.255.255].65535")
+#endif
+
+#define allocated_p(Buf) ((Buf).text != NULL)
+#define buffer_init(Buf) ((Buf).text = 0, (Buf.used) = 0)
+
+#define ctl_bufget __ctl_bufget
+#define ctl_bufput __ctl_bufput
+#define ctl_sa_ntop __ctl_sa_ntop
+#define ctl_sa_copy __ctl_sa_copy
+
+int ctl_bufget(struct ctl_buf *, ctl_logfunc);
+void ctl_bufput(struct ctl_buf *);
+const char * ctl_sa_ntop(const struct sockaddr *, char *, size_t,
+ ctl_logfunc);
+void ctl_sa_copy(const struct sockaddr *,
+ struct sockaddr *);
+
+/*! \file */
diff --git a/lib/bind/isc/ctl_srvr.c b/lib/bind/isc/ctl_srvr.c
new file mode 100644
index 0000000..52137c0
--- /dev/null
+++ b/lib/bind/isc/ctl_srvr.c
@@ -0,0 +1,784 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_srvr.c,v 1.6.18.2 2006/12/07 04:53:02 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 <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <isc/assertions.h>
+#include <isc/ctl.h>
+#include <isc/eventlib.h>
+#include <isc/list.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "ctl_p.h"
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Macros. */
+
+#define lastverb_p(verb) (verb->name == NULL || verb->func == NULL)
+#define address_expr ctl_sa_ntop((struct sockaddr *)&sess->sa, \
+ tmp, sizeof tmp, ctx->logger)
+
+/* Types. */
+
+enum state {
+ available = 0, initializing, writing, reading, reading_data,
+ processing, idling, quitting, closing
+};
+
+union sa_un {
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+};
+
+struct ctl_sess {
+ LINK(struct ctl_sess) link;
+ struct ctl_sctx * ctx;
+ enum state state;
+ int sock;
+ union sa_un sa;
+ evFileID rdID;
+ evStreamID wrID;
+ evTimerID rdtiID;
+ evTimerID wrtiID;
+ struct ctl_buf inbuf;
+ struct ctl_buf outbuf;
+ const struct ctl_verb * verb;
+ u_int helpcode;
+ const void * respctx;
+ u_int respflags;
+ ctl_srvrdone donefunc;
+ void * uap;
+ void * csctx;
+};
+
+struct ctl_sctx {
+ evContext ev;
+ void * uctx;
+ u_int unkncode;
+ u_int timeoutcode;
+ const struct ctl_verb * verbs;
+ const struct ctl_verb * connverb;
+ int sock;
+ int max_sess;
+ int cur_sess;
+ struct timespec timeout;
+ ctl_logfunc logger;
+ evConnID acID;
+ LIST(struct ctl_sess) sess;
+};
+
+/* Forward. */
+
+static void ctl_accept(evContext, void *, int,
+ const void *, int,
+ const void *, int);
+static void ctl_close(struct ctl_sess *);
+static void ctl_new_state(struct ctl_sess *,
+ enum state,
+ const char *);
+static void ctl_start_read(struct ctl_sess *);
+static void ctl_stop_read(struct ctl_sess *);
+static void ctl_readable(evContext, void *, int, int);
+static void ctl_rdtimeout(evContext, void *,
+ struct timespec,
+ struct timespec);
+static void ctl_wrtimeout(evContext, void *,
+ struct timespec,
+ struct timespec);
+static void ctl_docommand(struct ctl_sess *);
+static void ctl_writedone(evContext, void *, int, int);
+static void ctl_morehelp(struct ctl_sctx *,
+ struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *,
+ u_int, const void *, void *);
+static void ctl_signal_done(struct ctl_sctx *,
+ struct ctl_sess *);
+
+/* Private data. */
+
+static const char * state_names[] = {
+ "available", "initializing", "writing", "reading",
+ "reading_data", "processing", "idling", "quitting", "closing"
+};
+
+static const char space[] = " ";
+
+static const struct ctl_verb fakehelpverb = {
+ "fakehelp", ctl_morehelp , NULL
+};
+
+/* Public. */
+
+/*%
+ * void
+ * ctl_server()
+ * create, condition, and start a listener on the control port.
+ */
+struct ctl_sctx *
+ctl_server(evContext lev, const struct sockaddr *sap, size_t sap_len,
+ const struct ctl_verb *verbs,
+ u_int unkncode, u_int timeoutcode,
+ u_int timeout, int backlog, int max_sess,
+ ctl_logfunc logger, void *uctx)
+{
+ static const char me[] = "ctl_server";
+ static const int on = 1;
+ const struct ctl_verb *connverb;
+ struct ctl_sctx *ctx;
+ int save_errno;
+
+ if (logger == NULL)
+ logger = ctl_logger;
+ for (connverb = verbs;
+ connverb->name != NULL && connverb->func != NULL;
+ connverb++)
+ if (connverb->name[0] == '\0')
+ break;
+ if (connverb->func == NULL) {
+ (*logger)(ctl_error, "%s: no connection verb found", me);
+ return (NULL);
+ }
+ ctx = memget(sizeof *ctx);
+ if (ctx == NULL) {
+ (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
+ return (NULL);
+ }
+ ctx->ev = lev;
+ ctx->uctx = uctx;
+ ctx->unkncode = unkncode;
+ ctx->timeoutcode = timeoutcode;
+ ctx->verbs = verbs;
+ ctx->timeout = evConsTime(timeout, 0);
+ ctx->logger = logger;
+ ctx->connverb = connverb;
+ ctx->max_sess = max_sess;
+ ctx->cur_sess = 0;
+ INIT_LIST(ctx->sess);
+ ctx->sock = socket(sap->sa_family, SOCK_STREAM, PF_UNSPEC);
+ if (ctx->sock > evHighestFD(ctx->ev)) {
+ ctx->sock = -1;
+ errno = ENOTSOCK;
+ }
+ if (ctx->sock < 0) {
+ save_errno = errno;
+ (*ctx->logger)(ctl_error, "%s: socket: %s",
+ me, strerror(errno));
+ memput(ctx, sizeof *ctx);
+ errno = save_errno;
+ return (NULL);
+ }
+ if (ctx->sock > evHighestFD(lev)) {
+ close(ctx->sock);
+ (*ctx->logger)(ctl_error, "%s: file descriptor > evHighestFD");
+ errno = ENFILE;
+ memput(ctx, sizeof *ctx);
+ return (NULL);
+ }
+#ifdef NO_UNIX_REUSEADDR
+ if (sap->sa_family != AF_UNIX)
+#endif
+ if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR,
+ (const char *)&on, sizeof on) != 0) {
+ (*ctx->logger)(ctl_warning,
+ "%s: setsockopt(REUSEADDR): %s",
+ me, strerror(errno));
+ }
+ if (bind(ctx->sock, sap, sap_len) < 0) {
+ char tmp[MAX_NTOP];
+ save_errno = errno;
+ (*ctx->logger)(ctl_error, "%s: bind: %s: %s",
+ me, ctl_sa_ntop((const struct sockaddr *)sap,
+ tmp, sizeof tmp, ctx->logger),
+ strerror(save_errno));
+ close(ctx->sock);
+ memput(ctx, sizeof *ctx);
+ errno = save_errno;
+ return (NULL);
+ }
+ if (fcntl(ctx->sock, F_SETFD, 1) < 0) {
+ (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me,
+ strerror(errno));
+ }
+ if (evListen(lev, ctx->sock, backlog, ctl_accept, ctx,
+ &ctx->acID) < 0) {
+ save_errno = errno;
+ (*ctx->logger)(ctl_error, "%s: evListen(fd %d): %s",
+ me, ctx->sock, strerror(errno));
+ close(ctx->sock);
+ memput(ctx, sizeof *ctx);
+ errno = save_errno;
+ return (NULL);
+ }
+ (*ctx->logger)(ctl_debug, "%s: new ctx %p, sock %d",
+ me, ctx, ctx->sock);
+ return (ctx);
+}
+
+/*%
+ * void
+ * ctl_endserver(ctx)
+ * if the control listener is open, close it. clean out all eventlib
+ * stuff. close all active sessions.
+ */
+void
+ctl_endserver(struct ctl_sctx *ctx) {
+ static const char me[] = "ctl_endserver";
+ struct ctl_sess *this, *next;
+
+ (*ctx->logger)(ctl_debug, "%s: ctx %p, sock %d, acID %p, sess %p",
+ me, ctx, ctx->sock, ctx->acID.opaque, ctx->sess);
+ if (ctx->acID.opaque != NULL) {
+ (void)evCancelConn(ctx->ev, ctx->acID);
+ ctx->acID.opaque = NULL;
+ }
+ if (ctx->sock != -1) {
+ (void) close(ctx->sock);
+ ctx->sock = -1;
+ }
+ for (this = HEAD(ctx->sess); this != NULL; this = next) {
+ next = NEXT(this, link);
+ ctl_close(this);
+ }
+ memput(ctx, sizeof *ctx);
+}
+
+/*%
+ * If body is non-NULL then it we add a "." line after it.
+ * Caller must have escaped lines with leading ".".
+ */
+void
+ctl_response(struct ctl_sess *sess, u_int code, const char *text,
+ u_int flags, const void *respctx, ctl_srvrdone donefunc,
+ void *uap, const char *body, size_t bodylen)
+{
+ static const char me[] = "ctl_response";
+ struct iovec iov[3], *iovp = iov;
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP], *pc;
+ int n;
+
+ REQUIRE(sess->state == initializing ||
+ sess->state == processing ||
+ sess->state == reading_data ||
+ sess->state == writing);
+ REQUIRE(sess->wrtiID.opaque == NULL);
+ REQUIRE(sess->wrID.opaque == NULL);
+ ctl_new_state(sess, writing, me);
+ sess->donefunc = donefunc;
+ sess->uap = uap;
+ if (!allocated_p(sess->outbuf) &&
+ ctl_bufget(&sess->outbuf, ctx->logger) < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: cant get an output buffer",
+ me, address_expr);
+ goto untimely;
+ }
+ if (sizeof "000-\r\n" + strlen(text) > (size_t)MAX_LINELEN) {
+ (*ctx->logger)(ctl_error, "%s: %s: output buffer ovf, closing",
+ me, address_expr);
+ goto untimely;
+ }
+ sess->outbuf.used = SPRINTF((sess->outbuf.text, "%03d%c%s\r\n",
+ code, (flags & CTL_MORE) != 0 ? '-' : ' ',
+ text));
+ for (pc = sess->outbuf.text, n = 0;
+ n < (int)sess->outbuf.used-2; pc++, n++)
+ if (!isascii((unsigned char)*pc) ||
+ !isprint((unsigned char)*pc))
+ *pc = '\040';
+ *iovp++ = evConsIovec(sess->outbuf.text, sess->outbuf.used);
+ if (body != NULL) {
+ char *tmp;
+ DE_CONST(body, tmp);
+ *iovp++ = evConsIovec(tmp, bodylen);
+ DE_CONST(".\r\n", tmp);
+ *iovp++ = evConsIovec(tmp, 3);
+ }
+ (*ctx->logger)(ctl_debug, "%s: [%d] %s", me,
+ sess->outbuf.used, sess->outbuf.text);
+ if (evWrite(ctx->ev, sess->sock, iov, iovp - iov,
+ ctl_writedone, sess, &sess->wrID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: evWrite: %s", me,
+ address_expr, strerror(errno));
+ goto untimely;
+ }
+ if (evSetIdleTimer(ctx->ev, ctl_wrtimeout, sess, ctx->timeout,
+ &sess->wrtiID) < 0)
+ {
+ (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me,
+ address_expr, strerror(errno));
+ goto untimely;
+ }
+ if (evTimeRW(ctx->ev, sess->wrID, sess->wrtiID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: evTimeRW: %s", me,
+ address_expr, strerror(errno));
+ untimely:
+ ctl_signal_done(ctx, sess);
+ ctl_close(sess);
+ return;
+ }
+ sess->respctx = respctx;
+ sess->respflags = flags;
+}
+
+void
+ctl_sendhelp(struct ctl_sess *sess, u_int code) {
+ static const char me[] = "ctl_sendhelp";
+ struct ctl_sctx *ctx = sess->ctx;
+
+ sess->helpcode = code;
+ sess->verb = &fakehelpverb;
+ ctl_morehelp(ctx, sess, NULL, me, CTL_MORE,
+ (const void *)ctx->verbs, NULL);
+}
+
+void *
+ctl_getcsctx(struct ctl_sess *sess) {
+ return (sess->csctx);
+}
+
+void *
+ctl_setcsctx(struct ctl_sess *sess, void *csctx) {
+ void *old = sess->csctx;
+
+ sess->csctx = csctx;
+ return (old);
+}
+
+/* Private functions. */
+
+static void
+ctl_accept(evContext lev, void *uap, int fd,
+ const void *lav, int lalen,
+ const void *rav, int ralen)
+{
+ static const char me[] = "ctl_accept";
+ struct ctl_sctx *ctx = uap;
+ struct ctl_sess *sess = NULL;
+ char tmp[MAX_NTOP];
+
+ UNUSED(lev);
+ UNUSED(lalen);
+ UNUSED(ralen);
+
+ if (fd < 0) {
+ (*ctx->logger)(ctl_error, "%s: accept: %s",
+ me, strerror(errno));
+ return;
+ }
+ if (ctx->cur_sess == ctx->max_sess) {
+ (*ctx->logger)(ctl_error, "%s: %s: too many control sessions",
+ me, ctl_sa_ntop((const struct sockaddr *)rav,
+ tmp, sizeof tmp,
+ ctx->logger));
+ (void) close(fd);
+ return;
+ }
+ sess = memget(sizeof *sess);
+ if (sess == NULL) {
+ (*ctx->logger)(ctl_error, "%s: memget: %s", me,
+ strerror(errno));
+ (void) close(fd);
+ return;
+ }
+ if (fcntl(fd, F_SETFD, 1) < 0) {
+ (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me,
+ strerror(errno));
+ }
+ ctx->cur_sess++;
+ INIT_LINK(sess, link);
+ APPEND(ctx->sess, sess, link);
+ sess->ctx = ctx;
+ sess->sock = fd;
+ sess->wrID.opaque = NULL;
+ sess->rdID.opaque = NULL;
+ sess->wrtiID.opaque = NULL;
+ sess->rdtiID.opaque = NULL;
+ sess->respctx = NULL;
+ sess->csctx = NULL;
+ if (((const struct sockaddr *)rav)->sa_family == AF_UNIX)
+ ctl_sa_copy((const struct sockaddr *)lav,
+ (struct sockaddr *)&sess->sa);
+ else
+ ctl_sa_copy((const struct sockaddr *)rav,
+ (struct sockaddr *)&sess->sa);
+ sess->donefunc = NULL;
+ buffer_init(sess->inbuf);
+ buffer_init(sess->outbuf);
+ sess->state = available;
+ ctl_new_state(sess, initializing, me);
+ sess->verb = ctx->connverb;
+ (*ctx->logger)(ctl_debug, "%s: %s: accepting (fd %d)",
+ me, address_expr, sess->sock);
+ (*ctx->connverb->func)(ctx, sess, ctx->connverb, "", 0,
+ (const struct sockaddr *)rav, ctx->uctx);
+}
+
+static void
+ctl_new_state(struct ctl_sess *sess, enum state new_state, const char *reason)
+{
+ static const char me[] = "ctl_new_state";
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+
+ (*ctx->logger)(ctl_debug, "%s: %s: %s -> %s (%s)",
+ me, address_expr,
+ state_names[sess->state],
+ state_names[new_state], reason);
+ sess->state = new_state;
+}
+
+static void
+ctl_close(struct ctl_sess *sess) {
+ static const char me[] = "ctl_close";
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+
+ REQUIRE(sess->state == initializing ||
+ sess->state == writing ||
+ sess->state == reading ||
+ sess->state == processing ||
+ sess->state == reading_data ||
+ sess->state == idling);
+ REQUIRE(sess->sock != -1);
+ if (sess->state == reading || sess->state == reading_data)
+ ctl_stop_read(sess);
+ else if (sess->state == writing) {
+ if (sess->wrID.opaque != NULL) {
+ (void) evCancelRW(ctx->ev, sess->wrID);
+ sess->wrID.opaque = NULL;
+ }
+ if (sess->wrtiID.opaque != NULL) {
+ (void) evClearIdleTimer(ctx->ev, sess->wrtiID);
+ sess->wrtiID.opaque = NULL;
+ }
+ }
+ ctl_new_state(sess, closing, me);
+ (void) close(sess->sock);
+ if (allocated_p(sess->inbuf))
+ ctl_bufput(&sess->inbuf);
+ if (allocated_p(sess->outbuf))
+ ctl_bufput(&sess->outbuf);
+ (*ctx->logger)(ctl_debug, "%s: %s: closed (fd %d)",
+ me, address_expr, sess->sock);
+ UNLINK(ctx->sess, sess, link);
+ memput(sess, sizeof *sess);
+ ctx->cur_sess--;
+}
+
+static void
+ctl_start_read(struct ctl_sess *sess) {
+ static const char me[] = "ctl_start_read";
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+
+ REQUIRE(sess->state == initializing ||
+ sess->state == writing ||
+ sess->state == processing ||
+ sess->state == idling);
+ REQUIRE(sess->rdtiID.opaque == NULL);
+ REQUIRE(sess->rdID.opaque == NULL);
+ sess->inbuf.used = 0;
+ if (evSetIdleTimer(ctx->ev, ctl_rdtimeout, sess, ctx->timeout,
+ &sess->rdtiID) < 0)
+ {
+ (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me,
+ address_expr, strerror(errno));
+ ctl_close(sess);
+ return;
+ }
+ if (evSelectFD(ctx->ev, sess->sock, EV_READ,
+ ctl_readable, sess, &sess->rdID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: evSelectFD: %s", me,
+ address_expr, strerror(errno));
+ return;
+ }
+ ctl_new_state(sess, reading, me);
+}
+
+static void
+ctl_stop_read(struct ctl_sess *sess) {
+ static const char me[] = "ctl_stop_read";
+ struct ctl_sctx *ctx = sess->ctx;
+
+ REQUIRE(sess->state == reading || sess->state == reading_data);
+ REQUIRE(sess->rdID.opaque != NULL);
+ (void) evDeselectFD(ctx->ev, sess->rdID);
+ sess->rdID.opaque = NULL;
+ if (sess->rdtiID.opaque != NULL) {
+ (void) evClearIdleTimer(ctx->ev, sess->rdtiID);
+ sess->rdtiID.opaque = NULL;
+ }
+ ctl_new_state(sess, idling, me);
+}
+
+static void
+ctl_readable(evContext lev, void *uap, int fd, int evmask) {
+ static const char me[] = "ctl_readable";
+ struct ctl_sess *sess = uap;
+ struct ctl_sctx *ctx;
+ char *eos, tmp[MAX_NTOP];
+ ssize_t n;
+
+ REQUIRE(sess != NULL);
+ REQUIRE(fd >= 0);
+ REQUIRE(evmask == EV_READ);
+ REQUIRE(sess->state == reading || sess->state == reading_data);
+
+ ctx = sess->ctx;
+ evTouchIdleTimer(lev, sess->rdtiID);
+ if (!allocated_p(sess->inbuf) &&
+ ctl_bufget(&sess->inbuf, ctx->logger) < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: cant get an input buffer",
+ me, address_expr);
+ ctl_close(sess);
+ return;
+ }
+ n = read(sess->sock, sess->inbuf.text + sess->inbuf.used,
+ MAX_LINELEN - sess->inbuf.used);
+ if (n <= 0) {
+ (*ctx->logger)(ctl_debug, "%s: %s: read: %s",
+ me, address_expr,
+ (n == 0) ? "Unexpected EOF" : strerror(errno));
+ ctl_close(sess);
+ return;
+ }
+ sess->inbuf.used += n;
+ eos = memchr(sess->inbuf.text, '\n', sess->inbuf.used);
+ if (eos != NULL && eos != sess->inbuf.text && eos[-1] == '\r') {
+ eos[-1] = '\0';
+ if ((sess->respflags & CTL_DATA) != 0) {
+ INSIST(sess->verb != NULL);
+ (*sess->verb->func)(sess->ctx, sess, sess->verb,
+ sess->inbuf.text,
+ CTL_DATA, sess->respctx,
+ sess->ctx->uctx);
+ } else {
+ ctl_stop_read(sess);
+ ctl_docommand(sess);
+ }
+ sess->inbuf.used -= ((eos - sess->inbuf.text) + 1);
+ if (sess->inbuf.used == 0U)
+ ctl_bufput(&sess->inbuf);
+ else
+ memmove(sess->inbuf.text, eos + 1, sess->inbuf.used);
+ return;
+ }
+ if (sess->inbuf.used == (size_t)MAX_LINELEN) {
+ (*ctx->logger)(ctl_error, "%s: %s: line too long, closing",
+ me, address_expr);
+ ctl_close(sess);
+ }
+}
+
+static void
+ctl_wrtimeout(evContext lev, void *uap,
+ struct timespec due,
+ struct timespec itv)
+{
+ static const char me[] = "ctl_wrtimeout";
+ struct ctl_sess *sess = uap;
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+
+ UNUSED(lev);
+ UNUSED(due);
+ UNUSED(itv);
+
+ REQUIRE(sess->state == writing);
+ sess->wrtiID.opaque = NULL;
+ (*ctx->logger)(ctl_warning, "%s: %s: write timeout, closing",
+ me, address_expr);
+ if (sess->wrID.opaque != NULL) {
+ (void) evCancelRW(ctx->ev, sess->wrID);
+ sess->wrID.opaque = NULL;
+ }
+ ctl_signal_done(ctx, sess);
+ ctl_new_state(sess, processing, me);
+ ctl_close(sess);
+}
+
+static void
+ctl_rdtimeout(evContext lev, void *uap,
+ struct timespec due,
+ struct timespec itv)
+{
+ static const char me[] = "ctl_rdtimeout";
+ struct ctl_sess *sess = uap;
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+
+ UNUSED(lev);
+ UNUSED(due);
+ UNUSED(itv);
+
+ REQUIRE(sess->state == reading);
+ sess->rdtiID.opaque = NULL;
+ (*ctx->logger)(ctl_warning, "%s: %s: timeout, closing",
+ me, address_expr);
+ if (sess->state == reading || sess->state == reading_data)
+ ctl_stop_read(sess);
+ ctl_signal_done(ctx, sess);
+ ctl_new_state(sess, processing, me);
+ ctl_response(sess, ctx->timeoutcode, "Timeout.", CTL_EXIT, NULL,
+ NULL, NULL, NULL, 0);
+}
+
+static void
+ctl_docommand(struct ctl_sess *sess) {
+ static const char me[] = "ctl_docommand";
+ char *name, *rest, tmp[MAX_NTOP];
+ struct ctl_sctx *ctx = sess->ctx;
+ const struct ctl_verb *verb;
+
+ REQUIRE(allocated_p(sess->inbuf));
+ (*ctx->logger)(ctl_debug, "%s: %s: \"%s\" [%u]",
+ me, address_expr,
+ sess->inbuf.text, (u_int)sess->inbuf.used);
+ ctl_new_state(sess, processing, me);
+ name = sess->inbuf.text + strspn(sess->inbuf.text, space);
+ rest = name + strcspn(name, space);
+ if (*rest != '\0') {
+ *rest++ = '\0';
+ rest += strspn(rest, space);
+ }
+ for (verb = ctx->verbs;
+ verb != NULL && verb->name != NULL && verb->func != NULL;
+ verb++)
+ if (verb->name[0] != '\0' && strcasecmp(name, verb->name) == 0)
+ break;
+ if (verb != NULL && verb->name != NULL && verb->func != NULL) {
+ sess->verb = verb;
+ (*verb->func)(ctx, sess, verb, rest, 0, NULL, ctx->uctx);
+ } else {
+ char buf[1100];
+
+ if (sizeof "Unrecognized command \"\" (args \"\")" +
+ strlen(name) + strlen(rest) > sizeof buf)
+ strcpy(buf, "Unrecognized command (buf ovf)");
+ else
+ sprintf(buf,
+ "Unrecognized command \"%s\" (args \"%s\")",
+ name, rest);
+ ctl_response(sess, ctx->unkncode, buf, 0, NULL, NULL, NULL,
+ NULL, 0);
+ }
+}
+
+static void
+ctl_writedone(evContext lev, void *uap, int fd, int bytes) {
+ static const char me[] = "ctl_writedone";
+ struct ctl_sess *sess = uap;
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+ int save_errno = errno;
+
+ UNUSED(lev);
+ UNUSED(uap);
+
+ REQUIRE(sess->state == writing);
+ REQUIRE(fd == sess->sock);
+ REQUIRE(sess->wrtiID.opaque != NULL);
+ sess->wrID.opaque = NULL;
+ (void) evClearIdleTimer(ctx->ev, sess->wrtiID);
+ sess->wrtiID.opaque = NULL;
+ if (bytes < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: %s",
+ me, address_expr, strerror(save_errno));
+ ctl_close(sess);
+ return;
+ }
+
+ INSIST(allocated_p(sess->outbuf));
+ ctl_bufput(&sess->outbuf);
+ if ((sess->respflags & CTL_EXIT) != 0) {
+ ctl_signal_done(ctx, sess);
+ ctl_close(sess);
+ return;
+ } else if ((sess->respflags & CTL_MORE) != 0) {
+ INSIST(sess->verb != NULL);
+ (*sess->verb->func)(sess->ctx, sess, sess->verb, "",
+ CTL_MORE, sess->respctx, sess->ctx->uctx);
+ } else {
+ ctl_signal_done(ctx, sess);
+ ctl_start_read(sess);
+ }
+}
+
+static void
+ctl_morehelp(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *text,
+ u_int respflags, const void *respctx, void *uctx)
+{
+ const struct ctl_verb *this = respctx, *next = this + 1;
+
+ UNUSED(ctx);
+ UNUSED(verb);
+ UNUSED(text);
+ UNUSED(uctx);
+
+ REQUIRE(!lastverb_p(this));
+ REQUIRE((respflags & CTL_MORE) != 0);
+ if (lastverb_p(next))
+ respflags &= ~CTL_MORE;
+ ctl_response(sess, sess->helpcode, this->help, respflags, next,
+ NULL, NULL, NULL, 0);
+}
+
+static void
+ctl_signal_done(struct ctl_sctx *ctx, struct ctl_sess *sess) {
+ if (sess->donefunc != NULL) {
+ (*sess->donefunc)(ctx, sess, sess->uap);
+ sess->donefunc = NULL;
+ }
+}
+
+/*! \file */
diff --git a/lib/bind/isc/ev_connects.c b/lib/bind/isc/ev_connects.c
new file mode 100644
index 0000000..64e918d
--- /dev/null
+++ b/lib/bind/isc/ev_connects.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_connects.c - implement asynch connect/accept for the eventlib
+ * vix 16sep96 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_connects.c,v 1.5.18.3 2006/03/10 00:20:08 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+/* Macros. */
+
+#define GETXXXNAME(f, s, sa, len) ( \
+ (f((s), (&sa), (&len)) >= 0) ? 0 : \
+ (errno != EAFNOSUPPORT && errno != EOPNOTSUPP) ? -1 : ( \
+ memset(&(sa), 0, sizeof (sa)), \
+ (len) = sizeof (sa), \
+ (sa).sa_family = AF_UNIX, \
+ 0 \
+ ) \
+ )
+
+/* Forward. */
+
+static void listener(evContext ctx, void *uap, int fd, int evmask);
+static void connector(evContext ctx, void *uap, int fd, int evmask);
+
+/* Public. */
+
+int
+evListen(evContext opaqueCtx, int fd, int maxconn,
+ evConnFunc func, void *uap, evConnID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evConn *new;
+ int mode;
+
+ OKNEW(new);
+ new->flags = EV_CONN_LISTEN;
+ OKFREE(mode = fcntl(fd, F_GETFL, NULL), new); /*%< side effect: validate fd. */
+ /*
+ * Remember the nonblocking status. We assume that either evSelectFD
+ * has not been done to this fd, or that if it has then the caller
+ * will evCancelConn before they evDeselectFD. If our assumptions
+ * are not met, then we might restore the old nonblocking status
+ * incorrectly.
+ */
+ if ((mode & PORT_NONBLOCK) == 0) {
+#ifdef USE_FIONBIO_IOCTL
+ int on = 1;
+ OKFREE(ioctl(fd, FIONBIO, (char *)&on), new);
+#else
+ OKFREE(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK), new);
+#endif
+ new->flags |= EV_CONN_BLOCK;
+ }
+ OKFREE(listen(fd, maxconn), new);
+ if (evSelectFD(opaqueCtx, fd, EV_READ, listener, new, &new->file) < 0){
+ int save = errno;
+
+ FREE(new);
+ errno = save;
+ return (-1);
+ }
+ new->flags |= EV_CONN_SELECTED;
+ new->func = func;
+ new->uap = uap;
+ new->fd = fd;
+ if (ctx->conns != NULL)
+ ctx->conns->prev = new;
+ new->prev = NULL;
+ new->next = ctx->conns;
+ ctx->conns = new;
+ if (id)
+ id->opaque = new;
+ return (0);
+}
+
+int
+evConnect(evContext opaqueCtx, int fd, const void *ra, int ralen,
+ evConnFunc func, void *uap, evConnID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evConn *new;
+
+ OKNEW(new);
+ new->flags = 0;
+ /* Do the select() first to get the socket into nonblocking mode. */
+ if (evSelectFD(opaqueCtx, fd, EV_MASK_ALL,
+ connector, new, &new->file) < 0) {
+ int save = errno;
+
+ FREE(new);
+ errno = save;
+ return (-1);
+ }
+ new->flags |= EV_CONN_SELECTED;
+ if (connect(fd, ra, ralen) < 0 &&
+ errno != EWOULDBLOCK &&
+ errno != EAGAIN &&
+ errno != EINPROGRESS) {
+ int save = errno;
+
+ (void) evDeselectFD(opaqueCtx, new->file);
+ FREE(new);
+ errno = save;
+ return (-1);
+ }
+ /* No error, or EWOULDBLOCK. select() tells when it's ready. */
+ new->func = func;
+ new->uap = uap;
+ new->fd = fd;
+ if (ctx->conns != NULL)
+ ctx->conns->prev = new;
+ new->prev = NULL;
+ new->next = ctx->conns;
+ ctx->conns = new;
+ if (id)
+ id->opaque = new;
+ return (0);
+}
+
+int
+evCancelConn(evContext opaqueCtx, evConnID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evConn *this = id.opaque;
+ evAccept *acc, *nxtacc;
+ int mode;
+
+ if ((this->flags & EV_CONN_SELECTED) != 0)
+ (void) evDeselectFD(opaqueCtx, this->file);
+ if ((this->flags & EV_CONN_BLOCK) != 0) {
+ mode = fcntl(this->fd, F_GETFL, NULL);
+ if (mode == -1) {
+ if (errno != EBADF)
+ return (-1);
+ } else {
+#ifdef USE_FIONBIO_IOCTL
+ int off = 0;
+ OK(ioctl(this->fd, FIONBIO, (char *)&off));
+#else
+ OK(fcntl(this->fd, F_SETFL, mode & ~PORT_NONBLOCK));
+#endif
+ }
+ }
+
+ /* Unlink from ctx->conns. */
+ if (this->prev != NULL)
+ this->prev->next = this->next;
+ else
+ ctx->conns = this->next;
+ if (this->next != NULL)
+ this->next->prev = this->prev;
+
+ /*
+ * Remove `this' from the ctx->accepts list (zero or more times).
+ */
+ for (acc = HEAD(ctx->accepts), nxtacc = NULL;
+ acc != NULL;
+ acc = nxtacc)
+ {
+ nxtacc = NEXT(acc, link);
+ if (acc->conn == this) {
+ UNLINK(ctx->accepts, acc, link);
+ close(acc->fd);
+ FREE(acc);
+ }
+ }
+
+ /* Wrap up and get out. */
+ FREE(this);
+ return (0);
+}
+
+int evHold(evContext opaqueCtx, evConnID id) {
+ evConn *this = id.opaque;
+
+ if ((this->flags & EV_CONN_LISTEN) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((this->flags & EV_CONN_SELECTED) == 0)
+ return (0);
+ this->flags &= ~EV_CONN_SELECTED;
+ return (evDeselectFD(opaqueCtx, this->file));
+}
+
+int evUnhold(evContext opaqueCtx, evConnID id) {
+ evConn *this = id.opaque;
+ int ret;
+
+ if ((this->flags & EV_CONN_LISTEN) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((this->flags & EV_CONN_SELECTED) != 0)
+ return (0);
+ ret = evSelectFD(opaqueCtx, this->fd, EV_READ, listener, this,
+ &this->file);
+ if (ret == 0)
+ this->flags |= EV_CONN_SELECTED;
+ return (ret);
+}
+
+int
+evTryAccept(evContext opaqueCtx, evConnID id, int *sys_errno) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evConn *conn = id.opaque;
+ evAccept *new;
+
+ if ((conn->flags & EV_CONN_LISTEN) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ OKNEW(new);
+ new->conn = conn;
+ new->ralen = sizeof new->ra;
+ new->fd = accept(conn->fd, &new->ra.sa, &new->ralen);
+ if (new->fd > ctx->highestFD) {
+ close(new->fd);
+ new->fd = -1;
+ new->ioErrno = ENOTSOCK;
+ }
+ if (new->fd >= 0) {
+ new->lalen = sizeof new->la;
+ if (GETXXXNAME(getsockname, new->fd, new->la.sa, new->lalen) < 0) {
+ new->ioErrno = errno;
+ (void) close(new->fd);
+ new->fd = -1;
+ } else
+ new->ioErrno = 0;
+ } else {
+ new->ioErrno = errno;
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ FREE(new);
+ return (-1);
+ }
+ }
+ INIT_LINK(new, link);
+ APPEND(ctx->accepts, new, link);
+ *sys_errno = new->ioErrno;
+ return (0);
+}
+
+/* Private. */
+
+static void
+listener(evContext opaqueCtx, void *uap, int fd, int evmask) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evConn *conn = uap;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+ } la, ra;
+ int new;
+ ISC_SOCKLEN_T lalen = 0, ralen;
+
+ REQUIRE((evmask & EV_READ) != 0);
+ ralen = sizeof ra;
+ new = accept(fd, &ra.sa, &ralen);
+ if (new > ctx->highestFD) {
+ close(new);
+ new = -1;
+ errno = ENOTSOCK;
+ }
+ if (new >= 0) {
+ lalen = sizeof la;
+ if (GETXXXNAME(getsockname, new, la.sa, lalen) < 0) {
+ int save = errno;
+
+ (void) close(new);
+ errno = save;
+ new = -1;
+ }
+ } else if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return;
+ (*conn->func)(opaqueCtx, conn->uap, new, &la.sa, lalen, &ra.sa, ralen);
+}
+
+static void
+connector(evContext opaqueCtx, void *uap, int fd, int evmask) {
+ evConn *conn = uap;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+ } la, ra;
+ ISC_SOCKLEN_T lalen, ralen;
+#ifndef NETREAD_BROKEN
+ char buf[1];
+#endif
+ void *conn_uap;
+ evConnFunc conn_func;
+ evConnID id;
+ int socket_errno = 0;
+ ISC_SOCKLEN_T optlen;
+
+ UNUSED(evmask);
+
+ lalen = sizeof la;
+ ralen = sizeof ra;
+ conn_uap = conn->uap;
+ conn_func = conn->func;
+ id.opaque = conn;
+#ifdef SO_ERROR
+ optlen = sizeof socket_errno;
+ if (fd < 0 &&
+ getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, (char *)&socket_errno,
+ &optlen) < 0)
+ socket_errno = errno;
+ else
+ errno = socket_errno;
+#endif
+ if (evCancelConn(opaqueCtx, id) < 0 ||
+ socket_errno ||
+#ifdef NETREAD_BROKEN
+ 0 ||
+#else
+ read(fd, buf, 0) < 0 ||
+#endif
+ GETXXXNAME(getsockname, fd, la.sa, lalen) < 0 ||
+ GETXXXNAME(getpeername, fd, ra.sa, ralen) < 0) {
+ int save = errno;
+
+ (void) close(fd); /*%< XXX closing caller's fd */
+ errno = save;
+ fd = -1;
+ }
+ (*conn_func)(opaqueCtx, conn_uap, fd, &la.sa, lalen, &ra.sa, ralen);
+}
+
+/*! \file */
diff --git a/lib/bind/isc/ev_files.c b/lib/bind/isc/ev_files.c
new file mode 100644
index 0000000..71de091
--- /dev/null
+++ b/lib/bind/isc/ev_files.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_files.c - implement asynch file IO for the eventlib
+ * vix 11sep95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_files.c,v 1.5.18.3 2005/07/28 07:38:09 marka Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+static evFile *FindFD(const evContext_p *ctx, int fd, int eventmask);
+
+int
+evSelectFD(evContext opaqueCtx,
+ int fd,
+ int eventmask,
+ evFileFunc func,
+ void *uap,
+ evFileID *opaqueID
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evFile *id;
+ int mode;
+
+ evPrintf(ctx, 1,
+ "evSelectFD(ctx %p, fd %d, mask 0x%x, func %p, uap %p)\n",
+ ctx, fd, eventmask, func, uap);
+ if (eventmask == 0 || (eventmask & ~EV_MASK_ALL) != 0)
+ EV_ERR(EINVAL);
+#ifndef USE_POLL
+ if (fd > ctx->highestFD)
+ EV_ERR(EINVAL);
+#endif
+ OK(mode = fcntl(fd, F_GETFL, NULL)); /*%< side effect: validate fd. */
+ /*
+ * The first time we touch a file descriptor, we need to check to see
+ * if the application already had it in O_NONBLOCK mode and if so, all
+ * of our deselect()'s have to leave it in O_NONBLOCK. If not, then
+ * all but our last deselect() has to leave it in O_NONBLOCK.
+ */
+#ifdef USE_POLL
+ /* Make sure both ctx->pollfds[] and ctx->fdTable[] are large enough */
+ if (fd >= ctx->maxnfds && evPollfdRealloc(ctx, 1, fd) != 0)
+ EV_ERR(ENOMEM);
+#endif /* USE_POLL */
+ id = FindFD(ctx, fd, EV_MASK_ALL);
+ if (id == NULL) {
+ if (mode & PORT_NONBLOCK)
+ FD_SET(fd, &ctx->nonblockBefore);
+ else {
+#ifdef USE_FIONBIO_IOCTL
+ int on = 1;
+ OK(ioctl(fd, FIONBIO, (char *)&on));
+#else
+ OK(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK));
+#endif
+ FD_CLR(fd, &ctx->nonblockBefore);
+ }
+ }
+
+ /*
+ * If this descriptor is already in use, search for it again to see
+ * if any of the eventmask bits we want to set are already captured.
+ * We cannot usefully capture the same fd event more than once in the
+ * same context.
+ */
+ if (id != NULL && FindFD(ctx, fd, eventmask) != NULL)
+ EV_ERR(ETOOMANYREFS);
+
+ /* Allocate and fill. */
+ OKNEW(id);
+ id->func = func;
+ id->uap = uap;
+ id->fd = fd;
+ id->eventmask = eventmask;
+
+ /*
+ * Insert at head. Order could be important for performance if we
+ * believe that evGetNext()'s accesses to the fd_sets will be more
+ * serial and therefore more cache-lucky if the list is ordered by
+ * ``fd.'' We do not believe these things, so we don't do it.
+ *
+ * The interesting sequence is where GetNext() has cached a select()
+ * result and the caller decides to evSelectFD() on some descriptor.
+ * Since GetNext() starts at the head, it can miss new entries we add
+ * at the head. This is not a serious problem since the event being
+ * evSelectFD()'d for has to occur before evSelectFD() is called for
+ * the file event to be considered "missed" -- a real corner case.
+ * Maintaining a "tail" pointer for ctx->files would fix this, but I'm
+ * not sure it would be ``more correct.''
+ */
+ if (ctx->files != NULL)
+ ctx->files->prev = id;
+ id->prev = NULL;
+ id->next = ctx->files;
+ ctx->files = id;
+
+ /* Insert into fd table. */
+ if (ctx->fdTable[fd] != NULL)
+ ctx->fdTable[fd]->fdprev = id;
+ id->fdprev = NULL;
+ id->fdnext = ctx->fdTable[fd];
+ ctx->fdTable[fd] = id;
+
+ /* Turn on the appropriate bits in the {rd,wr,ex}Next fd_set's. */
+ if (eventmask & EV_READ)
+ FD_SET(fd, &ctx->rdNext);
+ if (eventmask & EV_WRITE)
+ FD_SET(fd, &ctx->wrNext);
+ if (eventmask & EV_EXCEPT)
+ FD_SET(fd, &ctx->exNext);
+
+ /* Update fdMax. */
+ if (fd > ctx->fdMax)
+ ctx->fdMax = fd;
+
+ /* Remember the ID if the caller provided us a place for it. */
+ if (opaqueID)
+ opaqueID->opaque = id;
+
+ return (0);
+}
+
+int
+evDeselectFD(evContext opaqueCtx, evFileID opaqueID) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evFile *del = opaqueID.opaque;
+ evFile *cur;
+ int mode, eventmask;
+
+ if (!del) {
+ evPrintf(ctx, 11, "evDeselectFD(NULL) ignored\n");
+ errno = EINVAL;
+ return (-1);
+ }
+
+ evPrintf(ctx, 1, "evDeselectFD(fd %d, mask 0x%x)\n",
+ del->fd, del->eventmask);
+
+ /* Get the mode. Unless the file has been closed, errors are bad. */
+ mode = fcntl(del->fd, F_GETFL, NULL);
+ if (mode == -1 && errno != EBADF)
+ EV_ERR(errno);
+
+ /* Remove from the list of files. */
+ if (del->prev != NULL)
+ del->prev->next = del->next;
+ else
+ ctx->files = del->next;
+ if (del->next != NULL)
+ del->next->prev = del->prev;
+
+ /* Remove from the fd table. */
+ if (del->fdprev != NULL)
+ del->fdprev->fdnext = del->fdnext;
+ else
+ ctx->fdTable[del->fd] = del->fdnext;
+ if (del->fdnext != NULL)
+ del->fdnext->fdprev = del->fdprev;
+
+ /*
+ * If the file descriptor does not appear in any other select() entry,
+ * and if !EV_WASNONBLOCK, and if we got no EBADF when we got the mode
+ * earlier, then: restore the fd to blocking status.
+ */
+ if (!(cur = FindFD(ctx, del->fd, EV_MASK_ALL)) &&
+ !FD_ISSET(del->fd, &ctx->nonblockBefore) &&
+ mode != -1) {
+ /*
+ * Note that we won't return an error status to the caller if
+ * this fcntl() fails since (a) we've already done the work
+ * and (b) the caller didn't ask us anything about O_NONBLOCK.
+ */
+#ifdef USE_FIONBIO_IOCTL
+ int off = 0;
+ (void) ioctl(del->fd, FIONBIO, (char *)&off);
+#else
+ (void) fcntl(del->fd, F_SETFL, mode & ~PORT_NONBLOCK);
+#endif
+ }
+
+ /*
+ * Now find all other uses of this descriptor and OR together an event
+ * mask so that we don't turn off {rd,wr,ex}Next bits that some other
+ * file event is using. As an optimization, stop if the event mask
+ * fills.
+ */
+ eventmask = 0;
+ for ((void)NULL;
+ cur != NULL && eventmask != EV_MASK_ALL;
+ cur = cur->next)
+ if (cur->fd == del->fd)
+ eventmask |= cur->eventmask;
+
+ /* OK, now we know which bits we can clear out. */
+ if (!(eventmask & EV_READ)) {
+ FD_CLR(del->fd, &ctx->rdNext);
+ if (FD_ISSET(del->fd, &ctx->rdLast)) {
+ FD_CLR(del->fd, &ctx->rdLast);
+ ctx->fdCount--;
+ }
+ }
+ if (!(eventmask & EV_WRITE)) {
+ FD_CLR(del->fd, &ctx->wrNext);
+ if (FD_ISSET(del->fd, &ctx->wrLast)) {
+ FD_CLR(del->fd, &ctx->wrLast);
+ ctx->fdCount--;
+ }
+ }
+ if (!(eventmask & EV_EXCEPT)) {
+ FD_CLR(del->fd, &ctx->exNext);
+ if (FD_ISSET(del->fd, &ctx->exLast)) {
+ FD_CLR(del->fd, &ctx->exLast);
+ ctx->fdCount--;
+ }
+ }
+
+ /* If this was the maxFD, find the new one. */
+ if (del->fd == ctx->fdMax) {
+ ctx->fdMax = -1;
+ for (cur = ctx->files; cur; cur = cur->next)
+ if (cur->fd > ctx->fdMax)
+ ctx->fdMax = cur->fd;
+ }
+
+ /* If this was the fdNext, cycle that to the next entry. */
+ if (del == ctx->fdNext)
+ ctx->fdNext = del->next;
+
+ /* Couldn't free it before now since we were using fields out of it. */
+ FREE(del);
+
+ return (0);
+}
+
+static evFile *
+FindFD(const evContext_p *ctx, int fd, int eventmask) {
+ evFile *id;
+
+ for (id = ctx->fdTable[fd]; id != NULL; id = id->fdnext)
+ if (id->fd == fd && (id->eventmask & eventmask) != 0)
+ break;
+ return (id);
+}
+
+/*! \file */
diff --git a/lib/bind/isc/ev_streams.c b/lib/bind/isc/ev_streams.c
new file mode 100644
index 0000000..ab61246
--- /dev/null
+++ b/lib/bind/isc/ev_streams.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_streams.c - implement asynch stream file IO for the eventlib
+ * vix 04mar96 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_streams.c,v 1.4.18.1 2005/04/27 05:01:06 sra Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+static int copyvec(evStream *str, const struct iovec *iov, int iocnt);
+static void consume(evStream *str, size_t bytes);
+static void done(evContext opaqueCtx, evStream *str);
+static void writable(evContext opaqueCtx, void *uap, int fd, int evmask);
+static void readable(evContext opaqueCtx, void *uap, int fd, int evmask);
+
+struct iovec
+evConsIovec(void *buf, size_t cnt) {
+ struct iovec ret;
+
+ memset(&ret, 0xf5, sizeof ret);
+ ret.iov_base = buf;
+ ret.iov_len = cnt;
+ return (ret);
+}
+
+int
+evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
+ evStreamFunc func, void *uap, evStreamID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evStream *new;
+ int save;
+
+ OKNEW(new);
+ new->func = func;
+ new->uap = uap;
+ new->fd = fd;
+ new->flags = 0;
+ if (evSelectFD(opaqueCtx, fd, EV_WRITE, writable, new, &new->file) < 0)
+ goto free;
+ if (copyvec(new, iov, iocnt) < 0)
+ goto free;
+ new->prevDone = NULL;
+ new->nextDone = NULL;
+ if (ctx->streams != NULL)
+ ctx->streams->prev = new;
+ new->prev = NULL;
+ new->next = ctx->streams;
+ ctx->streams = new;
+ if (id != NULL)
+ id->opaque = new;
+ return (0);
+ free:
+ save = errno;
+ FREE(new);
+ errno = save;
+ return (-1);
+}
+
+int
+evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
+ evStreamFunc func, void *uap, evStreamID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evStream *new;
+ int save;
+
+ OKNEW(new);
+ new->func = func;
+ new->uap = uap;
+ new->fd = fd;
+ new->flags = 0;
+ if (evSelectFD(opaqueCtx, fd, EV_READ, readable, new, &new->file) < 0)
+ goto free;
+ if (copyvec(new, iov, iocnt) < 0)
+ goto free;
+ new->prevDone = NULL;
+ new->nextDone = NULL;
+ if (ctx->streams != NULL)
+ ctx->streams->prev = new;
+ new->prev = NULL;
+ new->next = ctx->streams;
+ ctx->streams = new;
+ if (id)
+ id->opaque = new;
+ return (0);
+ free:
+ save = errno;
+ FREE(new);
+ errno = save;
+ return (-1);
+}
+
+int
+evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ {
+ evStream *str = id.opaque;
+
+ UNUSED(opaqueCtx);
+
+ str->timer = timer;
+ str->flags |= EV_STR_TIMEROK;
+ return (0);
+}
+
+int
+evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ {
+ evStream *str = id.opaque;
+
+ UNUSED(opaqueCtx);
+
+ str->flags &= ~EV_STR_TIMEROK;
+ return (0);
+}
+
+int
+evCancelRW(evContext opaqueCtx, evStreamID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evStream *old = id.opaque;
+
+ /*
+ * The streams list is doubly threaded. First, there's ctx->streams
+ * that's used by evDestroy() to find and cancel all streams. Second,
+ * there's ctx->strDone (head) and ctx->strLast (tail) which thread
+ * through the potentially smaller number of "IO completed" streams,
+ * used in evGetNext() to avoid scanning the entire list.
+ */
+
+ /* Unlink from ctx->streams. */
+ if (old->prev != NULL)
+ old->prev->next = old->next;
+ else
+ ctx->streams = old->next;
+ if (old->next != NULL)
+ old->next->prev = old->prev;
+
+ /*
+ * If 'old' is on the ctx->strDone list, remove it. Update
+ * ctx->strLast if necessary.
+ */
+ if (old->prevDone == NULL && old->nextDone == NULL) {
+ /*
+ * Either 'old' is the only item on the done list, or it's
+ * not on the done list. If the former, then we unlink it
+ * from the list. If the latter, we leave the list alone.
+ */
+ if (ctx->strDone == old) {
+ ctx->strDone = NULL;
+ ctx->strLast = NULL;
+ }
+ } else {
+ if (old->prevDone != NULL)
+ old->prevDone->nextDone = old->nextDone;
+ else
+ ctx->strDone = old->nextDone;
+ if (old->nextDone != NULL)
+ old->nextDone->prevDone = old->prevDone;
+ else
+ ctx->strLast = old->prevDone;
+ }
+
+ /* Deallocate the stream. */
+ if (old->file.opaque)
+ evDeselectFD(opaqueCtx, old->file);
+ memput(old->iovOrig, sizeof (struct iovec) * old->iovOrigCount);
+ FREE(old);
+ return (0);
+}
+
+/* Copy a scatter/gather vector and initialize a stream handler's IO. */
+static int
+copyvec(evStream *str, const struct iovec *iov, int iocnt) {
+ int i;
+
+ str->iovOrig = (struct iovec *)memget(sizeof(struct iovec) * iocnt);
+ if (str->iovOrig == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ str->ioTotal = 0;
+ for (i = 0; i < iocnt; i++) {
+ str->iovOrig[i] = iov[i];
+ str->ioTotal += iov[i].iov_len;
+ }
+ str->iovOrigCount = iocnt;
+ str->iovCur = str->iovOrig;
+ str->iovCurCount = str->iovOrigCount;
+ str->ioDone = 0;
+ return (0);
+}
+
+/* Pull off or truncate lead iovec(s). */
+static void
+consume(evStream *str, size_t bytes) {
+ while (bytes > 0U) {
+ if (bytes < (size_t)str->iovCur->iov_len) {
+ str->iovCur->iov_len -= bytes;
+ str->iovCur->iov_base = (void *)
+ ((u_char *)str->iovCur->iov_base + bytes);
+ str->ioDone += bytes;
+ bytes = 0;
+ } else {
+ bytes -= str->iovCur->iov_len;
+ str->ioDone += str->iovCur->iov_len;
+ str->iovCur++;
+ str->iovCurCount--;
+ }
+ }
+}
+
+/* Add a stream to Done list and deselect the FD. */
+static void
+done(evContext opaqueCtx, evStream *str) {
+ evContext_p *ctx = opaqueCtx.opaque;
+
+ if (ctx->strLast != NULL) {
+ str->prevDone = ctx->strLast;
+ ctx->strLast->nextDone = str;
+ ctx->strLast = str;
+ } else {
+ INSIST(ctx->strDone == NULL);
+ ctx->strDone = ctx->strLast = str;
+ }
+ evDeselectFD(opaqueCtx, str->file);
+ str->file.opaque = NULL;
+ /* evDrop() will call evCancelRW() on us. */
+}
+
+/* Dribble out some bytes on the stream. (Called by evDispatch().) */
+static void
+writable(evContext opaqueCtx, void *uap, int fd, int evmask) {
+ evStream *str = uap;
+ int bytes;
+
+ UNUSED(evmask);
+
+ bytes = writev(fd, str->iovCur, str->iovCurCount);
+ if (bytes > 0) {
+ if ((str->flags & EV_STR_TIMEROK) != 0)
+ evTouchIdleTimer(opaqueCtx, str->timer);
+ consume(str, bytes);
+ } else {
+ if (bytes < 0 && errno != EINTR) {
+ str->ioDone = -1;
+ str->ioErrno = errno;
+ }
+ }
+ if (str->ioDone == -1 || str->ioDone == str->ioTotal)
+ done(opaqueCtx, str);
+}
+
+/* Scoop up some bytes from the stream. (Called by evDispatch().) */
+static void
+readable(evContext opaqueCtx, void *uap, int fd, int evmask) {
+ evStream *str = uap;
+ int bytes;
+
+ UNUSED(evmask);
+
+ bytes = readv(fd, str->iovCur, str->iovCurCount);
+ if (bytes > 0) {
+ if ((str->flags & EV_STR_TIMEROK) != 0)
+ evTouchIdleTimer(opaqueCtx, str->timer);
+ consume(str, bytes);
+ } else {
+ if (bytes == 0)
+ str->ioDone = 0;
+ else {
+ if (errno != EINTR) {
+ str->ioDone = -1;
+ str->ioErrno = errno;
+ }
+ }
+ }
+ if (str->ioDone <= 0 || str->ioDone == str->ioTotal)
+ done(opaqueCtx, str);
+}
+
+/*! \file */
diff --git a/lib/bind/isc/ev_timers.c b/lib/bind/isc/ev_timers.c
new file mode 100644
index 0000000..cead2aa
--- /dev/null
+++ b/lib/bind/isc/ev_timers.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_timers.c - implement timers for the eventlib
+ * vix 09sep95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_timers.c,v 1.5.18.1 2005/04/27 05:01:06 sra Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <errno.h>
+
+#include <isc/assertions.h>
+#include <isc/eventlib.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+/* Constants. */
+
+#define MILLION 1000000
+#define BILLION 1000000000
+
+/* Forward. */
+
+static int due_sooner(void *, void *);
+static void set_index(void *, int);
+static void free_timer(void *, void *);
+static void print_timer(void *, void *);
+static void idle_timeout(evContext, void *, struct timespec, struct timespec);
+
+/* Private type. */
+
+typedef struct {
+ evTimerFunc func;
+ void * uap;
+ struct timespec lastTouched;
+ struct timespec max_idle;
+ evTimer * timer;
+} idle_timer;
+
+/* Public. */
+
+struct timespec
+evConsTime(time_t sec, long nsec) {
+ struct timespec x;
+
+ x.tv_sec = sec;
+ x.tv_nsec = nsec;
+ return (x);
+}
+
+struct timespec
+evAddTime(struct timespec addend1, struct timespec addend2) {
+ struct timespec x;
+
+ x.tv_sec = addend1.tv_sec + addend2.tv_sec;
+ x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
+ if (x.tv_nsec >= BILLION) {
+ x.tv_sec++;
+ x.tv_nsec -= BILLION;
+ }
+ return (x);
+}
+
+struct timespec
+evSubTime(struct timespec minuend, struct timespec subtrahend) {
+ struct timespec x;
+
+ x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
+ if (minuend.tv_nsec >= subtrahend.tv_nsec)
+ x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
+ else {
+ x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
+ x.tv_sec--;
+ }
+ return (x);
+}
+
+int
+evCmpTime(struct timespec a, struct timespec b) {
+ long x = a.tv_sec - b.tv_sec;
+
+ if (x == 0L)
+ x = a.tv_nsec - b.tv_nsec;
+ return (x < 0L ? (-1) : x > 0L ? (1) : (0));
+}
+
+struct timespec
+evNowTime() {
+ struct timeval now;
+#ifdef CLOCK_REALTIME
+ struct timespec tsnow;
+ int m = CLOCK_REALTIME;
+
+#ifdef CLOCK_MONOTONIC
+ if (__evOptMonoTime)
+ m = CLOCK_MONOTONIC;
+#endif
+ if (clock_gettime(m, &tsnow) == 0)
+ return (tsnow);
+#endif
+ if (gettimeofday(&now, NULL) < 0)
+ return (evConsTime(0, 0));
+ return (evTimeSpec(now));
+}
+
+struct timespec
+evUTCTime() {
+ struct timeval now;
+#ifdef CLOCK_REALTIME
+ struct timespec tsnow;
+ if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0)
+ return (tsnow);
+#endif
+ if (gettimeofday(&now, NULL) < 0)
+ return (evConsTime(0, 0));
+ return (evTimeSpec(now));
+}
+
+struct timespec
+evLastEventTime(evContext opaqueCtx) {
+ evContext_p *ctx = opaqueCtx.opaque;
+
+ return (ctx->lastEventTime);
+}
+
+struct timespec
+evTimeSpec(struct timeval tv) {
+ struct timespec ts;
+
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ return (ts);
+}
+
+struct timeval
+evTimeVal(struct timespec ts) {
+ struct timeval tv;
+
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
+ return (tv);
+}
+
+int
+evSetTimer(evContext opaqueCtx,
+ evTimerFunc func,
+ void *uap,
+ struct timespec due,
+ struct timespec inter,
+ evTimerID *opaqueID
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *id;
+
+ evPrintf(ctx, 1,
+"evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
+ ctx, func, uap,
+ (long)due.tv_sec, due.tv_nsec,
+ (long)inter.tv_sec, inter.tv_nsec);
+
+#ifdef __hpux
+ /*
+ * tv_sec and tv_nsec are unsigned.
+ */
+ if (due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#else
+ if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#endif
+
+ /* due={0,0} is a magic cookie meaning "now." */
+ if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L)
+ due = evNowTime();
+
+ /* Allocate and fill. */
+ OKNEW(id);
+ id->func = func;
+ id->uap = uap;
+ id->due = due;
+ id->inter = inter;
+
+ if (heap_insert(ctx->timers, id) < 0)
+ return (-1);
+
+ /* Remember the ID if the caller provided us a place for it. */
+ if (opaqueID)
+ opaqueID->opaque = id;
+
+ if (ctx->debug > 7) {
+ evPrintf(ctx, 7, "timers after evSetTimer:\n");
+ (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+ }
+
+ return (0);
+}
+
+int
+evClearTimer(evContext opaqueCtx, evTimerID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *del = id.opaque;
+
+ if (ctx->cur != NULL &&
+ ctx->cur->type == Timer &&
+ ctx->cur->u.timer.this == del) {
+ evPrintf(ctx, 8, "deferring delete of timer (executing)\n");
+ /*
+ * Setting the interval to zero ensures that evDrop() will
+ * clean up the timer.
+ */
+ del->inter = evConsTime(0, 0);
+ return (0);
+ }
+
+ if (heap_element(ctx->timers, del->index) != del)
+ EV_ERR(ENOENT);
+
+ if (heap_delete(ctx->timers, del->index) < 0)
+ return (-1);
+ FREE(del);
+
+ if (ctx->debug > 7) {
+ evPrintf(ctx, 7, "timers after evClearTimer:\n");
+ (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+ }
+
+ return (0);
+}
+
+int
+evConfigTimer(evContext opaqueCtx,
+ evTimerID id,
+ const char *param,
+ int value
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *timer = id.opaque;
+ int result=0;
+
+ UNUSED(value);
+
+ if (heap_element(ctx->timers, timer->index) != timer)
+ EV_ERR(ENOENT);
+
+ if (strcmp(param, "rate") == 0)
+ timer->mode |= EV_TMR_RATE;
+ else if (strcmp(param, "interval") == 0)
+ timer->mode &= ~EV_TMR_RATE;
+ else
+ EV_ERR(EINVAL);
+
+ return (result);
+}
+
+int
+evResetTimer(evContext opaqueCtx,
+ evTimerID id,
+ evTimerFunc func,
+ void *uap,
+ struct timespec due,
+ struct timespec inter
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *timer = id.opaque;
+ struct timespec old_due;
+ int result=0;
+
+ if (heap_element(ctx->timers, timer->index) != timer)
+ EV_ERR(ENOENT);
+
+#ifdef __hpux
+ /*
+ * tv_sec and tv_nsec are unsigned.
+ */
+ if (due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#else
+ if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#endif
+
+ old_due = timer->due;
+
+ timer->func = func;
+ timer->uap = uap;
+ timer->due = due;
+ timer->inter = inter;
+
+ switch (evCmpTime(due, old_due)) {
+ case -1:
+ result = heap_increased(ctx->timers, timer->index);
+ break;
+ case 0:
+ result = 0;
+ break;
+ case 1:
+ result = heap_decreased(ctx->timers, timer->index);
+ break;
+ }
+
+ if (ctx->debug > 7) {
+ evPrintf(ctx, 7, "timers after evResetTimer:\n");
+ (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+ }
+
+ return (result);
+}
+
+int
+evSetIdleTimer(evContext opaqueCtx,
+ evTimerFunc func,
+ void *uap,
+ struct timespec max_idle,
+ evTimerID *opaqueID
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ idle_timer *tt;
+
+ /* Allocate and fill. */
+ OKNEW(tt);
+ tt->func = func;
+ tt->uap = uap;
+ tt->lastTouched = ctx->lastEventTime;
+ tt->max_idle = max_idle;
+
+ if (evSetTimer(opaqueCtx, idle_timeout, tt,
+ evAddTime(ctx->lastEventTime, max_idle),
+ max_idle, opaqueID) < 0) {
+ FREE(tt);
+ return (-1);
+ }
+
+ tt->timer = opaqueID->opaque;
+
+ return (0);
+}
+
+int
+evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
+ evTimer *del = id.opaque;
+ idle_timer *tt = del->uap;
+
+ FREE(tt);
+ return (evClearTimer(opaqueCtx, id));
+}
+
+int
+evResetIdleTimer(evContext opaqueCtx,
+ evTimerID opaqueID,
+ evTimerFunc func,
+ void *uap,
+ struct timespec max_idle
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *timer = opaqueID.opaque;
+ idle_timer *tt = timer->uap;
+
+ tt->func = func;
+ tt->uap = uap;
+ tt->lastTouched = ctx->lastEventTime;
+ tt->max_idle = max_idle;
+
+ return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt,
+ evAddTime(ctx->lastEventTime, max_idle),
+ max_idle));
+}
+
+int
+evTouchIdleTimer(evContext opaqueCtx, evTimerID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *t = id.opaque;
+ idle_timer *tt = t->uap;
+
+ tt->lastTouched = ctx->lastEventTime;
+
+ return (0);
+}
+
+/* Public to the rest of eventlib. */
+
+heap_context
+evCreateTimers(const evContext_p *ctx) {
+
+ UNUSED(ctx);
+
+ return (heap_new(due_sooner, set_index, 2048));
+}
+
+void
+evDestroyTimers(const evContext_p *ctx) {
+ (void) heap_for_each(ctx->timers, free_timer, NULL);
+ (void) heap_free(ctx->timers);
+}
+
+/* Private. */
+
+static int
+due_sooner(void *a, void *b) {
+ evTimer *a_timer, *b_timer;
+
+ a_timer = a;
+ b_timer = b;
+ return (evCmpTime(a_timer->due, b_timer->due) < 0);
+}
+
+static void
+set_index(void *what, int index) {
+ evTimer *timer;
+
+ timer = what;
+ timer->index = index;
+}
+
+static void
+free_timer(void *what, void *uap) {
+ evTimer *t = what;
+
+ UNUSED(uap);
+
+ FREE(t);
+}
+
+static void
+print_timer(void *what, void *uap) {
+ evTimer *cur = what;
+ evContext_p *ctx = uap;
+
+ cur = what;
+ evPrintf(ctx, 7,
+ " func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
+ cur->func, cur->uap,
+ (long)cur->due.tv_sec, cur->due.tv_nsec,
+ (long)cur->inter.tv_sec, cur->inter.tv_nsec);
+}
+
+static void
+idle_timeout(evContext opaqueCtx,
+ void *uap,
+ struct timespec due,
+ struct timespec inter
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ idle_timer *this = uap;
+ struct timespec idle;
+
+ UNUSED(due);
+ UNUSED(inter);
+
+ idle = evSubTime(ctx->lastEventTime, this->lastTouched);
+ if (evCmpTime(idle, this->max_idle) >= 0) {
+ (this->func)(opaqueCtx, this->uap, this->timer->due,
+ this->max_idle);
+ /*
+ * Setting the interval to zero will cause the timer to
+ * be cleaned up in evDrop().
+ */
+ this->timer->inter = evConsTime(0, 0);
+ FREE(this);
+ } else {
+ /* evDrop() will reschedule the timer. */
+ this->timer->inter = evSubTime(this->max_idle, idle);
+ }
+}
+
+/*! \file */
diff --git a/lib/bind/isc/ev_waits.c b/lib/bind/isc/ev_waits.c
new file mode 100644
index 0000000..d33b061
--- /dev/null
+++ b/lib/bind/isc/ev_waits.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_waits.c - implement deferred function calls for the eventlib
+ * vix 05dec95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_waits.c,v 1.3.18.1 2005/04/27 05:01:06 sra Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <errno.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+/* Forward. */
+
+static void print_waits(evContext_p *ctx);
+static evWaitList * evNewWaitList(evContext_p *);
+static void evFreeWaitList(evContext_p *, evWaitList *);
+static evWaitList * evGetWaitList(evContext_p *, const void *, int);
+
+
+/* Public. */
+
+/*%
+ * Enter a new wait function on the queue.
+ */
+int
+evWaitFor(evContext opaqueCtx, const void *tag,
+ evWaitFunc func, void *uap, evWaitID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evWait *new;
+ evWaitList *wl = evGetWaitList(ctx, tag, 1);
+
+ OKNEW(new);
+ new->func = func;
+ new->uap = uap;
+ new->tag = tag;
+ new->next = NULL;
+ if (wl->last != NULL)
+ wl->last->next = new;
+ else
+ wl->first = new;
+ wl->last = new;
+ if (id != NULL)
+ id->opaque = new;
+ if (ctx->debug >= 9)
+ print_waits(ctx);
+ return (0);
+}
+
+/*%
+ * Mark runnable all waiting functions having a certain tag.
+ */
+int
+evDo(evContext opaqueCtx, const void *tag) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evWaitList *wl = evGetWaitList(ctx, tag, 0);
+ evWait *first;
+
+ if (!wl) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ first = wl->first;
+ INSIST(first != NULL);
+
+ if (ctx->waitDone.last != NULL)
+ ctx->waitDone.last->next = first;
+ else
+ ctx->waitDone.first = first;
+ ctx->waitDone.last = wl->last;
+ evFreeWaitList(ctx, wl);
+
+ return (0);
+}
+
+/*%
+ * Remove a waiting (or ready to run) function from the queue.
+ */
+int
+evUnwait(evContext opaqueCtx, evWaitID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evWait *this, *prev;
+ evWaitList *wl;
+ int found = 0;
+
+ this = id.opaque;
+ INSIST(this != NULL);
+ wl = evGetWaitList(ctx, this->tag, 0);
+ if (wl != NULL) {
+ for (prev = NULL, this = wl->first;
+ this != NULL;
+ prev = this, this = this->next)
+ if (this == (evWait *)id.opaque) {
+ found = 1;
+ if (prev != NULL)
+ prev->next = this->next;
+ else
+ wl->first = this->next;
+ if (wl->last == this)
+ wl->last = prev;
+ if (wl->first == NULL)
+ evFreeWaitList(ctx, wl);
+ break;
+ }
+ }
+
+ if (!found) {
+ /* Maybe it's done */
+ for (prev = NULL, this = ctx->waitDone.first;
+ this != NULL;
+ prev = this, this = this->next)
+ if (this == (evWait *)id.opaque) {
+ found = 1;
+ if (prev != NULL)
+ prev->next = this->next;
+ else
+ ctx->waitDone.first = this->next;
+ if (ctx->waitDone.last == this)
+ ctx->waitDone.last = prev;
+ break;
+ }
+ }
+
+ if (!found) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ FREE(this);
+
+ if (ctx->debug >= 9)
+ print_waits(ctx);
+
+ return (0);
+}
+
+int
+evDefer(evContext opaqueCtx, evWaitFunc func, void *uap) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evWait *new;
+
+ OKNEW(new);
+ new->func = func;
+ new->uap = uap;
+ new->tag = NULL;
+ new->next = NULL;
+ if (ctx->waitDone.last != NULL)
+ ctx->waitDone.last->next = new;
+ else
+ ctx->waitDone.first = new;
+ ctx->waitDone.last = new;
+ if (ctx->debug >= 9)
+ print_waits(ctx);
+ return (0);
+}
+
+/* Private. */
+
+static void
+print_waits(evContext_p *ctx) {
+ evWaitList *wl;
+ evWait *this;
+
+ evPrintf(ctx, 9, "wait waiting:\n");
+ for (wl = ctx->waitLists; wl != NULL; wl = wl->next) {
+ INSIST(wl->first != NULL);
+ evPrintf(ctx, 9, " tag %p:", wl->first->tag);
+ for (this = wl->first; this != NULL; this = this->next)
+ evPrintf(ctx, 9, " %p", this);
+ evPrintf(ctx, 9, "\n");
+ }
+ evPrintf(ctx, 9, "wait done:");
+ for (this = ctx->waitDone.first; this != NULL; this = this->next)
+ evPrintf(ctx, 9, " %p", this);
+ evPrintf(ctx, 9, "\n");
+}
+
+static evWaitList *
+evNewWaitList(evContext_p *ctx) {
+ evWaitList *new;
+
+ NEW(new);
+ if (new == NULL)
+ return (NULL);
+ new->first = new->last = NULL;
+ new->prev = NULL;
+ new->next = ctx->waitLists;
+ if (new->next != NULL)
+ new->next->prev = new;
+ ctx->waitLists = new;
+ return (new);
+}
+
+static void
+evFreeWaitList(evContext_p *ctx, evWaitList *this) {
+
+ INSIST(this != NULL);
+
+ if (this->prev != NULL)
+ this->prev->next = this->next;
+ else
+ ctx->waitLists = this->next;
+ if (this->next != NULL)
+ this->next->prev = this->prev;
+ FREE(this);
+}
+
+static evWaitList *
+evGetWaitList(evContext_p *ctx, const void *tag, int should_create) {
+ evWaitList *this;
+
+ for (this = ctx->waitLists; this != NULL; this = this->next) {
+ if (this->first != NULL && this->first->tag == tag)
+ break;
+ }
+ if (this == NULL && should_create)
+ this = evNewWaitList(ctx);
+ return (this);
+}
+
+/*! \file */
diff --git a/lib/bind/isc/eventlib.c b/lib/bind/isc/eventlib.c
new file mode 100644
index 0000000..20624d0
--- /dev/null
+++ b/lib/bind/isc/eventlib.c
@@ -0,0 +1,933 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* eventlib.c - implement glue for the eventlib
+ * vix 09sep95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: eventlib.c,v 1.5.18.5 2006/03/10 00:20:08 marka Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#ifdef SOLARIS2
+#include <limits.h>
+#endif /* SOLARIS2 */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+int __evOptMonoTime;
+
+#ifdef USE_POLL
+#define pselect Pselect
+#endif /* USE_POLL */
+
+/* Forward. */
+
+#if defined(NEED_PSELECT) || defined(USE_POLL)
+static int pselect(int, void *, void *, void *,
+ struct timespec *,
+ const sigset_t *);
+#endif
+
+int __evOptMonoTime;
+
+/* Public. */
+
+int
+evCreate(evContext *opaqueCtx) {
+ evContext_p *ctx;
+
+ /* Make sure the memory heap is initialized. */
+ if (meminit(0, 0) < 0 && errno != EEXIST)
+ return (-1);
+
+ OKNEW(ctx);
+
+ /* Global. */
+ ctx->cur = NULL;
+
+ /* Debugging. */
+ ctx->debug = 0;
+ ctx->output = NULL;
+
+ /* Connections. */
+ ctx->conns = NULL;
+ INIT_LIST(ctx->accepts);
+
+ /* Files. */
+ ctx->files = NULL;
+#ifdef USE_POLL
+ ctx->pollfds = NULL;
+ ctx->maxnfds = 0;
+ ctx->firstfd = 0;
+ emulMaskInit(ctx, rdLast, EV_READ, 1);
+ emulMaskInit(ctx, rdNext, EV_READ, 0);
+ emulMaskInit(ctx, wrLast, EV_WRITE, 1);
+ emulMaskInit(ctx, wrNext, EV_WRITE, 0);
+ emulMaskInit(ctx, exLast, EV_EXCEPT, 1);
+ emulMaskInit(ctx, exNext, EV_EXCEPT, 0);
+ emulMaskInit(ctx, nonblockBefore, EV_WASNONBLOCKING, 0);
+#endif /* USE_POLL */
+ FD_ZERO(&ctx->rdNext);
+ FD_ZERO(&ctx->wrNext);
+ FD_ZERO(&ctx->exNext);
+ FD_ZERO(&ctx->nonblockBefore);
+ ctx->fdMax = -1;
+ ctx->fdNext = NULL;
+ ctx->fdCount = 0; /*%< Invalidate {rd,wr,ex}Last. */
+#ifndef USE_POLL
+ ctx->highestFD = FD_SETSIZE - 1;
+ memset(ctx->fdTable, 0, sizeof ctx->fdTable);
+#else
+ ctx->highestFD = INT_MAX / sizeof(struct pollfd);
+ ctx->fdTable = NULL;
+#endif /* USE_POLL */
+#ifdef EVENTLIB_TIME_CHECKS
+ ctx->lastFdCount = 0;
+#endif
+
+ /* Streams. */
+ ctx->streams = NULL;
+ ctx->strDone = NULL;
+ ctx->strLast = NULL;
+
+ /* Timers. */
+ ctx->lastEventTime = evNowTime();
+#ifdef EVENTLIB_TIME_CHECKS
+ ctx->lastSelectTime = ctx->lastEventTime;
+#endif
+ ctx->timers = evCreateTimers(ctx);
+ if (ctx->timers == NULL)
+ return (-1);
+
+ /* Waits. */
+ ctx->waitLists = NULL;
+ ctx->waitDone.first = ctx->waitDone.last = NULL;
+ ctx->waitDone.prev = ctx->waitDone.next = NULL;
+
+ opaqueCtx->opaque = ctx;
+ return (0);
+}
+
+void
+evSetDebug(evContext opaqueCtx, int level, FILE *output) {
+ evContext_p *ctx = opaqueCtx.opaque;
+
+ ctx->debug = level;
+ ctx->output = output;
+}
+
+int
+evDestroy(evContext opaqueCtx) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ int revs = 424242; /*%< Doug Adams. */
+ evWaitList *this_wl, *next_wl;
+ evWait *this_wait, *next_wait;
+
+ /* Connections. */
+ while (revs-- > 0 && ctx->conns != NULL) {
+ evConnID id;
+
+ id.opaque = ctx->conns;
+ (void) evCancelConn(opaqueCtx, id);
+ }
+ INSIST(revs >= 0);
+
+ /* Streams. */
+ while (revs-- > 0 && ctx->streams != NULL) {
+ evStreamID id;
+
+ id.opaque = ctx->streams;
+ (void) evCancelRW(opaqueCtx, id);
+ }
+
+ /* Files. */
+ while (revs-- > 0 && ctx->files != NULL) {
+ evFileID id;
+
+ id.opaque = ctx->files;
+ (void) evDeselectFD(opaqueCtx, id);
+ }
+ INSIST(revs >= 0);
+
+ /* Timers. */
+ evDestroyTimers(ctx);
+
+ /* Waits. */
+ for (this_wl = ctx->waitLists;
+ revs-- > 0 && this_wl != NULL;
+ this_wl = next_wl) {
+ next_wl = this_wl->next;
+ for (this_wait = this_wl->first;
+ revs-- > 0 && this_wait != NULL;
+ this_wait = next_wait) {
+ next_wait = this_wait->next;
+ FREE(this_wait);
+ }
+ FREE(this_wl);
+ }
+ for (this_wait = ctx->waitDone.first;
+ revs-- > 0 && this_wait != NULL;
+ this_wait = next_wait) {
+ next_wait = this_wait->next;
+ FREE(this_wait);
+ }
+
+ FREE(ctx);
+ return (0);
+}
+
+int
+evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ struct timespec nextTime;
+ evTimer *nextTimer;
+ evEvent_p *new;
+ int x, pselect_errno, timerPast;
+#ifdef EVENTLIB_TIME_CHECKS
+ struct timespec interval;
+#endif
+
+ /* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
+ x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
+ if (x != 1)
+ EV_ERR(EINVAL);
+
+ /* Get the time of day. We'll do this again after select() blocks. */
+ ctx->lastEventTime = evNowTime();
+
+ again:
+ /* Finished accept()'s do not require a select(). */
+ if (!EMPTY(ctx->accepts)) {
+ OKNEW(new);
+ new->type = Accept;
+ new->u.accept.this = HEAD(ctx->accepts);
+ UNLINK(ctx->accepts, HEAD(ctx->accepts), link);
+ opaqueEv->opaque = new;
+ return (0);
+ }
+
+ /* Stream IO does not require a select(). */
+ if (ctx->strDone != NULL) {
+ OKNEW(new);
+ new->type = Stream;
+ new->u.stream.this = ctx->strDone;
+ ctx->strDone = ctx->strDone->nextDone;
+ if (ctx->strDone == NULL)
+ ctx->strLast = NULL;
+ opaqueEv->opaque = new;
+ return (0);
+ }
+
+ /* Waits do not require a select(). */
+ if (ctx->waitDone.first != NULL) {
+ OKNEW(new);
+ new->type = Wait;
+ new->u.wait.this = ctx->waitDone.first;
+ ctx->waitDone.first = ctx->waitDone.first->next;
+ if (ctx->waitDone.first == NULL)
+ ctx->waitDone.last = NULL;
+ opaqueEv->opaque = new;
+ return (0);
+ }
+
+ /* Get the status and content of the next timer. */
+ if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) {
+ nextTime = nextTimer->due;
+ timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
+ } else
+ timerPast = 0; /*%< Make gcc happy. */
+ evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount);
+ if (ctx->fdCount == 0) {
+ static const struct timespec NoTime = {0, 0L};
+ enum { JustPoll, Block, Timer } m;
+ struct timespec t, *tp;
+
+ /* Are there any events at all? */
+ if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
+ EV_ERR(ENOENT);
+
+ /* Figure out what select()'s timeout parameter should be. */
+ if ((options & EV_POLL) != 0) {
+ m = JustPoll;
+ t = NoTime;
+ tp = &t;
+ } else if (nextTimer == NULL) {
+ m = Block;
+ /* ``t'' unused. */
+ tp = NULL;
+ } else if (timerPast) {
+ m = JustPoll;
+ t = NoTime;
+ tp = &t;
+ } else {
+ m = Timer;
+ /* ``t'' filled in later. */
+ tp = &t;
+ }
+#ifdef EVENTLIB_TIME_CHECKS
+ if (ctx->debug > 0) {
+ interval = evSubTime(ctx->lastEventTime,
+ ctx->lastSelectTime);
+ if (interval.tv_sec > 0 || interval.tv_nsec > 0)
+ evPrintf(ctx, 1,
+ "time between pselect() %u.%09u count %d\n",
+ interval.tv_sec, interval.tv_nsec,
+ ctx->lastFdCount);
+ }
+#endif
+ do {
+#ifndef USE_POLL
+ /* XXX need to copy only the bits we are using. */
+ ctx->rdLast = ctx->rdNext;
+ ctx->wrLast = ctx->wrNext;
+ ctx->exLast = ctx->exNext;
+#else
+ /*
+ * The pollfd structure uses separate fields for
+ * the input and output events (corresponding to
+ * the ??Next and ??Last fd sets), so there's no
+ * need to copy one to the other.
+ */
+#endif /* USE_POLL */
+ if (m == Timer) {
+ INSIST(tp == &t);
+ t = evSubTime(nextTime, ctx->lastEventTime);
+ }
+
+ /* XXX should predict system's earliness and adjust. */
+ x = pselect(ctx->fdMax+1,
+ &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
+ tp, NULL);
+ pselect_errno = errno;
+
+#ifndef USE_POLL
+ evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
+ x, (x == -1) ? strerror(errno) : "none");
+#else
+ evPrintf(ctx, 4, "poll() returns %d (err: %s)\n",
+ x, (x == -1) ? strerror(errno) : "none");
+#endif /* USE_POLL */
+ /* Anything but a poll can change the time. */
+ if (m != JustPoll)
+ ctx->lastEventTime = evNowTime();
+
+ /* Select() likes to finish about 10ms early. */
+ } while (x == 0 && m == Timer &&
+ evCmpTime(ctx->lastEventTime, nextTime) < 0);
+#ifdef EVENTLIB_TIME_CHECKS
+ ctx->lastSelectTime = ctx->lastEventTime;
+#endif
+ if (x < 0) {
+ if (pselect_errno == EINTR) {
+ if ((options & EV_NULL) != 0)
+ goto again;
+ OKNEW(new);
+ new->type = Null;
+ /* No data. */
+ opaqueEv->opaque = new;
+ return (0);
+ }
+ if (pselect_errno == EBADF) {
+ for (x = 0; x <= ctx->fdMax; x++) {
+ struct stat sb;
+
+ if (FD_ISSET(x, &ctx->rdNext) == 0 &&
+ FD_ISSET(x, &ctx->wrNext) == 0 &&
+ FD_ISSET(x, &ctx->exNext) == 0)
+ continue;
+ if (fstat(x, &sb) == -1 &&
+ errno == EBADF)
+ evPrintf(ctx, 1, "EBADF: %d\n",
+ x);
+ }
+ abort();
+ }
+ EV_ERR(pselect_errno);
+ }
+ if (x == 0 && (nextTimer == NULL || !timerPast) &&
+ (options & EV_POLL))
+ EV_ERR(EWOULDBLOCK);
+ ctx->fdCount = x;
+#ifdef EVENTLIB_TIME_CHECKS
+ ctx->lastFdCount = x;
+#endif
+ }
+ INSIST(nextTimer || ctx->fdCount);
+
+ /* Timers go first since we'd like them to be accurate. */
+ if (nextTimer && !timerPast) {
+ /* Has anything happened since we blocked? */
+ timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
+ }
+ if (nextTimer && timerPast) {
+ OKNEW(new);
+ new->type = Timer;
+ new->u.timer.this = nextTimer;
+ opaqueEv->opaque = new;
+ return (0);
+ }
+
+ /* No timers, so there should be a ready file descriptor. */
+ x = 0;
+ while (ctx->fdCount > 0) {
+ evFile *fid;
+ int fd, eventmask;
+
+ if (ctx->fdNext == NULL) {
+ if (++x == 2) {
+ /*
+ * Hitting the end twice means that the last
+ * select() found some FD's which have since
+ * been deselected.
+ *
+ * On some systems, the count returned by
+ * selects is the total number of bits in
+ * all masks that are set, and on others it's
+ * the number of fd's that have some bit set,
+ * and on others, it's just broken. We
+ * always assume that it's the number of
+ * bits set in all masks, because that's what
+ * the man page says it should do, and
+ * the worst that can happen is we do an
+ * extra select().
+ */
+ ctx->fdCount = 0;
+ break;
+ }
+ ctx->fdNext = ctx->files;
+ }
+ fid = ctx->fdNext;
+ ctx->fdNext = fid->next;
+
+ fd = fid->fd;
+ eventmask = 0;
+ if (FD_ISSET(fd, &ctx->rdLast))
+ eventmask |= EV_READ;
+ if (FD_ISSET(fd, &ctx->wrLast))
+ eventmask |= EV_WRITE;
+ if (FD_ISSET(fd, &ctx->exLast))
+ eventmask |= EV_EXCEPT;
+ eventmask &= fid->eventmask;
+ if (eventmask != 0) {
+ if ((eventmask & EV_READ) != 0) {
+ FD_CLR(fd, &ctx->rdLast);
+ ctx->fdCount--;
+ }
+ if ((eventmask & EV_WRITE) != 0) {
+ FD_CLR(fd, &ctx->wrLast);
+ ctx->fdCount--;
+ }
+ if ((eventmask & EV_EXCEPT) != 0) {
+ FD_CLR(fd, &ctx->exLast);
+ ctx->fdCount--;
+ }
+ OKNEW(new);
+ new->type = File;
+ new->u.file.this = fid;
+ new->u.file.eventmask = eventmask;
+ opaqueEv->opaque = new;
+ return (0);
+ }
+ }
+ if (ctx->fdCount < 0) {
+ /*
+ * select()'s count is off on a number of systems, and
+ * can result in fdCount < 0.
+ */
+ evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
+ ctx->fdCount = 0;
+ }
+
+ /* We get here if the caller deselect()'s an FD. Gag me with a goto. */
+ goto again;
+}
+
+int
+evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evEvent_p *ev = opaqueEv.opaque;
+#ifdef EVENTLIB_TIME_CHECKS
+ void *func;
+ struct timespec start_time;
+ struct timespec interval;
+#endif
+
+#ifdef EVENTLIB_TIME_CHECKS
+ if (ctx->debug > 0)
+ start_time = evNowTime();
+#endif
+ ctx->cur = ev;
+ switch (ev->type) {
+ case Accept: {
+ evAccept *this = ev->u.accept.this;
+
+ evPrintf(ctx, 5,
+ "Dispatch.Accept: fd %d -> %d, func %p, uap %p\n",
+ this->conn->fd, this->fd,
+ this->conn->func, this->conn->uap);
+ errno = this->ioErrno;
+ (this->conn->func)(opaqueCtx, this->conn->uap, this->fd,
+ &this->la, this->lalen,
+ &this->ra, this->ralen);
+#ifdef EVENTLIB_TIME_CHECKS
+ func = this->conn->func;
+#endif
+ break;
+ }
+ case File: {
+ evFile *this = ev->u.file.this;
+ int eventmask = ev->u.file.eventmask;
+
+ evPrintf(ctx, 5,
+ "Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n",
+ this->fd, this->eventmask, this->func, this->uap);
+ (this->func)(opaqueCtx, this->uap, this->fd, eventmask);
+#ifdef EVENTLIB_TIME_CHECKS
+ func = this->func;
+#endif
+ break;
+ }
+ case Stream: {
+ evStream *this = ev->u.stream.this;
+
+ evPrintf(ctx, 5,
+ "Dispatch.Stream: fd %d, func %p, uap %p\n",
+ this->fd, this->func, this->uap);
+ errno = this->ioErrno;
+ (this->func)(opaqueCtx, this->uap, this->fd, this->ioDone);
+#ifdef EVENTLIB_TIME_CHECKS
+ func = this->func;
+#endif
+ break;
+ }
+ case Timer: {
+ evTimer *this = ev->u.timer.this;
+
+ evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n",
+ this->func, this->uap);
+ (this->func)(opaqueCtx, this->uap, this->due, this->inter);
+#ifdef EVENTLIB_TIME_CHECKS
+ func = this->func;
+#endif
+ break;
+ }
+ case Wait: {
+ evWait *this = ev->u.wait.this;
+
+ evPrintf(ctx, 5,
+ "Dispatch.Wait: tag %p, func %p, uap %p\n",
+ this->tag, this->func, this->uap);
+ (this->func)(opaqueCtx, this->uap, this->tag);
+#ifdef EVENTLIB_TIME_CHECKS
+ func = this->func;
+#endif
+ break;
+ }
+ case Null: {
+ /* No work. */
+#ifdef EVENTLIB_TIME_CHECKS
+ func = NULL;
+#endif
+ break;
+ }
+ default: {
+ abort();
+ }
+ }
+#ifdef EVENTLIB_TIME_CHECKS
+ if (ctx->debug > 0) {
+ interval = evSubTime(evNowTime(), start_time);
+ /*
+ * Complain if it took longer than 50 milliseconds.
+ *
+ * We call getuid() to make an easy to find mark in a kernel
+ * trace.
+ */
+ if (interval.tv_sec > 0 || interval.tv_nsec > 50000000)
+ evPrintf(ctx, 1,
+ "dispatch interval %u.%09u uid %d type %d func %p\n",
+ interval.tv_sec, interval.tv_nsec,
+ getuid(), ev->type, func);
+ }
+#endif
+ ctx->cur = NULL;
+ evDrop(opaqueCtx, opaqueEv);
+ return (0);
+}
+
+void
+evDrop(evContext opaqueCtx, evEvent opaqueEv) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evEvent_p *ev = opaqueEv.opaque;
+
+ switch (ev->type) {
+ case Accept: {
+ FREE(ev->u.accept.this);
+ break;
+ }
+ case File: {
+ /* No work. */
+ break;
+ }
+ case Stream: {
+ evStreamID id;
+
+ id.opaque = ev->u.stream.this;
+ (void) evCancelRW(opaqueCtx, id);
+ break;
+ }
+ case Timer: {
+ evTimer *this = ev->u.timer.this;
+ evTimerID opaque;
+
+ /* Check to see whether the user func cleared the timer. */
+ if (heap_element(ctx->timers, this->index) != this) {
+ evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n");
+ break;
+ }
+ /*
+ * Timer is still there. Delete it if it has expired,
+ * otherwise set it according to its next interval.
+ */
+ if (this->inter.tv_sec == (time_t)0 &&
+ this->inter.tv_nsec == 0L) {
+ opaque.opaque = this;
+ (void) evClearTimer(opaqueCtx, opaque);
+ } else {
+ opaque.opaque = this;
+ (void) evResetTimer(opaqueCtx, opaque, this->func,
+ this->uap,
+ evAddTime((this->mode & EV_TMR_RATE) ?
+ this->due :
+ ctx->lastEventTime,
+ this->inter),
+ this->inter);
+ }
+ break;
+ }
+ case Wait: {
+ FREE(ev->u.wait.this);
+ break;
+ }
+ case Null: {
+ /* No work. */
+ break;
+ }
+ default: {
+ abort();
+ }
+ }
+ FREE(ev);
+}
+
+int
+evMainLoop(evContext opaqueCtx) {
+ evEvent event;
+ int x;
+
+ while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
+ if ((x = evDispatch(opaqueCtx, event)) < 0)
+ break;
+ return (x);
+}
+
+int
+evHighestFD(evContext opaqueCtx) {
+ evContext_p *ctx = opaqueCtx.opaque;
+
+ return (ctx->highestFD);
+}
+
+void
+evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (ctx->output != NULL && ctx->debug >= level) {
+ vfprintf(ctx->output, fmt, ap);
+ fflush(ctx->output);
+ }
+ va_end(ap);
+}
+
+int
+evSetOption(evContext *opaqueCtx, const char *option, int value) {
+ /* evContext_p *ctx = opaqueCtx->opaque; */
+
+ UNUSED(opaqueCtx);
+ UNUSED(value);
+#ifndef CLOCK_MONOTONIC
+ UNUSED(option);
+#endif
+
+#ifdef CLOCK_MONOTONIC
+ if (strcmp(option, "monotime") == 0) {
+ if (opaqueCtx != NULL)
+ errno = EINVAL;
+ if (value == 0 || value == 1) {
+ __evOptMonoTime = value;
+ return (0);
+ } else {
+ errno = EINVAL;
+ return (-1);
+ }
+ }
+#endif
+ errno = ENOENT;
+ return (-1);
+}
+
+int
+evGetOption(evContext *opaqueCtx, const char *option, int *value) {
+ /* evContext_p *ctx = opaqueCtx->opaque; */
+
+ UNUSED(opaqueCtx);
+#ifndef CLOCK_MONOTONIC
+ UNUSED(value);
+ UNUSED(option);
+#endif
+
+#ifdef CLOCK_MONOTONIC
+ if (strcmp(option, "monotime") == 0) {
+ if (opaqueCtx != NULL)
+ errno = EINVAL;
+ *value = __evOptMonoTime;
+ return (0);
+ }
+#endif
+ errno = ENOENT;
+ return (-1);
+}
+
+#if defined(NEED_PSELECT) || defined(USE_POLL)
+/* XXX needs to move to the porting library. */
+static int
+pselect(int nfds, void *rfds, void *wfds, void *efds,
+ struct timespec *tsp,
+ const sigset_t *sigmask)
+{
+ struct timeval tv, *tvp;
+ sigset_t sigs;
+ int n;
+#ifdef USE_POLL
+ int polltimeout = INFTIM;
+ evContext_p *ctx;
+ struct pollfd *fds;
+ nfds_t pnfds;
+
+ UNUSED(nfds);
+#endif /* USE_POLL */
+
+ if (tsp) {
+ tvp = &tv;
+ tv = evTimeVal(*tsp);
+#ifdef USE_POLL
+ polltimeout = 1000 * tv.tv_sec + tv.tv_usec / 1000;
+#endif /* USE_POLL */
+ } else
+ tvp = NULL;
+ if (sigmask)
+ sigprocmask(SIG_SETMASK, sigmask, &sigs);
+#ifndef USE_POLL
+ n = select(nfds, rfds, wfds, efds, tvp);
+#else
+ /*
+ * rfds, wfds, and efds should all be from the same evContext_p,
+ * so any of them will do. If they're all NULL, the caller is
+ * presumably calling us to block.
+ */
+ if (rfds != NULL)
+ ctx = ((__evEmulMask *)rfds)->ctx;
+ else if (wfds != NULL)
+ ctx = ((__evEmulMask *)wfds)->ctx;
+ else if (efds != NULL)
+ ctx = ((__evEmulMask *)efds)->ctx;
+ else
+ ctx = NULL;
+ if (ctx != NULL && ctx->fdMax != -1) {
+ fds = &(ctx->pollfds[ctx->firstfd]);
+ pnfds = ctx->fdMax - ctx->firstfd + 1;
+ } else {
+ fds = NULL;
+ pnfds = 0;
+ }
+ n = poll(fds, pnfds, polltimeout);
+ if (n > 0) {
+ int i, e;
+
+ INSIST(ctx != NULL);
+ for (e = 0, i = ctx->firstfd; i <= ctx->fdMax; i++) {
+ if (ctx->pollfds[i].fd < 0)
+ continue;
+ if (FD_ISSET(i, &ctx->rdLast))
+ e++;
+ if (FD_ISSET(i, &ctx->wrLast))
+ e++;
+ if (FD_ISSET(i, &ctx->exLast))
+ e++;
+ }
+ n = e;
+ }
+#endif /* USE_POLL */
+ if (sigmask)
+ sigprocmask(SIG_SETMASK, &sigs, NULL);
+ if (tsp)
+ *tsp = evTimeSpec(tv);
+ return (n);
+}
+#endif
+
+#ifdef USE_POLL
+int
+evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) {
+
+ int i, maxnfds;
+ void *pollfds, *fdTable;
+
+ if (fd < ctx->maxnfds)
+ return (0);
+
+ /* Don't allow ridiculously small values for pollfd_chunk_size */
+ if (pollfd_chunk_size < 20)
+ pollfd_chunk_size = 20;
+
+ maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size;
+
+ pollfds = realloc(ctx->pollfds, maxnfds * sizeof(*ctx->pollfds));
+ if (pollfds != NULL)
+ ctx->pollfds = pollfds;
+ fdTable = realloc(ctx->fdTable, maxnfds * sizeof(*ctx->fdTable));
+ if (fdTable != NULL)
+ ctx->fdTable = fdTable;
+
+ if (pollfds == NULL || fdTable == NULL) {
+ evPrintf(ctx, 2, "pollfd() realloc (%ld) failed\n",
+ (long)maxnfds*sizeof(struct pollfd));
+ return (-1);
+ }
+
+ for (i = ctx->maxnfds; i < maxnfds; i++) {
+ ctx->pollfds[i].fd = -1;
+ ctx->pollfds[i].events = 0;
+ ctx->fdTable[i] = 0;
+ }
+
+ ctx->maxnfds = maxnfds;
+
+ return (0);
+}
+
+/* Find the appropriate 'events' or 'revents' field in the pollfds array */
+short *
+__fd_eventfield(int fd, __evEmulMask *maskp) {
+
+ evContext_p *ctx = (evContext_p *)maskp->ctx;
+
+ if (!maskp->result || maskp->type == EV_WASNONBLOCKING)
+ return (&(ctx->pollfds[fd].events));
+ else
+ return (&(ctx->pollfds[fd].revents));
+}
+
+/* Translate to poll(2) event */
+short
+__poll_event(__evEmulMask *maskp) {
+
+ switch ((maskp)->type) {
+ case EV_READ:
+ return (POLLRDNORM);
+ case EV_WRITE:
+ return (POLLWRNORM);
+ case EV_EXCEPT:
+ return (POLLRDBAND | POLLPRI | POLLWRBAND);
+ case EV_WASNONBLOCKING:
+ return (POLLHUP);
+ default:
+ return (0);
+ }
+}
+
+/*
+ * Clear the events corresponding to the specified mask. If this leaves
+ * the events mask empty (apart from the POLLHUP bit), set the fd field
+ * to -1 so that poll(2) will ignore this fd.
+ */
+void
+__fd_clr(int fd, __evEmulMask *maskp) {
+
+ evContext_p *ctx = maskp->ctx;
+
+ *__fd_eventfield(fd, maskp) &= ~__poll_event(maskp);
+ if ((ctx->pollfds[fd].events & ~POLLHUP) == 0) {
+ ctx->pollfds[fd].fd = -1;
+ if (fd == ctx->fdMax)
+ while (ctx->fdMax > ctx->firstfd &&
+ ctx->pollfds[ctx->fdMax].fd < 0)
+ ctx->fdMax--;
+ if (fd == ctx->firstfd)
+ while (ctx->firstfd <= ctx->fdMax &&
+ ctx->pollfds[ctx->firstfd].fd < 0)
+ ctx->firstfd++;
+ /*
+ * Do we have a empty set of descriptors?
+ */
+ if (ctx->firstfd > ctx->fdMax) {
+ ctx->fdMax = -1;
+ ctx->firstfd = 0;
+ }
+ }
+}
+
+/*
+ * Set the events bit(s) corresponding to the specified mask. If the events
+ * field has any other bits than POLLHUP set, also set the fd field so that
+ * poll(2) will watch this fd.
+ */
+void
+__fd_set(int fd, __evEmulMask *maskp) {
+
+ evContext_p *ctx = maskp->ctx;
+
+ *__fd_eventfield(fd, maskp) |= __poll_event(maskp);
+ if ((ctx->pollfds[fd].events & ~POLLHUP) != 0) {
+ ctx->pollfds[fd].fd = fd;
+ if (fd < ctx->firstfd || ctx->fdMax == -1)
+ ctx->firstfd = fd;
+ if (fd > ctx->fdMax)
+ ctx->fdMax = fd;
+ }
+}
+#endif /* USE_POLL */
+
+/*! \file */
diff --git a/lib/bind/isc/eventlib.mdoc b/lib/bind/isc/eventlib.mdoc
new file mode 100644
index 0000000..5e9cd85
--- /dev/null
+++ b/lib/bind/isc/eventlib.mdoc
@@ -0,0 +1,918 @@
+.\" $Id: eventlib.mdoc,v 1.3 2004/03/09 06:30:08 marka Exp $
+.\"
+.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 1995-1999 by Internet Software Consortium
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd March 6, 1996
+.Dt EVENTLIB 3
+.Os BSD 4
+.Sh NAME
+.Nm evConnFunc ,
+.Nm evFileFunc ,
+.Nm evStreamFunc ,
+.Nm evTimerFunc ,
+.Nm evWaitFunc ,
+.Nm evCreate ,
+.Nm evDestroy ,
+.Nm evGetNext ,
+.Nm evDispatch ,
+.Nm evDrop ,
+.Nm evMainLoop ,
+.Nm evConsTime ,
+.Nm evTimeSpec ,
+.Nm evTimeVal ,
+.Nm evAddTime ,
+.Nm evSubTime ,
+.Nm evCmpTime ,
+.Nm evNowTime ,
+.Nm evUTCTime ,
+.Nm evLastEventTime ,
+.Nm evSetTimer ,
+.Nm evResetTimer ,
+.Nm evConfigTimer ,
+.Nm evClearTimer ,
+.Nm evSetIdleTimer ,
+.Nm evTouchIdleTimer ,
+.Nm evClearIdleTimer ,
+.Nm evWaitFor ,
+.Nm evDo ,
+.Nm evUnwait ,
+.Nm evDefer ,
+.Nm evSelectFD ,
+.Nm evDeselectFD ,
+.Nm evWrite ,
+.Nm evRead ,
+.Nm evCancelRW ,
+.Nm evTimeRW ,
+.Nm evUntimeRW ,
+.Nm evListen ,
+.Nm evConnect ,
+.Nm evCancelConn ,
+.Nm evHold ,
+.Nm evUnhold ,
+.Nm evTryAccept ,
+.Nm evConsIovec ,
+.Nm evSetDebug ,
+.Nm evPrintf ,
+.Nm evInitID ,
+.Nm evTestID ,
+.Nm evGetOption ,
+.Nm evSetOption
+.Nd event handling library
+.Sh SYNOPSIS
+.Fd #include <isc/eventlib.h>
+.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/lib/bind/isc/eventlib_p.h b/lib/bind/isc/eventlib_p.h
new file mode 100644
index 0000000..5896553
--- /dev/null
+++ b/lib/bind/isc/eventlib_p.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file
+ * \brief private interfaces for eventlib
+ * \author vix 09sep95 [initial]
+ *
+ * $Id: eventlib_p.h,v 1.5.18.4 2006/03/10 00:20:08 marka Exp $
+ */
+
+#ifndef _EVENTLIB_P_H
+#define _EVENTLIB_P_H
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+#define EVENTLIB_DEBUG 1
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/heap.h>
+#include <isc/list.h>
+#include <isc/memcluster.h>
+
+#define EV_MASK_ALL (EV_READ | EV_WRITE | EV_EXCEPT)
+#define EV_ERR(e) return (errno = (e), -1)
+#define OK(x) if ((x) < 0) EV_ERR(errno); else (void)NULL
+#define OKFREE(x, y) if ((x) < 0) { FREE((y)); EV_ERR(errno); } \
+ else (void)NULL
+
+#define NEW(p) if (((p) = memget(sizeof *(p))) != NULL) \
+ FILL(p); \
+ else \
+ (void)NULL;
+#define OKNEW(p) if (!((p) = memget(sizeof *(p)))) { \
+ errno = ENOMEM; \
+ return (-1); \
+ } else \
+ FILL(p)
+#define FREE(p) memput((p), sizeof *(p))
+
+#if EVENTLIB_DEBUG
+#define FILL(p) memset((p), 0xF5, sizeof *(p))
+#else
+#define FILL(p)
+#endif
+
+#ifdef USE_POLL
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+#include <poll.h>
+#endif /* USE_POLL */
+
+typedef struct evConn {
+ evConnFunc func;
+ void * uap;
+ int fd;
+ int flags;
+#define EV_CONN_LISTEN 0x0001 /*%< Connection is a listener. */
+#define EV_CONN_SELECTED 0x0002 /*%< evSelectFD(conn->file). */
+#define EV_CONN_BLOCK 0x0004 /*%< Listener fd was blocking. */
+ evFileID file;
+ struct evConn * prev;
+ struct evConn * next;
+} evConn;
+
+typedef struct evAccept {
+ int fd;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+ } la;
+ ISC_SOCKLEN_T lalen;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+ } ra;
+ ISC_SOCKLEN_T ralen;
+ int ioErrno;
+ evConn * conn;
+ LINK(struct evAccept) link;
+} evAccept;
+
+typedef struct evFile {
+ evFileFunc func;
+ void * uap;
+ int fd;
+ int eventmask;
+ int preemptive;
+ struct evFile * prev;
+ struct evFile * next;
+ struct evFile * fdprev;
+ struct evFile * fdnext;
+} evFile;
+
+typedef struct evStream {
+ evStreamFunc func;
+ void * uap;
+ evFileID file;
+ evTimerID timer;
+ int flags;
+#define EV_STR_TIMEROK 0x0001 /*%< IFF timer valid. */
+ int fd;
+ struct iovec * iovOrig;
+ int iovOrigCount;
+ struct iovec * iovCur;
+ int iovCurCount;
+ int ioTotal;
+ int ioDone;
+ int ioErrno;
+ struct evStream *prevDone, *nextDone;
+ struct evStream *prev, *next;
+} evStream;
+
+typedef struct evTimer {
+ evTimerFunc func;
+ void * uap;
+ struct timespec due, inter;
+ int index;
+ int mode;
+#define EV_TMR_RATE 1
+} evTimer;
+
+typedef struct evWait {
+ evWaitFunc func;
+ void * uap;
+ const void * tag;
+ struct evWait * next;
+} evWait;
+
+typedef struct evWaitList {
+ evWait * first;
+ evWait * last;
+ struct evWaitList * prev;
+ struct evWaitList * next;
+} evWaitList;
+
+typedef struct evEvent_p {
+ enum { Accept, File, Stream, Timer, Wait, Free, Null } type;
+ union {
+ struct { evAccept *this; } accept;
+ struct { evFile *this; int eventmask; } file;
+ struct { evStream *this; } stream;
+ struct { evTimer *this; } timer;
+ struct { evWait *this; } wait;
+ struct { struct evEvent_p *next; } free;
+ struct { const void *placeholder; } null;
+ } u;
+} evEvent_p;
+
+#ifdef USE_POLL
+typedef struct {
+ void *ctx; /* pointer to the evContext_p */
+ uint32_t type; /* READ, WRITE, EXCEPT, nonblk */
+ uint32_t result; /* 1 => revents, 0 => events */
+} __evEmulMask;
+
+#define emulMaskInit(ctx, field, ev, lastnext) \
+ ctx->field.ctx = ctx; \
+ ctx->field.type = ev; \
+ ctx->field.result = lastnext;
+
+extern short *__fd_eventfield(int fd, __evEmulMask *maskp);
+extern short __poll_event(__evEmulMask *maskp);
+extern void __fd_clr(int fd, __evEmulMask *maskp);
+extern void __fd_set(int fd, __evEmulMask *maskp);
+
+#undef FD_ZERO
+#define FD_ZERO(maskp)
+
+#undef FD_SET
+#define FD_SET(fd, maskp) \
+ __fd_set(fd, maskp)
+
+#undef FD_CLR
+#define FD_CLR(fd, maskp) \
+ __fd_clr(fd, maskp)
+
+#undef FD_ISSET
+#define FD_ISSET(fd, maskp) \
+ ((*__fd_eventfield(fd, maskp) & __poll_event(maskp)) != 0)
+
+#endif /* USE_POLL */
+
+typedef struct {
+ /* Global. */
+ const evEvent_p *cur;
+ /* Debugging. */
+ int debug;
+ FILE *output;
+ /* Connections. */
+ evConn *conns;
+ LIST(evAccept) accepts;
+ /* Files. */
+ evFile *files, *fdNext;
+#ifndef USE_POLL
+ fd_set rdLast, rdNext;
+ fd_set wrLast, wrNext;
+ fd_set exLast, exNext;
+ fd_set nonblockBefore;
+ int fdMax, fdCount, highestFD;
+ evFile *fdTable[FD_SETSIZE];
+#else
+ struct pollfd *pollfds; /* Allocated as needed */
+ evFile **fdTable; /* Ditto */
+ int maxnfds; /* # elements in above */
+ int firstfd; /* First active fd */
+ int fdMax; /* Last active fd */
+ int fdCount; /* # fd:s with I/O */
+ int highestFD; /* max fd allowed by OS */
+ __evEmulMask rdLast, rdNext;
+ __evEmulMask wrLast, wrNext;
+ __evEmulMask exLast, exNext;
+ __evEmulMask nonblockBefore;
+#endif /* USE_POLL */
+#ifdef EVENTLIB_TIME_CHECKS
+ struct timespec lastSelectTime;
+ int lastFdCount;
+#endif
+ /* Streams. */
+ evStream *streams;
+ evStream *strDone, *strLast;
+ /* Timers. */
+ struct timespec lastEventTime;
+ heap_context timers;
+ /* Waits. */
+ evWaitList *waitLists;
+ evWaitList waitDone;
+} evContext_p;
+
+/* eventlib.c */
+#define evPrintf __evPrintf
+void evPrintf(const evContext_p *ctx, int level, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+
+#ifdef USE_POLL
+extern int evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd);
+#endif /* USE_POLL */
+
+/* ev_timers.c */
+#define evCreateTimers __evCreateTimers
+heap_context evCreateTimers(const evContext_p *);
+#define evDestroyTimers __evDestroyTimers
+void evDestroyTimers(const evContext_p *);
+
+/* ev_waits.c */
+#define evFreeWait __evFreeWait
+evWait *evFreeWait(evContext_p *ctx, evWait *old);
+
+/* Global options */
+extern int __evOptMonoTime;
+
+#endif /*_EVENTLIB_P_H*/
diff --git a/lib/bind/isc/heap.c b/lib/bind/isc/heap.c
new file mode 100644
index 0000000..bea7678
--- /dev/null
+++ b/lib/bind/isc/heap.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*%
+ * Heap implementation of priority queues adapted from the following:
+ *
+ * _Introduction to Algorithms_, Cormen, Leiserson, and Rivest,
+ * MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7.
+ *
+ * _Algorithms_, Second Edition, Sedgewick, Addison-Wesley, 1988,
+ * ISBN 0-201-06673-4, chapter 11.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: heap.c,v 1.2.18.2 2006/03/10 00:20:08 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "port_after.h"
+
+#include <isc/heap.h>
+
+/*%
+ * Note: to make heap_parent and heap_left easy to compute, the first
+ * element of the heap array is not used; i.e. heap subscripts are 1-based,
+ * not 0-based.
+ */
+#define heap_parent(i) ((i) >> 1)
+#define heap_left(i) ((i) << 1)
+
+#define ARRAY_SIZE_INCREMENT 512
+
+heap_context
+heap_new(heap_higher_priority_func higher_priority, heap_index_func index,
+ int array_size_increment) {
+ heap_context ctx;
+
+ if (higher_priority == NULL)
+ return (NULL);
+
+ ctx = (heap_context)malloc(sizeof (struct heap_context));
+ if (ctx == NULL)
+ return (NULL);
+
+ ctx->array_size = 0;
+ if (array_size_increment == 0)
+ ctx->array_size_increment = ARRAY_SIZE_INCREMENT;
+ else
+ ctx->array_size_increment = array_size_increment;
+ ctx->heap_size = 0;
+ ctx->heap = NULL;
+ ctx->higher_priority = higher_priority;
+ ctx->index = index;
+ return (ctx);
+}
+
+int
+heap_free(heap_context ctx) {
+ if (ctx == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (ctx->heap != NULL)
+ free(ctx->heap);
+ free(ctx);
+
+ return (0);
+}
+
+static int
+heap_resize(heap_context ctx) {
+ void **new_heap;
+
+ ctx->array_size += ctx->array_size_increment;
+ new_heap = (void **)realloc(ctx->heap,
+ (ctx->array_size) * (sizeof (void *)));
+ if (new_heap == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ ctx->heap = new_heap;
+ return (0);
+}
+
+static void
+float_up(heap_context ctx, int i, void *elt) {
+ int p;
+
+ for ( p = heap_parent(i);
+ i > 1 && ctx->higher_priority(elt, ctx->heap[p]);
+ i = p, p = heap_parent(i) ) {
+ ctx->heap[i] = ctx->heap[p];
+ if (ctx->index != NULL)
+ (ctx->index)(ctx->heap[i], i);
+ }
+ ctx->heap[i] = elt;
+ if (ctx->index != NULL)
+ (ctx->index)(ctx->heap[i], i);
+}
+
+static void
+sink_down(heap_context ctx, int i, void *elt) {
+ int j, size, half_size;
+
+ size = ctx->heap_size;
+ half_size = size / 2;
+ while (i <= half_size) {
+ /* find smallest of the (at most) two children */
+ j = heap_left(i);
+ if (j < size && ctx->higher_priority(ctx->heap[j+1],
+ ctx->heap[j]))
+ j++;
+ if (ctx->higher_priority(elt, ctx->heap[j]))
+ break;
+ ctx->heap[i] = ctx->heap[j];
+ if (ctx->index != NULL)
+ (ctx->index)(ctx->heap[i], i);
+ i = j;
+ }
+ ctx->heap[i] = elt;
+ if (ctx->index != NULL)
+ (ctx->index)(ctx->heap[i], i);
+}
+
+int
+heap_insert(heap_context ctx, void *elt) {
+ int i;
+
+ if (ctx == NULL || elt == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ i = ++ctx->heap_size;
+ if (ctx->heap_size >= ctx->array_size && heap_resize(ctx) < 0)
+ return (-1);
+
+ float_up(ctx, i, elt);
+
+ return (0);
+}
+
+int
+heap_delete(heap_context ctx, int i) {
+ void *elt;
+ int less;
+
+ if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (i == ctx->heap_size) {
+ ctx->heap_size--;
+ } else {
+ elt = ctx->heap[ctx->heap_size--];
+ less = ctx->higher_priority(elt, ctx->heap[i]);
+ ctx->heap[i] = elt;
+ if (less)
+ float_up(ctx, i, ctx->heap[i]);
+ else
+ sink_down(ctx, i, ctx->heap[i]);
+ }
+
+ return (0);
+}
+
+int
+heap_increased(heap_context ctx, int i) {
+ if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ float_up(ctx, i, ctx->heap[i]);
+
+ return (0);
+}
+
+int
+heap_decreased(heap_context ctx, int i) {
+ if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sink_down(ctx, i, ctx->heap[i]);
+
+ return (0);
+}
+
+void *
+heap_element(heap_context ctx, int i) {
+ if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ return (ctx->heap[i]);
+}
+
+int
+heap_for_each(heap_context ctx, heap_for_each_func action, void *uap) {
+ int i;
+
+ if (ctx == NULL || action == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ for (i = 1; i <= ctx->heap_size; i++)
+ (action)(ctx->heap[i], uap);
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/bind/isc/heap.mdoc b/lib/bind/isc/heap.mdoc
new file mode 100644
index 0000000..332a6ec
--- /dev/null
+++ b/lib/bind/isc/heap.mdoc
@@ -0,0 +1,378 @@
+.\" $Id: heap.mdoc,v 1.3 2004/03/09 06:30:08 marka Exp $
+.\"
+.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 1997,1999 by Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd January 1, 1997
+.\"Os OPERATING_SYSTEM [version/release]
+.Os BSD 4
+.Dt HEAP @SYSCALL_EXT@
+.Sh NAME
+.Nm heap_new ,
+.Nm heap_free ,
+.Nm heap_insert ,
+.Nm heap_delete ,
+.Nm heap_increased ,
+.Nm heap_decreased ,
+.Nm heap_element ,
+.Nm heap_for_each
+.Nd heap implementation of priority queues
+.Sh SYNOPSIS
+.Fd #include \&"heap.h\&"
+.Ft heap_context
+.Fn heap_new "heap_higher_priority_func higher_priority" \
+"heap_index_func index" "int array_size_increment"
+.Ft int
+.Fn heap_free "heap_context ctx"
+.Ft int
+.Fn heap_insert "heap_context ctx" "void *elt"
+.Ft int
+.Fn heap_delete "heap_context ctx" "int i"
+.Ft int
+.Fn heap_increased "heap_context ctx" "int i"
+.Ft int
+.Fn heap_decreased "heap_context ctx" "int i"
+.Ft void *
+.Fn heap_element "heap_context ctx" "int i"
+.Ft int
+.Fn heap_for_each "heap_context ctx" "heap_for_each_func action" "void *uap"
+.Sh DESCRIPTION
+These functions implement heap\-based priority queues. The user defines a
+priority scheme, and provides a function for comparison of the priority
+of heap elements
+(see the description of the
+.Ft heap_higher_priority_func
+function pointer, below).
+.Pp
+Each of the functions depends upon the
+.Ft heap_context
+type, which is a pointer to a
+.Ft struct heap_context
+.Pq see Pa heap.h No for more information .
+.Pp
+The
+.Pa heap.h
+header file also defines the following set of function
+function pointers:
+.Bd -literal -offset indent
+typedef int (*heap_higher_priority_func)(void *, void *);
+typedef void (*heap_index_func)(void *, int);
+typedef void (*heap_for_each_func)(void *, void *);
+.Ed
+.Pp
+These are pointers to user-defined functions.
+The
+.Ft heap_higher_priority_func
+type is a pointer to a function which compares two
+different heap (queue) elements and returns an
+.Ft int
+which answers the question, "Does the first queue element
+have a higher priority than the second?" In other words,
+a function pointer of this type
+.Em must
+return a number greater than zero
+if the element indicated by the first argument is of a higher priority than
+that indicated by the second element, and zero otherwise.
+.Pp
+The other two function pointers are documented in the descriptions
+of
+.Fn heap_new
+.Pq Va heap_index_func
+and
+.Fn heap_for_each
+.Pq Va heap_for_each_func ,
+below.
+.Pp
+The function
+.Fn heap_new
+initializes a
+.Ft struct heap_context
+and returns a pointer to it. The
+.Fa higher_priority
+function pointer
+.Em must
+be
+.No non\- Ns Dv NULL .
+As explained above, this refers to a
+function supplied by the user which compares the priority of two different
+queue or heap elements; see above for more information.
+The second argument,
+.Fa index ,
+is a pointer to a user-defined function whose arguments are
+a heap element and its index in the heap.
+.Fa Index
+is intended to provide the user a means of knowing the internal index
+of an element in the heap while maintaining the opacity of the implementation;
+since the user has to know the actual indexes of heap elements in order to use,
+e.g.,
+.Fn heap_delete
+or
+.Fn heap_element ,
+the user
+.Fa index
+function could store the index in the heap element, itself. If
+.Fa index
+is
+.No non\- Ns Dv NULL ,
+then it is called
+.Em whenever
+the index of an element changes, allowing the user to stay up\-to\-date
+with index changes.
+The last argument,
+.Fa array_size_increment
+will be used, as its name suggests, by
+.Xr malloc 3
+or
+.Xr realloc 3
+to increment the array which implements the heap; if zero, a default value
+will be used.
+.Pp
+The
+.Fn heap_free
+function frees the given
+.Ft heap_context
+argument
+.Pq Fa ctx ,
+which also frees the entire
+.Nm heap ,
+if it is
+.No non\- Ns Dv NULL .
+The argument
+.Fa ctx
+should be
+.No non\- Ns Dv NULL .
+.Pp
+The
+.Fn heap_insert
+function is used to insert the new heap element
+.Fa elt
+into the appropriate place (priority\-wise) in the
+.Ft heap
+indicated by
+.Fa ctx
+(a pointer to a
+.Ft heap_context ) .
+If
+.No non\- Ns Dv NULL ,
+the user-defined
+.Ft higher_priority
+function pointer associated with the indicated
+.Nm heap
+is used to determine that
+.Dq appropriate place ;
+the highest\-priority elements are at the front of the queue (top of
+the heap).
+(See the description of
+.Fn heap_new ,
+above, for more information.)
+.Pp
+The function
+.Fn heap_delete
+is used to delete the
+.Fa i\- Ns th
+element of the queue (heap), and fixing up the queue (heap) from that
+element onward via the priority as determined by the user function
+pointed to by
+.Ft higher_priority
+function pointer
+(see description of
+.Fn heap_new ,
+above).
+.Pp
+.Fn heap_increased
+.Pp
+.Fn heap_decreased
+.Pp
+The
+.Fn heap_element
+function returns the
+.Fa i\- Ns th
+element of the queue/heap indicated by
+.Fa ctx ,
+if possible.
+.Pp
+The
+.Fn heap_for_each
+function provides a mechanism for the user to increment through the entire
+queue (heap) and perform some
+.Fa action
+upon each of the queue elements. This
+.Fa action
+is pointer to a user\-defined function with two arguments, the first of
+which should be interpreted by the user's function as a heap element. The
+second value passed to the user function is just the
+.Fa uap
+argument to
+.Fn heap_for_each ;
+this allows the user to specify additional arguments, if necessary, to
+the function pointed to by
+.Fa action .
+.\" The following requests should be uncommented and
+.\" used where appropriate. This next request is
+.\" for sections 2 and 3 function return values only.
+.Sh RETURN VALUES
+.Bl -tag -width "heap_decreased()"
+.It Fn heap_new
+.Dv NULL
+if unable to
+.Xr malloc 3
+a
+.Ft struct heap_context
+or if the
+.Fa higher_priority
+function pointer is
+.Dv NULL ;
+otherwise, a valid
+.Ft heap_context
+.Ns .
+.It Fn heap_free
+-1 if
+.Fa ctx
+is
+.Dv NULL
+(with
+.Va errno
+set to
+.Dv EINVAL ) ;
+otherwise, 0.
+.It Fn heap_insert
+-1
+if either
+.Fa ctx
+or
+.Fa elt
+is
+.Dv NULL ,
+or if an attempt to
+.Xr malloc 3
+or
+.Xr realloc 3
+the heap array fails (with
+.Va errno
+set to
+.Dv EINVAL
+or
+.Dv ENOMEM ,
+respectively).
+Otherwise, 0.
+.It Fn heap_delete
+-1 if
+.Fa ctx
+is
+.Dv NULL
+or
+.Fa i
+is out\-of\-range (with
+.Va errno
+set to
+.Dv EINVAL ) ;
+0 otherwise.
+.It Fn heap_increased
+As for
+.Fn heap_delete .
+.It Fn heap_decreased
+As for
+.Fn heap_delete .
+.It Fn heap_element
+NULL if
+.Fa ctx
+is
+.Dv NULL
+or
+.Fa i
+out\-of-bounds (with
+.Va errno
+set to
+.Dv EINVAL ) ;
+otherwise, a pointer to the
+.Fa i\- Ns th
+queue element.
+.It Fn heap_for_each
+-1 if either
+.Fa ctx
+or
+.Fa action
+is
+.Dv NULL
+(with
+.Va errno
+set to
+.Dv EINVAL ) ;
+0 otherwise.
+.El
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\" .Sh ENVIRONMENT
+.Sh FILES
+.Bl -tag -width "heap.h000"
+.It Pa heap.h
+ heap library header file
+.El
+.\" .Sh EXAMPLES
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\" (command return values (to shell) and
+.\" fprintf/stderr type diagnostics)
+.Sh DIAGNOSTICS
+Please refer to
+.Sx RETURN VALUES .
+.\" The next request is for sections 2 and 3 error
+.\" and signal handling only.
+.Sh ERRORS
+The variable
+.Va errno
+is set by
+.Fn heap_free ,
+.Fn heap_insert ,
+.Fn heap_delete ,
+.Fn heap_increased ,
+and
+.Fn heap_decreased
+under the conditions of invalid input
+.Pq Dv EINVAL
+or lack of memory
+.Pq Dv ENOMEM ;
+please refer to
+.Sx RETURN VALUES .
+.Sh SEE ALSO
+.Xr malloc 3 ,
+.Xr realloc 3 .
+.Rs
+.%A Cormen
+.%A Leiserson
+.%A Rivest
+.%B Introduction to Algorithms
+.%Q "MIT Press / McGraw Hill"
+.%D 1990
+.%O ISBN 0\-262\-03141\-8
+.%P chapter 7
+.Re
+.Rs
+.%A Sedgewick
+.%B Algorithms, 2nd ed'n
+.%Q Addison\-Wesley
+.%D 1988
+.%O ISBN 0\-201\-06673\-4
+.%P chapter 11
+.Re
+.\" .Sh STANDARDS
+.\" .Sh HISTORY
+.Sh AUTHORS
+The
+.Nm heap
+library was implemented by Bob Halley (halley@vix.com) of Vixie Enterprises,
+Inc., for the Internet Software consortium, and was adapted from
+the two books listed in the
+.Sx SEE ALSO
+section, above.
+.\" .Sh BUGS
diff --git a/lib/bind/isc/hex.c b/lib/bind/isc/hex.c
new file mode 100644
index 0000000..e43be4f
--- /dev/null
+++ b/lib/bind/isc/hex.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2001 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <port_before.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <isc/misc.h>
+#include <port_after.h>
+
+static const char hex[17] = "0123456789abcdef";
+
+int
+isc_gethexstring(unsigned char *buf, size_t len, int count, FILE *fp,
+ int *multiline)
+{
+ int c, n;
+ unsigned char x;
+ char *s;
+ int result = count;
+
+ x = 0; /*%< silence compiler */
+ n = 0;
+ while (count > 0) {
+ c = fgetc(fp);
+
+ if ((c == EOF) ||
+ (c == '\n' && !*multiline) ||
+ (c == '(' && *multiline) ||
+ (c == ')' && !*multiline))
+ goto formerr;
+ /* comment */
+ if (c == ';') {
+ do {
+ c = fgetc(fp);
+ } while (c != EOF && c != '\n');
+ if (c == '\n' && *multiline)
+ continue;
+ goto formerr;
+ }
+ /* white space */
+ if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
+ continue;
+ /* multiline */
+ if ('(' == c || c == ')') {
+ *multiline = (c == '(' /*)*/);
+ continue;
+ }
+ if ((s = strchr(hex, tolower(c))) == NULL)
+ goto formerr;
+ x = (x<<4) | (s - hex);
+ if (++n == 2) {
+ if (len > 0U) {
+ *buf++ = x;
+ len--;
+ } else
+ result = -1;
+ count--;
+ n = 0;
+ }
+ }
+ return (result);
+
+ formerr:
+ if (c == '\n')
+ ungetc(c, fp);
+ return (-1);
+}
+
+void
+isc_puthexstring(FILE *fp, const unsigned char *buf, size_t buflen,
+ size_t len1, size_t len2, const char *sep)
+{
+ size_t i = 0;
+
+ if (len1 < 4U)
+ len1 = 4;
+ if (len2 < 4U)
+ len2 = 4;
+ while (buflen > 0U) {
+ fputc(hex[(buf[0]>>4)&0xf], fp);
+ fputc(hex[buf[0]&0xf], fp);
+ i += 2;
+ buflen--;
+ buf++;
+ if (i >= len1 && sep != NULL) {
+ fputs(sep, fp);
+ i = 0;
+ len1 = len2;
+ }
+ }
+}
+
+void
+isc_tohex(const unsigned char *buf, size_t buflen, char *t) {
+ while (buflen > 0U) {
+ *t++ = hex[(buf[0]>>4)&0xf];
+ *t++ = hex[buf[0]&0xf];
+ buf++;
+ buflen--;
+ }
+ *t = '\0';
+}
+
+/*! \file */
diff --git a/lib/bind/isc/logging.c b/lib/bind/isc/logging.c
new file mode 100644
index 0000000..ca7049c
--- /dev/null
+++ b/lib/bind/isc/logging.c
@@ -0,0 +1,722 @@
+/*
+ * 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.6.18.1 2005/04/27 05:01:07 sra Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/assertions.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+#include <isc/misc.h>
+
+#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);
+}
+
+/*! \file */
diff --git a/lib/bind/isc/logging.mdoc b/lib/bind/isc/logging.mdoc
new file mode 100644
index 0000000..98b2aed
--- /dev/null
+++ b/lib/bind/isc/logging.mdoc
@@ -0,0 +1,1056 @@
+.\" $Id: logging.mdoc,v 1.3 2004/03/09 06:30:08 marka Exp $
+.\"
+.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 1995-1999 by Internet Software Consortium
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" The following six UNCOMMENTED lines are required.
+.Dd January 1, 1996
+.\"Os OPERATING_SYSTEM [version/release]
+.Os BSD 4
+.\"Dt DOCUMENT_TITLE [section number] [volume]
+.Dt LOGGING @SYSCALL_EXT@
+.Sh NAME
+.Nm log_open_stream ,
+.Nm log_close_stream ,
+.Nm log_get_stream ,
+.Nm log_get_filename ,
+.Nm log_vwrite ,
+.Nm log_write ,
+.Nm log_new_context ,
+.Nm log_free_context ,
+.Nm log_add_channel ,
+.Nm log_remove_channel ,
+.Nm log_option ,
+.Nm log_category_is_active ,
+.Nm log_new_syslog_channel ,
+.Nm log_new_file_channel ,
+.Nm log_set_file_owner ,
+.Nm log_new_null_channel ,
+.Nm log_inc_references ,
+.Nm log_dec_references ,
+.Nm log_free_channel
+.Nd logging system
+.Sh SYNOPSIS
+.Fd #include <isc/logging.h>
+.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/lib/bind/isc/logging_p.h b/lib/bind/isc/logging_p.h
new file mode 100644
index 0000000..5e6314f
--- /dev/null
+++ b/lib/bind/isc/logging_p.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef LOGGING_P_H
+#define LOGGING_P_H
+
+typedef struct log_file_desc {
+ char *name;
+ size_t name_size;
+ FILE *stream;
+ unsigned int versions;
+ unsigned long max_size;
+ uid_t owner;
+ gid_t group;
+} log_file_desc;
+
+typedef union log_output {
+ int facility;
+ log_file_desc file;
+} log_output;
+
+struct log_channel {
+ int level; /*%< don't log messages > level */
+ log_channel_type type;
+ log_output out;
+ unsigned int flags;
+ int references;
+};
+
+typedef struct log_channel_list {
+ log_channel channel;
+ struct log_channel_list *next;
+} *log_channel_list;
+
+#define LOG_BUFFER_SIZE 20480
+
+struct log_context {
+ int num_categories;
+ char **category_names;
+ log_channel_list *categories;
+ int flags;
+ int level;
+ char buffer[LOG_BUFFER_SIZE];
+};
+
+#endif /* !LOGGING_P_H */
+/*! \file */
diff --git a/lib/bind/isc/memcluster.c b/lib/bind/isc/memcluster.c
new file mode 100644
index 0000000..a58a2fe
--- /dev/null
+++ b/lib/bind/isc/memcluster.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/* When this symbol is defined allocations via memget are made slightly
+ bigger and some debugging info stuck before and after the region given
+ back to the caller. */
+/* #define DEBUGGING_MEMCLUSTER */
+#define MEMCLUSTER_ATEND
+
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: memcluster.c,v 1.5.18.6 2006/08/30 23:30:35 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <isc/memcluster.h>
+#include <isc/assertions.h>
+
+#include "port_after.h"
+
+#ifdef MEMCLUSTER_RECORD
+#ifndef DEBUGGING_MEMCLUSTER
+#define DEBUGGING_MEMCLUSTER
+#endif
+#endif
+
+#define DEF_MAX_SIZE 1100
+#define DEF_MEM_TARGET 4096
+
+typedef u_int32_t fence_t;
+
+typedef struct {
+ void * next;
+#if defined(DEBUGGING_MEMCLUSTER)
+#if defined(MEMCLUSTER_RECORD)
+ const char * file;
+ int line;
+#endif
+ size_t size;
+ fence_t fencepost;
+#endif
+} memcluster_element;
+
+#define SMALL_SIZE_LIMIT sizeof(memcluster_element)
+#define P_SIZE sizeof(void *)
+#define FRONT_FENCEPOST 0xfebafeba
+#define BACK_FENCEPOST 0xabefabef
+#define FENCEPOST_SIZE 4
+
+#ifndef MEMCLUSTER_LITTLE_MALLOC
+#define MEMCLUSTER_BIG_MALLOC 1
+#define NUM_BASIC_BLOCKS 64
+#endif
+
+struct stats {
+ u_long gets;
+ u_long totalgets;
+ u_long blocks;
+ u_long freefrags;
+};
+
+#ifdef DO_PTHREADS
+#include <pthread.h>
+static pthread_mutex_t memlock = PTHREAD_MUTEX_INITIALIZER;
+#define MEMLOCK (void)pthread_mutex_lock(&memlock)
+#define MEMUNLOCK (void)pthread_mutex_unlock(&memlock)
+#else
+/*
+ * Catch bad lock usage in non threaded build.
+ */
+static unsigned int memlock = 0;
+#define MEMLOCK do { INSIST(memlock == 0); memlock = 1; } while (0)
+#define MEMUNLOCK do { INSIST(memlock == 1); memlock = 0; } while (0)
+#endif /* DO_PTHEADS */
+
+/* Private data. */
+
+static size_t max_size;
+static size_t mem_target;
+#ifndef MEMCLUSTER_BIG_MALLOC
+static size_t mem_target_half;
+static size_t mem_target_fudge;
+#endif
+static memcluster_element ** freelists;
+#ifdef MEMCLUSTER_RECORD
+static memcluster_element ** activelists;
+#endif
+#ifdef MEMCLUSTER_BIG_MALLOC
+static memcluster_element * basic_blocks;
+#endif
+static struct stats * stats;
+
+/* Forward. */
+
+static size_t quantize(size_t);
+#if defined(DEBUGGING_MEMCLUSTER)
+static void check(unsigned char *, int, size_t);
+#endif
+
+/* Public. */
+
+int
+meminit(size_t init_max_size, size_t target_size) {
+
+#if defined(DEBUGGING_MEMCLUSTER)
+ INSIST(sizeof(fence_t) == FENCEPOST_SIZE);
+#endif
+ if (freelists != NULL) {
+ errno = EEXIST;
+ return (-1);
+ }
+ if (init_max_size == 0U)
+ max_size = DEF_MAX_SIZE;
+ else
+ max_size = init_max_size;
+ if (target_size == 0U)
+ mem_target = DEF_MEM_TARGET;
+ else
+ mem_target = target_size;
+#ifndef MEMCLUSTER_BIG_MALLOC
+ mem_target_half = mem_target / 2;
+ mem_target_fudge = mem_target + mem_target / 4;
+#endif
+ freelists = malloc(max_size * sizeof (memcluster_element *));
+ stats = malloc((max_size+1) * sizeof (struct stats));
+ if (freelists == NULL || stats == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memset(freelists, 0,
+ max_size * sizeof (memcluster_element *));
+ memset(stats, 0, (max_size + 1) * sizeof (struct stats));
+#ifdef MEMCLUSTER_RECORD
+ activelists = malloc((max_size + 1) * sizeof (memcluster_element *));
+ if (activelists == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memset(activelists, 0,
+ (max_size + 1) * sizeof (memcluster_element *));
+#endif
+#ifdef MEMCLUSTER_BIG_MALLOC
+ basic_blocks = NULL;
+#endif
+ return (0);
+}
+
+void *
+__memget(size_t size) {
+ return (__memget_record(size, NULL, 0));
+}
+
+void *
+__memget_record(size_t size, const char *file, int line) {
+ size_t new_size = quantize(size);
+#if defined(DEBUGGING_MEMCLUSTER)
+ memcluster_element *e;
+ char *p;
+ fence_t fp = BACK_FENCEPOST;
+#endif
+ void *ret;
+
+ MEMLOCK;
+
+#if !defined(MEMCLUSTER_RECORD)
+ UNUSED(file);
+ UNUSED(line);
+#endif
+ if (freelists == NULL) {
+ if (meminit(0, 0) == -1) {
+ MEMUNLOCK;
+ return (NULL);
+ }
+ }
+ if (size == 0U) {
+ MEMUNLOCK;
+ errno = EINVAL;
+ return (NULL);
+ }
+ if (size >= max_size || new_size >= max_size) {
+ /* memget() was called on something beyond our upper limit. */
+ stats[max_size].gets++;
+ stats[max_size].totalgets++;
+#if defined(DEBUGGING_MEMCLUSTER)
+ e = malloc(new_size);
+ if (e == NULL) {
+ MEMUNLOCK;
+ errno = ENOMEM;
+ return (NULL);
+ }
+ e->next = NULL;
+ e->size = size;
+#ifdef MEMCLUSTER_RECORD
+ e->file = file;
+ e->line = line;
+ e->next = activelists[max_size];
+ activelists[max_size] = e;
+#endif
+ MEMUNLOCK;
+ e->fencepost = FRONT_FENCEPOST;
+ p = (char *)e + sizeof *e + size;
+ memcpy(p, &fp, sizeof fp);
+ return ((char *)e + sizeof *e);
+#else
+ MEMUNLOCK;
+ return (malloc(size));
+#endif
+ }
+
+ /*
+ * If there are no blocks in the free list for this size, get a chunk
+ * of memory and then break it up into "new_size"-sized blocks, adding
+ * them to the free list.
+ */
+ if (freelists[new_size] == NULL) {
+ int i, frags;
+ size_t total_size;
+ void *new;
+ char *curr, *next;
+
+#ifdef MEMCLUSTER_BIG_MALLOC
+ if (basic_blocks == NULL) {
+ new = malloc(NUM_BASIC_BLOCKS * mem_target);
+ if (new == NULL) {
+ MEMUNLOCK;
+ errno = ENOMEM;
+ return (NULL);
+ }
+ curr = new;
+ next = curr + mem_target;
+ for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
+ ((memcluster_element *)curr)->next = next;
+ curr = next;
+ next += mem_target;
+ }
+ /*
+ * curr is now pointing at the last block in the
+ * array.
+ */
+ ((memcluster_element *)curr)->next = NULL;
+ basic_blocks = new;
+ }
+ total_size = mem_target;
+ new = basic_blocks;
+ basic_blocks = basic_blocks->next;
+#else
+ if (new_size > mem_target_half)
+ total_size = mem_target_fudge;
+ else
+ total_size = mem_target;
+ new = malloc(total_size);
+ if (new == NULL) {
+ MEMUNLOCK;
+ errno = ENOMEM;
+ return (NULL);
+ }
+#endif
+ frags = total_size / new_size;
+ stats[new_size].blocks++;
+ stats[new_size].freefrags += frags;
+ /* Set up a linked-list of blocks of size "new_size". */
+ curr = new;
+ next = curr + new_size;
+ for (i = 0; i < (frags - 1); i++) {
+#if defined (DEBUGGING_MEMCLUSTER)
+ memset(curr, 0xa5, new_size);
+#endif
+ ((memcluster_element *)curr)->next = next;
+ curr = next;
+ next += new_size;
+ }
+ /* curr is now pointing at the last block in the array. */
+#if defined (DEBUGGING_MEMCLUSTER)
+ memset(curr, 0xa5, new_size);
+#endif
+ ((memcluster_element *)curr)->next = freelists[new_size];
+ freelists[new_size] = new;
+ }
+
+ /* The free list uses the "rounded-up" size "new_size". */
+#if defined (DEBUGGING_MEMCLUSTER)
+ e = freelists[new_size];
+ ret = (char *)e + sizeof *e;
+ /*
+ * Check to see if this buffer has been written to while on free list.
+ */
+ check(ret, 0xa5, new_size - sizeof *e);
+ /*
+ * Mark memory we are returning.
+ */
+ memset(ret, 0xe5, size);
+#else
+ ret = freelists[new_size];
+#endif
+ freelists[new_size] = freelists[new_size]->next;
+#if defined(DEBUGGING_MEMCLUSTER)
+ e->next = NULL;
+ e->size = size;
+ e->fencepost = FRONT_FENCEPOST;
+#ifdef MEMCLUSTER_RECORD
+ e->file = file;
+ e->line = line;
+ e->next = activelists[size];
+ activelists[size] = e;
+#endif
+ p = (char *)e + sizeof *e + size;
+ memcpy(p, &fp, sizeof fp);
+#endif
+
+ /*
+ * The stats[] uses the _actual_ "size" requested by the
+ * caller, with the caveat (in the code above) that "size" >= the
+ * max. size (max_size) ends up getting recorded as a call to
+ * max_size.
+ */
+ stats[size].gets++;
+ stats[size].totalgets++;
+ stats[new_size].freefrags--;
+ MEMUNLOCK;
+#if defined(DEBUGGING_MEMCLUSTER)
+ return ((char *)e + sizeof *e);
+#else
+ return (ret);
+#endif
+}
+
+/*%
+ * This is a call from an external caller,
+ * so we want to count this as a user "put".
+ */
+void
+__memput(void *mem, size_t size) {
+ __memput_record(mem, size, NULL, 0);
+}
+
+void
+__memput_record(void *mem, size_t size, const char *file, int line) {
+ size_t new_size = quantize(size);
+#if defined (DEBUGGING_MEMCLUSTER)
+ memcluster_element *e;
+ memcluster_element *el;
+#ifdef MEMCLUSTER_RECORD
+ memcluster_element *prev;
+#endif
+ fence_t fp;
+ char *p;
+#endif
+
+ MEMLOCK;
+
+#if !defined (MEMCLUSTER_RECORD)
+ UNUSED(file);
+ UNUSED(line);
+#endif
+
+ REQUIRE(freelists != NULL);
+
+ if (size == 0U) {
+ MEMUNLOCK;
+ errno = EINVAL;
+ return;
+ }
+
+#if defined (DEBUGGING_MEMCLUSTER)
+ e = (memcluster_element *) ((char *)mem - sizeof *e);
+ INSIST(e->fencepost == FRONT_FENCEPOST);
+ INSIST(e->size == size);
+ p = (char *)e + sizeof *e + size;
+ memcpy(&fp, p, sizeof fp);
+ INSIST(fp == BACK_FENCEPOST);
+ INSIST(((u_long)mem % 4) == 0);
+#ifdef MEMCLUSTER_RECORD
+ prev = NULL;
+ if (size == max_size || new_size >= max_size)
+ el = activelists[max_size];
+ else
+ el = activelists[size];
+ while (el != NULL && el != e) {
+ prev = el;
+ el = el->next;
+ }
+ INSIST(el != NULL); /*%< double free */
+ if (prev == NULL) {
+ if (size == max_size || new_size >= max_size)
+ activelists[max_size] = el->next;
+ else
+ activelists[size] = el->next;
+ } else
+ prev->next = el->next;
+#endif
+#endif
+
+ if (size == max_size || new_size >= max_size) {
+ /* memput() called on something beyond our upper limit */
+#if defined(DEBUGGING_MEMCLUSTER)
+ free(e);
+#else
+ free(mem);
+#endif
+
+ INSIST(stats[max_size].gets != 0U);
+ stats[max_size].gets--;
+ MEMUNLOCK;
+ return;
+ }
+
+ /* The free list uses the "rounded-up" size "new_size": */
+#if defined(DEBUGGING_MEMCLUSTER)
+ memset(mem, 0xa5, new_size - sizeof *e); /*%< catch write after free */
+ e->size = 0; /*%< catch double memput() */
+#ifdef MEMCLUSTER_RECORD
+ e->file = file;
+ e->line = line;
+#endif
+#ifdef MEMCLUSTER_ATEND
+ e->next = NULL;
+ el = freelists[new_size];
+ while (el != NULL && el->next != NULL)
+ el = el->next;
+ if (el)
+ el->next = e;
+ else
+ freelists[new_size] = e;
+#else
+ e->next = freelists[new_size];
+ freelists[new_size] = (void *)e;
+#endif
+#else
+ ((memcluster_element *)mem)->next = freelists[new_size];
+ freelists[new_size] = (memcluster_element *)mem;
+#endif
+
+ /*
+ * The stats[] uses the _actual_ "size" requested by the
+ * caller, with the caveat (in the code above) that "size" >= the
+ * max. size (max_size) ends up getting recorded as a call to
+ * max_size.
+ */
+ INSIST(stats[size].gets != 0U);
+ stats[size].gets--;
+ stats[new_size].freefrags++;
+ MEMUNLOCK;
+}
+
+void *
+__memget_debug(size_t size, const char *file, int line) {
+ void *ptr;
+ ptr = __memget_record(size, file, line);
+ fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line,
+ (u_long)size, ptr);
+ return (ptr);
+}
+
+void
+__memput_debug(void *ptr, size_t size, const char *file, int line) {
+ fprintf(stderr, "%s:%d: memput(%p, %lu)\n", file, line, ptr,
+ (u_long)size);
+ __memput_record(ptr, size, file, line);
+}
+
+/*%
+ * Print the stats[] on the stream "out" with suitable formatting.
+ */
+void
+memstats(FILE *out) {
+ size_t i;
+#ifdef MEMCLUSTER_RECORD
+ memcluster_element *e;
+#endif
+
+ MEMLOCK;
+
+ if (freelists == NULL) {
+ MEMUNLOCK;
+ return;
+ }
+ for (i = 1; i <= max_size; i++) {
+ const struct stats *s = &stats[i];
+
+ if (s->totalgets == 0U && s->gets == 0U)
+ continue;
+ fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
+ (i == max_size) ? ">=" : " ",
+ (unsigned long)i, s->totalgets, s->gets);
+ if (s->blocks != 0U)
+ fprintf(out, " (%lu bl, %lu ff)",
+ s->blocks, s->freefrags);
+ fputc('\n', out);
+ }
+#ifdef MEMCLUSTER_RECORD
+ fprintf(out, "Active Memory:\n");
+ for (i = 1; i <= max_size; i++) {
+ if ((e = activelists[i]) != NULL)
+ while (e != NULL) {
+ fprintf(out, "%s:%d %p:%lu\n",
+ e->file != NULL ? e->file :
+ "<UNKNOWN>", e->line,
+ (char *)e + sizeof *e,
+ (u_long)e->size);
+ e = e->next;
+ }
+ }
+#endif
+ MEMUNLOCK;
+}
+
+int
+memactive(void) {
+ size_t i;
+
+ if (stats == NULL)
+ return (0);
+ for (i = 1; i <= max_size; i++)
+ if (stats[i].gets != 0U)
+ return (1);
+ return (0);
+}
+
+/* Private. */
+
+/*%
+ * Round up size to a multiple of sizeof(void *). This guarantees that a
+ * block is at least sizeof void *, and that we won't violate alignment
+ * restrictions, both of which are needed to make lists of blocks.
+ */
+static size_t
+quantize(size_t size) {
+ int remainder;
+ /*
+ * If there is no remainder for the integer division of
+ *
+ * (rightsize/P_SIZE)
+ *
+ * then we already have a good size; if not, then we need
+ * to round up the result in order to get a size big
+ * enough to satisfy the request _and_ aligned on P_SIZE boundaries.
+ */
+ remainder = size % P_SIZE;
+ if (remainder != 0)
+ size += P_SIZE - remainder;
+#if defined(DEBUGGING_MEMCLUSTER)
+ return (size + SMALL_SIZE_LIMIT + sizeof (int));
+#else
+ return (size);
+#endif
+}
+
+#if defined(DEBUGGING_MEMCLUSTER)
+static void
+check(unsigned char *a, int value, size_t len) {
+ size_t i;
+ for (i = 0; i < len; i++)
+ INSIST(a[i] == value);
+}
+#endif
+
+/*! \file */
diff --git a/lib/bind/isc/memcluster.mdoc b/lib/bind/isc/memcluster.mdoc
new file mode 100644
index 0000000..20b39d0
--- /dev/null
+++ b/lib/bind/isc/memcluster.mdoc
@@ -0,0 +1,376 @@
+.\" $Id: memcluster.mdoc,v 1.3 2004/03/09 06:30:08 marka Exp $
+.\"
+.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 1995-1999 by Internet Software Consortium
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" The following six UNCOMMENTED lines are required.
+.Dd Month day, year
+.\"Os OPERATING_SYSTEM [version/release]
+.Os BSD 4
+.\"Dt DOCUMENT_TITLE [section number] [volume]
+.Dt MEMCLUSTER 3
+.Sh NAME
+.Nm meminit ,
+.Nm memget ,
+.Nm memput ,
+.Nm memstats
+.Nd memory allocation/deallocation system
+.Sh SYNOPSIS
+.Fd #include \&<isc/memcluster.h\&>
+.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/lib/bind/isc/movefile.c b/lib/bind/isc/movefile.c
new file mode 100644
index 0000000..191c46e
--- /dev/null
+++ b/lib/bind/isc/movefile.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2000 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#include <port_before.h>
+#include <stdio.h>
+#include <isc/misc.h>
+#include <port_after.h>
+#ifndef HAVE_MOVEFILE
+/*
+ * rename() is lame (can't overwrite an existing file) on some systems.
+ * use movefile() instead, and let lame OS ports do what they need to.
+ */
+
+int
+isc_movefile(const char *oldname, const char *newname) {
+ return (rename(oldname, newname));
+}
+#else
+ static int os_port_has_isc_movefile = 1;
+#endif
+
+/*! \file */
diff --git a/lib/bind/isc/tree.c b/lib/bind/isc/tree.c
new file mode 100644
index 0000000..5553636
--- /dev/null
+++ b/lib/bind/isc/tree.c
@@ -0,0 +1,534 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: tree.c,v 1.3.18.1 2005/04/27 05:01:08 sra Exp $";
+#endif
+
+/*%
+ * tree - balanced binary tree library
+ *
+ * vix 05apr94 [removed vixie.h dependencies; cleaned up formatting, names]
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 23jun86 [added delete uar to add for replaced nodes]
+ * vix 20jun86 [added tree_delete per wirth a+ds (mod2 v.) p. 224]
+ * vix 06feb86 [added tree_mung()]
+ * vix 02feb86 [added tree balancing from wirth "a+ds=p" p. 220-221]
+ * vix 14dec85 [written]
+ */
+
+/*%
+ * This program text was created by Paul Vixie using examples from the book:
+ * "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN
+ * 0-13-022005-1. Any errors in the conversion from Modula-2 to C are Paul
+ * Vixie's.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*#define DEBUG "tree"*/
+
+#include "port_before.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#include <isc/memcluster.h>
+#include <isc/tree.h>
+
+#ifdef DEBUG
+static int debugDepth = 0;
+static char *debugFuncs[256];
+# define ENTER(proc) { \
+ debugFuncs[debugDepth] = proc; \
+ fprintf(stderr, "ENTER(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ debugDepth++; \
+ }
+# define RET(value) { \
+ debugDepth--; \
+ fprintf(stderr, "RET(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ return (value); \
+ }
+# define RETV { \
+ debugDepth--; \
+ fprintf(stderr, "RETV(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ return; \
+ }
+# define MSG(msg) fprintf(stderr, "MSG(%s)\n", msg);
+#else
+# define ENTER(proc) ;
+# define RET(value) return (value);
+# define RETV return;
+# define MSG(msg) ;
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+static tree * sprout(tree **, tree_t, int *, int (*)(), void (*)());
+static int delete(tree **, int (*)(), tree_t, void (*)(), int *, int *);
+static void del(tree **, int *, tree **, void (*)(), int *);
+static void bal_L(tree **, int *);
+static void bal_R(tree **, int *);
+
+void
+tree_init(tree **ppr_tree) {
+ ENTER("tree_init")
+ *ppr_tree = NULL;
+ RETV
+}
+
+tree_t
+tree_srch(tree **ppr_tree, int (*pfi_compare)(tree_t, tree_t), tree_t p_user) {
+ ENTER("tree_srch")
+
+ if (*ppr_tree) {
+ int i_comp = (*pfi_compare)(p_user, (**ppr_tree).data);
+
+ if (i_comp > 0)
+ RET(tree_srch(&(**ppr_tree).right,
+ pfi_compare,
+ p_user))
+
+ if (i_comp < 0)
+ RET(tree_srch(&(**ppr_tree).left,
+ pfi_compare,
+ p_user))
+
+ /* not higher, not lower... this must be the one.
+ */
+ RET((**ppr_tree).data)
+ }
+
+ /* grounded. NOT found.
+ */
+ RET(NULL)
+}
+
+tree_t
+tree_add(tree **ppr_tree, int (*pfi_compare)(tree_t, tree_t),
+ tree_t p_user, void (*pfv_uar)())
+{
+ int i_balance = FALSE;
+
+ ENTER("tree_add")
+ if (!sprout(ppr_tree, p_user, &i_balance, pfi_compare, pfv_uar))
+ RET(NULL)
+ RET(p_user)
+}
+
+int
+tree_delete(tree **ppr_p, int (*pfi_compare)(tree_t, tree_t),
+ tree_t p_user, void (*pfv_uar)())
+{
+ int i_balance = FALSE, i_uar_called = FALSE;
+
+ ENTER("tree_delete");
+ RET(delete(ppr_p, pfi_compare, p_user, pfv_uar,
+ &i_balance, &i_uar_called))
+}
+
+int
+tree_trav(tree **ppr_tree, int (*pfi_uar)(tree_t)) {
+ ENTER("tree_trav")
+
+ if (!*ppr_tree)
+ RET(TRUE)
+
+ if (!tree_trav(&(**ppr_tree).left, pfi_uar))
+ RET(FALSE)
+ if (!(*pfi_uar)((**ppr_tree).data))
+ RET(FALSE)
+ if (!tree_trav(&(**ppr_tree).right, pfi_uar))
+ RET(FALSE)
+ RET(TRUE)
+}
+
+void
+tree_mung(tree **ppr_tree, void (*pfv_uar)(tree_t)) {
+ ENTER("tree_mung")
+ if (*ppr_tree) {
+ tree_mung(&(**ppr_tree).left, pfv_uar);
+ tree_mung(&(**ppr_tree).right, pfv_uar);
+ if (pfv_uar)
+ (*pfv_uar)((**ppr_tree).data);
+ memput(*ppr_tree, sizeof(tree));
+ *ppr_tree = NULL;
+ }
+ RETV
+}
+
+static tree *
+sprout(tree **ppr, tree_t p_data, int *pi_balance,
+ int (*pfi_compare)(tree_t, tree_t), void (*pfv_delete)(tree_t))
+{
+ tree *p1, *p2, *sub;
+ int cmp;
+
+ ENTER("sprout")
+
+ /* are we grounded? if so, add the node "here" and set the rebalance
+ * flag, then exit.
+ */
+ if (!*ppr) {
+ MSG("grounded. adding new node, setting h=true")
+ *ppr = (tree *) memget(sizeof(tree));
+ if (*ppr) {
+ (*ppr)->left = NULL;
+ (*ppr)->right = NULL;
+ (*ppr)->bal = 0;
+ (*ppr)->data = p_data;
+ *pi_balance = TRUE;
+ }
+ RET(*ppr);
+ }
+
+ /* compare the data using routine passed by caller.
+ */
+ cmp = (*pfi_compare)(p_data, (*ppr)->data);
+
+ /* if LESS, prepare to move to the left.
+ */
+ if (cmp < 0) {
+ MSG("LESS. sprouting left.")
+ sub = sprout(&(*ppr)->left, p_data, pi_balance,
+ pfi_compare, pfv_delete);
+ if (sub && *pi_balance) { /*%< left branch has grown */
+ MSG("LESS: left branch has grown")
+ switch ((*ppr)->bal) {
+ case 1:
+ /* right branch WAS longer; bal is ok now */
+ MSG("LESS: case 1.. bal restored implicitly")
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ break;
+ case 0:
+ /* balance WAS okay; now left branch longer */
+ MSG("LESS: case 0.. balnce bad but still ok")
+ (*ppr)->bal = -1;
+ break;
+ case -1:
+ /* left branch was already too long. rebal */
+ MSG("LESS: case -1: rebalancing")
+ p1 = (*ppr)->left;
+ if (p1->bal == -1) { /*%< LL */
+ MSG("LESS: single LL")
+ (*ppr)->left = p1->right;
+ p1->right = *ppr;
+ (*ppr)->bal = 0;
+ *ppr = p1;
+ } else { /*%< double LR */
+ MSG("LESS: double LR")
+
+ p2 = p1->right;
+ p1->right = p2->left;
+ p2->left = p1;
+
+ (*ppr)->left = p2->right;
+ p2->right = *ppr;
+
+ if (p2->bal == -1)
+ (*ppr)->bal = 1;
+ else
+ (*ppr)->bal = 0;
+
+ if (p2->bal == 1)
+ p1->bal = -1;
+ else
+ p1->bal = 0;
+ *ppr = p2;
+ } /*else*/
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ } /*switch*/
+ } /*if*/
+ RET(sub)
+ } /*if*/
+
+ /* if MORE, prepare to move to the right.
+ */
+ if (cmp > 0) {
+ MSG("MORE: sprouting to the right")
+ sub = sprout(&(*ppr)->right, p_data, pi_balance,
+ pfi_compare, pfv_delete);
+ if (sub && *pi_balance) {
+ MSG("MORE: right branch has grown")
+
+ switch ((*ppr)->bal) {
+ case -1:
+ MSG("MORE: balance was off, fixed implicitly")
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ break;
+ case 0:
+ MSG("MORE: balance was okay, now off but ok")
+ (*ppr)->bal = 1;
+ break;
+ case 1:
+ MSG("MORE: balance was off, need to rebalance")
+ p1 = (*ppr)->right;
+ if (p1->bal == 1) { /*%< RR */
+ MSG("MORE: single RR")
+ (*ppr)->right = p1->left;
+ p1->left = *ppr;
+ (*ppr)->bal = 0;
+ *ppr = p1;
+ } else { /*%< double RL */
+ MSG("MORE: double RL")
+
+ p2 = p1->left;
+ p1->left = p2->right;
+ p2->right = p1;
+
+ (*ppr)->right = p2->left;
+ p2->left = *ppr;
+
+ if (p2->bal == 1)
+ (*ppr)->bal = -1;
+ else
+ (*ppr)->bal = 0;
+
+ if (p2->bal == -1)
+ p1->bal = 1;
+ else
+ p1->bal = 0;
+
+ *ppr = p2;
+ } /*else*/
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ } /*switch*/
+ } /*if*/
+ RET(sub)
+ } /*if*/
+
+ /* not less, not more: this is the same key! replace...
+ */
+ MSG("FOUND: Replacing data value")
+ *pi_balance = FALSE;
+ if (pfv_delete)
+ (*pfv_delete)((*ppr)->data);
+ (*ppr)->data = p_data;
+ RET(*ppr)
+}
+
+static int
+delete(tree **ppr_p, int (*pfi_compare)(tree_t, tree_t), tree_t p_user,
+ void (*pfv_uar)(tree_t), int *pi_balance, int *pi_uar_called)
+{
+ tree *pr_q;
+ int i_comp, i_ret;
+
+ ENTER("delete")
+
+ if (*ppr_p == NULL) {
+ MSG("key not in tree")
+ RET(FALSE)
+ }
+
+ i_comp = (*pfi_compare)((*ppr_p)->data, p_user);
+ if (i_comp > 0) {
+ MSG("too high - scan left")
+ i_ret = delete(&(*ppr_p)->left, pfi_compare, p_user, pfv_uar,
+ pi_balance, pi_uar_called);
+ if (*pi_balance)
+ bal_L(ppr_p, pi_balance);
+ } else if (i_comp < 0) {
+ MSG("too low - scan right")
+ i_ret = delete(&(*ppr_p)->right, pfi_compare, p_user, pfv_uar,
+ pi_balance, pi_uar_called);
+ if (*pi_balance)
+ bal_R(ppr_p, pi_balance);
+ } else {
+ MSG("equal")
+ pr_q = *ppr_p;
+ if (pr_q->right == NULL) {
+ MSG("right subtree null")
+ *ppr_p = pr_q->left;
+ *pi_balance = TRUE;
+ } else if (pr_q->left == NULL) {
+ MSG("right subtree non-null, left subtree null")
+ *ppr_p = pr_q->right;
+ *pi_balance = TRUE;
+ } else {
+ MSG("neither subtree null")
+ del(&pr_q->left, pi_balance, &pr_q,
+ pfv_uar, pi_uar_called);
+ if (*pi_balance)
+ bal_L(ppr_p, pi_balance);
+ }
+ if (!*pi_uar_called && pfv_uar)
+ (*pfv_uar)(pr_q->data);
+ /* Thanks to wuth@castrov.cuc.ab.ca for the following stmt. */
+ memput(pr_q, sizeof(tree));
+ i_ret = TRUE;
+ }
+ RET(i_ret)
+}
+
+static void
+del(tree **ppr_r, int *pi_balance, tree **ppr_q,
+ void (*pfv_uar)(tree_t), int *pi_uar_called)
+{
+ ENTER("del")
+
+ if ((*ppr_r)->right != NULL) {
+ del(&(*ppr_r)->right, pi_balance, ppr_q,
+ pfv_uar, pi_uar_called);
+ if (*pi_balance)
+ bal_R(ppr_r, pi_balance);
+ } else {
+ if (pfv_uar)
+ (*pfv_uar)((*ppr_q)->data);
+ *pi_uar_called = TRUE;
+ (*ppr_q)->data = (*ppr_r)->data;
+ *ppr_q = *ppr_r;
+ *ppr_r = (*ppr_r)->left;
+ *pi_balance = TRUE;
+ }
+
+ RETV
+}
+
+static void
+bal_L(tree **ppr_p, int *pi_balance) {
+ tree *p1, *p2;
+ int b1, b2;
+
+ ENTER("bal_L")
+ MSG("left branch has shrunk")
+
+ switch ((*ppr_p)->bal) {
+ case -1:
+ MSG("was imbalanced, fixed implicitly")
+ (*ppr_p)->bal = 0;
+ break;
+ case 0:
+ MSG("was okay, is now one off")
+ (*ppr_p)->bal = 1;
+ *pi_balance = FALSE;
+ break;
+ case 1:
+ MSG("was already off, this is too much")
+ p1 = (*ppr_p)->right;
+ b1 = p1->bal;
+ if (b1 >= 0) {
+ MSG("single RR")
+ (*ppr_p)->right = p1->left;
+ p1->left = *ppr_p;
+ if (b1 == 0) {
+ MSG("b1 == 0")
+ (*ppr_p)->bal = 1;
+ p1->bal = -1;
+ *pi_balance = FALSE;
+ } else {
+ MSG("b1 != 0")
+ (*ppr_p)->bal = 0;
+ p1->bal = 0;
+ }
+ *ppr_p = p1;
+ } else {
+ MSG("double RL")
+ p2 = p1->left;
+ b2 = p2->bal;
+ p1->left = p2->right;
+ p2->right = p1;
+ (*ppr_p)->right = p2->left;
+ p2->left = *ppr_p;
+ if (b2 == 1)
+ (*ppr_p)->bal = -1;
+ else
+ (*ppr_p)->bal = 0;
+ if (b2 == -1)
+ p1->bal = 1;
+ else
+ p1->bal = 0;
+ *ppr_p = p2;
+ p2->bal = 0;
+ }
+ }
+ RETV
+}
+
+static void
+bal_R(tree **ppr_p, int *pi_balance) {
+ tree *p1, *p2;
+ int b1, b2;
+
+ ENTER("bal_R")
+ MSG("right branch has shrunk")
+ switch ((*ppr_p)->bal) {
+ case 1:
+ MSG("was imbalanced, fixed implicitly")
+ (*ppr_p)->bal = 0;
+ break;
+ case 0:
+ MSG("was okay, is now one off")
+ (*ppr_p)->bal = -1;
+ *pi_balance = FALSE;
+ break;
+ case -1:
+ MSG("was already off, this is too much")
+ p1 = (*ppr_p)->left;
+ b1 = p1->bal;
+ if (b1 <= 0) {
+ MSG("single LL")
+ (*ppr_p)->left = p1->right;
+ p1->right = *ppr_p;
+ if (b1 == 0) {
+ MSG("b1 == 0")
+ (*ppr_p)->bal = -1;
+ p1->bal = 1;
+ *pi_balance = FALSE;
+ } else {
+ MSG("b1 != 0")
+ (*ppr_p)->bal = 0;
+ p1->bal = 0;
+ }
+ *ppr_p = p1;
+ } else {
+ MSG("double LR")
+ p2 = p1->right;
+ b2 = p2->bal;
+ p1->right = p2->left;
+ p2->left = p1;
+ (*ppr_p)->left = p2->right;
+ p2->right = *ppr_p;
+ if (b2 == -1)
+ (*ppr_p)->bal = 1;
+ else
+ (*ppr_p)->bal = 0;
+ if (b2 == 1)
+ p1->bal = -1;
+ else
+ p1->bal = 0;
+ *ppr_p = p2;
+ p2->bal = 0;
+ }
+ }
+ RETV
+}
+
+/*! \file */
diff --git a/lib/bind/isc/tree.mdoc b/lib/bind/isc/tree.mdoc
new file mode 100644
index 0000000..2c24e1f
--- /dev/null
+++ b/lib/bind/isc/tree.mdoc
@@ -0,0 +1,154 @@
+.\" $Id: tree.mdoc,v 1.3 2004/03/09 06:30:09 marka Exp $
+.\"
+.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 1995-1999 by Internet Software Consortium
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd April 5, 1994
+.Dt TREE 3
+.Os BSD 4
+.Sh NAME
+.Nm tree_init ,
+.Nm tree_mung ,
+.Nm tree_srch ,
+.Nm tree_add ,
+.Nm tree_delete ,
+.Nm tree_trav
+.Nd balanced binary tree routines
+.Sh SYNOPSIS
+.Ft void
+.Fn tree_init "void **tree"
+.Ft void *
+.Fn tree_srch "void **tree" "int (*compare)()" "void *data"
+.Ft void
+.Fn tree_add "void **tree" "int (*compare)()" \
+"void *data" "void (*del_uar)()"
+.Ft int
+.Fn tree_delete "void **tree" "int (*compare)()" \
+"void *data" "void (*del_uar)()"
+.Ft int
+.Fn tree_trav "void **tree" "int (*trav_uar)()"
+.Ft void
+.Fn tree_mung "void **tree" "void (*del_uar)()"
+.Sh DESCRIPTION
+These functions create and manipulate a balanced binary (AVL) tree. Each node
+of the tree contains the expected left & right subtree pointers, a short int
+balance indicator, and a pointer to the user data. On a 32 bit system, this
+means an overhead of 4+4+2+4 bytes per node (or, on a RISC or otherwise
+alignment constrained system with implied padding, 4+4+4+4 bytes per node).
+There is no key data type enforced by this package; a caller supplied
+compare routine is used to compare user data blocks.
+.Pp
+Balanced binary trees are very fast on searches and replacements, but have a
+moderately high cost for additions and deletions. If your application does a
+lot more searches and replacements than it does additions and deletions, the
+balanced (AVL) binary tree is a good choice for a data structure.
+.Pp
+.Fn Tree_init
+creates an empty tree and binds it to
+.Dq Fa tree
+(which for this and all other routines in this package should be declared as
+a pointer to void or int, and passed by reference), which can then be used by
+other routines in this package. Note that more than one
+.Dq Fa tree
+variable can exist at once; thus multiple trees can be manipulated
+simultaneously.
+.Pp
+.Fn Tree_srch
+searches a tree for a specific node and returns either
+.Fa NULL
+if no node was found, or the value of the user data pointer if the node
+was found.
+.Fn compare
+is the address of a function to compare two user data blocks. This routine
+should work much the way
+.Xr strcmp 3
+does; in fact,
+.Xr strcmp
+could be used if the user data was a \s-2NUL\s+2 terminated string.
+.Dq Fa Data
+is the address of a user data block to be used by
+.Fn compare
+as the search criteria. The tree is searched for a node where
+.Fn compare
+returns 0.
+.Pp
+.Fn Tree_add
+inserts or replaces a node in the specified tree. The tree specified by
+.Dq Fa tree
+is searched as in
+.Fn tree_srch ,
+and if a node is found to match
+.Dq Fa data ,
+then the
+.Fn del_uar
+function, if non\-\s-2NULL\s+2, is called with the address of the user data
+block for the node (this routine should deallocate any dynamic memory which
+is referenced exclusively by the node); the user data pointer for the node
+is then replaced by the value of
+.Dq Fa data .
+If no node is found to match, a new node is added (which may or may not
+cause a transparent rebalance operation), with a user data pointer equal to
+.Dq Fa data .
+A rebalance may or may not occur, depending on where the node is added
+and what the rest of the tree looks like.
+.Fn Tree_add
+will return the
+.Dq Fa data
+pointer unless catastrophe occurs in which case it will return \s-2NULL\s+2.
+.Pp
+.Fn Tree_delete
+deletes a node from
+.Dq Fa tree .
+A rebalance may or may not occur, depending on where the node is removed from
+and what the rest of the tree looks like.
+.Fn Tree_delete
+returns TRUE if a node was deleted, FALSE otherwise.
+.Pp
+.Fn Tree_trav
+traverses all of
+.Dq Fa tree ,
+calling
+.Fn trav_uar
+with the address of each user data block. If
+.Fn trav_uar
+returns FALSE at any time,
+.Fn tree_trav
+will immediately return FALSE to its caller. Otherwise all nodes will be
+reached and
+.Fn tree_trav
+will return TRUE.
+.Pp
+.Fn Tree_mung
+deletes every node in
+.Dq Fa tree ,
+calling
+.Fn del_uar
+(if it is not \s-2NULL\s+2) with the user data address from each node (see
+.Fn tree_add
+and
+.Fn tree_delete
+above). The tree is left in the same state that
+.Fn tree_init
+leaves it in \- i.e., empty.
+.Sh BUGS
+Should have a way for the caller to specify application-specific
+.Xr malloc
+and
+.Xr free
+functions to be used internally when allocating meta data.
+.Sh AUTHOR
+Paul Vixie, converted and augumented from Modula\-2 examples in
+.Dq Algorithms & Data Structures ,
+Niklaus Wirth, Prentice\-Hall, ISBN 0\-13\-022005\-1.
diff --git a/lib/bind/make/includes.in b/lib/bind/make/includes.in
new file mode 100644
index 0000000..d7e21cb
--- /dev/null
+++ b/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.2 2004/03/16 05:22:19 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/lib/bind/make/mkdep.in b/lib/bind/make/mkdep.in
new file mode 100644
index 0000000..60aea6f
--- /dev/null
+++ b/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/lib/bind/make/rules.in b/lib/bind/make/rules.in
new file mode 100644
index 0000000..5033b15
--- /dev/null
+++ b/lib/bind/make/rules.in
@@ -0,0 +1,177 @@
+# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2001, 2002 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: rules.in,v 1.9.18.4 2007/08/28 07:20:04 tbox Exp $
+
+###
+### Common Makefile rules for BIND 9.
+###
+
+###
+### Paths
+###
+### Note: paths that vary by Makefile MUST NOT be listed
+### here, or they won't get expanded correctly.
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+sbindir = @sbindir@
+includedir = @includedir@
+libdir = @libdir@
+sysconfdir = @sysconfdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+
+DESTDIR =
+MAKEDEFS= 'DESTDIR=${DESTDIR}'
+
+@SET_MAKE@
+
+top_builddir = @BIND9_TOP_BUILDDIR@
+abs_top_srcdir = @abs_top_srcdir@
+
+###
+### All
+###
+### Makefile may define:
+### TARGETS
+
+all: subdirs ${TARGETS}
+
+###
+### Subdirectories
+###
+### Makefile may define:
+### SUBDIRS
+
+ALL_SUBDIRS = ${SUBDIRS} nulldir
+
+#
+# We use a single-colon rule so that additional dependencies of
+# subdirectories can be specified after the inclusion of this file.
+# The "depend" target is treated the same way.
+#
+subdirs:
+ @for i in ${ALL_SUBDIRS}; do \
+ if [ "$$i" != "nulldir" -a -d $$i ]; then \
+ echo "making all in `pwd`/$$i"; \
+ (cd $$i; ${MAKE} ${MAKEDEFS} all) || exit 1; \
+ fi; \
+ done
+
+install clean distclean docclean manclean::
+ @for i in ${ALL_SUBDIRS}; do \
+ if [ "$$i" != "nulldir" -a -d $$i ]; then \
+ echo "making $@ in `pwd`/$$i"; \
+ (cd $$i; ${MAKE} ${MAKEDEFS} $@) || exit 1; \
+ fi \
+ done
+
+###
+### C Programs
+###
+### Makefile must define
+### CC
+### Makefile may define
+### CFLAGS
+### CINCLUDES
+### CDEFINES
+### CWARNINGS
+### User may define externally
+### EXT_CFLAGS
+
+CC = @CC@
+CFLAGS = @CFLAGS@
+STD_CINCLUDES = @STD_CINCLUDES@
+STD_CDEFINES = @STD_CDEFINES@
+STD_CWARNINGS = @STD_CWARNINGS@
+
+.SUFFIXES:
+.SUFFIXES: .c .@O@
+
+ALWAYS_INCLUDES = -I${top_builddir} -I${abs_top_srcdir}/@PORT_INCLUDE@
+ALWAYS_DEFINES = @ALWAYS_DEFINES@
+ALWAYS_WARNINGS =
+
+ALL_CPPFLAGS = \
+ ${ALWAYS_INCLUDES} ${CINCLUDES} ${STD_CINCLUDES} \
+ ${ALWAYS_DEFINES} ${CDEFINES} ${STD_CDEFINES}
+
+ALL_CFLAGS = ${EXT_CFLAGS} ${CFLAGS} \
+ ${ALL_CPPFLAGS} \
+ ${ALWAYS_WARNINGS} ${STD_CWARNINGS} ${CWARNINGS}
+
+.c.@O@:
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c $<
+
+SHELL = @SHELL@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_MODE_COMPILE = ${LIBTOOL} @LIBTOOL_MODE_COMPILE@
+LIBTOOL_MODE_INSTALL = ${LIBTOOL} @LIBTOOL_MODE_INSTALL@
+LIBTOOL_MODE_LINK = ${LIBTOOL} @LIBTOOL_MODE_LINK@
+PURIFY = @PURIFY@
+
+MKDEP = ${SHELL} ${top_builddir}/make/mkdep
+
+cleandir: distclean
+
+clean distclean::
+ rm -f *.@O@ *.lo *.la core *.core .depend
+ rm -rf .libs
+
+distclean::
+ rm -f Makefile
+
+depend:
+ @for i in ${ALL_SUBDIRS}; do \
+ if [ "$$i" != "nulldir" -a -d $$i ]; then \
+ echo "making depend in `pwd`/$$i"; \
+ (cd $$i; ${MAKE} ${MAKEDEFS} $@) || exit 1; \
+ fi \
+ done
+ @if [ X"${SRCS}" != X -a X"${PSRCS}" != X ] ; then \
+ echo ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+ ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+ echo ${MKDEP} -ap ${ALL_CPPFLAGS} ${PSRCS}; \
+ ${MKDEP} -ap ${ALL_CPPFLAGS} ${PSRCS}; \
+ ${DEPENDEXTRA} \
+ elif [ X"${SRCS}" != X ] ; then \
+ echo ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+ ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+ ${DEPENDEXTRA} \
+ elif [ X"${PSRCS}" != X ] ; then \
+ echo ${MKDEP} ${ALL_CPPFLAGS} ${PSRCS}; \
+ ${MKDEP} -p ${ALL_CPPFLAGS} ${PSRCS}; \
+ ${DEPENDEXTRA} \
+ fi
+
+FORCE:
+
+###
+### Libraries
+###
+
+AR = @AR@
+ARFLAGS = @ARFLAGS@
+RANLIB = @RANLIB@
+
+###
+### Installation
+###
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
diff --git a/lib/bind/mkinstalldirs b/lib/bind/mkinstalldirs
new file mode 100755
index 0000000..74a611a
--- /dev/null
+++ b/lib/bind/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# 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/lib/bind/nameser/Makefile.in b/lib/bind/nameser/Makefile.in
new file mode 100644
index 0000000..d033eee
--- /dev/null
+++ b/lib/bind/nameser/Makefile.in
@@ -0,0 +1,31 @@
+# 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: Makefile.in,v 1.5 2004/03/16 05:22:19 marka Exp $
+
+srcdir= @srcdir@
+VPATH = @srcdir@
+
+OBJS= ns_date.@O@ ns_name.@O@ ns_netint.@O@ ns_parse.@O@ ns_print.@O@ \
+ ns_samedomain.@O@ ns_sign.@O@ ns_ttl.@O@ ns_verify.@O@
+
+SRCS= ns_date.c ns_name.c ns_netint.c ns_parse.c ns_print.c \
+ ns_samedomain.c ns_sign.c ns_ttl.c ns_verify.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I${srcdir}/../include
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/nameser/ns_date.c b/lib/bind/nameser/ns_date.c
new file mode 100644
index 0000000..af1455c
--- /dev/null
+++ b/lib/bind/nameser/ns_date.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_date.c,v 1.5.18.1 2005/04/27 05:01:08 sra Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static int datepart(const char *, int, int, int, int *);
+
+/* Public. */
+
+/*%
+ * Convert a date in ASCII into the number of seconds since
+ * 1 January 1970 (GMT assumed). Format is yyyymmddhhmmss, all
+ * digits required, no spaces allowed.
+ */
+
+u_int32_t
+ns_datetosecs(const char *cp, int *errp) {
+ struct tm time;
+ u_int32_t result;
+ int mdays, i;
+ static const int days_per_month[12] =
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+ if (strlen(cp) != 14U) {
+ *errp = 1;
+ return (0);
+ }
+ *errp = 0;
+
+ memset(&time, 0, sizeof time);
+ time.tm_year = datepart(cp + 0, 4, 1990, 9999, errp) - 1900;
+ time.tm_mon = datepart(cp + 4, 2, 01, 12, errp) - 1;
+ time.tm_mday = datepart(cp + 6, 2, 01, 31, errp);
+ time.tm_hour = datepart(cp + 8, 2, 00, 23, errp);
+ time.tm_min = datepart(cp + 10, 2, 00, 59, errp);
+ time.tm_sec = datepart(cp + 12, 2, 00, 59, errp);
+ if (*errp) /*%< Any parse errors? */
+ return (0);
+
+ /*
+ * OK, now because timegm() is not available in all environments,
+ * we will do it by hand. Roll up sleeves, curse the gods, begin!
+ */
+
+#define SECS_PER_DAY ((u_int32_t)24*60*60)
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+ result = time.tm_sec; /*%< Seconds */
+ result += time.tm_min * 60; /*%< Minutes */
+ result += time.tm_hour * (60*60); /*%< Hours */
+ result += (time.tm_mday - 1) * SECS_PER_DAY; /*%< Days */
+ /* Months are trickier. Look without leaping, then leap */
+ mdays = 0;
+ for (i = 0; i < time.tm_mon; i++)
+ mdays += days_per_month[i];
+ result += mdays * SECS_PER_DAY; /*%< Months */
+ if (time.tm_mon > 1 && isleap(1900+time.tm_year))
+ result += SECS_PER_DAY; /*%< Add leapday for this year */
+ /* First figure years without leapdays, then add them in. */
+ /* The loop is slow, FIXME, but simple and accurate. */
+ result += (time.tm_year - 70) * (SECS_PER_DAY*365); /*%< Years */
+ for (i = 70; i < time.tm_year; i++)
+ if (isleap(1900+i))
+ result += SECS_PER_DAY; /*%< Add leapday for prev year */
+ return (result);
+}
+
+/* Private. */
+
+/*%
+ * Parse part of a date. Set error flag if any error.
+ * Don't reset the flag if there is no error.
+ */
+static int
+datepart(const char *buf, int size, int min, int max, int *errp) {
+ int result = 0;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (!isdigit((unsigned char)(buf[i])))
+ *errp = 1;
+ result = (result * 10) + buf[i] - '0';
+ }
+ if (result < min)
+ *errp = 1;
+ if (result > max)
+ *errp = 1;
+ return (result);
+}
+
+/*! \file */
diff --git a/lib/bind/nameser/ns_name.c b/lib/bind/nameser/ns_name.c
new file mode 100644
index 0000000..31dee36
--- /dev/null
+++ b/lib/bind/nameser/ns_name.c
@@ -0,0 +1,973 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_name.c,v 1.8.18.2 2005/04/27 05:01:08 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+#define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING 0x41
+
+/* Data. */
+
+static const char digits[] = "0123456789";
+
+static const char digitvalue[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
+};
+
+/* Forward. */
+
+static int special(int);
+static int printable(int);
+static int dn_find(const u_char *, const u_char *,
+ const u_char * const *,
+ const u_char * const *);
+static int encode_bitsring(const char **, const char *,
+ unsigned char **, unsigned char **,
+ unsigned const char *);
+static int labellen(const u_char *);
+static int decode_bitstring(const unsigned char **,
+ char *, const char *);
+
+/* Public. */
+
+/*%
+ * Convert an encoded domain name to printable ascii as per RFC1035.
+
+ * return:
+ *\li Number of bytes written to buffer, or -1 (with errno set)
+ *
+ * notes:
+ *\li The root is returned as "."
+ *\li All other domains are returned in non absolute form
+ */
+int
+ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
+{
+ const u_char *cp;
+ char *dn, *eom;
+ u_char c;
+ u_int n;
+ int l;
+
+ cp = src;
+ dn = dst;
+ eom = dst + dstsiz;
+
+ while ((n = *cp++) != 0) {
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Some kind of compression pointer. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dn != dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE; /*%< XXX */
+ return(-1);
+ }
+ if (dn + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+ int m;
+
+ if (n != DNS_LABELTYPE_BITSTRING) {
+ /* XXX: labellen should reject this case */
+ errno = EINVAL;
+ return(-1);
+ }
+ if ((m = decode_bitstring(&cp, dn, eom)) < 0)
+ {
+ errno = EMSGSIZE;
+ return(-1);
+ }
+ dn += m;
+ continue;
+ }
+ for ((void)NULL; l > 0; l--) {
+ c = *cp++;
+ if (special(c)) {
+ if (dn + 1 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = (char)c;
+ } else if (!printable(c)) {
+ if (dn + 3 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = digits[c / 100];
+ *dn++ = digits[(c % 100) / 10];
+ *dn++ = digits[c % 10];
+ } else {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = (char)c;
+ }
+ }
+ }
+ if (dn == dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\0';
+ return (dn - dst);
+}
+
+/*%
+ * Convert a ascii string into an encoded domain name as per RFC1035.
+ *
+ * return:
+ *
+ *\li -1 if it fails
+ *\li 1 if string was fully qualified
+ *\li 0 is string was not fully qualified
+ *
+ * notes:
+ *\li Enforces label and domain length limits.
+ */
+
+int
+ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
+{
+ u_char *label, *bp, *eom;
+ int c, n, escaped, e = 0;
+ char *cp;
+
+ escaped = 0;
+ bp = dst;
+ eom = dst + dstsiz;
+ label = bp++;
+
+ while ((c = *src++) != 0) {
+ if (escaped) {
+ if (c == '[') { /*%< start a bit string label */
+ if ((cp = strchr(src, ']')) == NULL) {
+ errno = EINVAL; /*%< ??? */
+ return(-1);
+ }
+ if ((e = encode_bitsring(&src, cp + 2,
+ &label, &bp, eom))
+ != 0) {
+ errno = e;
+ return(-1);
+ }
+ escaped = 0;
+ label = bp++;
+ if ((c = *src++) == 0)
+ goto done;
+ else if (c != '.') {
+ errno = EINVAL;
+ return(-1);
+ }
+ continue;
+ }
+ else if ((cp = strchr(digits, c)) != NULL) {
+ n = (cp - digits) * 100;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits) * 10;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits);
+ if (n > 255) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ c = n;
+ }
+ escaped = 0;
+ } else if (c == '\\') {
+ escaped = 1;
+ continue;
+ } else if (c == '.') {
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ /* Fully qualified ? */
+ if (*src == '\0') {
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = '\0';
+ }
+ if ((bp - dst) > MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (1);
+ }
+ if (c == 0 || *src == '.') {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ label = bp++;
+ continue;
+ }
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = (u_char)c;
+ }
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ done:
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = 0;
+ }
+ if ((bp - dst) > MAXCDNAME) { /*%< src too big */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (0);
+}
+
+/*%
+ * Convert a network strings labels into all lowercase.
+ *
+ * return:
+ *\li Number of bytes written to buffer, or -1 (with errno set)
+ *
+ * notes:
+ *\li Enforces label and domain length limits.
+ */
+
+int
+ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
+{
+ const u_char *cp;
+ u_char *dn, *eom;
+ u_char c;
+ u_int n;
+ int l;
+
+ cp = src;
+ dn = dst;
+ eom = dst + dstsiz;
+
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ while ((n = *cp++) != 0) {
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Some kind of compression pointer. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = n;
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dn + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ for ((void)NULL; l > 0; l--) {
+ c = *cp++;
+ if (isupper(c))
+ *dn++ = tolower(c);
+ else
+ *dn++ = c;
+ }
+ }
+ *dn++ = '\0';
+ return (dn - dst);
+}
+
+/*%
+ * Unpack a domain name from a message, source may be compressed.
+ *
+ * return:
+ *\li -1 if it fails, or consumed octets if it succeeds.
+ */
+int
+ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
+ u_char *dst, size_t dstsiz)
+{
+ const u_char *srcp, *dstlim;
+ u_char *dstp;
+ int n, len, checked, l;
+
+ len = -1;
+ checked = 0;
+ dstp = dst;
+ srcp = src;
+ dstlim = dst + dstsiz;
+ if (srcp < msg || srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ /* Fetch next label in domain name. */
+ while ((n = *srcp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0:
+ case NS_TYPE_ELT:
+ /* Limit checks. */
+ if ((l = labellen(srcp - 1)) < 0) {
+ errno = EMSGSIZE;
+ return(-1);
+ }
+ if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ checked += l + 1;
+ *dstp++ = n;
+ memcpy(dstp, srcp, l);
+ dstp += l;
+ srcp += l;
+ break;
+
+ case NS_CMPRSFLGS:
+ if (srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (len < 0)
+ len = srcp - src + 1;
+ srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
+ if (srcp < msg || srcp >= eom) { /*%< Out of range. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ checked += 2;
+ /*
+ * Check for loops in the compressed name;
+ * if we've looked at the whole message,
+ * there must be a loop.
+ */
+ if (checked >= eom - msg) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+
+ default:
+ errno = EMSGSIZE;
+ return (-1); /*%< flag error */
+ }
+ }
+ *dstp = '\0';
+ if (len < 0)
+ len = srcp - src;
+ return (len);
+}
+
+/*%
+ * Pack domain name 'domain' into 'comp_dn'.
+ *
+ * return:
+ *\li Size of the compressed name, or -1.
+ *
+ * notes:
+ *\li 'dnptrs' is an array of pointers to previous compressed names.
+ *\li dnptrs[0] is a pointer to the beginning of the message. The array
+ * ends with NULL.
+ *\li 'lastdnptr' is a pointer to the end of the array pointed to
+ * by 'dnptrs'.
+ *
+ * Side effects:
+ *\li The list of pointers in dnptrs is updated for labels inserted into
+ * the message as we compress the name. If 'dnptr' is NULL, we don't
+ * try to compress names. If 'lastdnptr' is NULL, we don't update the
+ * list.
+ */
+int
+ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
+ const u_char **dnptrs, const u_char **lastdnptr)
+{
+ u_char *dstp;
+ const u_char **cpp, **lpp, *eob, *msg;
+ const u_char *srcp;
+ int n, l, first = 1;
+
+ srcp = src;
+ dstp = dst;
+ eob = dstp + dstsiz;
+ lpp = cpp = NULL;
+ if (dnptrs != NULL) {
+ if ((msg = *dnptrs++) != NULL) {
+ for (cpp = dnptrs; *cpp != NULL; cpp++)
+ (void)NULL;
+ lpp = cpp; /*%< end of list to search */
+ }
+ } else
+ msg = NULL;
+
+ /* make sure the domain we are about to add is legal */
+ l = 0;
+ do {
+ int l0;
+
+ n = *srcp;
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if ((l0 = labellen(srcp)) < 0) {
+ errno = EINVAL;
+ return(-1);
+ }
+ l += l0 + 1;
+ if (l > MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ srcp += l0 + 1;
+ } while (n != 0);
+
+ /* from here on we need to reset compression pointer array on error */
+ srcp = src;
+ do {
+ /* Look to see if we can use pointers. */
+ n = *srcp;
+ if (n != 0 && msg != NULL) {
+ l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
+ (const u_char * const *)lpp);
+ if (l >= 0) {
+ if (dstp + 1 >= eob) {
+ goto cleanup;
+ }
+ *dstp++ = (l >> 8) | NS_CMPRSFLGS;
+ *dstp++ = l % 256;
+ return (dstp - dst);
+ }
+ /* Not found, save it. */
+ if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
+ (dstp - msg) < 0x4000 && first) {
+ *cpp++ = dstp;
+ *cpp = NULL;
+ first = 0;
+ }
+ }
+ /* copy label to buffer */
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Should not happen. */
+ goto cleanup;
+ }
+ n = labellen(srcp);
+ if (dstp + 1 + n >= eob) {
+ goto cleanup;
+ }
+ memcpy(dstp, srcp, n + 1);
+ srcp += n + 1;
+ dstp += n + 1;
+ } while (n != 0);
+
+ if (dstp > eob) {
+cleanup:
+ if (msg != NULL)
+ *lpp = NULL;
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (dstp - dst);
+}
+
+/*%
+ * Expand compressed domain name to presentation format.
+ *
+ * return:
+ *\li Number of bytes read out of `src', or -1 (with errno set).
+ *
+ * note:
+ *\li Root domain returns as "." not "".
+ */
+int
+ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
+ char *dst, size_t dstsiz)
+{
+ u_char tmp[NS_MAXCDNAME];
+ int n;
+
+ if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
+ return (-1);
+ if (ns_name_ntop(tmp, dst, dstsiz) == -1)
+ return (-1);
+ return (n);
+}
+
+/*%
+ * Compress a domain name into wire format, using compression pointers.
+ *
+ * return:
+ *\li Number of bytes consumed in `dst' or -1 (with errno set).
+ *
+ * notes:
+ *\li 'dnptrs' is an array of pointers to previous compressed names.
+ *\li dnptrs[0] is a pointer to the beginning of the message.
+ *\li The list ends with NULL. 'lastdnptr' is a pointer to the end of the
+ * array pointed to by 'dnptrs'. Side effect is to update the list of
+ * pointers for labels inserted into the message as we compress the name.
+ *\li If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
+ * is NULL, we don't update the list.
+ */
+int
+ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
+ const u_char **dnptrs, const u_char **lastdnptr)
+{
+ u_char tmp[NS_MAXCDNAME];
+
+ if (ns_name_pton(src, tmp, sizeof tmp) == -1)
+ return (-1);
+ return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
+}
+
+/*%
+ * Reset dnptrs so that there are no active references to pointers at or
+ * after src.
+ */
+void
+ns_name_rollback(const u_char *src, const u_char **dnptrs,
+ const u_char **lastdnptr)
+{
+ while (dnptrs < lastdnptr && *dnptrs != NULL) {
+ if (*dnptrs >= src) {
+ *dnptrs = NULL;
+ break;
+ }
+ dnptrs++;
+ }
+}
+
+/*%
+ * Advance *ptrptr to skip over the compressed name it points at.
+ *
+ * return:
+ *\li 0 on success, -1 (with errno set) on failure.
+ */
+int
+ns_name_skip(const u_char **ptrptr, const u_char *eom)
+{
+ const u_char *cp;
+ u_int n;
+ int l;
+
+ cp = *ptrptr;
+ while (cp < eom && (n = *cp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /*%< normal case, n == len */
+ cp += n;
+ continue;
+ case NS_TYPE_ELT: /*%< EDNS0 extended label */
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE; /*%< XXX */
+ return(-1);
+ }
+ cp += l;
+ continue;
+ case NS_CMPRSFLGS: /*%< indirection */
+ cp++;
+ break;
+ default: /*%< illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+ }
+ if (cp > eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *ptrptr = cp;
+ return (0);
+}
+
+/* Private. */
+
+/*%
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this characted special ("in need of quoting") ?
+ *
+ * return:
+ *\li boolean.
+ */
+static int
+special(int ch) {
+ switch (ch) {
+ case 0x22: /*%< '"' */
+ case 0x2E: /*%< '.' */
+ case 0x3B: /*%< ';' */
+ case 0x5C: /*%< '\\' */
+ case 0x28: /*%< '(' */
+ case 0x29: /*%< ')' */
+ /* Special modifiers in zone files. */
+ case 0x40: /*%< '@' */
+ case 0x24: /*%< '$' */
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+/*%
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this character visible and not a space when printed ?
+ *
+ * return:
+ *\li boolean.
+ */
+static int
+printable(int ch) {
+ return (ch > 0x20 && ch < 0x7f);
+}
+
+/*%
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * convert this character to lower case if it's upper case.
+ */
+static int
+mklower(int ch) {
+ if (ch >= 0x41 && ch <= 0x5A)
+ return (ch + 0x20);
+ return (ch);
+}
+
+/*%
+ * Search for the counted-label name in an array of compressed names.
+ *
+ * return:
+ *\li offset from msg if found, or -1.
+ *
+ * notes:
+ *\li dnptrs is the pointer to the first name on the list,
+ *\li not the pointer to the start of the message.
+ */
+static int
+dn_find(const u_char *domain, const u_char *msg,
+ const u_char * const *dnptrs,
+ const u_char * const *lastdnptr)
+{
+ const u_char *dn, *cp, *sp;
+ const u_char * const *cpp;
+ u_int n;
+
+ for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+ sp = *cpp;
+ /*
+ * terminate search on:
+ * root label
+ * compression pointer
+ * unusable offset
+ */
+ while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
+ (sp - msg) < 0x4000) {
+ dn = domain;
+ cp = sp;
+ while ((n = *cp++) != 0) {
+ /*
+ * check for indirection
+ */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /*%< normal case, n == len */
+ n = labellen(cp - 1); /*%< XXX */
+ if (n != *dn++)
+ goto next;
+
+ for ((void)NULL; n > 0; n--)
+ if (mklower(*dn++) !=
+ mklower(*cp++))
+ goto next;
+ /* Is next root for both ? */
+ if (*dn == '\0' && *cp == '\0')
+ return (sp - msg);
+ if (*dn)
+ continue;
+ goto next;
+ case NS_CMPRSFLGS: /*%< indirection */
+ cp = msg + (((n & 0x3f) << 8) | *cp);
+ break;
+
+ default: /*%< illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ }
+ next: ;
+ sp += *sp + 1;
+ }
+ }
+ errno = ENOENT;
+ return (-1);
+}
+
+static int
+decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
+{
+ const unsigned char *cp = *cpp;
+ char *beg = dn, tc;
+ int b, blen, plen, i;
+
+ if ((blen = (*cp & 0xff)) == 0)
+ blen = 256;
+ plen = (blen + 3) / 4;
+ plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
+ if (dn + plen >= eom)
+ return(-1);
+
+ cp++;
+ i = SPRINTF((dn, "\\[x"));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ for (b = blen; b > 7; b -= 8, cp++) {
+ i = SPRINTF((dn, "%02x", *cp & 0xff));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ }
+ if (b > 4) {
+ tc = *cp++;
+ i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ } else if (b > 0) {
+ tc = *cp++;
+ i = SPRINTF((dn, "%1x",
+ ((tc >> 4) & 0x0f) & (0x0f << (4 - b))));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ }
+ i = SPRINTF((dn, "/%d]", blen));
+ if (i < 0)
+ return (-1);
+ dn += i;
+
+ *cpp = cp;
+ return(dn - beg);
+}
+
+static int
+encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
+ unsigned char ** dst, unsigned const char *eom)
+{
+ int afterslash = 0;
+ const char *cp = *bp;
+ unsigned char *tp;
+ char c;
+ const char *beg_blen;
+ char *end_blen = NULL;
+ int value = 0, count = 0, tbcount = 0, blen = 0;
+
+ beg_blen = end_blen = NULL;
+
+ /* a bitstring must contain at least 2 characters */
+ if (end - cp < 2)
+ return(EINVAL);
+
+ /* XXX: currently, only hex strings are supported */
+ if (*cp++ != 'x')
+ return(EINVAL);
+ if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
+ return(EINVAL);
+
+ for (tp = *dst + 1; cp < end && tp < eom; cp++) {
+ switch((c = *cp)) {
+ case ']': /*%< end of the bitstring */
+ if (afterslash) {
+ if (beg_blen == NULL)
+ return(EINVAL);
+ blen = (int)strtol(beg_blen, &end_blen, 10);
+ if (*end_blen != ']')
+ return(EINVAL);
+ }
+ if (count)
+ *tp++ = ((value << 4) & 0xff);
+ cp++; /*%< skip ']' */
+ goto done;
+ case '/':
+ afterslash = 1;
+ break;
+ default:
+ if (afterslash) {
+ if (!isdigit(c&0xff))
+ return(EINVAL);
+ if (beg_blen == NULL) {
+
+ if (c == '0') {
+ /* blen never begings with 0 */
+ return(EINVAL);
+ }
+ beg_blen = cp;
+ }
+ } else {
+ if (!isxdigit(c&0xff))
+ return(EINVAL);
+ value <<= 4;
+ value += digitvalue[(int)c];
+ count += 4;
+ tbcount += 4;
+ if (tbcount > 256)
+ return(EINVAL);
+ if (count == 8) {
+ *tp++ = value;
+ count = 0;
+ }
+ }
+ break;
+ }
+ }
+ done:
+ if (cp >= end || tp >= eom)
+ return(EMSGSIZE);
+
+ /*
+ * bit length validation:
+ * If a <length> is present, the number of digits in the <bit-data>
+ * MUST be just sufficient to contain the number of bits specified
+ * by the <length>. If there are insignificant bits in a final
+ * hexadecimal or octal digit, they MUST be zero.
+ * RFC2673, Section 3.2.
+ */
+ if (blen > 0) {
+ int traillen;
+
+ if (((blen + 3) & ~3) != tbcount)
+ return(EINVAL);
+ traillen = tbcount - blen; /*%< between 0 and 3 */
+ if (((value << (8 - traillen)) & 0xff) != 0)
+ return(EINVAL);
+ }
+ else
+ blen = tbcount;
+ if (blen == 256)
+ blen = 0;
+
+ /* encode the type and the significant bit fields */
+ **labelp = DNS_LABELTYPE_BITSTRING;
+ **dst = blen;
+
+ *bp = cp;
+ *dst = tp;
+
+ return(0);
+}
+
+static int
+labellen(const u_char *lp)
+{
+ int bitlen;
+ u_char l = *lp;
+
+ if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* should be avoided by the caller */
+ return(-1);
+ }
+
+ if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+ if (l == DNS_LABELTYPE_BITSTRING) {
+ if ((bitlen = *(lp + 1)) == 0)
+ bitlen = 256;
+ return((bitlen + 7 ) / 8 + 1);
+ }
+ return(-1); /*%< unknwon ELT */
+ }
+ return(l);
+}
+
+/*! \file */
diff --git a/lib/bind/nameser/ns_netint.c b/lib/bind/nameser/ns_netint.c
new file mode 100644
index 0000000..b08c58b
--- /dev/null
+++ b/lib/bind/nameser/ns_netint.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_netint.c,v 1.2.18.1 2005/04/27 05:01:08 sra Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <arpa/nameser.h>
+
+#include "port_after.h"
+
+/* Public. */
+
+u_int
+ns_get16(const u_char *src) {
+ u_int dst;
+
+ NS_GET16(dst, src);
+ return (dst);
+}
+
+u_long
+ns_get32(const u_char *src) {
+ u_long dst;
+
+ NS_GET32(dst, src);
+ return (dst);
+}
+
+void
+ns_put16(u_int src, u_char *dst) {
+ NS_PUT16(src, dst);
+}
+
+void
+ns_put32(u_long src, u_char *dst) {
+ NS_PUT32(src, dst);
+}
+
+/*! \file */
diff --git a/lib/bind/nameser/ns_parse.c b/lib/bind/nameser/ns_parse.c
new file mode 100644
index 0000000..c4658d8
--- /dev/null
+++ b/lib/bind/nameser/ns_parse.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_parse.c,v 1.5.18.4 2007/08/27 03:34:24 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+
+#include "port_after.h"
+
+/* Forward. */
+
+static void setsection(ns_msg *msg, ns_sect sect);
+
+/* Macros. */
+
+#if !defined(SOLARIS2) || defined(__COVERITY__)
+#define RETERR(err) do { errno = (err); return (-1); } while (0)
+#else
+#define RETERR(err) \
+ do { errno = (err); if (errno == errno) return (-1); } while (0)
+#endif
+
+/* Public. */
+
+/* These need to be in the same order as the nres.h:ns_flag enum. */
+struct _ns_flagdata _ns_flagdata[16] = {
+ { 0x8000, 15 }, /*%< qr. */
+ { 0x7800, 11 }, /*%< opcode. */
+ { 0x0400, 10 }, /*%< aa. */
+ { 0x0200, 9 }, /*%< tc. */
+ { 0x0100, 8 }, /*%< rd. */
+ { 0x0080, 7 }, /*%< ra. */
+ { 0x0040, 6 }, /*%< z. */
+ { 0x0020, 5 }, /*%< ad. */
+ { 0x0010, 4 }, /*%< cd. */
+ { 0x000f, 0 }, /*%< rcode. */
+ { 0x0000, 0 }, /*%< expansion (1/6). */
+ { 0x0000, 0 }, /*%< expansion (2/6). */
+ { 0x0000, 0 }, /*%< expansion (3/6). */
+ { 0x0000, 0 }, /*%< expansion (4/6). */
+ { 0x0000, 0 }, /*%< expansion (5/6). */
+ { 0x0000, 0 }, /*%< expansion (6/6). */
+};
+
+int ns_msg_getflag(ns_msg handle, int flag) {
+ return(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift);
+}
+
+int
+ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) {
+ const u_char *optr = ptr;
+
+ for ((void)NULL; count > 0; count--) {
+ int b, rdlength;
+
+ b = dn_skipname(ptr, eom);
+ if (b < 0)
+ RETERR(EMSGSIZE);
+ ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
+ if (section != ns_s_qd) {
+ if (ptr + NS_INT32SZ + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ ptr += NS_INT32SZ/*TTL*/;
+ NS_GET16(rdlength, ptr);
+ ptr += rdlength/*RData*/;
+ }
+ }
+ if (ptr > eom)
+ RETERR(EMSGSIZE);
+ return (ptr - optr);
+}
+
+int
+ns_initparse(const u_char *msg, int msglen, ns_msg *handle) {
+ const u_char *eom = msg + msglen;
+ int i;
+
+ memset(handle, 0x5e, sizeof *handle);
+ handle->_msg = msg;
+ handle->_eom = eom;
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_id, msg);
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_flags, msg);
+ for (i = 0; i < ns_s_max; i++) {
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_counts[i], msg);
+ }
+ for (i = 0; i < ns_s_max; i++)
+ if (handle->_counts[i] == 0)
+ handle->_sections[i] = NULL;
+ else {
+ int b = ns_skiprr(msg, eom, (ns_sect)i,
+ handle->_counts[i]);
+
+ if (b < 0)
+ return (-1);
+ handle->_sections[i] = msg;
+ msg += b;
+ }
+ if (msg != eom)
+ RETERR(EMSGSIZE);
+ setsection(handle, ns_s_max);
+ return (0);
+}
+
+int
+ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) {
+ int b;
+ int tmp;
+
+ /* Make section right. */
+ tmp = section;
+ if (tmp < 0 || section >= ns_s_max)
+ RETERR(ENODEV);
+ if (section != handle->_sect)
+ setsection(handle, section);
+
+ /* Make rrnum right. */
+ if (rrnum == -1)
+ rrnum = handle->_rrnum;
+ if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
+ RETERR(ENODEV);
+ if (rrnum < handle->_rrnum)
+ setsection(handle, section);
+ if (rrnum > handle->_rrnum) {
+ b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
+ rrnum - handle->_rrnum);
+
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ handle->_rrnum = rrnum;
+ }
+
+ /* Do the parse. */
+ b = dn_expand(handle->_msg, handle->_eom,
+ handle->_msg_ptr, rr->name, NS_MAXDNAME);
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(rr->type, handle->_msg_ptr);
+ NS_GET16(rr->rr_class, handle->_msg_ptr);
+ if (section == ns_s_qd) {
+ rr->ttl = 0;
+ rr->rdlength = 0;
+ rr->rdata = NULL;
+ } else {
+ if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET32(rr->ttl, handle->_msg_ptr);
+ NS_GET16(rr->rdlength, handle->_msg_ptr);
+ if (handle->_msg_ptr + rr->rdlength > handle->_eom)
+ RETERR(EMSGSIZE);
+ rr->rdata = handle->_msg_ptr;
+ handle->_msg_ptr += rr->rdlength;
+ }
+ if (++handle->_rrnum > handle->_counts[(int)section])
+ setsection(handle, (ns_sect)((int)section + 1));
+
+ /* All done. */
+ return (0);
+}
+
+/* Private. */
+
+static void
+setsection(ns_msg *msg, ns_sect sect) {
+ msg->_sect = sect;
+ if (sect == ns_s_max) {
+ msg->_rrnum = -1;
+ msg->_msg_ptr = NULL;
+ } else {
+ msg->_rrnum = 0;
+ msg->_msg_ptr = msg->_sections[(int)sect];
+ }
+}
+
+/*! \file */
diff --git a/lib/bind/nameser/ns_print.c b/lib/bind/nameser/ns_print.c
new file mode 100644
index 0000000..0679ba4
--- /dev/null
+++ b/lib/bind/nameser/ns_print.c
@@ -0,0 +1,897 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_print.c,v 1.6.18.4 2005/04/27 05:01:09 sra Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <isc/assertions.h>
+#include <isc/dst.h>
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static size_t prune_origin(const char *name, const char *origin);
+static int charstr(const u_char *rdata, const u_char *edata,
+ char **buf, size_t *buflen);
+static int addname(const u_char *msg, size_t msglen,
+ const u_char **p, const char *origin,
+ char **buf, size_t *buflen);
+static void addlen(size_t len, char **buf, size_t *buflen);
+static int addstr(const char *src, size_t len,
+ char **buf, size_t *buflen);
+static int addtab(size_t len, size_t target, int spaced,
+ char **buf, size_t *buflen);
+
+/* Macros. */
+
+#define T(x) \
+ do { \
+ if ((x) < 0) \
+ return (-1); \
+ } while (0)
+
+/* Public. */
+
+/*%
+ * Convert an RR to presentation format.
+ *
+ * return:
+ *\li Number of characters written to buf, or -1 (check errno).
+ */
+int
+ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
+ const char *name_ctx, const char *origin,
+ char *buf, size_t buflen)
+{
+ int n;
+
+ n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
+ ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
+ ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
+ name_ctx, origin, buf, buflen);
+ return (n);
+}
+
+/*%
+ * Convert the fields of an RR into presentation format.
+ *
+ * return:
+ *\li Number of characters written to buf, or -1 (check errno).
+ */
+int
+ns_sprintrrf(const u_char *msg, size_t msglen,
+ const char *name, ns_class class, ns_type type,
+ u_long ttl, const u_char *rdata, size_t rdlen,
+ const char *name_ctx, const char *origin,
+ char *buf, size_t buflen)
+{
+ const char *obuf = buf;
+ const u_char *edata = rdata + rdlen;
+ int spaced = 0;
+
+ const char *comment;
+ char tmp[100];
+ int len, x;
+
+ /*
+ * Owner.
+ */
+ if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
+ T(addstr("\t\t\t", 3, &buf, &buflen));
+ } else {
+ len = prune_origin(name, origin);
+ if (*name == '\0') {
+ goto root;
+ } else if (len == 0) {
+ T(addstr("@\t\t\t", 4, &buf, &buflen));
+ } else {
+ T(addstr(name, len, &buf, &buflen));
+ /* Origin not used or not root, and no trailing dot? */
+ if (((origin == NULL || origin[0] == '\0') ||
+ (origin[0] != '.' && origin[1] != '\0' &&
+ name[len] == '\0')) && name[len - 1] != '.') {
+ root:
+ T(addstr(".", 1, &buf, &buflen));
+ len++;
+ }
+ T(spaced = addtab(len, 24, spaced, &buf, &buflen));
+ }
+ }
+
+ /*
+ * TTL, Class, Type.
+ */
+ T(x = ns_format_ttl(ttl, buf, buflen));
+ addlen(x, &buf, &buflen);
+ len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
+ T(addstr(tmp, len, &buf, &buflen));
+ T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
+
+ /*
+ * RData.
+ */
+ switch (type) {
+ case ns_t_a:
+ if (rdlen != (size_t)NS_INADDRSZ)
+ goto formerr;
+ (void) inet_ntop(AF_INET, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ns:
+ case ns_t_ptr:
+ case ns_t_dname:
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+
+ case ns_t_hinfo:
+ case ns_t_isdn:
+ /* First word. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+
+ /* Second word, optional in ISDN records. */
+ if (type == ns_t_isdn && rdata == edata)
+ break;
+
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ break;
+
+ case ns_t_soa: {
+ u_long t;
+
+ /* Server name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Administrator name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" (\n", 3, &buf, &buflen));
+ spaced = 0;
+
+ if ((edata - rdata) != 5*NS_INT32SZ)
+ goto formerr;
+
+ /* Serial number. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ len = SPRINTF((tmp, "%lu", t));
+ T(addstr(tmp, len, &buf, &buflen));
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; serial\n", 9, &buf, &buflen));
+ spaced = 0;
+
+ /* Refresh interval. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; refresh\n", 10, &buf, &buflen));
+ spaced = 0;
+
+ /* Retry interval. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; retry\n", 8, &buf, &buflen));
+ spaced = 0;
+
+ /* Expiry. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; expiry\n", 9, &buf, &buflen));
+ spaced = 0;
+
+ /* Minimum TTL. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(addstr(" )", 2, &buf, &buflen));
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; minimum\n", 10, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_mx:
+ case ns_t_afsdb:
+ case ns_t_rt: {
+ u_int t;
+
+ if (rdlen < (size_t)NS_INT16SZ)
+ goto formerr;
+
+ /* Priority. */
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Target. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_px: {
+ u_int t;
+
+ if (rdlen < (size_t)NS_INT16SZ)
+ goto formerr;
+
+ /* Priority. */
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Name1. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Name2. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_x25:
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ break;
+
+ case ns_t_txt:
+ while (rdata < edata) {
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ if (rdata < edata)
+ T(addstr(" ", 1, &buf, &buflen));
+ }
+ break;
+
+ case ns_t_nsap: {
+ char t[2+255*3];
+
+ (void) inet_nsap_ntoa(rdlen, rdata, t);
+ T(addstr(t, strlen(t), &buf, &buflen));
+ break;
+ }
+
+ case ns_t_aaaa:
+ if (rdlen != (size_t)NS_IN6ADDRSZ)
+ goto formerr;
+ (void) inet_ntop(AF_INET6, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+
+ case ns_t_loc: {
+ char t[255];
+
+ /* XXX protocol format checking? */
+ (void) loc_ntoa(rdata, t);
+ T(addstr(t, strlen(t), &buf, &buflen));
+ break;
+ }
+
+ case ns_t_naptr: {
+ u_int order, preference;
+ char t[50];
+
+ if (rdlen < 2U*NS_INT16SZ)
+ goto formerr;
+
+ /* Order, Precedence. */
+ order = ns_get16(rdata); rdata += NS_INT16SZ;
+ preference = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((t, "%u %u ", order, preference));
+ T(addstr(t, len, &buf, &buflen));
+
+ /* Flags. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Service. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Regexp. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len < 0)
+ return (-1);
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Server. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_srv: {
+ u_int priority, weight, port;
+ char t[50];
+
+ if (rdlen < 3U*NS_INT16SZ)
+ goto formerr;
+
+ /* Priority, Weight, Port. */
+ priority = ns_get16(rdata); rdata += NS_INT16SZ;
+ weight = ns_get16(rdata); rdata += NS_INT16SZ;
+ port = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((t, "%u %u %u ", priority, weight, port));
+ T(addstr(t, len, &buf, &buflen));
+
+ /* Server. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_minfo:
+ case ns_t_rp:
+ /* Name1. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Name2. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+
+ case ns_t_wks: {
+ int n, lcnt;
+
+ if (rdlen < 1U + NS_INT32SZ)
+ goto formerr;
+
+ /* Address. */
+ (void) inet_ntop(AF_INET, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += NS_INADDRSZ;
+
+ /* Protocol. */
+ len = SPRINTF((tmp, " %u ( ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata += NS_INT8SZ;
+
+ /* Bit map. */
+ n = 0;
+ lcnt = 0;
+ while (rdata < edata) {
+ u_int c = *rdata++;
+ do {
+ if (c & 0200) {
+ if (lcnt == 0) {
+ T(addstr("\n\t\t\t\t", 5,
+ &buf, &buflen));
+ lcnt = 10;
+ spaced = 0;
+ }
+ len = SPRINTF((tmp, "%d ", n));
+ T(addstr(tmp, len, &buf, &buflen));
+ lcnt--;
+ }
+ c <<= 1;
+ } while (++n & 07);
+ }
+ T(addstr(")", 1, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_key: {
+ char base64_key[NS_MD5RSA_MAX_BASE64];
+ u_int keyflags, protocol, algorithm, key_id;
+ const char *leader;
+ int n;
+
+ if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
+ goto formerr;
+
+ /* Key flags, Protocol, Algorithm. */
+ key_id = dst_s_dns_key_id(rdata, edata-rdata);
+ keyflags = ns_get16(rdata); rdata += NS_INT16SZ;
+ protocol = *rdata++;
+ algorithm = *rdata++;
+ len = SPRINTF((tmp, "0x%04x %u %u",
+ keyflags, protocol, algorithm));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Public key data. */
+ len = b64_ntop(rdata, edata - rdata,
+ base64_key, sizeof base64_key);
+ if (len < 0)
+ goto formerr;
+ if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ } else
+ leader = " ";
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+ T(addstr(base64_key + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ n = SPRINTF((tmp, " ; key_tag= %u", key_id));
+ T(addstr(tmp, n, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_sig: {
+ char base64_key[NS_MD5RSA_MAX_BASE64];
+ u_int type, algorithm, labels, footprint;
+ const char *leader;
+ u_long t;
+ int n;
+
+ if (rdlen < 22U)
+ goto formerr;
+
+ /* Type covered, Algorithm, Label count, Original TTL. */
+ type = ns_get16(rdata); rdata += NS_INT16SZ;
+ algorithm = *rdata++;
+ labels = *rdata++;
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s %d %d %lu ",
+ p_type(type), algorithm, labels, t));
+ T(addstr(tmp, len, &buf, &buflen));
+ if (labels > (u_int)dn_count_labels(name))
+ goto formerr;
+
+ /* Signature expiry. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Time signed. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Signature Footprint. */
+ footprint = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", footprint));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Signer's name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ /* Signature. */
+ len = b64_ntop(rdata, edata - rdata,
+ base64_key, sizeof base64_key);
+ if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ } else
+ leader = " ";
+ if (len < 0)
+ goto formerr;
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+ T(addstr(base64_key + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_nxt: {
+ int n, c;
+
+ /* Next domain name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ /* Type bit map. */
+ n = edata - rdata;
+ for (c = 0; c < n*8; c++)
+ if (NS_NXT_BIT_ISSET(c, rdata)) {
+ len = SPRINTF((tmp, " %s", p_type(c)));
+ T(addstr(tmp, len, &buf, &buflen));
+ }
+ break;
+ }
+
+ case ns_t_cert: {
+ u_int c_type, key_tag, alg;
+ int n;
+ unsigned int siz;
+ char base64_cert[8192], tmp[40];
+ const char *leader;
+
+ c_type = ns_get16(rdata); rdata += NS_INT16SZ;
+ key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
+ alg = (u_int) *rdata++;
+
+ len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
+ T(addstr(tmp, len, &buf, &buflen));
+ siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_cert) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ }
+ else {
+ len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
+
+ if (len < 0)
+ goto formerr;
+ else if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ }
+ else
+ leader = " ";
+
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader),
+ &buf, &buflen));
+ T(addstr(base64_cert + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ break;
+ }
+
+ case ns_t_tkey: {
+ /* KJD - need to complete this */
+ u_long t;
+ int mode, err, keysize;
+
+ /* Algorithm name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Inception. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Experation. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Mode , Error, Key Size. */
+ /* Priority, Weight, Port. */
+ mode = ns_get16(rdata); rdata += NS_INT16SZ;
+ err = ns_get16(rdata); rdata += NS_INT16SZ;
+ keysize = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* XXX need to dump key, print otherdata length & other data */
+ break;
+ }
+
+ case ns_t_tsig: {
+ /* BEW - need to complete this */
+ int n;
+
+ T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+ rdata += 8; /*%< time */
+ n = ns_get16(rdata); rdata += INT16SZ;
+ rdata += n; /*%< sig */
+ n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
+ sprintf(buf, "%d", ns_get16(rdata));
+ rdata += INT16SZ;
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+ }
+
+ case ns_t_a6: {
+ struct in6_addr a;
+ int pbyte, pbit;
+
+ /* prefix length */
+ if (rdlen == 0U) goto formerr;
+ len = SPRINTF((tmp, "%d ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ pbit = *rdata;
+ if (pbit > 128) goto formerr;
+ pbyte = (pbit & ~7) / 8;
+ rdata++;
+
+ /* address suffix: provided only when prefix len != 128 */
+ if (pbit < 128) {
+ if (rdata + pbyte >= edata) goto formerr;
+ memset(&a, 0, sizeof(a));
+ memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
+ (void) inet_ntop(AF_INET6, &a, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += sizeof(a) - pbyte;
+ }
+
+ /* prefix name: provided only when prefix len > 0 */
+ if (pbit == 0)
+ break;
+ if (rdata >= edata) goto formerr;
+ T(addstr(" ", 1, &buf, &buflen));
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_opt: {
+ len = SPRINTF((tmp, "%u bytes", class));
+ T(addstr(tmp, len, &buf, &buflen));
+ break;
+ }
+
+ default:
+ comment = "unknown RR type";
+ goto hexify;
+ }
+ return (buf - obuf);
+ formerr:
+ comment = "RR format error";
+ hexify: {
+ int n, m;
+ char *p;
+
+ len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
+ rdlen != 0U ? " (" : "", comment));
+ T(addstr(tmp, len, &buf, &buflen));
+ while (rdata < edata) {
+ p = tmp;
+ p += SPRINTF((p, "\n\t"));
+ spaced = 0;
+ n = MIN(16, edata - rdata);
+ for (m = 0; m < n; m++)
+ p += SPRINTF((p, "%02x ", rdata[m]));
+ T(addstr(tmp, p - tmp, &buf, &buflen));
+ if (n < 16) {
+ T(addstr(")", 1, &buf, &buflen));
+ T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
+ }
+ p = tmp;
+ p += SPRINTF((p, "; "));
+ for (m = 0; m < n; m++)
+ *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
+ ? rdata[m]
+ : '.';
+ T(addstr(tmp, p - tmp, &buf, &buflen));
+ rdata += n;
+ }
+ return (buf - obuf);
+ }
+}
+
+/* Private. */
+
+/*%
+ * size_t
+ * prune_origin(name, origin)
+ * Find out if the name is at or under the current origin.
+ * return:
+ * Number of characters in name before start of origin,
+ * or length of name if origin does not match.
+ * notes:
+ * This function should share code with samedomain().
+ */
+static size_t
+prune_origin(const char *name, const char *origin) {
+ const char *oname = name;
+
+ while (*name != '\0') {
+ if (origin != NULL && ns_samename(name, origin) == 1)
+ return (name - oname - (name > oname));
+ while (*name != '\0') {
+ if (*name == '\\') {
+ name++;
+ /* XXX need to handle \nnn form. */
+ if (*name == '\0')
+ break;
+ } else if (*name == '.') {
+ name++;
+ break;
+ }
+ name++;
+ }
+ }
+ return (name - oname);
+}
+
+/*%
+ * int
+ * charstr(rdata, edata, buf, buflen)
+ * Format a <character-string> into the presentation buffer.
+ * return:
+ * Number of rdata octets consumed
+ * 0 for protocol format error
+ * -1 for output buffer error
+ * side effects:
+ * buffer is advanced on success.
+ */
+static int
+charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
+ const u_char *odata = rdata;
+ size_t save_buflen = *buflen;
+ char *save_buf = *buf;
+
+ if (addstr("\"", 1, buf, buflen) < 0)
+ goto enospc;
+ if (rdata < edata) {
+ int n = *rdata;
+
+ if (rdata + 1 + n <= edata) {
+ rdata++;
+ while (n-- > 0) {
+ if (strchr("\n\"\\", *rdata) != NULL)
+ if (addstr("\\", 1, buf, buflen) < 0)
+ goto enospc;
+ if (addstr((const char *)rdata, 1,
+ buf, buflen) < 0)
+ goto enospc;
+ rdata++;
+ }
+ }
+ }
+ if (addstr("\"", 1, buf, buflen) < 0)
+ goto enospc;
+ return (rdata - odata);
+ enospc:
+ errno = ENOSPC;
+ *buf = save_buf;
+ *buflen = save_buflen;
+ return (-1);
+}
+
+static int
+addname(const u_char *msg, size_t msglen,
+ const u_char **pp, const char *origin,
+ char **buf, size_t *buflen)
+{
+ size_t newlen, save_buflen = *buflen;
+ char *save_buf = *buf;
+ int n;
+
+ n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
+ if (n < 0)
+ goto enospc; /*%< Guess. */
+ newlen = prune_origin(*buf, origin);
+ if (**buf == '\0') {
+ goto root;
+ } else if (newlen == 0U) {
+ /* Use "@" instead of name. */
+ if (newlen + 2 > *buflen)
+ goto enospc; /* No room for "@\0". */
+ (*buf)[newlen++] = '@';
+ (*buf)[newlen] = '\0';
+ } else {
+ if (((origin == NULL || origin[0] == '\0') ||
+ (origin[0] != '.' && origin[1] != '\0' &&
+ (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
+ /* No trailing dot. */
+ root:
+ if (newlen + 2 > *buflen)
+ goto enospc; /* No room for ".\0". */
+ (*buf)[newlen++] = '.';
+ (*buf)[newlen] = '\0';
+ }
+ }
+ *pp += n;
+ addlen(newlen, buf, buflen);
+ **buf = '\0';
+ return (newlen);
+ enospc:
+ errno = ENOSPC;
+ *buf = save_buf;
+ *buflen = save_buflen;
+ return (-1);
+}
+
+static void
+addlen(size_t len, char **buf, size_t *buflen) {
+ INSIST(len <= *buflen);
+ *buf += len;
+ *buflen -= len;
+}
+
+static int
+addstr(const char *src, size_t len, char **buf, size_t *buflen) {
+ if (len >= *buflen) {
+ errno = ENOSPC;
+ return (-1);
+ }
+ memcpy(*buf, src, len);
+ addlen(len, buf, buflen);
+ **buf = '\0';
+ return (0);
+}
+
+static int
+addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
+ size_t save_buflen = *buflen;
+ char *save_buf = *buf;
+ int t;
+
+ if (spaced || len >= target - 1) {
+ T(addstr(" ", 2, buf, buflen));
+ spaced = 1;
+ } else {
+ for (t = (target - len - 1) / 8; t >= 0; t--)
+ if (addstr("\t", 1, buf, buflen) < 0) {
+ *buflen = save_buflen;
+ *buf = save_buf;
+ return (-1);
+ }
+ spaced = 0;
+ }
+ return (spaced);
+}
+
+/*! \file */
diff --git a/lib/bind/nameser/ns_samedomain.c b/lib/bind/nameser/ns_samedomain.c
new file mode 100644
index 0000000..a720f6a
--- /dev/null
+++ b/lib/bind/nameser/ns_samedomain.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_samedomain.c,v 1.5.18.1 2005/04/27 05:01:09 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <arpa/nameser.h>
+#include <errno.h>
+#include <string.h>
+
+#include "port_after.h"
+
+/*%
+ * Check whether a name belongs to a domain.
+ *
+ * Inputs:
+ *\li a - the domain whose ancestory is being verified
+ *\li b - the potential ancestor we're checking against
+ *
+ * Return:
+ *\li boolean - is a at or below b?
+ *
+ * Notes:
+ *\li Trailing dots are first removed from name and domain.
+ * Always compare complete subdomains, not only whether the
+ * domain name is the trailing string of the given name.
+ *
+ *\li "host.foobar.top" lies in "foobar.top" and in "top" and in ""
+ * but NOT in "bar.top"
+ */
+
+int
+ns_samedomain(const char *a, const char *b) {
+ size_t la, lb;
+ int diff, i, escaped;
+ const char *cp;
+
+ la = strlen(a);
+ lb = strlen(b);
+
+ /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */
+ if (la != 0U && a[la - 1] == '.') {
+ escaped = 0;
+ /* Note this loop doesn't get executed if la==1. */
+ for (i = la - 2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (!escaped)
+ la--;
+ }
+
+ /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */
+ if (lb != 0U && b[lb - 1] == '.') {
+ escaped = 0;
+ /* note this loop doesn't get executed if lb==1 */
+ for (i = lb - 2; i >= 0; i--)
+ if (b[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (!escaped)
+ lb--;
+ }
+
+ /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */
+ if (lb == 0U)
+ return (1);
+
+ /* 'b' longer than 'a' means 'a' can't be in 'b'. */
+ if (lb > la)
+ return (0);
+
+ /* 'a' and 'b' being equal at this point indicates sameness. */
+ if (lb == la)
+ return (strncasecmp(a, b, lb) == 0);
+
+ /* Ok, we know la > lb. */
+
+ diff = la - lb;
+
+ /*
+ * If 'a' is only 1 character longer than 'b', then it can't be
+ * a subdomain of 'b' (because of the need for the '.' label
+ * separator).
+ */
+ if (diff < 2)
+ return (0);
+
+ /*
+ * If the character before the last 'lb' characters of 'b'
+ * isn't '.', then it can't be a match (this lets us avoid
+ * having "foobar.com" match "bar.com").
+ */
+ if (a[diff - 1] != '.')
+ return (0);
+
+ /*
+ * We're not sure about that '.', however. It could be escaped
+ * and thus not a really a label separator.
+ */
+ escaped = 0;
+ for (i = diff - 2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (escaped)
+ return (0);
+
+ /* Now compare aligned trailing substring. */
+ cp = a + diff;
+ return (strncasecmp(cp, b, lb) == 0);
+}
+
+/*%
+ * is "a" a subdomain of "b"?
+ */
+int
+ns_subdomain(const char *a, const char *b) {
+ return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
+}
+
+/*%
+ * make a canonical copy of domain name "src"
+ *
+ * notes:
+ * \code
+ * foo -> foo.
+ * foo. -> foo.
+ * foo.. -> foo.
+ * foo\. -> foo\..
+ * foo\\. -> foo\\.
+ * \endcode
+ */
+
+int
+ns_makecanon(const char *src, char *dst, size_t dstsize) {
+ size_t n = strlen(src);
+
+ if (n + sizeof "." > dstsize) { /*%< Note: sizeof == 2 */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ strcpy(dst, src);
+ while (n >= 1U && dst[n - 1] == '.') /*%< Ends in "." */
+ if (n >= 2U && dst[n - 2] == '\\' && /*%< Ends in "\." */
+ (n < 3U || dst[n - 3] != '\\')) /*%< But not "\\." */
+ break;
+ else
+ dst[--n] = '\0';
+ dst[n++] = '.';
+ dst[n] = '\0';
+ return (0);
+}
+
+/*%
+ * determine whether domain name "a" is the same as domain name "b"
+ *
+ * return:
+ *\li -1 on error
+ *\li 0 if names differ
+ *\li 1 if names are the same
+ */
+
+int
+ns_samename(const char *a, const char *b) {
+ char ta[NS_MAXDNAME], tb[NS_MAXDNAME];
+
+ if (ns_makecanon(a, ta, sizeof ta) < 0 ||
+ ns_makecanon(b, tb, sizeof tb) < 0)
+ return (-1);
+ if (strcasecmp(ta, tb) == 0)
+ return (1);
+ else
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/bind/nameser/ns_sign.c b/lib/bind/nameser/ns_sign.c
new file mode 100644
index 0000000..ab4b0ef
--- /dev/null
+++ b/lib/bind/nameser/ns_sign.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_sign.c,v 1.4.18.2 2006/03/10 00:20:08 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/dst.h>
+#include <isc/assertions.h>
+
+#include "port_after.h"
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eob) { \
+ errno = EMSGSIZE; \
+ return(NS_TSIG_ERROR_NO_SPACE); \
+ } \
+ } while (0)
+
+/*%
+ * ns_sign
+ *
+ * Parameters:
+ *\li msg message to be sent
+ *\li msglen input - length of message
+ * output - length of signed message
+ *\li msgsize length of buffer containing message
+ *\li error value to put in the error field
+ *\li key tsig key used for signing
+ *\li querysig (response), the signature in the query
+ *\li querysiglen (response), the length of the signature in the query
+ *\li sig a buffer to hold the generated signature
+ *\li siglen input - length of signature buffer
+ * output - length of signature
+ *
+ * Errors:
+ *\li - bad input data (-1)
+ *\li - bad key / sign failed (-BADKEY)
+ *\li - not enough space (NS_TSIG_ERROR_NO_SPACE)
+ */
+int
+ns_sign(u_char *msg, int *msglen, int msgsize, int error, void *k,
+ const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
+ time_t in_timesigned)
+{
+ return(ns_sign2(msg, msglen, msgsize, error, k,
+ querysig, querysiglen, sig, siglen,
+ in_timesigned, NULL, NULL));
+}
+
+int
+ns_sign2(u_char *msg, int *msglen, int msgsize, int error, void *k,
+ const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
+ time_t in_timesigned, u_char **dnptrs, u_char **lastdnptr)
+{
+ HEADER *hp = (HEADER *)msg;
+ DST_KEY *key = (DST_KEY *)k;
+ u_char *cp, *eob;
+ u_char *lenp;
+ u_char *alg;
+ int n;
+ time_t timesigned;
+ u_char name[NS_MAXCDNAME];
+
+ dst_init();
+ if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL)
+ return (-1);
+
+ cp = msg + *msglen;
+ eob = msg + msgsize;
+
+ /* Name. */
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+ n = ns_name_pton(key->dk_key_name, name, sizeof name);
+ if (n != -1)
+ n = ns_name_pack(name, cp, eob - cp,
+ (const u_char **)dnptrs,
+ (const u_char **)lastdnptr);
+
+ } else {
+ n = ns_name_pton("", name, sizeof name);
+ if (n != -1)
+ n = ns_name_pack(name, cp, eob - cp, NULL, NULL);
+ }
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ cp += n;
+
+ /* Type, class, ttl, length (not filled in yet). */
+ BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
+ PUTSHORT(ns_t_tsig, cp);
+ PUTSHORT(ns_c_any, cp);
+ PUTLONG(0, cp); /*%< TTL */
+ lenp = cp;
+ cp += 2;
+
+ /* Alg. */
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+ if (key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL);
+ }
+ else
+ n = dn_comp("", cp, eob - cp, NULL, NULL);
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ alg = cp;
+ cp += n;
+
+ /* Time. */
+ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+ PUTSHORT(0, cp);
+ timesigned = time(NULL);
+ if (error != ns_r_badtime)
+ PUTLONG(timesigned, cp);
+ else
+ PUTLONG(in_timesigned, cp);
+ PUTSHORT(NS_TSIG_FUDGE, cp);
+
+ /* Compute the signature. */
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+ void *ctx;
+ u_char buf[NS_MAXCDNAME], *cp2;
+ int n;
+
+ dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
+
+ /* Digest the query signature, if this is a response. */
+ if (querysiglen > 0 && querysig != NULL) {
+ u_int16_t len_n = htons(querysiglen);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
+ (u_char *)&len_n, INT16SZ, NULL, 0);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
+ querysig, querysiglen, NULL, 0);
+ }
+
+ /* Digest the message. */
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen,
+ NULL, 0);
+
+ /* Digest the key name. */
+ n = ns_name_ntol(name, buf, sizeof(buf));
+ INSIST(n > 0);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the class and TTL. */
+ cp2 = buf;
+ PUTSHORT(ns_c_any, cp2);
+ PUTLONG(0, cp2);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf,
+ NULL, 0);
+
+ /* Digest the algorithm. */
+ n = ns_name_ntol(alg, buf, sizeof(buf));
+ INSIST(n > 0);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the time signed, fudge, error, and other data */
+ cp2 = buf;
+ PUTSHORT(0, cp2); /*%< Top 16 bits of time */
+ if (error != ns_r_badtime)
+ PUTLONG(timesigned, cp2);
+ else
+ PUTLONG(in_timesigned, cp2);
+ PUTSHORT(NS_TSIG_FUDGE, cp2);
+ PUTSHORT(error, cp2); /*%< Error */
+ if (error != ns_r_badtime)
+ PUTSHORT(0, cp2); /*%< Other data length */
+ else {
+ PUTSHORT(INT16SZ+INT32SZ, cp2); /*%< Other data length */
+ PUTSHORT(0, cp2); /*%< Top 16 bits of time */
+ PUTLONG(timesigned, cp2);
+ }
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf,
+ NULL, 0);
+
+ n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
+ sig, *siglen);
+ if (n < 0)
+ return (-ns_r_badkey);
+ *siglen = n;
+ } else
+ *siglen = 0;
+
+ /* Add the signature. */
+ BOUNDS_CHECK(cp, INT16SZ + (*siglen));
+ PUTSHORT(*siglen, cp);
+ memcpy(cp, sig, *siglen);
+ cp += (*siglen);
+
+ /* The original message ID & error. */
+ BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
+ PUTSHORT(ntohs(hp->id), cp); /*%< already in network order */
+ PUTSHORT(error, cp);
+
+ /* Other data. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ if (error != ns_r_badtime)
+ PUTSHORT(0, cp); /*%< Other data length */
+ else {
+ PUTSHORT(INT16SZ+INT32SZ, cp); /*%< Other data length */
+ BOUNDS_CHECK(cp, INT32SZ+INT16SZ);
+ PUTSHORT(0, cp); /*%< Top 16 bits of time */
+ PUTLONG(timesigned, cp);
+ }
+
+ /* Go back and fill in the length. */
+ PUTSHORT(cp - lenp - INT16SZ, lenp);
+
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+ *msglen = (cp - msg);
+ return (0);
+}
+
+int
+ns_sign_tcp_init(void *k, const u_char *querysig, int querysiglen,
+ ns_tcp_tsig_state *state)
+{
+ dst_init();
+ if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
+ return (-1);
+ state->counter = -1;
+ state->key = k;
+ if (state->key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ if (querysiglen > (int)sizeof(state->sig))
+ return (-1);
+ memcpy(state->sig, querysig, querysiglen);
+ state->siglen = querysiglen;
+ return (0);
+}
+
+int
+ns_sign_tcp(u_char *msg, int *msglen, int msgsize, int error,
+ ns_tcp_tsig_state *state, int done)
+{
+ return (ns_sign_tcp2(msg, msglen, msgsize, error, state,
+ done, NULL, NULL));
+}
+
+int
+ns_sign_tcp2(u_char *msg, int *msglen, int msgsize, int error,
+ ns_tcp_tsig_state *state, int done,
+ u_char **dnptrs, u_char **lastdnptr)
+{
+ u_char *cp, *eob, *lenp;
+ u_char buf[MAXDNAME], *cp2;
+ HEADER *hp = (HEADER *)msg;
+ time_t timesigned;
+ int n;
+
+ if (msg == NULL || msglen == NULL || state == NULL)
+ return (-1);
+
+ state->counter++;
+ if (state->counter == 0)
+ return (ns_sign2(msg, msglen, msgsize, error, state->key,
+ state->sig, state->siglen,
+ state->sig, &state->siglen, 0,
+ dnptrs, lastdnptr));
+
+ if (state->siglen > 0) {
+ u_int16_t siglen_n = htons(state->siglen);
+ dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx,
+ NULL, 0, NULL, 0);
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ (u_char *)&siglen_n, INT16SZ, NULL, 0);
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ state->sig, state->siglen, NULL, 0);
+ state->siglen = 0;
+ }
+
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen,
+ NULL, 0);
+
+ if (done == 0 && (state->counter % 100 != 0))
+ return (0);
+
+ cp = msg + *msglen;
+ eob = msg + msgsize;
+
+ /* Name. */
+ n = dn_comp(state->key->dk_key_name, cp, eob - cp, dnptrs, lastdnptr);
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ cp += n;
+
+ /* Type, class, ttl, length (not filled in yet). */
+ BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
+ PUTSHORT(ns_t_tsig, cp);
+ PUTSHORT(ns_c_any, cp);
+ PUTLONG(0, cp); /*%< TTL */
+ lenp = cp;
+ cp += 2;
+
+ /* Alg. */
+ n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL);
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ cp += n;
+
+ /* Time. */
+ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+ PUTSHORT(0, cp);
+ timesigned = time(NULL);
+ PUTLONG(timesigned, cp);
+ PUTSHORT(NS_TSIG_FUDGE, cp);
+
+ /*
+ * Compute the signature.
+ */
+
+ /* Digest the time signed and fudge. */
+ cp2 = buf;
+ PUTSHORT(0, cp2); /*%< Top 16 bits of time */
+ PUTLONG(timesigned, cp2);
+ PUTSHORT(NS_TSIG_FUDGE, cp2);
+
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ buf, cp2 - buf, NULL, 0);
+
+ n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
+ state->sig, sizeof(state->sig));
+ if (n < 0)
+ return (-ns_r_badkey);
+ state->siglen = n;
+
+ /* Add the signature. */
+ BOUNDS_CHECK(cp, INT16SZ + state->siglen);
+ PUTSHORT(state->siglen, cp);
+ memcpy(cp, state->sig, state->siglen);
+ cp += state->siglen;
+
+ /* The original message ID & error. */
+ BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
+ PUTSHORT(ntohs(hp->id), cp); /*%< already in network order */
+ PUTSHORT(error, cp);
+
+ /* Other data. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ PUTSHORT(0, cp);
+
+ /* Go back and fill in the length. */
+ PUTSHORT(cp - lenp - INT16SZ, lenp);
+
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+ *msglen = (cp - msg);
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/bind/nameser/ns_ttl.c b/lib/bind/nameser/ns_ttl.c
new file mode 100644
index 0000000..627ddf1
--- /dev/null
+++ b/lib/bind/nameser/ns_ttl.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_ttl.c,v 1.2.18.2 2005/07/28 07:38:10 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static int fmt1(int t, char s, char **buf, size_t *buflen);
+
+/* Macros. */
+
+#define T(x) if ((x) < 0) return (-1); else (void)NULL
+
+/* Public. */
+
+int
+ns_format_ttl(u_long src, char *dst, size_t dstlen) {
+ char *odst = dst;
+ int secs, mins, hours, days, weeks, x;
+ char *p;
+
+ secs = src % 60; src /= 60;
+ mins = src % 60; src /= 60;
+ hours = src % 24; src /= 24;
+ days = src % 7; src /= 7;
+ weeks = src; src = 0;
+
+ x = 0;
+ if (weeks) {
+ T(fmt1(weeks, 'W', &dst, &dstlen));
+ x++;
+ }
+ if (days) {
+ T(fmt1(days, 'D', &dst, &dstlen));
+ x++;
+ }
+ if (hours) {
+ T(fmt1(hours, 'H', &dst, &dstlen));
+ x++;
+ }
+ if (mins) {
+ T(fmt1(mins, 'M', &dst, &dstlen));
+ x++;
+ }
+ if (secs || !(weeks || days || hours || mins)) {
+ T(fmt1(secs, 'S', &dst, &dstlen));
+ x++;
+ }
+
+ if (x > 1) {
+ int ch;
+
+ for (p = odst; (ch = *p) != '\0'; p++)
+ if (isascii(ch) && isupper(ch))
+ *p = tolower(ch);
+ }
+
+ return (dst - odst);
+}
+
+int
+ns_parse_ttl(const char *src, u_long *dst) {
+ u_long ttl, tmp;
+ int ch, digits, dirty;
+
+ ttl = 0;
+ tmp = 0;
+ digits = 0;
+ dirty = 0;
+ while ((ch = *src++) != '\0') {
+ if (!isascii(ch) || !isprint(ch))
+ goto einval;
+ if (isdigit(ch)) {
+ tmp *= 10;
+ tmp += (ch - '0');
+ digits++;
+ continue;
+ }
+ if (digits == 0)
+ goto einval;
+ if (islower(ch))
+ ch = toupper(ch);
+ switch (ch) {
+ case 'W': tmp *= 7;
+ case 'D': tmp *= 24;
+ case 'H': tmp *= 60;
+ case 'M': tmp *= 60;
+ case 'S': break;
+ default: goto einval;
+ }
+ ttl += tmp;
+ tmp = 0;
+ digits = 0;
+ dirty = 1;
+ }
+ if (digits > 0) {
+ if (dirty)
+ goto einval;
+ else
+ ttl += tmp;
+ } else if (!dirty)
+ goto einval;
+ *dst = ttl;
+ return (0);
+
+ einval:
+ errno = EINVAL;
+ return (-1);
+}
+
+/* Private. */
+
+static int
+fmt1(int t, char s, char **buf, size_t *buflen) {
+ char tmp[50];
+ size_t len;
+
+ len = SPRINTF((tmp, "%d%c", t, s));
+ if (len + 1 > *buflen)
+ return (-1);
+ strcpy(*buf, tmp);
+ *buf += len;
+ *buflen -= len;
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/bind/nameser/ns_verify.c b/lib/bind/nameser/ns_verify.c
new file mode 100644
index 0000000..b80b588
--- /dev/null
+++ b/lib/bind/nameser/ns_verify.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_verify.c,v 1.2.18.3 2006/03/10 00:20:08 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/dst.h>
+
+#include "port_after.h"
+
+/* Private. */
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eom) { \
+ return (NS_TSIG_ERROR_FORMERR); \
+ } \
+ } while (0)
+
+/* Public. */
+
+u_char *
+ns_find_tsig(u_char *msg, u_char *eom) {
+ HEADER *hp = (HEADER *)msg;
+ int n, type;
+ u_char *cp = msg, *start;
+
+ if (msg == NULL || eom == NULL || msg > eom)
+ return (NULL);
+
+ if (cp + HFIXEDSZ >= eom)
+ return (NULL);
+
+ if (hp->arcount == 0)
+ return (NULL);
+
+ cp += HFIXEDSZ;
+
+ n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount));
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount));
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount));
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ n = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1);
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ start = cp;
+ n = dn_skipname(cp, eom);
+ if (n < 0)
+ return (NULL);
+ cp += n;
+ if (cp + INT16SZ >= eom)
+ return (NULL);
+
+ GETSHORT(type, cp);
+ if (type != ns_t_tsig)
+ return (NULL);
+ return (start);
+}
+
+/* ns_verify
+ *
+ * Parameters:
+ *\li statp res stuff
+ *\li msg received message
+ *\li msglen length of message
+ *\li key tsig key used for verifying.
+ *\li querysig (response), the signature in the query
+ *\li querysiglen (response), the length of the signature in the query
+ *\li sig (query), a buffer to hold the signature
+ *\li siglen (query), input - length of signature buffer
+ * output - length of signature
+ *
+ * Errors:
+ *\li - bad input (-1)
+ *\li - invalid dns message (NS_TSIG_ERROR_FORMERR)
+ *\li - TSIG is not present (NS_TSIG_ERROR_NO_TSIG)
+ *\li - key doesn't match (-ns_r_badkey)
+ *\li - TSIG verification fails with BADKEY (-ns_r_badkey)
+ *\li - TSIG verification fails with BADSIG (-ns_r_badsig)
+ *\li - TSIG verification fails with BADTIME (-ns_r_badtime)
+ *\li - TSIG verification succeeds, error set to BAKEY (ns_r_badkey)
+ *\li - TSIG verification succeeds, error set to BADSIG (ns_r_badsig)
+ *\li - TSIG verification succeeds, error set to BADTIME (ns_r_badtime)
+ */
+int
+ns_verify(u_char *msg, int *msglen, void *k,
+ const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
+ time_t *timesigned, int nostrip)
+{
+ HEADER *hp = (HEADER *)msg;
+ DST_KEY *key = (DST_KEY *)k;
+ u_char *cp = msg, *eom;
+ char name[MAXDNAME], alg[MAXDNAME];
+ u_char *recstart, *rdatastart;
+ u_char *sigstart, *otherstart;
+ int n;
+ int error;
+ u_int16_t type, length;
+ u_int16_t fudge, sigfieldlen, otherfieldlen;
+
+ dst_init();
+ if (msg == NULL || msglen == NULL || *msglen < 0)
+ return (-1);
+
+ eom = msg + *msglen;
+
+ recstart = ns_find_tsig(msg, eom);
+ if (recstart == NULL)
+ return (NS_TSIG_ERROR_NO_TSIG);
+
+ cp = recstart;
+
+ /* Read the key name. */
+ n = dn_expand(msg, eom, cp, name, MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ cp += n;
+
+ /* Read the type. */
+ BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
+ GETSHORT(type, cp);
+ if (type != ns_t_tsig)
+ return (NS_TSIG_ERROR_NO_TSIG);
+
+ /* Skip the class and TTL, save the length. */
+ cp += INT16SZ + INT32SZ;
+ GETSHORT(length, cp);
+ if (eom - cp != length)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /* Read the algorithm name. */
+ rdatastart = cp;
+ n = dn_expand(msg, eom, cp, alg, MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+ return (-ns_r_badkey);
+ cp += n;
+
+ /* Read the time signed and fudge. */
+ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+ cp += INT16SZ;
+ GETLONG((*timesigned), cp);
+ GETSHORT(fudge, cp);
+
+ /* Read the signature. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ GETSHORT(sigfieldlen, cp);
+ BOUNDS_CHECK(cp, sigfieldlen);
+ sigstart = cp;
+ cp += sigfieldlen;
+
+ /* Skip id and read error. */
+ BOUNDS_CHECK(cp, 2*INT16SZ);
+ cp += INT16SZ;
+ GETSHORT(error, cp);
+
+ /* Parse the other data. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ GETSHORT(otherfieldlen, cp);
+ BOUNDS_CHECK(cp, otherfieldlen);
+ otherstart = cp;
+ cp += otherfieldlen;
+
+ if (cp != eom)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /* Verify that the key used is OK. */
+ if (key != NULL) {
+ if (key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ if (error != ns_r_badsig && error != ns_r_badkey) {
+ if (ns_samename(key->dk_key_name, name) != 1)
+ return (-ns_r_badkey);
+ }
+ }
+
+ hp->arcount = htons(ntohs(hp->arcount) - 1);
+
+ /*
+ * Do the verification.
+ */
+
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+ void *ctx;
+ u_char buf[MAXDNAME];
+ u_char buf2[MAXDNAME];
+
+ /* Digest the query signature, if this is a response. */
+ dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
+ if (querysiglen > 0 && querysig != NULL) {
+ u_int16_t len_n = htons(querysiglen);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ (u_char *)&len_n, INT16SZ, NULL, 0);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ querysig, querysiglen, NULL, 0);
+ }
+
+ /* Digest the message. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, recstart - msg,
+ NULL, 0);
+
+ /* Digest the key name. */
+ n = ns_name_pton(name, buf2, sizeof(buf2));
+ if (n < 0)
+ return (-1);
+ n = ns_name_ntol(buf2, buf, sizeof(buf));
+ if (n < 0)
+ return (-1);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the class and TTL. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ recstart + dn_skipname(recstart, eom) + INT16SZ,
+ INT16SZ + INT32SZ, NULL, 0);
+
+ /* Digest the algorithm. */
+ n = ns_name_pton(alg, buf2, sizeof(buf2));
+ if (n < 0)
+ return (-1);
+ n = ns_name_ntol(buf2, buf, sizeof(buf));
+ if (n < 0)
+ return (-1);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the time signed and fudge. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ rdatastart + dn_skipname(rdatastart, eom),
+ INT16SZ + INT32SZ + INT16SZ, NULL, 0);
+
+ /* Digest the error and other data. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ otherstart - INT16SZ - INT16SZ,
+ otherfieldlen + INT16SZ + INT16SZ, NULL, 0);
+
+ n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
+ sigstart, sigfieldlen);
+
+ if (n < 0)
+ return (-ns_r_badsig);
+
+ if (sig != NULL && siglen != NULL) {
+ if (*siglen < sigfieldlen)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ memcpy(sig, sigstart, sigfieldlen);
+ *siglen = sigfieldlen;
+ }
+ } else {
+ if (sigfieldlen > 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ if (sig != NULL && siglen != NULL)
+ *siglen = 0;
+ }
+
+ /* Reset the counter, since we still need to check for badtime. */
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+
+ /* Verify the time. */
+ if (abs((*timesigned) - time(NULL)) > fudge)
+ return (-ns_r_badtime);
+
+ if (nostrip == 0) {
+ *msglen = recstart - msg;
+ hp->arcount = htons(ntohs(hp->arcount) - 1);
+ }
+
+ if (error != NOERROR)
+ return (error);
+
+ return (0);
+}
+
+int
+ns_verify_tcp_init(void *k, const u_char *querysig, int querysiglen,
+ ns_tcp_tsig_state *state)
+{
+ dst_init();
+ if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
+ return (-1);
+ state->counter = -1;
+ state->key = k;
+ if (state->key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ if (querysiglen > (int)sizeof(state->sig))
+ return (-1);
+ memcpy(state->sig, querysig, querysiglen);
+ state->siglen = querysiglen;
+ return (0);
+}
+
+int
+ns_verify_tcp(u_char *msg, int *msglen, ns_tcp_tsig_state *state,
+ int required)
+{
+ HEADER *hp = (HEADER *)msg;
+ u_char *recstart, *sigstart;
+ unsigned int sigfieldlen, otherfieldlen;
+ u_char *cp, *eom, *cp2;
+ char name[MAXDNAME], alg[MAXDNAME];
+ u_char buf[MAXDNAME];
+ int n, type, length, fudge, error;
+ time_t timesigned;
+
+ if (msg == NULL || msglen == NULL || state == NULL)
+ return (-1);
+
+ eom = msg + *msglen;
+
+ state->counter++;
+ if (state->counter == 0)
+ return (ns_verify(msg, msglen, state->key,
+ state->sig, state->siglen,
+ state->sig, &state->siglen, &timesigned, 0));
+
+ if (state->siglen > 0) {
+ u_int16_t siglen_n = htons(state->siglen);
+
+ dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx,
+ NULL, 0, NULL, 0);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ (u_char *)&siglen_n, INT16SZ, NULL, 0);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ state->sig, state->siglen, NULL, 0);
+ state->siglen = 0;
+ }
+
+ cp = recstart = ns_find_tsig(msg, eom);
+
+ if (recstart == NULL) {
+ if (required)
+ return (NS_TSIG_ERROR_NO_TSIG);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ msg, *msglen, NULL, 0);
+ return (0);
+ }
+
+ hp->arcount = htons(ntohs(hp->arcount) - 1);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ msg, recstart - msg, NULL, 0);
+
+ /* Read the key name. */
+ n = dn_expand(msg, eom, cp, name, MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ cp += n;
+
+ /* Read the type. */
+ BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
+ GETSHORT(type, cp);
+ if (type != ns_t_tsig)
+ return (NS_TSIG_ERROR_NO_TSIG);
+
+ /* Skip the class and TTL, save the length. */
+ cp += INT16SZ + INT32SZ;
+ GETSHORT(length, cp);
+ if (eom - cp != length)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /* Read the algorithm name. */
+ n = dn_expand(msg, eom, cp, alg, MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+ return (-ns_r_badkey);
+ cp += n;
+
+ /* Verify that the key used is OK. */
+ if ((ns_samename(state->key->dk_key_name, name) != 1 ||
+ state->key->dk_alg != KEY_HMAC_MD5))
+ return (-ns_r_badkey);
+
+ /* Read the time signed and fudge. */
+ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+ cp += INT16SZ;
+ GETLONG(timesigned, cp);
+ GETSHORT(fudge, cp);
+
+ /* Read the signature. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ GETSHORT(sigfieldlen, cp);
+ BOUNDS_CHECK(cp, sigfieldlen);
+ sigstart = cp;
+ cp += sigfieldlen;
+
+ /* Skip id and read error. */
+ BOUNDS_CHECK(cp, 2*INT16SZ);
+ cp += INT16SZ;
+ GETSHORT(error, cp);
+
+ /* Parse the other data. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ GETSHORT(otherfieldlen, cp);
+ BOUNDS_CHECK(cp, otherfieldlen);
+ cp += otherfieldlen;
+
+ if (cp != eom)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /*
+ * Do the verification.
+ */
+
+ /* Digest the time signed and fudge. */
+ cp2 = buf;
+ PUTSHORT(0, cp2); /*%< Top 16 bits of time. */
+ PUTLONG(timesigned, cp2);
+ PUTSHORT(NS_TSIG_FUDGE, cp2);
+
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ buf, cp2 - buf, NULL, 0);
+
+ n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
+ sigstart, sigfieldlen);
+ if (n < 0)
+ return (-ns_r_badsig);
+
+ if (sigfieldlen > sizeof(state->sig))
+ return (NS_TSIG_ERROR_NO_SPACE);
+
+ memcpy(state->sig, sigstart, sigfieldlen);
+ state->siglen = sigfieldlen;
+
+ /* Verify the time. */
+ if (abs(timesigned - time(NULL)) > fudge)
+ return (-ns_r_badtime);
+
+ *msglen = recstart - msg;
+
+ if (error != NOERROR)
+ return (error);
+
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/bind/port/Makefile.in b/lib/bind/port/Makefile.in
new file mode 100644
index 0000000..99e5985
--- /dev/null
+++ b/lib/bind/port/Makefile.in
@@ -0,0 +1,14 @@
+# 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.
diff --git a/lib/bind/port/freebsd/Makefile.in b/lib/bind/port/freebsd/Makefile.in
new file mode 100644
index 0000000..99e5985
--- /dev/null
+++ b/lib/bind/port/freebsd/Makefile.in
@@ -0,0 +1,14 @@
+# 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.
diff --git a/lib/bind/port/freebsd/include/Makefile.in b/lib/bind/port/freebsd/include/Makefile.in
new file mode 100644
index 0000000..68bef09
--- /dev/null
+++ b/lib/bind/port/freebsd/include/Makefile.in
@@ -0,0 +1,34 @@
+# 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: Makefile.in,v 1.2 2004/03/16 05:22:22 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+HEADERS= sys/bitypes.h
+
+all:
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/sys
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/sys; \
+ done
diff --git a/lib/bind/port/freebsd/include/sys/bitypes.h b/lib/bind/port/freebsd/include/sys/bitypes.h
new file mode 100644
index 0000000..ef3a6d4
--- /dev/null
+++ b/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/lib/bind/port_after.h.in b/lib/bind/port_after.h.in
new file mode 100644
index 0000000..f248d23
--- /dev/null
+++ b/lib/bind/port_after.h.in
@@ -0,0 +1,415 @@
+#ifndef port_after_h
+#define port_after_h
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#if (!defined(BSD)) || (BSD < 199306)
+#include <sys/bitypes.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+
+@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@
+@PORT_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 <sys/socket.h>
+ * has had this type added. The type number below is correct on most BSD-
+ * derived systems for which AF_INET6 is defined.
+ */
+#ifndef AF_INET6
+#define AF_INET6 24
+#endif
+
+#ifndef PF_INET6
+#define PF_INET6 AF_INET6
+#endif
+
+#ifdef HAS_IN_ADDR6
+/* Map to pre-RFC structure. */
+#define in6_addr in_addr6
+#endif
+
+#ifndef HAS_INET6_STRUCTS
+/* Replace with structure from later rev of O/S if known. */
+struct in6_addr {
+ u_int8_t s6_addr[16];
+};
+
+#define IN6ADDR_ANY_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}
+
+#define IN6ADDR_LOOPBACK_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}
+
+/* Replace with structure from later rev of O/S if known. */
+struct sockaddr_in6 {
+#ifdef HAVE_SA_LEN
+ u_int8_t sin6_len; /* length of this struct */
+ u_int8_t sin6_family; /* AF_INET6 */
+#else
+ u_int16_t sin6_family; /* AF_INET6 */
+#endif
+ u_int16_t sin6_port; /* transport layer port # */
+ u_int32_t sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ u_int32_t sin6_scope_id; /* set of interfaces for a scope */
+};
+#endif /* HAS_INET6_STRUCTS */
+
+#ifdef BROKEN_IN6ADDR_INIT_MACROS
+#undef IN6ADDR_ANY_INIT
+#undef IN6ADDR_LOOPBACK_INIT
+#endif
+
+#ifdef _AIX
+#ifndef IN6ADDR_ANY_INIT
+#define IN6ADDR_ANY_INIT {{{ 0, 0, 0, 0 }}}
+#endif
+#ifndef IN6ADDR_LOOPBACK_INIT
+#if BYTE_ORDER == BIG_ENDIAN
+#define IN6ADDR_LOOPBACK_INIT {{{ 0, 0, 0, 1 }}}
+#else
+#define IN6ADDR_LOOPBACK_INIT {{{0, 0, 0, 0x01000000}}}
+#endif
+#endif
+#endif
+
+#ifndef IN6ADDR_ANY_INIT
+#ifdef s6_addr
+#define IN6ADDR_ANY_INIT \
+ {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
+#else
+#define IN6ADDR_ANY_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}
+#endif
+
+#endif
+#ifndef IN6ADDR_LOOPBACK_INIT
+#ifdef s6_addr
+#define IN6ADDR_LOOPBACK_INIT \
+ {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
+#else
+#define IN6ADDR_LOOPBACK_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}
+#endif
+#endif
+
+#ifndef HAVE_SOCKADDR_STORAGE
+#define __SS_MAXSIZE 128
+#define __SS_ALLIGSIZE (sizeof (long))
+
+struct sockaddr_storage {
+#ifdef HAVE_SA_LEN
+ u_int8_t ss_len; /* address length */
+ u_int8_t ss_family; /* address family */
+ char __ss_pad1[__SS_ALLIGSIZE - 2 * sizeof(u_int8_t)];
+ long __ss_align;
+ char __ss_pad2[__SS_MAXSIZE - 2 * __SS_ALLIGSIZE];
+#else
+ u_int16_t ss_family; /* address family */
+ char __ss_pad1[__SS_ALLIGSIZE - sizeof(u_int16_t)];
+ long __ss_align;
+ char __ss_pad2[__SS_MAXSIZE - 2 * __SS_ALLIGSIZE];
+#endif
+};
+#endif
+
+
+#if !defined(HAS_INET6_STRUCTS) || defined(NEED_IN6ADDR_ANY)
+#define in6addr_any isc_in6addr_any
+extern const struct in6_addr in6addr_any;
+#endif
+
+/*
+ * IN6_ARE_ADDR_EQUAL, IN6_IS_ADDR_UNSPECIFIED, IN6_IS_ADDR_V4COMPAT and
+ * IN6_IS_ADDR_V4MAPPED are broken in glibc 2.1.
+ */
+#ifdef __GLIBC__
+#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2)
+#undef IN6_ARE_ADDR_EQUAL
+#undef IN6_IS_ADDR_UNSPECIFIED
+#undef IN6_IS_ADDR_V4COMPAT
+#undef IN6_IS_ADDR_V4MAPPED
+#endif
+#endif
+
+#ifndef IN6_ARE_ADDR_EQUAL
+#define IN6_ARE_ADDR_EQUAL(a,b) \
+ (memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0)
+#endif
+
+#ifndef IN6_IS_ADDR_UNSPECIFIED
+#define IN6_IS_ADDR_UNSPECIFIED(a) \
+ IN6_ARE_ADDR_EQUAL(a, &in6addr_any)
+#endif
+
+#ifndef IN6_IS_ADDR_LOOPBACK
+extern const struct in6_addr isc_in6addr_loopback;
+#define IN6_IS_ADDR_LOOPBACK(a) \
+ IN6_ARE_ADDR_EQUAL(a, &isc_in6addr_loopback)
+#endif
+
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ ((a)->s6_addr[0] == 0x00 && (a)->s6_addr[1] == 0x00 && \
+ (a)->s6_addr[2] == 0x00 && (a)->s6_addr[3] == 0x00 && \
+ (a)->s6_addr[4] == 0x00 && (a)->s6_addr[5] == 0x00 && \
+ (a)->s6_addr[6] == 0x00 && (a)->s6_addr[9] == 0x00 && \
+ (a)->s6_addr[8] == 0x00 && (a)->s6_addr[9] == 0x00 && \
+ (a)->s6_addr[10] == 0xff && (a)->s6_addr[11] == 0xff)
+#endif
+
+#ifndef IN6_IS_ADDR_SITELOCAL
+#define IN6_IS_ADDR_SITELOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
+#endif
+
+#ifndef IN6_IS_ADDR_LINKLOCAL
+#define IN6_IS_ADDR_LINKLOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
+#endif
+
+#ifndef IN6_IS_ADDR_MULTICAST
+#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff)
+#endif
+
+#ifndef __IPV6_ADDR_MC_SCOPE
+#define __IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
+#endif
+
+#ifndef __IPV6_ADDR_SCOPE_SITELOCAL
+#define __IPV6_ADDR_SCOPE_SITELOCAL 0x05
+#endif
+#ifndef __IPV6_ADDR_SCOPE_ORGLOCAL
+#define __IPV6_ADDR_SCOPE_ORGLOCAL 0x08
+#endif
+
+#ifndef IN6_IS_ADDR_MC_SITELOCAL
+#define IN6_IS_ADDR_MC_SITELOCAL(a) \
+ (IN6_IS_ADDR_MULTICAST(a) && \
+ (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_SITELOCAL))
+#endif
+
+#ifndef IN6_IS_ADDR_MC_ORGLOCAL
+#define IN6_IS_ADDR_MC_ORGLOCAL(a) \
+ (IN6_IS_ADDR_MULTICAST(a) && \
+ (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_ORGLOCAL))
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+#ifndef INET6_ADDRSTRLEN
+/* sizeof("aaaa:bbbb:cccc:dddd:eeee:ffff:123.123.123.123") */
+#define INET6_ADDRSTRLEN 46
+#endif
+
+#ifndef MIN
+#define MIN(x,y) (((x) <= (y)) ? (x) : (y))
+#endif
+
+#ifndef MAX
+#define MAX(x,y) (((x) >= (y)) ? (x) : (y))
+#endif
+
+#ifdef NEED_DAEMON
+int daemon(int nochdir, int noclose);
+#endif
+
+#ifdef NEED_STRSEP
+char * strsep(char **stringp, const char *delim);
+#endif
+
+#ifndef ALIGN
+#define ALIGN(p) (((uintptr_t)(p) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
+#endif
+
+#ifdef NEED_SETGROUPENT
+int setgroupent(int stayopen);
+#endif
+
+#ifdef NEED_GETGROUPLIST
+int getgrouplist(GETGROUPLIST_ARGS);
+#endif
+
+#ifdef POSIX_GETGRNAM_R
+int
+__posix_getgrnam_r(const char *, struct group *, char *, int, struct group **);
+#endif
+
+#ifdef NEED_GETGRNAM_R
+int
+getgrnam_r(const char *, struct group *, char *, size_t, struct group **);
+#endif
+
+#ifdef POSIX_GETGRGID_R
+int
+__posix_getgrgid_r(gid_t, struct group *, char *, int, struct group **) ;
+#endif
+
+#ifdef NEED_GETGRGID_R
+int
+getgrgid_r(gid_t, struct group *, char *, size_t, struct group **);
+#endif
+
+#ifdef NEED_GETGRENT_R
+GROUP_R_RETURN getgrent_r(struct group *gptr, GROUP_R_ARGS);
+#endif
+
+#ifdef NEED_SETGRENT_R
+GROUP_R_SET_RETURN setgrent_r(GROUP_R_ENT_ARGS);
+#endif
+
+#ifdef NEED_ENDGRENT_R
+GROUP_R_END_RETURN endgrent_r(GROUP_R_ENT_ARGS);
+#endif
+
+#if defined(NEED_INNETGR_R) && defined(NGR_R_RETURN)
+NGR_R_RETURN
+innetgr_r(const char *, const char *, const char *, const char *);
+#endif
+
+#ifdef NEED_SETNETGRENT_R
+#ifdef NGR_R_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);
+
+#ifdef NGR_R_ARGS
+int getnetgrent_r(char **machinep, char **userp, char **domainp, NGR_R_ARGS);
+#endif
+
+#ifdef SETNETGRENT_ARGS
+void setnetgrent(SETNETGRENT_ARGS);
+#else
+void setnetgrent(const char *netgroup);
+#endif
+
+void endnetgrent(void);
+
+#ifdef INNETGR_ARGS
+int innetgr(INNETGR_ARGS);
+#else
+int innetgr(const char *netgroup, const char *machine,
+ const char *user, const char *domain);
+#endif
+
+#ifdef NGR_R_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/lib/bind/port_before.h.in b/lib/bind/port_before.h.in
new file mode 100644
index 0000000..1f6ff1a
--- /dev/null
+++ b/lib/bind/port_before.h.in
@@ -0,0 +1,162 @@
+#ifndef port_before_h
+#define port_before_h
+#include <config.h>
+
+struct group; /* silence warning */
+struct passwd; /* silence warning */
+struct timeval; /* silence warning */
+struct timezone; /* silence warning */
+
+#ifdef HAVE_SYS_TIMERS_H
+#include <sys/timers.h>
+#endif
+#include <limits.h>
+
+#ifdef ISC_PLATFORM_NEEDTIMESPEC
+#include <time.h> /* For time_t */
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+#endif
+#ifndef HAVE_MEMMOVE
+#define memmove(a,b,c) bcopy(b,a,c)
+#endif
+
+@WANT_IRS_GR@
+@WANT_IRS_NIS@
+@WANT_IRS_PW@
+
+@BSD_COMP@
+@USE_POLL@
+@HAVE_MD5@
+@SOLARIS2@
+
+@DO_PTHREADS@
+@GETGROUPLIST_ARGS@
+@GETNETBYADDR_ADDR_T@
+@SETPWENT_VOID@
+@SETGRENT_VOID@
+
+@NET_R_ARGS@
+@NET_R_BAD@
+@NET_R_COPY@
+@NET_R_COPY_ARGS@
+@NET_R_END_RESULT@
+@NET_R_END_RETURN@
+@NET_R_ENT_ARGS@
+@NET_R_OK@
+@NET_R_RETURN@
+@NET_R_SET_RESULT@
+@NET_R_SETANSWER@
+@NET_R_SET_RETURN@
+@NETENT_DATA@
+
+@GROUP_R_RETURN@
+@GROUP_R_SET_RETURN@
+@GROUP_R_SET_RESULT@
+@GROUP_R_END_RETURN@
+@GROUP_R_END_RESULT@
+@GROUP_R_ARGS@
+@GROUP_R_ENT_ARGS@
+@GROUP_R_OK@
+@GROUP_R_BAD@
+
+@HOST_R_ARGS@
+@HOST_R_BAD@
+@HOST_R_COPY@
+@HOST_R_COPY_ARGS@
+@HOST_R_END_RESULT@
+@HOST_R_END_RETURN@
+@HOST_R_ENT_ARGS@
+@HOST_R_ERRNO@
+@HOST_R_OK@
+@HOST_R_RETURN@
+@HOST_R_SETANSWER@
+@HOST_R_SET_RESULT@
+@HOST_R_SET_RETURN@
+@HOSTENT_DATA@
+
+@NGR_R_ARGS@
+@NGR_R_BAD@
+@NGR_R_COPY@
+@NGR_R_COPY_ARGS@
+@NGR_R_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_ENT_UNUSED@
+@PROTO_R_OK@
+@PROTO_R_SETANSWER@
+@PROTO_R_RETURN@
+@PROTO_R_SET_RESULT@
+@PROTO_R_SET_RETURN@
+@PROTOENT_DATA@
+
+@PASS_R_ARGS@
+@PASS_R_BAD@
+@PASS_R_COPY@
+@PASS_R_COPY_ARGS@
+@PASS_R_END_RESULT@
+@PASS_R_END_RETURN@
+@PASS_R_ENT_ARGS@
+@PASS_R_OK@
+@PASS_R_RETURN@
+@PASS_R_SET_RESULT@
+@PASS_R_SET_RETURN@
+
+@SERV_R_ARGS@
+@SERV_R_BAD@
+@SERV_R_COPY@
+@SERV_R_COPY_ARGS@
+@SERV_R_END_RESULT@
+@SERV_R_END_RETURN@
+@SERV_R_ENT_ARGS@
+@SERV_R_ENT_UNUSED@
+@SERV_R_OK@
+@SERV_R_SETANSWER@
+@SERV_R_RETURN@
+@SERV_R_SET_RESULT@
+@SERV_R_SET_RETURN@
+@SERVENT_DATA@
+
+
+#define DE_CONST(konst, var) \
+ do { \
+ union { const void *k; void *v; } _u; \
+ _u.k = konst; \
+ var = _u.v; \
+ } while (0)
+
+#define UNUSED(x) (x) = (x)
+
+@SOLARIS_BITTYPES@
+@ISC_SOCKLEN_T@
+
+#ifdef __GNUC__
+#define ISC_FORMAT_PRINTF(fmt, args) \
+ __attribute__((__format__(__printf__, fmt, args)))
+#else
+#define ISC_FORMAT_PRINTF(fmt, args)
+#endif
+
+/* Pull in host order macros when _XOPEN_SOURCE_EXTENDED is defined. */
+#if defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)
+#include <sys/byteorder.h>
+#endif
+
+#endif
+
+/*! \file */
diff --git a/lib/bind/resolv/Makefile.in b/lib/bind/resolv/Makefile.in
new file mode 100644
index 0000000..cc661b6
--- /dev/null
+++ b/lib/bind/resolv/Makefile.in
@@ -0,0 +1,34 @@
+# Copyright (C) 2004, 2005 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: Makefile.in,v 1.4.18.2 2005/07/29 00:12:55 marka Exp $
+
+srcdir= @srcdir@
+VPATH = @srcdir@
+
+OBJS= herror.@O@ mtctxres.@O@ res_comp.@O@ res_data.@O@ res_debug.@O@ \
+ res_findzonecut.@O@ res_init.@O@ res_mkquery.@O@ res_mkupdate.@O@ \
+ res_query.@O@ res_send.@O@ res_sendsigned.@O@ res_update.@O@
+
+SRCS= herror.c mtctxres.c res_comp.c res_data.c res_debug.c \
+ res_findzonecut.c res_init.c res_mkquery.c res_mkupdate.c \
+ res_query.c res_send.c res_sendsigned.c res_update.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I${srcdir}/../include
+CWARNINGS=
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/resolv/herror.c b/lib/bind/resolv/herror.c
new file mode 100644
index 0000000..9232426
--- /dev/null
+++ b/lib/bind/resolv/herror.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: herror.c,v 1.3.18.1 2005/04/27 05:01:09 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <unistd.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+const char *h_errlist[] = {
+ "Resolver Error 0 (no error)",
+ "Unknown host", /*%< 1 HOST_NOT_FOUND */
+ "Host name lookup failure", /*%< 2 TRY_AGAIN */
+ "Unknown server error", /*%< 3 NO_RECOVERY */
+ "No address associated with name", /*%< 4 NO_ADDRESS */
+};
+int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] };
+
+#if !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
+#undef h_errno
+int h_errno;
+#endif
+
+/*%
+ * herror --
+ * print the error indicated by the h_errno value.
+ */
+void
+herror(const char *s) {
+ struct iovec iov[4], *v = iov;
+ char *t;
+
+ if (s != NULL && *s != '\0') {
+ DE_CONST(s, t);
+ v->iov_base = t;
+ v->iov_len = strlen(t);
+ v++;
+ DE_CONST(": ", t);
+ v->iov_base = t;
+ v->iov_len = 2;
+ v++;
+ }
+ DE_CONST(hstrerror(*__h_errno()), t);
+ v->iov_base = t;
+ v->iov_len = strlen(v->iov_base);
+ v++;
+ DE_CONST("\n", t);
+ v->iov_base = t;
+ v->iov_len = 1;
+ writev(STDERR_FILENO, iov, (v - iov) + 1);
+}
+
+/*%
+ * hstrerror --
+ * return the string associated with a given "host" errno value.
+ */
+const char *
+hstrerror(int err) {
+ if (err < 0)
+ return ("Resolver internal error");
+ else if (err < h_nerr)
+ return (h_errlist[err]);
+ return ("Unknown resolver error");
+}
+
+/*! \file */
diff --git a/lib/bind/resolv/mtctxres.c b/lib/bind/resolv/mtctxres.c
new file mode 100644
index 0000000..635bbd4
--- /dev/null
+++ b/lib/bind/resolv/mtctxres.c
@@ -0,0 +1,129 @@
+#include <port_before.h>
+#ifdef DO_PTHREADS
+#include <pthread.h>
+#endif
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <resolv_mt.h>
+#include <irs.h>
+#include <port_after.h>
+
+#ifdef DO_PTHREADS
+static pthread_key_t key;
+static int mt_key_initialized = 0;
+
+static int __res_init_ctx(void);
+static void __res_destroy_ctx(void *);
+
+#if defined(sun) && !defined(__GNUC__)
+#pragma init (_mtctxres_init)
+#endif
+#endif
+
+static mtctxres_t sharedctx;
+
+#ifdef DO_PTHREADS
+/*
+ * Initialize the TSD key. By doing this at library load time, we're
+ * implicitly running without interference from other threads, so there's
+ * no need for locking.
+ */
+static void
+_mtctxres_init(void) {
+ int pthread_keycreate_ret;
+
+ pthread_keycreate_ret = pthread_key_create(&key, __res_destroy_ctx);
+ if (pthread_keycreate_ret == 0)
+ mt_key_initialized = 1;
+}
+#endif
+
+/*
+ * To support binaries that used the private MT-safe interface in
+ * Solaris 8, we still need to provide the __res_enable_mt()
+ * and __res_disable_mt() entry points. They're do-nothing routines.
+ */
+int
+__res_enable_mt(void) {
+ return (-1);
+}
+
+int
+__res_disable_mt(void) {
+ return (0);
+}
+
+#ifdef DO_PTHREADS
+static int
+__res_init_ctx(void) {
+
+ mtctxres_t *mt;
+ int ret;
+
+
+ if (pthread_getspecific(key) != 0) {
+ /* Already exists */
+ return (0);
+ }
+
+ if ((mt = malloc(sizeof (mtctxres_t))) == 0) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ memset(mt, 0, sizeof (mtctxres_t));
+
+ if ((ret = pthread_setspecific(key, mt)) != 0) {
+ free(mt);
+ errno = ret;
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+__res_destroy_ctx(void *value) {
+
+ mtctxres_t *mt = (mtctxres_t *)value;
+
+ if (mt != 0)
+ free(mt);
+}
+#endif
+
+mtctxres_t *
+___mtctxres(void) {
+#ifdef DO_PTHREADS
+ mtctxres_t *mt;
+
+ /*
+ * This if clause should only be executed if we are linking
+ * statically. When linked dynamically _mtctxres_init() should
+ * be called at binding time due the #pragma above.
+ */
+ if (!mt_key_initialized) {
+ static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER;
+ if (pthread_mutex_lock(&keylock) == 0) {
+ _mtctxres_init();
+ (void) pthread_mutex_unlock(&keylock);
+ }
+ }
+
+ /*
+ * If we have already been called in this thread return the existing
+ * context. Otherwise recreat a new context and return it. If
+ * that fails return a global context.
+ */
+ if (mt_key_initialized) {
+ if (((mt = pthread_getspecific(key)) != 0) ||
+ (__res_init_ctx() == 0 &&
+ (mt = pthread_getspecific(key)) != 0)) {
+ return (mt);
+ }
+ }
+#endif
+ return (&sharedctx);
+}
diff --git a/lib/bind/resolv/res_comp.c b/lib/bind/resolv/res_comp.c
new file mode 100644
index 0000000..4dc3c2a
--- /dev/null
+++ b/lib/bind/resolv/res_comp.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_comp.c,v 1.3.18.2 2005/07/28 07:38:11 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "port_after.h"
+
+/*%
+ * Expand compressed domain name 'src' to full domain name.
+ *
+ * \li 'msg' is a pointer to the begining of the message,
+ * \li 'eom' points to the first location after the message,
+ * \li 'dst' is a pointer to a buffer of size 'dstsiz' for the result.
+ * \li Return size of compressed name or -1 if there was an error.
+ */
+int
+dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
+ char *dst, int dstsiz)
+{
+ int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
+
+ if (n > 0 && dst[0] == '.')
+ dst[0] = '\0';
+ return (n);
+}
+
+/*%
+ * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
+ *
+ * \li Return the size of the compressed name or -1.
+ * \li 'length' is the size of the array pointed to by 'comp_dn'.
+ */
+int
+dn_comp(const char *src, u_char *dst, int dstsiz,
+ u_char **dnptrs, u_char **lastdnptr)
+{
+ return (ns_name_compress(src, dst, (size_t)dstsiz,
+ (const u_char **)dnptrs,
+ (const u_char **)lastdnptr));
+}
+
+/*%
+ * Skip over a compressed domain name. Return the size or -1.
+ */
+int
+dn_skipname(const u_char *ptr, const u_char *eom) {
+ const u_char *saveptr = ptr;
+
+ if (ns_name_skip(&ptr, eom) == -1)
+ return (-1);
+ return (ptr - saveptr);
+}
+
+/*%
+ * Verify that a domain name uses an acceptable character set.
+ *
+ * Note the conspicuous absence of ctype macros in these definitions. On
+ * non-ASCII hosts, we can't depend on string literals or ctype macros to
+ * tell us anything about network-format data. The rest of the BIND system
+ * is not careful about this, but for some reason, we're doing it right here.
+ */
+#define PERIOD 0x2e
+#define hyphenchar(c) ((c) == 0x2d)
+#define bslashchar(c) ((c) == 0x5c)
+#define periodchar(c) ((c) == PERIOD)
+#define asterchar(c) ((c) == 0x2a)
+#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
+ || ((c) >= 0x61 && (c) <= 0x7a))
+#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
+
+#define borderchar(c) (alphachar(c) || digitchar(c))
+#define middlechar(c) (borderchar(c) || hyphenchar(c))
+#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
+
+int
+res_hnok(const char *dn) {
+ int pch = PERIOD, ch = *dn++;
+
+ while (ch != '\0') {
+ int nch = *dn++;
+
+ if (periodchar(ch)) {
+ (void)NULL;
+ } else if (periodchar(pch)) {
+ if (!borderchar(ch))
+ return (0);
+ } else if (periodchar(nch) || nch == '\0') {
+ if (!borderchar(ch))
+ return (0);
+ } else {
+ if (!middlechar(ch))
+ return (0);
+ }
+ pch = ch, ch = nch;
+ }
+ return (1);
+}
+
+/*%
+ * hostname-like (A, MX, WKS) owners can have "*" as their first label
+ * but must otherwise be as a host name.
+ */
+int
+res_ownok(const char *dn) {
+ if (asterchar(dn[0])) {
+ if (periodchar(dn[1]))
+ return (res_hnok(dn+2));
+ if (dn[1] == '\0')
+ return (1);
+ }
+ return (res_hnok(dn));
+}
+
+/*%
+ * SOA RNAMEs and RP RNAMEs can have any printable character in their first
+ * label, but the rest of the name has to look like a host name.
+ */
+int
+res_mailok(const char *dn) {
+ int ch, escaped = 0;
+
+ /* "." is a valid missing representation */
+ if (*dn == '\0')
+ return (1);
+
+ /* otherwise <label>.<hostname> */
+ while ((ch = *dn++) != '\0') {
+ if (!domainchar(ch))
+ return (0);
+ if (!escaped && periodchar(ch))
+ break;
+ if (escaped)
+ escaped = 0;
+ else if (bslashchar(ch))
+ escaped = 1;
+ }
+ if (periodchar(ch))
+ return (res_hnok(dn));
+ return (0);
+}
+
+/*%
+ * This function is quite liberal, since RFC1034's character sets are only
+ * recommendations.
+ */
+int
+res_dnok(const char *dn) {
+ int ch;
+
+ while ((ch = *dn++) != '\0')
+ if (!domainchar(ch))
+ return (0);
+ return (1);
+}
+
+#ifdef BIND_4_COMPAT
+/*%
+ * This module must export the following externally-visible symbols:
+ * ___putlong
+ * ___putshort
+ * __getlong
+ * __getshort
+ * Note that one _ comes from C and the others come from us.
+ */
+
+#ifdef SOLARIS2
+#ifdef __putlong
+#undef __putlong
+#endif
+#ifdef __putshort
+#undef __putshort
+#endif
+#pragma weak putlong = __putlong
+#pragma weak putshort = __putshort
+#endif /* SOLARIS2 */
+
+void __putlong(u_int32_t src, u_char *dst) { ns_put32(src, dst); }
+void __putshort(u_int16_t src, u_char *dst) { ns_put16(src, dst); }
+#ifndef __ultrix__
+u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); }
+u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); }
+#endif /*__ultrix__*/
+#endif /*BIND_4_COMPAT*/
+
+/*! \file */
diff --git a/lib/bind/resolv/res_data.c b/lib/bind/resolv/res_data.c
new file mode 100644
index 0000000..736315c
--- /dev/null
+++ b/lib/bind/resolv/res_data.c
@@ -0,0 +1,297 @@
+/*
+ * 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 const char rcsid[] = "$Id: res_data.c,v 1.3.18.2 2007/09/14 05:35:47 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <res_update.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+const char *_res_opcodes[] = {
+ "QUERY",
+ "IQUERY",
+ "CQUERYM",
+ "CQUERYU", /*%< experimental */
+ "NOTIFY", /*%< experimental */
+ "UPDATE",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "ZONEINIT",
+ "ZONEREF",
+};
+
+#ifdef BIND_UPDATE
+const char *_res_sectioncodes[] = {
+ "ZONE",
+ "PREREQUISITES",
+ "UPDATE",
+ "ADDITIONAL",
+};
+#endif
+
+#undef _res
+#ifndef __BIND_NOSTATIC
+struct __res_state _res
+# if defined(__BIND_RES_TEXT)
+ = { RES_TIMEOUT, } /*%< Motorola, et al. */
+# endif
+ ;
+
+#if defined(DO_PTHREADS) || defined(__linux)
+#define _res (*__res_state())
+#endif
+
+/* Proto. */
+
+int res_ourserver_p(const res_state, const struct sockaddr_in *);
+
+int
+res_init(void) {
+ extern int __res_vinit(res_state, int);
+
+ /*
+ * These three fields used to be statically initialized. This made
+ * it hard to use this code in a shared library. It is necessary,
+ * now that we're doing dynamic initialization here, that we preserve
+ * the old semantics: if an application modifies one of these three
+ * fields of _res before res_init() is called, res_init() will not
+ * alter them. Of course, if an application is setting them to
+ * _zero_ before calling res_init(), hoping to override what used
+ * to be the static default, we can't detect it and unexpected results
+ * will follow. Zero for any of these fields would make no sense,
+ * so one can safely assume that the applications were already getting
+ * unexpected results.
+ *
+ * _res.options is tricky since some apps were known to diddle the bits
+ * before res_init() was first called. We can't replicate that semantic
+ * with dynamic initialization (they may have turned bits off that are
+ * set in RES_DEFAULT). Our solution is to declare such applications
+ * "broken". They could fool us by setting RES_INIT but none do (yet).
+ */
+ if (!_res.retrans)
+ _res.retrans = RES_TIMEOUT;
+ if (!_res.retry)
+ _res.retry = 4;
+ if (!(_res.options & RES_INIT))
+ _res.options = RES_DEFAULT;
+
+ /*
+ * This one used to initialize implicitly to zero, so unless the app
+ * has set it to something in particular, we can randomize it now.
+ */
+ if (!_res.id)
+ _res.id = res_randomid();
+
+ return (__res_vinit(&_res, 1));
+}
+
+void
+p_query(const u_char *msg) {
+ fp_query(msg, stdout);
+}
+
+void
+fp_query(const u_char *msg, FILE *file) {
+ fp_nquery(msg, PACKETSZ, file);
+}
+
+void
+fp_nquery(const u_char *msg, int len, FILE *file) {
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1)
+ return;
+
+ res_pquery(&_res, msg, len, file);
+}
+
+int
+res_mkquery(int op, /*!< opcode of query */
+ const char *dname, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ const u_char *data, /*!< resource record data */
+ int datalen, /*!< length of data */
+ const u_char *newrr_in, /*!< new rr for modify or append */
+ u_char *buf, /*!< buffer to put query */
+ int buflen) /*!< size of buffer */
+{
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+ return (res_nmkquery(&_res, op, dname, class, type,
+ data, datalen,
+ newrr_in, buf, buflen));
+}
+
+int
+res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nmkupdate(&_res, rrecp_in, buf, buflen));
+}
+
+int
+res_query(const char *name, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ u_char *answer, /*!< buffer to put answer */
+ int anslen) /*!< size of answer buffer */
+{
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+ return (res_nquery(&_res, name, class, type, answer, anslen));
+}
+
+void
+res_send_setqhook(res_send_qhook hook) {
+ _res.qhook = hook;
+}
+
+void
+res_send_setrhook(res_send_rhook hook) {
+ _res.rhook = hook;
+}
+
+int
+res_isourserver(const struct sockaddr_in *inp) {
+ return (res_ourserver_p(&_res, inp));
+}
+
+int
+res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ /* errno should have been set by res_init() in this case. */
+ return (-1);
+ }
+
+ return (res_nsend(&_res, buf, buflen, ans, anssiz));
+}
+
+int
+res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
+ u_char *ans, int anssiz)
+{
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ /* errno should have been set by res_init() in this case. */
+ return (-1);
+ }
+
+ return (res_nsendsigned(&_res, buf, buflen, key, ans, anssiz));
+}
+
+void
+res_close(void) {
+ res_nclose(&_res);
+}
+
+int
+res_update(ns_updrec *rrecp_in) {
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nupdate(&_res, rrecp_in, NULL));
+}
+
+int
+res_search(const char *name, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ u_char *answer, /*!< buffer to put answer */
+ int anslen) /*!< size of answer */
+{
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nsearch(&_res, name, class, type, answer, anslen));
+}
+
+int
+res_querydomain(const char *name,
+ const char *domain,
+ int class, int type, /*!< class and type of query */
+ u_char *answer, /*!< buffer to put answer */
+ int anslen) /*!< size of answer */
+{
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nquerydomain(&_res, name, domain,
+ class, type,
+ answer, anslen));
+}
+
+const char *
+hostalias(const char *name) {
+ static char abuf[MAXDNAME];
+
+ return (res_hostalias(&_res, name, abuf, sizeof abuf));
+}
+
+#ifdef ultrix
+int
+local_hostname_length(const char *hostname) {
+ int len_host, len_domain;
+
+ if (!*_res.defdname)
+ res_init();
+ len_host = strlen(hostname);
+ len_domain = strlen(_res.defdname);
+ if (len_host > len_domain &&
+ !strcasecmp(hostname + len_host - len_domain, _res.defdname) &&
+ hostname[len_host - len_domain - 1] == '.')
+ return (len_host - len_domain - 1);
+ return (0);
+}
+#endif /*ultrix*/
+
+#endif
+
+/*! \file */
diff --git a/lib/bind/resolv/res_debug.c b/lib/bind/resolv/res_debug.c
new file mode 100644
index 0000000..2ed234e
--- /dev/null
+++ b/lib/bind/resolv/res_debug.c
@@ -0,0 +1,1165 @@
+/*
+ * Copyright (c) 1985
+ * 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 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.
+ */
+
+/*
+ * 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_debug.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_debug.c,v 1.10.18.5 2005/07/28 07:38:11 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <resolv_mt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+extern const char *_res_opcodes[];
+extern const char *_res_sectioncodes[];
+
+/*%
+ * Print the current options.
+ */
+void
+fp_resstat(const res_state statp, FILE *file) {
+ u_long mask;
+
+ fprintf(file, ";; res options:");
+ for (mask = 1; mask != 0U; mask <<= 1)
+ if (statp->options & mask)
+ fprintf(file, " %s", p_option(mask));
+ putc('\n', file);
+}
+
+static void
+do_section(const res_state statp,
+ ns_msg *handle, ns_sect section,
+ int pflag, FILE *file)
+{
+ int n, sflag, rrnum;
+ static int buflen = 2048;
+ char *buf;
+ ns_opcode opcode;
+ ns_rr rr;
+
+ /*
+ * Print answer records.
+ */
+ sflag = (statp->pfcode & pflag);
+ if (statp->pfcode && !sflag)
+ return;
+
+ buf = malloc(buflen);
+ if (buf == NULL) {
+ fprintf(file, ";; memory allocation failure\n");
+ return;
+ }
+
+ opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode);
+ rrnum = 0;
+ for (;;) {
+ if (ns_parserr(handle, section, rrnum, &rr)) {
+ if (errno != ENODEV)
+ fprintf(file, ";; ns_parserr: %s\n",
+ strerror(errno));
+ else if (rrnum > 0 && sflag != 0 &&
+ (statp->pfcode & RES_PRF_HEAD1))
+ putc('\n', file);
+ goto cleanup;
+ }
+ if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1))
+ fprintf(file, ";; %s SECTION:\n",
+ p_section(section, opcode));
+ if (section == ns_s_qd)
+ fprintf(file, ";;\t%s, type = %s, class = %s\n",
+ ns_rr_name(rr),
+ p_type(ns_rr_type(rr)),
+ p_class(ns_rr_class(rr)));
+ else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) {
+ u_int32_t ttl = ns_rr_ttl(rr);
+ fprintf(file,
+ "; EDNS: version: %u, udp=%u, flags=%04x\n",
+ (ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff);
+ } else {
+ n = ns_sprintrr(handle, &rr, NULL, NULL,
+ buf, buflen);
+ if (n < 0) {
+ if (errno == ENOSPC) {
+ free(buf);
+ buf = NULL;
+ if (buflen < 131072)
+ buf = malloc(buflen += 1024);
+ if (buf == NULL) {
+ fprintf(file,
+ ";; memory allocation failure\n");
+ return;
+ }
+ continue;
+ }
+ fprintf(file, ";; ns_sprintrr: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+ fputs(buf, file);
+ fputc('\n', file);
+ }
+ rrnum++;
+ }
+ cleanup:
+ if (buf != NULL)
+ free(buf);
+}
+
+/*%
+ * Print the contents of a query.
+ * This is intended to be primarily a debugging routine.
+ */
+void
+res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
+ ns_msg handle;
+ int qdcount, ancount, nscount, arcount;
+ u_int opcode, rcode, id;
+
+ if (ns_initparse(msg, len, &handle) < 0) {
+ fprintf(file, ";; ns_initparse: %s\n", strerror(errno));
+ return;
+ }
+ opcode = ns_msg_getflag(handle, ns_f_opcode);
+ rcode = ns_msg_getflag(handle, ns_f_rcode);
+ id = ns_msg_id(handle);
+ qdcount = ns_msg_count(handle, ns_s_qd);
+ ancount = ns_msg_count(handle, ns_s_an);
+ nscount = ns_msg_count(handle, ns_s_ns);
+ arcount = ns_msg_count(handle, ns_s_ar);
+
+ /*
+ * Print header fields.
+ */
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX) || rcode)
+ fprintf(file,
+ ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n",
+ _res_opcodes[opcode], p_rcode(rcode), id);
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX))
+ putc(';', file);
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD2)) {
+ fprintf(file, "; flags:");
+ if (ns_msg_getflag(handle, ns_f_qr))
+ fprintf(file, " qr");
+ if (ns_msg_getflag(handle, ns_f_aa))
+ fprintf(file, " aa");
+ if (ns_msg_getflag(handle, ns_f_tc))
+ fprintf(file, " tc");
+ if (ns_msg_getflag(handle, ns_f_rd))
+ fprintf(file, " rd");
+ if (ns_msg_getflag(handle, ns_f_ra))
+ fprintf(file, " ra");
+ if (ns_msg_getflag(handle, ns_f_z))
+ fprintf(file, " ??");
+ if (ns_msg_getflag(handle, ns_f_ad))
+ fprintf(file, " ad");
+ if (ns_msg_getflag(handle, ns_f_cd))
+ fprintf(file, " cd");
+ }
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD1)) {
+ fprintf(file, "; %s: %d",
+ p_section(ns_s_qd, opcode), qdcount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_an, opcode), ancount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_ns, opcode), nscount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_ar, opcode), arcount);
+ }
+ if ((!statp->pfcode) || (statp->pfcode &
+ (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
+ putc('\n',file);
+ }
+ /*
+ * Print the various sections.
+ */
+ do_section(statp, &handle, ns_s_qd, RES_PRF_QUES, file);
+ do_section(statp, &handle, ns_s_an, RES_PRF_ANS, file);
+ do_section(statp, &handle, ns_s_ns, RES_PRF_AUTH, file);
+ do_section(statp, &handle, ns_s_ar, RES_PRF_ADD, file);
+ if (qdcount == 0 && ancount == 0 &&
+ nscount == 0 && arcount == 0)
+ putc('\n', file);
+}
+
+const u_char *
+p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) {
+ char name[MAXDNAME];
+ int n;
+
+ if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
+ return (NULL);
+ if (name[0] == '\0')
+ putc('.', file);
+ else
+ fputs(name, file);
+ return (cp + n);
+}
+
+const u_char *
+p_cdname(const u_char *cp, const u_char *msg, FILE *file) {
+ return (p_cdnname(cp, msg, PACKETSZ, file));
+}
+
+/*%
+ * Return a fully-qualified domain name from a compressed name (with
+ length supplied). */
+
+const u_char *
+p_fqnname(cp, msg, msglen, name, namelen)
+ const u_char *cp, *msg;
+ int msglen;
+ char *name;
+ int namelen;
+{
+ int n, newlen;
+
+ if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
+ return (NULL);
+ newlen = strlen(name);
+ if (newlen == 0 || name[newlen - 1] != '.') {
+ if (newlen + 1 >= namelen) /*%< Lack space for final dot */
+ return (NULL);
+ else
+ strcpy(name + newlen, ".");
+ }
+ return (cp + n);
+}
+
+/* XXX: the rest of these functions need to become length-limited, too. */
+
+const u_char *
+p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
+ char name[MAXDNAME];
+ const u_char *n;
+
+ n = p_fqnname(cp, msg, MAXCDNAME, name, sizeof name);
+ if (n == NULL)
+ return (NULL);
+ fputs(name, file);
+ return (n);
+}
+
+/*%
+ * Names of RR classes and qclasses. Classes and qclasses are the same, except
+ * that C_ANY is a qclass but not a class. (You can ask for records of class
+ * C_ANY, but you can't have any records of that class in the database.)
+ */
+const struct res_sym __p_class_syms[] = {
+ {C_IN, "IN", (char *)0},
+ {C_CHAOS, "CH", (char *)0},
+ {C_CHAOS, "CHAOS", (char *)0},
+ {C_HS, "HS", (char *)0},
+ {C_HS, "HESIOD", (char *)0},
+ {C_ANY, "ANY", (char *)0},
+ {C_NONE, "NONE", (char *)0},
+ {C_IN, (char *)0, (char *)0}
+};
+
+/*%
+ * Names of message sections.
+ */
+const struct res_sym __p_default_section_syms[] = {
+ {ns_s_qd, "QUERY", (char *)0},
+ {ns_s_an, "ANSWER", (char *)0},
+ {ns_s_ns, "AUTHORITY", (char *)0},
+ {ns_s_ar, "ADDITIONAL", (char *)0},
+ {0, (char *)0, (char *)0}
+};
+
+const struct res_sym __p_update_section_syms[] = {
+ {S_ZONE, "ZONE", (char *)0},
+ {S_PREREQ, "PREREQUISITE", (char *)0},
+ {S_UPDATE, "UPDATE", (char *)0},
+ {S_ADDT, "ADDITIONAL", (char *)0},
+ {0, (char *)0, (char *)0}
+};
+
+const struct res_sym __p_key_syms[] = {
+ {NS_ALG_MD5RSA, "RSA", "RSA KEY with MD5 hash"},
+ {NS_ALG_DH, "DH", "Diffie Hellman"},
+ {NS_ALG_DSA, "DSA", "Digital Signature Algorithm"},
+ {NS_ALG_EXPIRE_ONLY, "EXPIREONLY", "No algorithm"},
+ {NS_ALG_PRIVATE_OID, "PRIVATE", "Algorithm obtained from OID"},
+ {0, NULL, NULL}
+};
+
+const struct res_sym __p_cert_syms[] = {
+ {cert_t_pkix, "PKIX", "PKIX (X.509v3) Certificate"},
+ {cert_t_spki, "SPKI", "SPKI certificate"},
+ {cert_t_pgp, "PGP", "PGP certificate"},
+ {cert_t_url, "URL", "URL Private"},
+ {cert_t_oid, "OID", "OID Private"},
+ {0, NULL, NULL}
+};
+
+/*%
+ * Names of RR types and qtypes. Types and qtypes are the same, except
+ * that T_ANY is a qtype but not a type. (You can ask for records of type
+ * T_ANY, but you can't have any records of that type in the database.)
+ */
+const struct res_sym __p_type_syms[] = {
+ {ns_t_a, "A", "address"},
+ {ns_t_ns, "NS", "name server"},
+ {ns_t_md, "MD", "mail destination (deprecated)"},
+ {ns_t_mf, "MF", "mail forwarder (deprecated)"},
+ {ns_t_cname, "CNAME", "canonical name"},
+ {ns_t_soa, "SOA", "start of authority"},
+ {ns_t_mb, "MB", "mailbox"},
+ {ns_t_mg, "MG", "mail group member"},
+ {ns_t_mr, "MR", "mail rename"},
+ {ns_t_null, "NULL", "null"},
+ {ns_t_wks, "WKS", "well-known service (deprecated)"},
+ {ns_t_ptr, "PTR", "domain name pointer"},
+ {ns_t_hinfo, "HINFO", "host information"},
+ {ns_t_minfo, "MINFO", "mailbox information"},
+ {ns_t_mx, "MX", "mail exchanger"},
+ {ns_t_txt, "TXT", "text"},
+ {ns_t_rp, "RP", "responsible person"},
+ {ns_t_afsdb, "AFSDB", "DCE or AFS server"},
+ {ns_t_x25, "X25", "X25 address"},
+ {ns_t_isdn, "ISDN", "ISDN address"},
+ {ns_t_rt, "RT", "router"},
+ {ns_t_nsap, "NSAP", "nsap address"},
+ {ns_t_nsap_ptr, "NSAP_PTR", "domain name pointer"},
+ {ns_t_sig, "SIG", "signature"},
+ {ns_t_key, "KEY", "key"},
+ {ns_t_px, "PX", "mapping information"},
+ {ns_t_gpos, "GPOS", "geographical position (withdrawn)"},
+ {ns_t_aaaa, "AAAA", "IPv6 address"},
+ {ns_t_loc, "LOC", "location"},
+ {ns_t_nxt, "NXT", "next valid name (unimplemented)"},
+ {ns_t_eid, "EID", "endpoint identifier (unimplemented)"},
+ {ns_t_nimloc, "NIMLOC", "NIMROD locator (unimplemented)"},
+ {ns_t_srv, "SRV", "server selection"},
+ {ns_t_atma, "ATMA", "ATM address (unimplemented)"},
+ {ns_t_tkey, "TKEY", "tkey"},
+ {ns_t_tsig, "TSIG", "transaction signature"},
+ {ns_t_ixfr, "IXFR", "incremental zone transfer"},
+ {ns_t_axfr, "AXFR", "zone transfer"},
+ {ns_t_zxfr, "ZXFR", "compressed zone transfer"},
+ {ns_t_mailb, "MAILB", "mailbox-related data (deprecated)"},
+ {ns_t_maila, "MAILA", "mail agent (deprecated)"},
+ {ns_t_naptr, "NAPTR", "URN Naming Authority"},
+ {ns_t_kx, "KX", "Key Exchange"},
+ {ns_t_cert, "CERT", "Certificate"},
+ {ns_t_a6, "A6", "IPv6 Address"},
+ {ns_t_dname, "DNAME", "dname"},
+ {ns_t_sink, "SINK", "Kitchen Sink (experimental)"},
+ {ns_t_opt, "OPT", "EDNS Options"},
+ {ns_t_any, "ANY", "\"any\""},
+ {0, NULL, NULL}
+};
+
+/*%
+ * Names of DNS rcodes.
+ */
+const struct res_sym __p_rcode_syms[] = {
+ {ns_r_noerror, "NOERROR", "no error"},
+ {ns_r_formerr, "FORMERR", "format error"},
+ {ns_r_servfail, "SERVFAIL", "server failed"},
+ {ns_r_nxdomain, "NXDOMAIN", "no such domain name"},
+ {ns_r_notimpl, "NOTIMP", "not implemented"},
+ {ns_r_refused, "REFUSED", "refused"},
+ {ns_r_yxdomain, "YXDOMAIN", "domain name exists"},
+ {ns_r_yxrrset, "YXRRSET", "rrset exists"},
+ {ns_r_nxrrset, "NXRRSET", "rrset doesn't exist"},
+ {ns_r_notauth, "NOTAUTH", "not authoritative"},
+ {ns_r_notzone, "NOTZONE", "Not in zone"},
+ {ns_r_max, "", ""},
+ {ns_r_badsig, "BADSIG", "bad signature"},
+ {ns_r_badkey, "BADKEY", "bad key"},
+ {ns_r_badtime, "BADTIME", "bad time"},
+ {0, NULL, NULL}
+};
+
+int
+sym_ston(const struct res_sym *syms, const char *name, int *success) {
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (strcasecmp (name, syms->name) == 0) {
+ if (success)
+ *success = 1;
+ return (syms->number);
+ }
+ }
+ if (success)
+ *success = 0;
+ return (syms->number); /*%< The default value. */
+}
+
+const char *
+sym_ntos(const struct res_sym *syms, int number, int *success) {
+ char *unname = sym_ntos_unname;
+
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (number == syms->number) {
+ if (success)
+ *success = 1;
+ return (syms->name);
+ }
+ }
+
+ sprintf(unname, "%d", number); /*%< XXX nonreentrant */
+ if (success)
+ *success = 0;
+ return (unname);
+}
+
+const char *
+sym_ntop(const struct res_sym *syms, int number, int *success) {
+ char *unname = sym_ntop_unname;
+
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (number == syms->number) {
+ if (success)
+ *success = 1;
+ return (syms->humanname);
+ }
+ }
+ sprintf(unname, "%d", number); /*%< XXX nonreentrant */
+ if (success)
+ *success = 0;
+ return (unname);
+}
+
+/*%
+ * Return a string for the type.
+ */
+const char *
+p_type(int type) {
+ int success;
+ const char *result;
+ static char typebuf[20];
+
+ result = sym_ntos(__p_type_syms, type, &success);
+ if (success)
+ return (result);
+ if (type < 0 || type > 0xffff)
+ return ("BADTYPE");
+ sprintf(typebuf, "TYPE%d", type);
+ return (typebuf);
+}
+
+/*%
+ * Return a string for the type.
+ */
+const char *
+p_section(int section, int opcode) {
+ const struct res_sym *symbols;
+
+ switch (opcode) {
+ case ns_o_update:
+ symbols = __p_update_section_syms;
+ break;
+ default:
+ symbols = __p_default_section_syms;
+ break;
+ }
+ return (sym_ntos(symbols, section, (int *)0));
+}
+
+/*%
+ * Return a mnemonic for class.
+ */
+const char *
+p_class(int class) {
+ int success;
+ const char *result;
+ static char classbuf[20];
+
+ result = sym_ntos(__p_class_syms, class, &success);
+ if (success)
+ return (result);
+ if (class < 0 || class > 0xffff)
+ return ("BADCLASS");
+ sprintf(classbuf, "CLASS%d", class);
+ return (classbuf);
+}
+
+/*%
+ * Return a mnemonic for an option
+ */
+const char *
+p_option(u_long option) {
+ char *nbuf = p_option_nbuf;
+
+ switch (option) {
+ case RES_INIT: return "init";
+ case RES_DEBUG: return "debug";
+ case RES_AAONLY: return "aaonly(unimpl)";
+ case RES_USEVC: return "usevc";
+ case RES_PRIMARY: return "primry(unimpl)";
+ case RES_IGNTC: return "igntc";
+ case RES_RECURSE: return "recurs";
+ case RES_DEFNAMES: return "defnam";
+ case RES_STAYOPEN: return "styopn";
+ case RES_DNSRCH: return "dnsrch";
+ case RES_INSECURE1: return "insecure1";
+ case RES_INSECURE2: return "insecure2";
+ case RES_NOALIASES: return "noaliases";
+ case RES_USE_INET6: return "inet6";
+#ifdef RES_USE_EDNS0 /*%< KAME extension */
+ case RES_USE_EDNS0: return "edns0";
+#endif
+#ifdef RES_USE_DNAME
+ case RES_USE_DNAME: return "dname";
+#endif
+#ifdef RES_USE_DNSSEC
+ case RES_USE_DNSSEC: return "dnssec";
+#endif
+#ifdef RES_NOTLDQUERY
+ case RES_NOTLDQUERY: return "no-tld-query";
+#endif
+#ifdef RES_NO_NIBBLE2
+ case RES_NO_NIBBLE2: return "no-nibble2";
+#endif
+ /* XXX nonreentrant */
+ default: sprintf(nbuf, "?0x%lx?", (u_long)option);
+ return (nbuf);
+ }
+}
+
+/*%
+ * Return a mnemonic for a time to live.
+ */
+const char *
+p_time(u_int32_t value) {
+ char *nbuf = p_time_nbuf;
+
+ if (ns_format_ttl(value, nbuf, sizeof nbuf) < 0)
+ sprintf(nbuf, "%u", value);
+ return (nbuf);
+}
+
+/*%
+ * Return a string for the rcode.
+ */
+const char *
+p_rcode(int rcode) {
+ return (sym_ntos(__p_rcode_syms, rcode, (int *)0));
+}
+
+/*%
+ * Return a string for a res_sockaddr_union.
+ */
+const char *
+p_sockun(union res_sockaddr_union u, char *buf, size_t size) {
+ char ret[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:123.123.123.123"];
+
+ switch (u.sin.sin_family) {
+ case AF_INET:
+ inet_ntop(AF_INET, &u.sin.sin_addr, ret, sizeof ret);
+ break;
+#ifdef HAS_INET6_STRUCTS
+ case AF_INET6:
+ inet_ntop(AF_INET6, &u.sin6.sin6_addr, ret, sizeof ret);
+ break;
+#endif
+ default:
+ sprintf(ret, "[af%d]", u.sin.sin_family);
+ break;
+ }
+ if (size > 0U) {
+ strncpy(buf, ret, size - 1);
+ buf[size - 1] = '0';
+ }
+ return (buf);
+}
+
+/*%
+ * routines to convert between on-the-wire RR format and zone file format.
+ * Does not contain conversion to/from decimal degrees; divide or multiply
+ * by 60*60*1000 for that.
+ */
+
+static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
+ 1000000,10000000,100000000,1000000000};
+
+/*% takes an XeY precision/size value, returns a string representation. */
+static const char *
+precsize_ntoa(prec)
+ u_int8_t prec;
+{
+ char *retbuf = precsize_ntoa_retbuf;
+ unsigned long val;
+ int mantissa, exponent;
+
+ mantissa = (int)((prec >> 4) & 0x0f) % 10;
+ exponent = (int)((prec >> 0) & 0x0f) % 10;
+
+ val = mantissa * poweroften[exponent];
+
+ (void) sprintf(retbuf, "%lu.%.2lu", val/100, val%100);
+ return (retbuf);
+}
+
+/*% converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer. */
+static u_int8_t
+precsize_aton(const char **strptr) {
+ unsigned int mval = 0, cmval = 0;
+ u_int8_t retval = 0;
+ const char *cp;
+ int exponent;
+ int mantissa;
+
+ cp = *strptr;
+
+ while (isdigit((unsigned char)*cp))
+ mval = mval * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /*%< centimeters */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ cmval = (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ cmval += (*cp++ - '0');
+ }
+ }
+ }
+ cmval = (mval * 100) + cmval;
+
+ for (exponent = 0; exponent < 9; exponent++)
+ if (cmval < poweroften[exponent+1])
+ break;
+
+ mantissa = cmval / poweroften[exponent];
+ if (mantissa > 9)
+ mantissa = 9;
+
+ retval = (mantissa << 4) | exponent;
+
+ *strptr = cp;
+
+ return (retval);
+}
+
+/*% converts ascii lat/lon to unsigned encoded 32-bit number. moves pointer. */
+static u_int32_t
+latlon2ul(const char **latlonstrptr, int *which) {
+ const char *cp;
+ u_int32_t retval;
+ int deg = 0, min = 0, secs = 0, secsfrac = 0;
+
+ cp = *latlonstrptr;
+
+ while (isdigit((unsigned char)*cp))
+ deg = deg * 10 + (*cp++ - '0');
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ if (!(isdigit((unsigned char)*cp)))
+ goto fndhemi;
+
+ while (isdigit((unsigned char)*cp))
+ min = min * 10 + (*cp++ - '0');
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ if (!(isdigit((unsigned char)*cp)))
+ goto fndhemi;
+
+ while (isdigit((unsigned char)*cp))
+ secs = secs * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /*%< decimal seconds */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac = (*cp++ - '0') * 100;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac += (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac += (*cp++ - '0');
+ }
+ }
+ }
+ }
+
+ while (!isspace((unsigned char)*cp)) /*%< if any trailing garbage */
+ cp++;
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ fndhemi:
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'E': case 'e':
+ retval = ((unsigned)1<<31)
+ + (((((deg * 60) + min) * 60) + secs) * 1000)
+ + secsfrac;
+ break;
+ case 'S': case 's':
+ case 'W': case 'w':
+ retval = ((unsigned)1<<31)
+ - (((((deg * 60) + min) * 60) + secs) * 1000)
+ - secsfrac;
+ break;
+ default:
+ retval = 0; /*%< invalid value -- indicates error */
+ break;
+ }
+
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'S': case 's':
+ *which = 1; /*%< latitude */
+ break;
+ case 'E': case 'e':
+ case 'W': case 'w':
+ *which = 2; /*%< longitude */
+ break;
+ default:
+ *which = 0; /*%< error */
+ break;
+ }
+
+ cp++; /*%< skip the hemisphere */
+ while (!isspace((unsigned char)*cp)) /*%< if any trailing garbage */
+ cp++;
+
+ while (isspace((unsigned char)*cp)) /*%< move to next field */
+ cp++;
+
+ *latlonstrptr = cp;
+
+ return (retval);
+}
+
+/*%
+ * converts a zone file representation in a string to an RDATA on-the-wire
+ * representation. */
+int
+loc_aton(ascii, binary)
+ const char *ascii;
+ u_char *binary;
+{
+ const char *cp, *maxcp;
+ u_char *bcp;
+
+ u_int32_t latit = 0, longit = 0, alt = 0;
+ u_int32_t lltemp1 = 0, lltemp2 = 0;
+ int altmeters = 0, altfrac = 0, altsign = 1;
+ u_int8_t hp = 0x16; /*%< default = 1e6 cm = 10000.00m = 10km */
+ u_int8_t vp = 0x13; /*%< default = 1e3 cm = 10.00m */
+ u_int8_t siz = 0x12; /*%< default = 1e2 cm = 1.00m */
+ int which1 = 0, which2 = 0;
+
+ cp = ascii;
+ maxcp = cp + strlen(ascii);
+
+ lltemp1 = latlon2ul(&cp, &which1);
+
+ lltemp2 = latlon2ul(&cp, &which2);
+
+ switch (which1 + which2) {
+ case 3: /*%< 1 + 2, the only valid combination */
+ if ((which1 == 1) && (which2 == 2)) { /*%< normal case */
+ latit = lltemp1;
+ longit = lltemp2;
+ } else if ((which1 == 2) && (which2 == 1)) { /*%< reversed */
+ longit = lltemp1;
+ latit = lltemp2;
+ } else { /*%< some kind of brokenness */
+ return (0);
+ }
+ break;
+ default: /*%< we didn't get one of each */
+ return (0);
+ }
+
+ /* altitude */
+ if (*cp == '-') {
+ altsign = -1;
+ cp++;
+ }
+
+ if (*cp == '+')
+ cp++;
+
+ while (isdigit((unsigned char)*cp))
+ altmeters = altmeters * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /*%< decimal meters */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ altfrac = (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ altfrac += (*cp++ - '0');
+ }
+ }
+ }
+
+ alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ siz = precsize_aton(&cp);
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ hp = precsize_aton(&cp);
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ vp = precsize_aton(&cp);
+
+ defaults:
+
+ bcp = binary;
+ *bcp++ = (u_int8_t) 0; /*%< version byte */
+ *bcp++ = siz;
+ *bcp++ = hp;
+ *bcp++ = vp;
+ PUTLONG(latit,bcp);
+ PUTLONG(longit,bcp);
+ PUTLONG(alt,bcp);
+
+ return (16); /*%< size of RR in octets */
+}
+
+/*% takes an on-the-wire LOC RR and formats it in a human readable format. */
+const char *
+loc_ntoa(binary, ascii)
+ const u_char *binary;
+ char *ascii;
+{
+ static const char *error = "?";
+ static char tmpbuf[sizeof
+"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
+ const u_char *cp = binary;
+
+ int latdeg, latmin, latsec, latsecfrac;
+ int longdeg, longmin, longsec, longsecfrac;
+ char northsouth, eastwest;
+ const char *altsign;
+ int altmeters, altfrac;
+
+ const u_int32_t referencealt = 100000 * 100;
+
+ int32_t latval, longval, altval;
+ u_int32_t templ;
+ u_int8_t sizeval, hpval, vpval, versionval;
+
+ char *sizestr, *hpstr, *vpstr;
+
+ versionval = *cp++;
+
+ if (ascii == NULL)
+ ascii = tmpbuf;
+
+ if (versionval) {
+ (void) sprintf(ascii, "; error: unknown LOC RR version");
+ return (ascii);
+ }
+
+ sizeval = *cp++;
+
+ hpval = *cp++;
+ vpval = *cp++;
+
+ GETLONG(templ, cp);
+ latval = (templ - ((unsigned)1<<31));
+
+ GETLONG(templ, cp);
+ longval = (templ - ((unsigned)1<<31));
+
+ GETLONG(templ, cp);
+ if (templ < referencealt) { /*%< below WGS 84 spheroid */
+ altval = referencealt - templ;
+ altsign = "-";
+ } else {
+ altval = templ - referencealt;
+ altsign = "";
+ }
+
+ if (latval < 0) {
+ northsouth = 'S';
+ latval = -latval;
+ } else
+ northsouth = 'N';
+
+ latsecfrac = latval % 1000;
+ latval = latval / 1000;
+ latsec = latval % 60;
+ latval = latval / 60;
+ latmin = latval % 60;
+ latval = latval / 60;
+ latdeg = latval;
+
+ if (longval < 0) {
+ eastwest = 'W';
+ longval = -longval;
+ } else
+ eastwest = 'E';
+
+ longsecfrac = longval % 1000;
+ longval = longval / 1000;
+ longsec = longval % 60;
+ longval = longval / 60;
+ longmin = longval % 60;
+ longval = longval / 60;
+ longdeg = longval;
+
+ altfrac = altval % 100;
+ altmeters = (altval / 100);
+
+ sizestr = strdup(precsize_ntoa(sizeval));
+ hpstr = strdup(precsize_ntoa(hpval));
+ vpstr = strdup(precsize_ntoa(vpval));
+
+ sprintf(ascii,
+ "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %s%d.%.2dm %sm %sm %sm",
+ latdeg, latmin, latsec, latsecfrac, northsouth,
+ longdeg, longmin, longsec, longsecfrac, eastwest,
+ altsign, altmeters, altfrac,
+ (sizestr != NULL) ? sizestr : error,
+ (hpstr != NULL) ? hpstr : error,
+ (vpstr != NULL) ? vpstr : error);
+
+ if (sizestr != NULL)
+ free(sizestr);
+ if (hpstr != NULL)
+ free(hpstr);
+ if (vpstr != NULL)
+ free(vpstr);
+
+ return (ascii);
+}
+
+
+/*% Return the number of DNS hierarchy levels in the name. */
+int
+dn_count_labels(const char *name) {
+ int i, len, count;
+
+ len = strlen(name);
+ for (i = 0, count = 0; i < len; i++) {
+ /* XXX need to check for \. or use named's nlabels(). */
+ if (name[i] == '.')
+ count++;
+ }
+
+ /* don't count initial wildcard */
+ if (name[0] == '*')
+ if (count)
+ count--;
+
+ /* don't count the null label for root. */
+ /* if terminating '.' not found, must adjust */
+ /* count to include last label */
+ if (len > 0 && name[len-1] != '.')
+ count++;
+ return (count);
+}
+
+/*%
+ * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
+ * SIG records are required to be printed like this, by the Secure DNS RFC.
+ */
+char *
+p_secstodate (u_long secs) {
+ char *output = p_secstodate_output;
+ time_t clock = secs;
+ struct tm *time;
+#ifdef HAVE_TIME_R
+ struct tm res;
+
+ time = gmtime_r(&clock, &res);
+#else
+ time = gmtime(&clock);
+#endif
+ time->tm_year += 1900;
+ time->tm_mon += 1;
+ sprintf(output, "%04d%02d%02d%02d%02d%02d",
+ time->tm_year, time->tm_mon, time->tm_mday,
+ time->tm_hour, time->tm_min, time->tm_sec);
+ return (output);
+}
+
+u_int16_t
+res_nametoclass(const char *buf, int *successp) {
+ unsigned long result;
+ char *endptr;
+ int success;
+
+ result = sym_ston(__p_class_syms, buf, &success);
+ if (success)
+ goto done;
+
+ if (strncasecmp(buf, "CLASS", 5) != 0 ||
+ !isdigit((unsigned char)buf[5]))
+ goto done;
+ errno = 0;
+ result = strtoul(buf + 5, &endptr, 10);
+ if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
+ success = 1;
+ done:
+ if (successp)
+ *successp = success;
+ return (result);
+}
+
+u_int16_t
+res_nametotype(const char *buf, int *successp) {
+ unsigned long result;
+ char *endptr;
+ int success;
+
+ result = sym_ston(__p_type_syms, buf, &success);
+ if (success)
+ goto done;
+
+ if (strncasecmp(buf, "type", 4) != 0 ||
+ !isdigit((unsigned char)buf[4]))
+ goto done;
+ errno = 0;
+ result = strtoul(buf + 4, &endptr, 10);
+ if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
+ success = 1;
+ done:
+ if (successp)
+ *successp = success;
+ return (result);
+}
+
+/*! \file */
diff --git a/lib/bind/resolv/res_debug.h b/lib/bind/resolv/res_debug.h
new file mode 100644
index 0000000..c28171d
--- /dev/null
+++ b/lib/bind/resolv/res_debug.h
@@ -0,0 +1,35 @@
+/*
+ * 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 _RES_DEBUG_H_
+#define _RES_DEBUG_H_
+
+#ifndef DEBUG
+# define Dprint(cond, args) /*empty*/
+# define DprintQ(cond, args, query, size) /*empty*/
+# define Aerror(statp, file, string, error, address) /*empty*/
+# define Perror(statp, file, string, error) /*empty*/
+#else
+# define Dprint(cond, args) if (cond) {fprintf args;} else {}
+# define DprintQ(cond, args, query, size) if (cond) {\
+ fprintf args;\
+ res_pquery(statp, query, size, stdout);\
+ } else {}
+#endif
+
+#endif /* _RES_DEBUG_H_ */
+/*! \file */
diff --git a/lib/bind/resolv/res_findzonecut.c b/lib/bind/resolv/res_findzonecut.c
new file mode 100644
index 0000000..207d66c
--- /dev/null
+++ b/lib/bind/resolv/res_findzonecut.c
@@ -0,0 +1,722 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_findzonecut.c,v 1.7.18.3 2005/10/11 00:25:11 marka Exp $";
+#endif /* not lint */
+
+/*
+ * 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.
+ */
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/list.h>
+
+#include "port_after.h"
+
+#include <resolv.h>
+
+/* Data structures. */
+
+typedef struct rr_a {
+ LINK(struct rr_a) link;
+ union res_sockaddr_union addr;
+} rr_a;
+typedef LIST(rr_a) rrset_a;
+
+typedef struct rr_ns {
+ LINK(struct rr_ns) link;
+ const char * name;
+ unsigned int flags;
+ rrset_a addrs;
+} rr_ns;
+typedef LIST(rr_ns) rrset_ns;
+
+#define RR_NS_HAVE_V4 0x01
+#define RR_NS_HAVE_V6 0x02
+
+/* Forward. */
+
+static int satisfy(res_state, const char *, rrset_ns *,
+ union res_sockaddr_union *, int);
+static int add_addrs(res_state, rr_ns *,
+ union res_sockaddr_union *, int);
+static int get_soa(res_state, const char *, ns_class, int,
+ char *, size_t, char *, size_t,
+ rrset_ns *);
+static int get_ns(res_state, const char *, ns_class, int, rrset_ns *);
+static int get_glue(res_state, ns_class, int, rrset_ns *);
+static int save_ns(res_state, ns_msg *, ns_sect,
+ const char *, ns_class, int, rrset_ns *);
+static int save_a(res_state, ns_msg *, ns_sect,
+ const char *, ns_class, int, rr_ns *);
+static void free_nsrrset(rrset_ns *);
+static void free_nsrr(rrset_ns *, rr_ns *);
+static rr_ns * find_ns(rrset_ns *, const char *);
+static int do_query(res_state, const char *, ns_class, ns_type,
+ u_char *, ns_msg *);
+static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2);
+
+/* Macros. */
+
+#define DPRINTF(x) do {\
+ int save_errno = errno; \
+ if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \
+ errno = save_errno; \
+ } while (0)
+
+/* Public. */
+
+/*%
+ * find enclosing zone for a <dname,class>, and some server addresses
+ *
+ * parameters:
+ *\li res - resolver context to work within (is modified)
+ *\li dname - domain name whose enclosing zone is desired
+ *\li class - class of dname (and its enclosing zone)
+ *\li zname - found zone name
+ *\li zsize - allocated size of zname
+ *\li addrs - found server addresses
+ *\li naddrs - max number of addrs
+ *
+ * return values:
+ *\li < 0 - an error occurred (check errno)
+ *\li = 0 - zname is now valid, but addrs[] wasn't changed
+ *\li > 0 - zname is now valid, and return value is number of addrs[] found
+ *
+ * notes:
+ *\li this function calls res_nsend() which means it depends on correctly
+ * functioning recursive nameservers (usually defined in /etc/resolv.conf
+ * or its local equivilent).
+ *
+ *\li we start by asking for an SOA<dname,class>. if we get one as an
+ * answer, that just means <dname,class> is a zone top, which is fine.
+ * more than likely we'll be told to go pound sand, in the form of a
+ * negative answer.
+ *
+ *\li note that we are not prepared to deal with referrals since that would
+ * only come from authority servers and our correctly functioning local
+ * recursive server would have followed the referral and got us something
+ * more definite.
+ *
+ *\li if the authority section contains an SOA, this SOA should also be the
+ * closest enclosing zone, since any intermediary zone cuts would've been
+ * returned as referrals and dealt with by our correctly functioning local
+ * recursive name server. but an SOA in the authority section should NOT
+ * match our dname (since that would have been returned in the answer
+ * section). an authority section SOA has to be "above" our dname.
+ *
+ *\li however, since authority section SOA's were once optional, it's
+ * possible that we'll have to go hunting for the enclosing SOA by
+ * ripping labels off the front of our dname -- this is known as "doing
+ * it the hard way."
+ *
+ *\li ultimately we want some server addresses, which are ideally the ones
+ * pertaining to the SOA.MNAME, but only if there is a matching NS RR.
+ * so the second phase (after we find an SOA) is to go looking for the
+ * NS RRset for that SOA's zone.
+ *
+ *\li no answer section processed by this code is allowed to contain CNAME
+ * or DNAME RR's. for the SOA query this means we strip a label and
+ * keep going. for the NS and A queries this means we just give up.
+ */
+
+int
+res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, struct in_addr *addrs, int naddrs)
+{
+ int result, i;
+ union res_sockaddr_union *u;
+
+
+ opts |= RES_IPV4ONLY;
+ opts &= ~RES_IPV6ONLY;
+
+ u = calloc(naddrs, sizeof(*u));
+ if (u == NULL)
+ return(-1);
+
+ result = res_findzonecut2(statp, dname, class, opts, zname, zsize,
+ u, naddrs);
+
+ for (i = 0; i < result; i++) {
+ addrs[i] = u[i].sin.sin_addr;
+ }
+ free(u);
+ return (result);
+}
+
+int
+res_findzonecut2(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, union res_sockaddr_union *addrs,
+ int naddrs)
+{
+ char mname[NS_MAXDNAME];
+ u_long save_pfcode;
+ rrset_ns nsrrs;
+ int n;
+
+ DPRINTF(("START dname='%s' class=%s, zsize=%ld, naddrs=%d",
+ dname, p_class(class), (long)zsize, naddrs));
+ save_pfcode = statp->pfcode;
+ statp->pfcode |= RES_PRF_HEAD2 | RES_PRF_HEAD1 | RES_PRF_HEADX |
+ RES_PRF_QUES | RES_PRF_ANS |
+ RES_PRF_AUTH | RES_PRF_ADD;
+ INIT_LIST(nsrrs);
+
+ DPRINTF(("get the soa, and see if it has enough glue"));
+ if ((n = get_soa(statp, dname, class, opts, zname, zsize,
+ mname, sizeof mname, &nsrrs)) < 0 ||
+ ((opts & RES_EXHAUSTIVE) == 0 &&
+ (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
+ goto done;
+
+ DPRINTF(("get the ns rrset and see if it has enough glue"));
+ if ((n = get_ns(statp, zname, class, opts, &nsrrs)) < 0 ||
+ ((opts & RES_EXHAUSTIVE) == 0 &&
+ (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
+ goto done;
+
+ DPRINTF(("get the missing glue and see if it's finally enough"));
+ if ((n = get_glue(statp, class, opts, &nsrrs)) >= 0)
+ n = satisfy(statp, mname, &nsrrs, addrs, naddrs);
+
+ done:
+ DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK"));
+ free_nsrrset(&nsrrs);
+ statp->pfcode = save_pfcode;
+ return (n);
+}
+
+/* Private. */
+
+static int
+satisfy(res_state statp, const char *mname, rrset_ns *nsrrsp,
+ union res_sockaddr_union *addrs, int naddrs)
+{
+ rr_ns *nsrr;
+ int n, x;
+
+ n = 0;
+ nsrr = find_ns(nsrrsp, mname);
+ if (nsrr != NULL) {
+ x = add_addrs(statp, nsrr, addrs, naddrs);
+ addrs += x;
+ naddrs -= x;
+ n += x;
+ }
+ for (nsrr = HEAD(*nsrrsp);
+ nsrr != NULL && naddrs > 0;
+ nsrr = NEXT(nsrr, link))
+ if (ns_samename(nsrr->name, mname) != 1) {
+ x = add_addrs(statp, nsrr, addrs, naddrs);
+ addrs += x;
+ naddrs -= x;
+ n += x;
+ }
+ DPRINTF(("satisfy(%s): %d", mname, n));
+ return (n);
+}
+
+static int
+add_addrs(res_state statp, rr_ns *nsrr,
+ union res_sockaddr_union *addrs, int naddrs)
+{
+ rr_a *arr;
+ int n = 0;
+
+ for (arr = HEAD(nsrr->addrs); arr != NULL; arr = NEXT(arr, link)) {
+ if (naddrs <= 0)
+ return (0);
+ *addrs++ = arr->addr;
+ naddrs--;
+ n++;
+ }
+ DPRINTF(("add_addrs: %d", n));
+ return (n);
+}
+
+static int
+get_soa(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, char *mname, size_t msize,
+ rrset_ns *nsrrsp)
+{
+ char tname[NS_MAXDNAME];
+ u_char *resp = NULL;
+ int n, i, ancount, nscount;
+ ns_sect sect;
+ ns_msg msg;
+ u_int rcode;
+
+ /*
+ * Find closest enclosing SOA, even if it's for the root zone.
+ */
+
+ /* First canonicalize dname (exactly one unescaped trailing "."). */
+ if (ns_makecanon(dname, tname, sizeof tname) < 0)
+ goto cleanup;
+ dname = tname;
+
+ resp = malloc(NS_MAXMSG);
+ if (resp == NULL)
+ goto cleanup;
+
+ /* Now grovel the subdomains, hunting for an SOA answer or auth. */
+ for (;;) {
+ /* Leading or inter-label '.' are skipped here. */
+ while (*dname == '.')
+ dname++;
+
+ /* Is there an SOA? */
+ n = do_query(statp, dname, class, ns_t_soa, resp, &msg);
+ if (n < 0) {
+ DPRINTF(("get_soa: do_query('%s', %s) failed (%d)",
+ dname, p_class(class), n));
+ goto cleanup;
+ }
+ if (n > 0) {
+ DPRINTF(("get_soa: CNAME or DNAME found"));
+ sect = ns_s_max, n = 0;
+ } else {
+ rcode = ns_msg_getflag(msg, ns_f_rcode);
+ ancount = ns_msg_count(msg, ns_s_an);
+ nscount = ns_msg_count(msg, ns_s_ns);
+ if (ancount > 0 && rcode == ns_r_noerror)
+ sect = ns_s_an, n = ancount;
+ else if (nscount > 0)
+ sect = ns_s_ns, n = nscount;
+ else
+ sect = ns_s_max, n = 0;
+ }
+ for (i = 0; i < n; i++) {
+ const char *t;
+ const u_char *rdata;
+ ns_rr rr;
+
+ if (ns_parserr(&msg, sect, i, &rr) < 0) {
+ DPRINTF(("get_soa: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ goto cleanup;
+ }
+ if (ns_rr_type(rr) == ns_t_cname ||
+ ns_rr_type(rr) == ns_t_dname)
+ break;
+ if (ns_rr_type(rr) != ns_t_soa ||
+ ns_rr_class(rr) != class)
+ continue;
+ t = ns_rr_name(rr);
+ switch (sect) {
+ case ns_s_an:
+ if (ns_samedomain(dname, t) == 0) {
+ DPRINTF(
+ ("get_soa: ns_samedomain('%s', '%s') == 0",
+ dname, t)
+ );
+ errno = EPROTOTYPE;
+ goto cleanup;
+ }
+ break;
+ case ns_s_ns:
+ if (ns_samename(dname, t) == 1 ||
+ ns_samedomain(dname, t) == 0) {
+ DPRINTF(
+ ("get_soa: ns_samename() || !ns_samedomain('%s', '%s')",
+ dname, t)
+ );
+ errno = EPROTOTYPE;
+ goto cleanup;
+ }
+ break;
+ default:
+ abort();
+ }
+ if (strlen(t) + 1 > zsize) {
+ DPRINTF(("get_soa: zname(%lu) too small (%lu)",
+ (unsigned long)zsize,
+ (unsigned long)strlen(t) + 1));
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ strcpy(zname, t);
+ rdata = ns_rr_rdata(rr);
+ if (ns_name_uncompress(resp, ns_msg_end(msg), rdata,
+ mname, msize) < 0) {
+ DPRINTF(("get_soa: ns_name_uncompress failed")
+ );
+ goto cleanup;
+ }
+ if (save_ns(statp, &msg, ns_s_ns,
+ zname, class, opts, nsrrsp) < 0) {
+ DPRINTF(("get_soa: save_ns failed"));
+ goto cleanup;
+ }
+ free(resp);
+ return (0);
+ }
+
+ /* If we're out of labels, then not even "." has an SOA! */
+ if (*dname == '\0')
+ break;
+
+ /* Find label-terminating "."; top of loop will skip it. */
+ while (*dname != '.') {
+ if (*dname == '\\')
+ if (*++dname == '\0') {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ dname++;
+ }
+ }
+ DPRINTF(("get_soa: out of labels"));
+ errno = EDESTADDRREQ;
+ cleanup:
+ if (resp != NULL)
+ free(resp);
+ return (-1);
+}
+
+static int
+get_ns(res_state statp, const char *zname, ns_class class, int opts,
+ rrset_ns *nsrrsp)
+{
+ u_char *resp;
+ ns_msg msg;
+ int n;
+
+ resp = malloc(NS_MAXMSG);
+ if (resp == NULL)
+ return (-1);
+
+ /* Go and get the NS RRs for this zone. */
+ n = do_query(statp, zname, class, ns_t_ns, resp, &msg);
+ if (n != 0) {
+ DPRINTF(("get_ns: do_query('%s', %s) failed (%d)",
+ zname, p_class(class), n));
+ free(resp);
+ return (-1);
+ }
+
+ /* Remember the NS RRs and associated A RRs that came back. */
+ if (save_ns(statp, &msg, ns_s_an, zname, class, opts, nsrrsp) < 0) {
+ DPRINTF(("get_ns save_ns('%s', %s) failed",
+ zname, p_class(class)));
+ free(resp);
+ return (-1);
+ }
+
+ free(resp);
+ return (0);
+}
+
+static int
+get_glue(res_state statp, ns_class class, int opts, rrset_ns *nsrrsp) {
+ rr_ns *nsrr, *nsrr_n;
+ u_char *resp;
+
+ resp = malloc(NS_MAXMSG);
+ if (resp == NULL)
+ return(-1);
+
+ /* Go and get the A RRs for each empty NS RR on our list. */
+ for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = nsrr_n) {
+ ns_msg msg;
+ int n;
+
+ nsrr_n = NEXT(nsrr, link);
+
+ if ((nsrr->flags & RR_NS_HAVE_V4) == 0) {
+ n = do_query(statp, nsrr->name, class, ns_t_a,
+ resp, &msg);
+ if (n < 0) {
+ DPRINTF(
+ ("get_glue: do_query('%s', %s') failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ if (n > 0) {
+ DPRINTF((
+ "get_glue: do_query('%s', %s') CNAME or DNAME found",
+ nsrr->name, p_class(class)));
+ }
+ if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
+ opts, nsrr) < 0) {
+ DPRINTF(("get_glue: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ }
+
+ if ((nsrr->flags & RR_NS_HAVE_V6) == 0) {
+ n = do_query(statp, nsrr->name, class, ns_t_aaaa,
+ resp, &msg);
+ if (n < 0) {
+ DPRINTF(
+ ("get_glue: do_query('%s', %s') failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ if (n > 0) {
+ DPRINTF((
+ "get_glue: do_query('%s', %s') CNAME or DNAME found",
+ nsrr->name, p_class(class)));
+ }
+ if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
+ opts, nsrr) < 0) {
+ DPRINTF(("get_glue: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ }
+
+ /* If it's still empty, it's just chaff. */
+ if (EMPTY(nsrr->addrs)) {
+ DPRINTF(("get_glue: removing empty '%s' NS",
+ nsrr->name));
+ free_nsrr(nsrrsp, nsrr);
+ }
+ }
+ free(resp);
+ return (0);
+
+ cleanup:
+ free(resp);
+ return (-1);
+}
+
+static int
+save_ns(res_state statp, ns_msg *msg, ns_sect sect,
+ const char *owner, ns_class class, int opts,
+ rrset_ns *nsrrsp)
+{
+ int i;
+
+ for (i = 0; i < ns_msg_count(*msg, sect); i++) {
+ char tname[MAXDNAME];
+ const u_char *rdata;
+ rr_ns *nsrr;
+ ns_rr rr;
+
+ if (ns_parserr(msg, sect, i, &rr) < 0) {
+ DPRINTF(("save_ns: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ return (-1);
+ }
+ if (ns_rr_type(rr) != ns_t_ns ||
+ ns_rr_class(rr) != class ||
+ ns_samename(ns_rr_name(rr), owner) != 1)
+ continue;
+ nsrr = find_ns(nsrrsp, ns_rr_name(rr));
+ if (nsrr == NULL) {
+ nsrr = malloc(sizeof *nsrr);
+ if (nsrr == NULL) {
+ DPRINTF(("save_ns: malloc failed"));
+ return (-1);
+ }
+ rdata = ns_rr_rdata(rr);
+ if (ns_name_uncompress(ns_msg_base(*msg),
+ ns_msg_end(*msg), rdata,
+ tname, sizeof tname) < 0) {
+ DPRINTF(("save_ns: ns_name_uncompress failed")
+ );
+ free(nsrr);
+ return (-1);
+ }
+ nsrr->name = strdup(tname);
+ if (nsrr->name == NULL) {
+ DPRINTF(("save_ns: strdup failed"));
+ free(nsrr);
+ return (-1);
+ }
+ INIT_LINK(nsrr, link);
+ INIT_LIST(nsrr->addrs);
+ nsrr->flags = 0;
+ APPEND(*nsrrsp, nsrr, link);
+ }
+ if (save_a(statp, msg, ns_s_ar,
+ nsrr->name, class, opts, nsrr) < 0) {
+ DPRINTF(("save_ns: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+static int
+save_a(res_state statp, ns_msg *msg, ns_sect sect,
+ const char *owner, ns_class class, int opts,
+ rr_ns *nsrr)
+{
+ int i;
+
+ for (i = 0; i < ns_msg_count(*msg, sect); i++) {
+ ns_rr rr;
+ rr_a *arr;
+
+ if (ns_parserr(msg, sect, i, &rr) < 0) {
+ DPRINTF(("save_a: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ return (-1);
+ }
+ if ((ns_rr_type(rr) != ns_t_a &&
+ ns_rr_type(rr) != ns_t_aaaa) ||
+ ns_rr_class(rr) != class ||
+ ns_samename(ns_rr_name(rr), owner) != 1 ||
+ ns_rr_rdlen(rr) != NS_INADDRSZ)
+ continue;
+ if ((opts & RES_IPV6ONLY) != 0 && ns_rr_type(rr) != ns_t_aaaa)
+ continue;
+ if ((opts & RES_IPV4ONLY) != 0 && ns_rr_type(rr) != ns_t_a)
+ continue;
+ arr = malloc(sizeof *arr);
+ if (arr == NULL) {
+ DPRINTF(("save_a: malloc failed"));
+ return (-1);
+ }
+ INIT_LINK(arr, link);
+ memset(&arr->addr, 0, sizeof(arr->addr));
+ switch (ns_rr_type(rr)) {
+ case ns_t_a:
+ arr->addr.sin.sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+ arr->addr.sin.sin_len = sizeof(arr->addr.sin);
+#endif
+ memcpy(&arr->addr.sin.sin_addr, ns_rr_rdata(rr),
+ NS_INADDRSZ);
+ arr->addr.sin.sin_port = htons(NAMESERVER_PORT);
+ nsrr->flags |= RR_NS_HAVE_V4;
+ break;
+ case ns_t_aaaa:
+ arr->addr.sin6.sin6_family = AF_INET6;
+#ifdef HAVE_SA_LEN
+ arr->addr.sin6.sin6_len = sizeof(arr->addr.sin6);
+#endif
+ memcpy(&arr->addr.sin6.sin6_addr, ns_rr_rdata(rr), 16);
+ arr->addr.sin.sin_port = htons(NAMESERVER_PORT);
+ nsrr->flags |= RR_NS_HAVE_V6;
+ break;
+ default:
+ abort();
+ }
+ APPEND(nsrr->addrs, arr, link);
+ }
+ return (0);
+}
+
+static void
+free_nsrrset(rrset_ns *nsrrsp) {
+ rr_ns *nsrr;
+
+ while ((nsrr = HEAD(*nsrrsp)) != NULL)
+ free_nsrr(nsrrsp, nsrr);
+}
+
+static void
+free_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) {
+ rr_a *arr;
+ char *tmp;
+
+ while ((arr = HEAD(nsrr->addrs)) != NULL) {
+ UNLINK(nsrr->addrs, arr, link);
+ free(arr);
+ }
+ DE_CONST(nsrr->name, tmp);
+ free(tmp);
+ UNLINK(*nsrrsp, nsrr, link);
+ free(nsrr);
+}
+
+static rr_ns *
+find_ns(rrset_ns *nsrrsp, const char *dname) {
+ rr_ns *nsrr;
+
+ for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = NEXT(nsrr, link))
+ if (ns_samename(nsrr->name, dname) == 1)
+ return (nsrr);
+ return (NULL);
+}
+
+static int
+do_query(res_state statp, const char *dname, ns_class class, ns_type qtype,
+ u_char *resp, ns_msg *msg)
+{
+ u_char req[NS_PACKETSZ];
+ int i, n;
+
+ n = res_nmkquery(statp, ns_o_query, dname, class, qtype,
+ NULL, 0, NULL, req, NS_PACKETSZ);
+ if (n < 0) {
+ DPRINTF(("do_query: res_nmkquery failed"));
+ return (-1);
+ }
+ n = res_nsend(statp, req, n, resp, NS_MAXMSG);
+ if (n < 0) {
+ DPRINTF(("do_query: res_nsend failed"));
+ return (-1);
+ }
+ if (n == 0) {
+ DPRINTF(("do_query: res_nsend returned 0"));
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (ns_initparse(resp, n, msg) < 0) {
+ DPRINTF(("do_query: ns_initparse failed"));
+ return (-1);
+ }
+ n = 0;
+ for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) {
+ ns_rr rr;
+
+ if (ns_parserr(msg, ns_s_an, i, &rr) < 0) {
+ DPRINTF(("do_query: ns_parserr failed"));
+ return (-1);
+ }
+ n += (ns_rr_class(rr) == class &&
+ (ns_rr_type(rr) == ns_t_cname ||
+ ns_rr_type(rr) == ns_t_dname));
+ }
+ return (n);
+}
+
+static void
+res_dprintf(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ fputs(";; res_findzonecut: ", stderr);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+}
+
+/*! \file */
diff --git a/lib/bind/resolv/res_init.c b/lib/bind/resolv/res_init.c
new file mode 100644
index 0000000..f580b9c
--- /dev/null
+++ b/lib/bind/resolv/res_init.c
@@ -0,0 +1,801 @@
+/*
+ * Copyright (c) 1985, 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.
+ */
+
+/*
+ * 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_init.c 8.1 (Berkeley) 6/7/93";
+static const char rcsid[] = "$Id: res_init.c,v 1.16.18.7 2007/07/09 01:52:58 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include "port_after.h"
+
+/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
+#include <resolv.h>
+
+#include "res_private.h"
+
+/*% Options. Should all be left alone. */
+#define RESOLVSORT
+#define DEBUG
+
+#ifdef SOLARIS2
+#include <sys/systeminfo.h>
+#endif
+
+static void res_setoptions __P((res_state, const char *, const char *));
+
+#ifdef RESOLVSORT
+static const char sort_mask[] = "/&";
+#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
+static u_int32_t net_mask __P((struct in_addr));
+#endif
+
+#if !defined(isascii) /*%< XXX - could be a function */
+# define isascii(c) (!(c & 0200))
+#endif
+
+/*
+ * Resolver state default settings.
+ */
+
+/*%
+ * Set up default settings. If the configuration file exist, the values
+ * there will have precedence. Otherwise, the server address is set to
+ * INADDR_ANY and the default domain name comes from the gethostname().
+ *
+ * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
+ * rather than INADDR_ANY ("0.0.0.0") as the default name server address
+ * since it was noted that INADDR_ANY actually meant ``the first interface
+ * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
+ * it had to be "up" in order for you to reach your own name server. It
+ * was later decided that since the recommended practice is to always
+ * install local static routes through 127.0.0.1 for all your network
+ * interfaces, that we could solve this problem without a code change.
+ *
+ * The configuration file should always be used, since it is the only way
+ * to specify a default domain. If you are running a server on your local
+ * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
+ * in the configuration file.
+ *
+ * Return 0 if completes successfully, -1 on error
+ */
+int
+res_ninit(res_state statp) {
+ extern int __res_vinit(res_state, int);
+
+ return (__res_vinit(statp, 0));
+}
+
+/*% This function has to be reachable by res_data.c but not publically. */
+int
+__res_vinit(res_state statp, int preinit) {
+ register FILE *fp;
+ register char *cp, **pp;
+ register int n;
+ char buf[BUFSIZ];
+ int nserv = 0; /*%< number of nameserver records read from file */
+ int haveenv = 0;
+ int havesearch = 0;
+#ifdef RESOLVSORT
+ int nsort = 0;
+ char *net;
+#endif
+ int dots;
+ union res_sockaddr_union u[2];
+ int maxns = MAXNS;
+
+ RES_SET_H_ERRNO(statp, 0);
+ if (statp->_u._ext.ext != NULL)
+ res_ndestroy(statp);
+
+ if (!preinit) {
+ statp->retrans = RES_TIMEOUT;
+ statp->retry = RES_DFLRETRY;
+ statp->options = RES_DEFAULT;
+ statp->id = res_randomid();
+ }
+
+ memset(u, 0, sizeof(u));
+#ifdef USELOOPBACK
+ u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
+#else
+ u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
+#endif
+ u[nserv].sin.sin_family = AF_INET;
+ u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
+#ifdef HAVE_SA_LEN
+ u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
+#endif
+ nserv++;
+#ifdef HAS_INET6_STRUCTS
+#ifdef USELOOPBACK
+ u[nserv].sin6.sin6_addr = in6addr_loopback;
+#else
+ u[nserv].sin6.sin6_addr = in6addr_any;
+#endif
+ u[nserv].sin6.sin6_family = AF_INET6;
+ u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
+#ifdef HAVE_SA_LEN
+ u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ nserv++;
+#endif
+ statp->nscount = 0;
+ statp->ndots = 1;
+ statp->pfcode = 0;
+ statp->_vcsock = -1;
+ statp->_flags = 0;
+ statp->qhook = NULL;
+ statp->rhook = NULL;
+ statp->_u._ext.nscount = 0;
+ statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
+ if (statp->_u._ext.ext != NULL) {
+ memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
+ statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
+ strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
+ strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
+ } else {
+ /*
+ * Historically res_init() rarely, if at all, failed.
+ * Examples and applications exist which do not check
+ * our return code. Furthermore several applications
+ * simply call us to get the systems domainname. So
+ * rather then immediately fail here we store the
+ * failure, which is returned later, in h_errno. And
+ * prevent the collection of 'nameserver' information
+ * by setting maxns to 0. Thus applications that fail
+ * to check our return code wont be able to make
+ * queries anyhow.
+ */
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ maxns = 0;
+ }
+#ifdef RESOLVSORT
+ statp->nsort = 0;
+#endif
+ res_setservers(statp, u, nserv);
+
+#ifdef SOLARIS2
+ /*
+ * The old libresolv derived the defaultdomain from NIS/NIS+.
+ * We want to keep this behaviour
+ */
+ {
+ char buf[sizeof(statp->defdname)], *cp;
+ int ret;
+
+ if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
+ (unsigned int)ret <= sizeof(buf)) {
+ if (buf[0] == '+')
+ buf[0] = '.';
+ cp = strchr(buf, '.');
+ cp = (cp == NULL) ? buf : (cp + 1);
+ strncpy(statp->defdname, cp,
+ sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ }
+ }
+#endif /* SOLARIS2 */
+
+ /* Allow user to override the local domain definition */
+ if ((cp = getenv("LOCALDOMAIN")) != NULL) {
+ (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ haveenv++;
+
+ /*
+ * Set search list to be blank-separated strings
+ * from rest of env value. Permits users of LOCALDOMAIN
+ * to still have a search list, and anyone to set the
+ * one that they want to use as an individual (even more
+ * important now that the rfc1535 stuff restricts searches)
+ */
+ cp = statp->defdname;
+ pp = statp->dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
+ if (*cp == '\n') /*%< silly backwards compat */
+ break;
+ else if (*cp == ' ' || *cp == '\t') {
+ *cp = 0;
+ n = 1;
+ } else if (n) {
+ *pp++ = cp;
+ n = 0;
+ havesearch = 1;
+ }
+ }
+ /* null terminate last domain if there are excess */
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
+ cp++;
+ *cp = '\0';
+ *pp++ = 0;
+ }
+
+#define MATCH(line, name) \
+ (!strncmp(line, name, sizeof(name) - 1) && \
+ (line[sizeof(name) - 1] == ' ' || \
+ line[sizeof(name) - 1] == '\t'))
+
+ nserv = 0;
+ if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
+ /* read the config file */
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ /* skip comments */
+ if (*buf == ';' || *buf == '#')
+ continue;
+ /* read default domain name */
+ if (MATCH(buf, "domain")) {
+ if (haveenv) /*%< skip if have from environ */
+ continue;
+ cp = buf + sizeof("domain") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
+ *cp = '\0';
+ havesearch = 0;
+ continue;
+ }
+ /* set search list */
+ if (MATCH(buf, "search")) {
+ if (haveenv) /*%< skip if have from environ */
+ continue;
+ cp = buf + sizeof("search") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ if ((cp = strchr(statp->defdname, '\n')) != NULL)
+ *cp = '\0';
+ /*
+ * Set search list to be blank-separated strings
+ * on rest of line.
+ */
+ cp = statp->defdname;
+ pp = statp->dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
+ if (*cp == ' ' || *cp == '\t') {
+ *cp = 0;
+ n = 1;
+ } else if (n) {
+ *pp++ = cp;
+ n = 0;
+ }
+ }
+ /* null terminate last domain if there are excess */
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t')
+ cp++;
+ *cp = '\0';
+ *pp++ = 0;
+ havesearch = 1;
+ continue;
+ }
+ /* read nameservers to query */
+ if (MATCH(buf, "nameserver") && nserv < maxns) {
+ struct addrinfo hints, *ai;
+ char sbuf[NI_MAXSERV];
+ const size_t minsiz =
+ sizeof(statp->_u._ext.ext->nsaddrs[0]);
+
+ cp = buf + sizeof("nameserver") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ cp[strcspn(cp, ";# \t\n")] = '\0';
+ if ((*cp != '\0') && (*cp != '\n')) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+ sprintf(sbuf, "%u", NAMESERVER_PORT);
+ if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 &&
+ ai->ai_addrlen <= minsiz) {
+ if (statp->_u._ext.ext != NULL) {
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+ ai->ai_addr, ai->ai_addrlen);
+ }
+ if (ai->ai_addrlen <=
+ sizeof(statp->nsaddr_list[nserv])) {
+ memcpy(&statp->nsaddr_list[nserv],
+ ai->ai_addr, ai->ai_addrlen);
+ } else
+ statp->nsaddr_list[nserv].sin_family = 0;
+ freeaddrinfo(ai);
+ nserv++;
+ }
+ }
+ continue;
+ }
+#ifdef RESOLVSORT
+ if (MATCH(buf, "sortlist")) {
+ struct in_addr a;
+
+ cp = buf + sizeof("sortlist") - 1;
+ while (nsort < MAXRESOLVSORT) {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '\0' || *cp == '\n' || *cp == ';')
+ break;
+ net = cp;
+ while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
+ isascii(*cp) && !isspace((unsigned char)*cp))
+ cp++;
+ n = *cp;
+ *cp = 0;
+ if (inet_aton(net, &a)) {
+ statp->sort_list[nsort].addr = a;
+ if (ISSORTMASK(n)) {
+ *cp++ = n;
+ net = cp;
+ while (*cp && *cp != ';' &&
+ isascii(*cp) &&
+ !isspace((unsigned char)*cp))
+ cp++;
+ n = *cp;
+ *cp = 0;
+ if (inet_aton(net, &a)) {
+ statp->sort_list[nsort].mask = a.s_addr;
+ } else {
+ statp->sort_list[nsort].mask =
+ net_mask(statp->sort_list[nsort].addr);
+ }
+ } else {
+ statp->sort_list[nsort].mask =
+ net_mask(statp->sort_list[nsort].addr);
+ }
+ nsort++;
+ }
+ *cp = n;
+ }
+ continue;
+ }
+#endif
+ if (MATCH(buf, "options")) {
+ res_setoptions(statp, buf + sizeof("options") - 1, "conf");
+ continue;
+ }
+ }
+ if (nserv > 0)
+ statp->nscount = nserv;
+#ifdef RESOLVSORT
+ statp->nsort = nsort;
+#endif
+ (void) fclose(fp);
+ }
+/*
+ * Last chance to get a nameserver. This should not normally
+ * be necessary
+ */
+#ifdef NO_RESOLV_CONF
+ if(nserv == 0)
+ nserv = get_nameservers(statp);
+#endif
+
+ if (statp->defdname[0] == 0 &&
+ gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
+ (cp = strchr(buf, '.')) != NULL)
+ strcpy(statp->defdname, cp + 1);
+
+ /* find components of local domain that might be searched */
+ if (havesearch == 0) {
+ pp = statp->dnsrch;
+ *pp++ = statp->defdname;
+ *pp = NULL;
+
+ dots = 0;
+ for (cp = statp->defdname; *cp; cp++)
+ dots += (*cp == '.');
+
+ cp = statp->defdname;
+ while (pp < statp->dnsrch + MAXDFLSRCH) {
+ if (dots < LOCALDOMAINPARTS)
+ break;
+ cp = strchr(cp, '.') + 1; /*%< we know there is one */
+ *pp++ = cp;
+ dots--;
+ }
+ *pp = NULL;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG) {
+ printf(";; res_init()... default dnsrch list:\n");
+ for (pp = statp->dnsrch; *pp; pp++)
+ printf(";;\t%s\n", *pp);
+ printf(";;\t..END..\n");
+ }
+#endif
+ }
+
+ if ((cp = getenv("RES_OPTIONS")) != NULL)
+ res_setoptions(statp, cp, "env");
+ statp->options |= RES_INIT;
+ return (statp->res_h_errno);
+}
+
+static void
+res_setoptions(res_state statp, const char *options, const char *source)
+{
+ const char *cp = options;
+ int i;
+ struct __res_state_ext *ext = statp->_u._ext.ext;
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_setoptions(\"%s\", \"%s\")...\n",
+ options, source);
+#endif
+ while (*cp) {
+ /* skip leading and inner runs of spaces */
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ /* search for and process individual options */
+ if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
+ i = atoi(cp + sizeof("ndots:") - 1);
+ if (i <= RES_MAXNDOTS)
+ statp->ndots = i;
+ else
+ statp->ndots = RES_MAXNDOTS;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";;\tndots=%d\n", statp->ndots);
+#endif
+ } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
+ i = atoi(cp + sizeof("timeout:") - 1);
+ if (i <= RES_MAXRETRANS)
+ statp->retrans = i;
+ else
+ statp->retrans = RES_MAXRETRANS;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";;\ttimeout=%d\n", statp->retrans);
+#endif
+#ifdef SOLARIS2
+ } else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
+ /*
+ * For backward compatibility, 'retrans' is
+ * supported as an alias for 'timeout', though
+ * without an imposed maximum.
+ */
+ statp->retrans = atoi(cp + sizeof("retrans:") - 1);
+ } else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
+ /*
+ * For backward compatibility, 'retry' is
+ * supported as an alias for 'attempts', though
+ * without an imposed maximum.
+ */
+ statp->retry = atoi(cp + sizeof("retry:") - 1);
+#endif /* SOLARIS2 */
+ } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
+ i = atoi(cp + sizeof("attempts:") - 1);
+ if (i <= RES_MAXRETRY)
+ statp->retry = i;
+ else
+ statp->retry = RES_MAXRETRY;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";;\tattempts=%d\n", statp->retry);
+#endif
+ } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
+#ifdef DEBUG
+ if (!(statp->options & RES_DEBUG)) {
+ printf(";; res_setoptions(\"%s\", \"%s\")..\n",
+ options, source);
+ statp->options |= RES_DEBUG;
+ }
+ printf(";;\tdebug\n");
+#endif
+ } else if (!strncmp(cp, "no_tld_query",
+ sizeof("no_tld_query") - 1) ||
+ !strncmp(cp, "no-tld-query",
+ sizeof("no-tld-query") - 1)) {
+ statp->options |= RES_NOTLDQUERY;
+ } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
+ statp->options |= RES_USE_INET6;
+ } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
+ statp->options |= RES_ROTATE;
+ } else if (!strncmp(cp, "no-check-names",
+ sizeof("no-check-names") - 1)) {
+ statp->options |= RES_NOCHECKNAME;
+ }
+#ifdef RES_USE_EDNS0
+ else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
+ statp->options |= RES_USE_EDNS0;
+ }
+#endif
+ else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
+ statp->options |= RES_USE_DNAME;
+ }
+ else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
+ if (ext == NULL)
+ goto skip;
+ cp += sizeof("nibble:") - 1;
+ i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
+ strncpy(ext->nsuffix, cp, i);
+ ext->nsuffix[i] = '\0';
+ }
+ else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
+ if (ext == NULL)
+ goto skip;
+ cp += sizeof("nibble2:") - 1;
+ i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
+ strncpy(ext->nsuffix2, cp, i);
+ ext->nsuffix2[i] = '\0';
+ }
+ else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
+ cp += sizeof("v6revmode:") - 1;
+ /* "nibble" and "bitstring" used to be valid */
+ if (!strncmp(cp, "single", sizeof("single") - 1)) {
+ statp->options |= RES_NO_NIBBLE2;
+ } else if (!strncmp(cp, "both", sizeof("both") - 1)) {
+ statp->options &=
+ ~RES_NO_NIBBLE2;
+ }
+ }
+ else {
+ /* XXX - print a warning here? */
+ }
+ skip:
+ /* skip to next run of spaces */
+ while (*cp && *cp != ' ' && *cp != '\t')
+ cp++;
+ }
+}
+
+#ifdef RESOLVSORT
+/* XXX - should really support CIDR which means explicit masks always. */
+static u_int32_t
+net_mask(in) /*!< XXX - should really use system's version of this */
+ struct in_addr in;
+{
+ register u_int32_t i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (htonl(IN_CLASSA_NET));
+ else if (IN_CLASSB(i))
+ return (htonl(IN_CLASSB_NET));
+ return (htonl(IN_CLASSC_NET));
+}
+#endif
+
+u_int
+res_randomid(void) {
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+ return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
+}
+
+/*%
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it. This provides support for endhostent()
+ * which expects to close the socket.
+ *
+ * This routine is not expected to be user visible.
+ */
+void
+res_nclose(res_state statp) {
+ int ns;
+
+ if (statp->_vcsock >= 0) {
+ (void) close(statp->_vcsock);
+ statp->_vcsock = -1;
+ statp->_flags &= ~(RES_F_VC | RES_F_CONN);
+ }
+ for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
+ if (statp->_u._ext.nssocks[ns] != -1) {
+ (void) close(statp->_u._ext.nssocks[ns]);
+ statp->_u._ext.nssocks[ns] = -1;
+ }
+ }
+}
+
+void
+res_ndestroy(res_state statp) {
+ res_nclose(statp);
+ if (statp->_u._ext.ext != NULL)
+ free(statp->_u._ext.ext);
+ statp->options &= ~RES_INIT;
+ statp->_u._ext.ext = NULL;
+}
+
+const char *
+res_get_nibblesuffix(res_state statp) {
+ if (statp->_u._ext.ext)
+ return (statp->_u._ext.ext->nsuffix);
+ return ("ip6.arpa");
+}
+
+const char *
+res_get_nibblesuffix2(res_state statp) {
+ if (statp->_u._ext.ext)
+ return (statp->_u._ext.ext->nsuffix2);
+ return ("ip6.int");
+}
+
+void
+res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
+ int i, nserv;
+ size_t size;
+
+ /* close open servers */
+ res_nclose(statp);
+
+ /* cause rtt times to be forgotten */
+ statp->_u._ext.nscount = 0;
+
+ nserv = 0;
+ for (i = 0; i < cnt && nserv < MAXNS; i++) {
+ switch (set->sin.sin_family) {
+ case AF_INET:
+ size = sizeof(set->sin);
+ if (statp->_u._ext.ext)
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+ &set->sin, size);
+ if (size <= sizeof(statp->nsaddr_list[nserv]))
+ memcpy(&statp->nsaddr_list[nserv],
+ &set->sin, size);
+ else
+ statp->nsaddr_list[nserv].sin_family = 0;
+ nserv++;
+ break;
+
+#ifdef HAS_INET6_STRUCTS
+ case AF_INET6:
+ size = sizeof(set->sin6);
+ if (statp->_u._ext.ext)
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+ &set->sin6, size);
+ if (size <= sizeof(statp->nsaddr_list[nserv]))
+ memcpy(&statp->nsaddr_list[nserv],
+ &set->sin6, size);
+ else
+ statp->nsaddr_list[nserv].sin_family = 0;
+ nserv++;
+ break;
+#endif
+
+ default:
+ break;
+ }
+ set++;
+ }
+ statp->nscount = nserv;
+
+}
+
+int
+res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
+ int i;
+ size_t size;
+ u_int16_t family;
+
+ for (i = 0; i < statp->nscount && i < cnt; i++) {
+ if (statp->_u._ext.ext)
+ family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
+ else
+ family = statp->nsaddr_list[i].sin_family;
+
+ switch (family) {
+ case AF_INET:
+ size = sizeof(set->sin);
+ if (statp->_u._ext.ext)
+ memcpy(&set->sin,
+ &statp->_u._ext.ext->nsaddrs[i],
+ size);
+ else
+ memcpy(&set->sin, &statp->nsaddr_list[i],
+ size);
+ break;
+
+#ifdef HAS_INET6_STRUCTS
+ case AF_INET6:
+ size = sizeof(set->sin6);
+ if (statp->_u._ext.ext)
+ memcpy(&set->sin6,
+ &statp->_u._ext.ext->nsaddrs[i],
+ size);
+ else
+ memcpy(&set->sin6, &statp->nsaddr_list[i],
+ size);
+ break;
+#endif
+
+ default:
+ set->sin.sin_family = 0;
+ break;
+ }
+ set++;
+ }
+ return (statp->nscount);
+}
+
+/*! \file */
diff --git a/lib/bind/resolv/res_mkquery.c b/lib/bind/resolv/res_mkquery.c
new file mode 100644
index 0000000..50e4a9e
--- /dev/null
+++ b/lib/bind/resolv/res_mkquery.c
@@ -0,0 +1,257 @@
+/*
+ * 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_mkquery.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_mkquery.c,v 1.5.18.1 2005/04/27 05:01:11 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include "port_after.h"
+
+/* Options. Leave them on. */
+#define DEBUG
+
+extern const char *_res_opcodes[];
+
+/*%
+ * Form all types of queries.
+ * Returns the size of the result or -1.
+ */
+int
+res_nmkquery(res_state statp,
+ int op, /*!< opcode of query */
+ const char *dname, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ const u_char *data, /*!< resource record data */
+ int datalen, /*!< length of data */
+ const u_char *newrr_in, /*!< new rr for modify or append */
+ u_char *buf, /*!< buffer to put query */
+ int buflen) /*!< size of buffer */
+{
+ register HEADER *hp;
+ register u_char *cp, *ep;
+ register int n;
+ u_char *dnptrs[20], **dpp, **lastdnptr;
+
+ UNUSED(newrr_in);
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_nmkquery(%s, %s, %s, %s)\n",
+ _res_opcodes[op], dname, p_class(class), p_type(type));
+#endif
+ /*
+ * Initialize header fields.
+ */
+ if ((buf == NULL) || (buflen < HFIXEDSZ))
+ return (-1);
+ memset(buf, 0, HFIXEDSZ);
+ hp = (HEADER *) buf;
+ hp->id = htons(++statp->id);
+ hp->opcode = op;
+ hp->rd = (statp->options & RES_RECURSE) != 0U;
+ hp->rcode = NOERROR;
+ cp = buf + HFIXEDSZ;
+ ep = buf + buflen;
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+ /*
+ * perform opcode specific processing
+ */
+ switch (op) {
+ case QUERY: /*FALLTHROUGH*/
+ case NS_NOTIFY_OP:
+ if (ep - cp < QFIXEDSZ)
+ return (-1);
+ if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs,
+ lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ ns_put16(type, cp);
+ cp += INT16SZ;
+ ns_put16(class, cp);
+ cp += INT16SZ;
+ hp->qdcount = htons(1);
+ if (op == QUERY || data == NULL)
+ break;
+ /*
+ * Make an additional record for completion domain.
+ */
+ if ((ep - cp) < RRFIXEDSZ)
+ return (-1);
+ n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
+ dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ns_put16(T_NULL, cp);
+ cp += INT16SZ;
+ ns_put16(class, cp);
+ cp += INT16SZ;
+ ns_put32(0, cp);
+ cp += INT32SZ;
+ ns_put16(0, cp);
+ cp += INT16SZ;
+ hp->arcount = htons(1);
+ break;
+
+ case IQUERY:
+ /*
+ * Initialize answer section
+ */
+ if (ep - cp < 1 + RRFIXEDSZ + datalen)
+ return (-1);
+ *cp++ = '\0'; /*%< no domain name */
+ ns_put16(type, cp);
+ cp += INT16SZ;
+ ns_put16(class, cp);
+ cp += INT16SZ;
+ ns_put32(0, cp);
+ cp += INT32SZ;
+ ns_put16(datalen, cp);
+ cp += INT16SZ;
+ if (datalen) {
+ memcpy(cp, data, datalen);
+ cp += datalen;
+ }
+ hp->ancount = htons(1);
+ break;
+
+ default:
+ return (-1);
+ }
+ return (cp - buf);
+}
+
+#ifdef RES_USE_EDNS0
+/* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */
+#ifndef T_OPT
+#define T_OPT 41
+#endif
+
+int
+res_nopt(res_state statp,
+ int n0, /*%< current offset in buffer */
+ u_char *buf, /*%< buffer to put query */
+ int buflen, /*%< size of buffer */
+ int anslen) /*%< UDP answer buffer size */
+{
+ register HEADER *hp;
+ register u_char *cp, *ep;
+ u_int16_t flags = 0;
+
+#ifdef DEBUG
+ if ((statp->options & RES_DEBUG) != 0U)
+ printf(";; res_nopt()\n");
+#endif
+
+ hp = (HEADER *) buf;
+ cp = buf + n0;
+ ep = buf + buflen;
+
+ if ((ep - cp) < 1 + RRFIXEDSZ)
+ return (-1);
+
+ *cp++ = 0; /*%< "." */
+ ns_put16(T_OPT, cp); /*%< TYPE */
+ cp += INT16SZ;
+ ns_put16(anslen & 0xffff, cp); /*%< CLASS = UDP payload size */
+ cp += INT16SZ;
+ *cp++ = NOERROR; /*%< extended RCODE */
+ *cp++ = 0; /*%< EDNS version */
+ if (statp->options & RES_USE_DNSSEC) {
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_opt()... ENDS0 DNSSEC\n");
+#endif
+ flags |= NS_OPT_DNSSEC_OK;
+ }
+ ns_put16(flags, cp);
+ cp += INT16SZ;
+ ns_put16(0, cp); /*%< RDLEN */
+ cp += INT16SZ;
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+
+ return (cp - buf);
+}
+#endif
+
+/*! \file */
diff --git a/lib/bind/resolv/res_mkupdate.c b/lib/bind/resolv/res_mkupdate.c
new file mode 100644
index 0000000..4299275
--- /dev/null
+++ b/lib/bind/resolv/res_mkupdate.c
@@ -0,0 +1,1162 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file
+ * \brief
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * &lt;viraj_bais@ccm.fm.intel.com>
+ */
+
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_mkupdate.c,v 1.4.18.4 2005/10/14 05:44:12 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <res_update.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "port_after.h"
+
+/* Options. Leave them on. */
+#define DEBUG
+#define MAXPORT 1024
+
+static int getnum_str(u_char **, u_char *);
+static int gethexnum_str(u_char **, u_char *);
+static int getword_str(char *, int, u_char **, u_char *);
+static int getstr_str(char *, int, u_char **, u_char *);
+
+#define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
+
+/* Forward. */
+
+int res_protocolnumber(const char *);
+int res_servicenumber(const char *);
+
+/*%
+ * Form update packets.
+ * Returns the size of the resulting packet if no error
+ *
+ * On error,
+ * returns
+ *\li -1 if error in reading a word/number in rdata
+ * portion for update packets
+ *\li -2 if length of buffer passed is insufficient
+ *\li -3 if zone section is not the first section in
+ * the linked list, or section order has a problem
+ *\li -4 on a number overflow
+ *\li -5 unknown operation or no records
+ */
+int
+res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
+ ns_updrec *rrecp_start = rrecp_in;
+ HEADER *hp;
+ u_char *cp, *sp2, *startp, *endp;
+ int n, i, soanum, multiline;
+ ns_updrec *rrecp;
+ struct in_addr ina;
+ struct in6_addr in6a;
+ char buf2[MAXDNAME];
+ u_char buf3[MAXDNAME];
+ int section, numrrs = 0, counts[ns_s_max];
+ u_int16_t rtype, rclass;
+ u_int32_t n1, rttl;
+ u_char *dnptrs[20], **dpp, **lastdnptr;
+ int siglen, keylen, certlen;
+
+ /*
+ * Initialize header fields.
+ */
+ if ((buf == NULL) || (buflen < HFIXEDSZ))
+ return (-1);
+ memset(buf, 0, HFIXEDSZ);
+ hp = (HEADER *) buf;
+ hp->id = htons(++statp->id);
+ hp->opcode = ns_o_update;
+ hp->rcode = NOERROR;
+ cp = buf + HFIXEDSZ;
+ buflen -= HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+
+ if (rrecp_start == NULL)
+ return (-5);
+ else if (rrecp_start->r_section != S_ZONE)
+ return (-3);
+
+ memset(counts, 0, sizeof counts);
+ for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) {
+ numrrs++;
+ section = rrecp->r_section;
+ if (section < 0 || section >= ns_s_max)
+ return (-1);
+ counts[section]++;
+ for (i = section + 1; i < ns_s_max; i++)
+ if (counts[i])
+ return (-3);
+ rtype = rrecp->r_type;
+ rclass = rrecp->r_class;
+ rttl = rrecp->r_ttl;
+ /* overload class and type */
+ if (section == S_PREREQ) {
+ rttl = 0;
+ switch (rrecp->r_opcode) {
+ case YXDOMAIN:
+ rclass = C_ANY;
+ rtype = T_ANY;
+ rrecp->r_size = 0;
+ break;
+ case NXDOMAIN:
+ rclass = C_NONE;
+ rtype = T_ANY;
+ rrecp->r_size = 0;
+ break;
+ case NXRRSET:
+ rclass = C_NONE;
+ rrecp->r_size = 0;
+ break;
+ case YXRRSET:
+ if (rrecp->r_size == 0)
+ rclass = C_ANY;
+ break;
+ default:
+ fprintf(stderr,
+ "res_mkupdate: incorrect opcode: %d\n",
+ rrecp->r_opcode);
+ fflush(stderr);
+ return (-1);
+ }
+ } else if (section == S_UPDATE) {
+ switch (rrecp->r_opcode) {
+ case DELETE:
+ rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
+ break;
+ case ADD:
+ break;
+ default:
+ fprintf(stderr,
+ "res_mkupdate: incorrect opcode: %d\n",
+ rrecp->r_opcode);
+ fflush(stderr);
+ return (-1);
+ }
+ }
+
+ /*
+ * XXX appending default domain to owner name is omitted,
+ * fqdn must be provided
+ */
+ if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
+ lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n + 2*INT16SZ);
+ PUTSHORT(rtype, cp);
+ PUTSHORT(rclass, cp);
+ if (section == S_ZONE) {
+ if (numrrs != 1 || rrecp->r_type != T_SOA)
+ return (-3);
+ continue;
+ }
+ ShrinkBuffer(INT32SZ + INT16SZ);
+ PUTLONG(rttl, cp);
+ sp2 = cp; /*%< save pointer to length byte */
+ cp += INT16SZ;
+ if (rrecp->r_size == 0) {
+ if (section == S_UPDATE && rclass != C_ANY)
+ return (-1);
+ else {
+ PUTSHORT(0, sp2);
+ continue;
+ }
+ }
+ startp = rrecp->r_data;
+ endp = startp + rrecp->r_size - 1;
+ /* XXX this should be done centrally. */
+ switch (rrecp->r_type) {
+ case T_A:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (!inet_aton(buf2, &ina))
+ return (-1);
+ n1 = ntohl(ina.s_addr);
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(n1, cp);
+ break;
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ case ns_t_dname:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ for (i = 0; i < 2; i++) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen,
+ dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ }
+ if (rrecp->r_type == T_SOA) {
+ ShrinkBuffer(5 * INT32SZ);
+ while (isspace(*startp) || !*startp)
+ startp++;
+ if (*startp == '(') {
+ multiline = 1;
+ startp++;
+ } else
+ multiline = 0;
+ /* serial, refresh, retry, expire, minimum */
+ for (i = 0; i < 5; i++) {
+ soanum = getnum_str(&startp, endp);
+ if (soanum < 0)
+ return (-1);
+ PUTLONG(soanum, cp);
+ }
+ if (multiline) {
+ while (isspace(*startp) || !*startp)
+ startp++;
+ if (*startp != ')')
+ return (-1);
+ }
+ }
+ break;
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case T_SRV:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, NULL, NULL);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case T_PX:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ PUTSHORT(n, cp);
+ ShrinkBuffer(INT16SZ);
+ for (i = 0; i < 2; i++) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs,
+ lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ }
+ break;
+ case T_WKS: {
+ char bm[MAXPORT/8];
+ unsigned int maxbm = 0;
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (!inet_aton(buf2, &ina))
+ return (-1);
+ n1 = ntohl(ina.s_addr);
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(n1, cp);
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if ((i = res_protocolnumber(buf2)) < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = i & 0xff;
+
+ for (i = 0; i < MAXPORT/8 ; i++)
+ bm[i] = 0;
+
+ while (getword_str(buf2, sizeof buf2, &startp, endp)) {
+ if ((n = res_servicenumber(buf2)) <= 0)
+ return (-1);
+
+ if (n < MAXPORT) {
+ bm[n/8] |= (0x80>>(n%8));
+ if ((unsigned)n > maxbm)
+ maxbm = n;
+ } else
+ return (-1);
+ }
+ maxbm = maxbm/8 + 1;
+ ShrinkBuffer(maxbm);
+ memcpy(cp, bm, maxbm);
+ cp += maxbm;
+ break;
+ }
+ case T_HINFO:
+ for (i = 0; i < 2; i++) {
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ }
+ break;
+ case T_TXT:
+ for (;;) {
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ if (cp != (sp2 + INT16SZ))
+ break;
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ }
+ break;
+ case T_X25:
+ /* RFC1183 */
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ return (-1);
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ break;
+ case T_ISDN:
+ /* RFC1183 */
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ return (-1);
+ if ((n > 255) || (n == 0))
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ n = 0;
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ break;
+ case T_NSAP:
+ if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) {
+ ShrinkBuffer(n);
+ memcpy(cp, buf2, n);
+ cp += n;
+ } else {
+ return (-1);
+ }
+ break;
+ case T_LOC:
+ if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) {
+ ShrinkBuffer(n);
+ memcpy(cp, buf2, n);
+ cp += n;
+ } else
+ return (-1);
+ break;
+ case ns_t_sig:
+ {
+ int sig_type, success, dateerror;
+ u_int32_t exptime, timesigned;
+
+ /* type */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ sig_type = sym_ston(__p_type_syms, buf2, &success);
+ if (!success || sig_type == ns_t_any)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(sig_type, cp);
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* labels */
+ n = getnum_str(&startp, endp);
+ if (n <= 0 || n > 255)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* ottl & expire */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ exptime = ns_datetosecs(buf2, &dateerror);
+ if (!dateerror) {
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(rttl, cp);
+ }
+ else {
+ char *ulendp;
+ u_int32_t ottl;
+
+ errno = 0;
+ ottl = strtoul(buf2, &ulendp, 10);
+ if (errno != 0 ||
+ (ulendp != NULL && *ulendp != '\0'))
+ return (-1);
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(ottl, cp);
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ exptime = ns_datetosecs(buf2, &dateerror);
+ if (dateerror)
+ return (-1);
+ }
+ /* expire */
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(exptime, cp);
+ /* timesigned */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ timesigned = ns_datetosecs(buf2, &dateerror);
+ if (!dateerror) {
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(timesigned, cp);
+ }
+ else
+ return (-1);
+ /* footprint */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* signer name */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ /* sig */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ siglen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (siglen < 0)
+ return (-1);
+ ShrinkBuffer(siglen);
+ memcpy(cp, buf3, siglen);
+ cp += siglen;
+ break;
+ }
+ case ns_t_key:
+ /* flags */
+ n = gethexnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* proto */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* key */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ keylen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (keylen < 0)
+ return (-1);
+ ShrinkBuffer(keylen);
+ memcpy(cp, buf3, keylen);
+ cp += keylen;
+ break;
+ case ns_t_nxt:
+ {
+ int success, nxt_type;
+ u_char data[32];
+ int maxtype;
+
+ /* next name */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, NULL, NULL);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ maxtype = 0;
+ memset(data, 0, sizeof data);
+ for (;;) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ break;
+ nxt_type = sym_ston(__p_type_syms, buf2,
+ &success);
+ if (!success || !ns_t_rr_p(nxt_type))
+ return (-1);
+ NS_NXT_BIT_SET(nxt_type, data);
+ if (nxt_type > maxtype)
+ maxtype = nxt_type;
+ }
+ n = maxtype/NS_NXT_BITS+1;
+ ShrinkBuffer(n);
+ memcpy(cp, data, n);
+ cp += n;
+ break;
+ }
+ case ns_t_cert:
+ /* type */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* key tag */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* cert */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ certlen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (certlen < 0)
+ return (-1);
+ ShrinkBuffer(certlen);
+ memcpy(cp, buf3, certlen);
+ cp += certlen;
+ break;
+ case ns_t_aaaa:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (inet_pton(AF_INET6, buf2, &in6a) <= 0)
+ return (-1);
+ ShrinkBuffer(NS_IN6ADDRSZ);
+ memcpy(cp, &in6a, NS_IN6ADDRSZ);
+ cp += NS_IN6ADDRSZ;
+ break;
+ case ns_t_naptr:
+ /* Order Preference Flags Service Replacement Regexp */
+ /* Order */
+ n = getnum_str(&startp, endp);
+ if (n < 0 || n > 65535)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* Preference */
+ n = getnum_str(&startp, endp);
+ if (n < 0 || n > 65535)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* Flags */
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ /* Service Classes */
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ /* Pattern */
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ /* Replacement */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, NULL, NULL);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ default:
+ return (-1);
+ } /*switch*/
+ n = (u_int16_t)((cp - sp2) - INT16SZ);
+ PUTSHORT(n, sp2);
+ } /*for*/
+
+ hp->qdcount = htons(counts[0]);
+ hp->ancount = htons(counts[1]);
+ hp->nscount = htons(counts[2]);
+ hp->arcount = htons(counts[3]);
+ return (cp - buf);
+}
+
+/*%
+ * Get a whitespace delimited word from a string (not file)
+ * into buf. modify the start pointer to point after the
+ * word in the string.
+ */
+static int
+getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
+ char *cp;
+ int c;
+
+ for (cp = buf; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (cp != buf) /*%< trailing whitespace */
+ break;
+ else { /*%< leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ (*startpp)++;
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = (u_char)c;
+ }
+ *cp = '\0';
+ return (cp != buf);
+}
+
+/*%
+ * get a white spae delimited string from memory. Process quoted strings
+ * and \\DDD escapes. Return length or -1 on error. Returned string may
+ * contain nulls.
+ */
+static char digits[] = "0123456789";
+static int
+getstr_str(char *buf, int size, u_char **startpp, u_char *endp) {
+ char *cp;
+ int c, c1 = 0;
+ int inquote = 0;
+ int seen_quote = 0;
+ int escape = 0;
+ int dig = 0;
+
+ for (cp = buf; *startpp <= endp; ) {
+ if ((c = **startpp) == '\0')
+ break;
+ /* leading white space */
+ if ((cp == buf) && !seen_quote && isspace(c)) {
+ (*startpp)++;
+ continue;
+ }
+
+ switch (c) {
+ case '\\':
+ if (!escape) {
+ escape = 1;
+ dig = 0;
+ c1 = 0;
+ (*startpp)++;
+ continue;
+ }
+ goto do_escape;
+ case '"':
+ if (!escape) {
+ inquote = !inquote;
+ seen_quote = 1;
+ (*startpp)++;
+ continue;
+ }
+ /* fall through */
+ default:
+ do_escape:
+ if (escape) {
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ c1 = c1 * 10 +
+ (strchr(digits, c) - digits);
+
+ if (++dig == 3) {
+ c = c1 &0xff;
+ break;
+ }
+ (*startpp)++;
+ continue;
+ }
+ escape = 0;
+ } else if (!inquote && isspace(c))
+ goto done;
+ if (cp >= buf+size-1)
+ goto done;
+ *cp++ = (u_char)c;
+ (*startpp)++;
+ }
+ }
+ done:
+ *cp = '\0';
+ return ((cp == buf)? (seen_quote? 0: -1): (cp - buf));
+}
+
+/*%
+ * Get a whitespace delimited base 16 number from a string (not file) into buf
+ * update the start pointer to point after the number in the string.
+ */
+static int
+gethexnum_str(u_char **startpp, u_char *endp) {
+ int c, n;
+ int seendigit = 0;
+ int m = 0;
+
+ if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
+ return getnum_str(startpp, endp);
+ (*startpp)+=2;
+ for (n = 0; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (seendigit) /*%< trailing whitespace */
+ break;
+ else { /*%< leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ if (c == ';') {
+ while ((*startpp <= endp) &&
+ ((c = **startpp) != '\n'))
+ (*startpp)++;
+ if (seendigit)
+ break;
+ continue;
+ }
+ if (!isxdigit(c)) {
+ if (c == ')' && seendigit) {
+ (*startpp)--;
+ break;
+ }
+ return (-1);
+ }
+ (*startpp)++;
+ if (isdigit(c))
+ n = n * 16 + (c - '0');
+ else
+ n = n * 16 + (tolower(c) - 'a' + 10);
+ seendigit = 1;
+ }
+ return (n + m);
+}
+
+/*%
+ * Get a whitespace delimited base 10 number from a string (not file) into buf
+ * update the start pointer to point after the number in the string.
+ */
+static int
+getnum_str(u_char **startpp, u_char *endp) {
+ int c, n;
+ int seendigit = 0;
+ int m = 0;
+
+ for (n = 0; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (seendigit) /*%< trailing whitespace */
+ break;
+ else { /*%< leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ if (c == ';') {
+ while ((*startpp <= endp) &&
+ ((c = **startpp) != '\n'))
+ (*startpp)++;
+ if (seendigit)
+ break;
+ continue;
+ }
+ if (!isdigit(c)) {
+ if (c == ')' && seendigit) {
+ (*startpp)--;
+ break;
+ }
+ return (-1);
+ }
+ (*startpp)++;
+ n = n * 10 + (c - '0');
+ seendigit = 1;
+ }
+ return (n + m);
+}
+
+/*%
+ * Allocate a resource record buffer & save rr info.
+ */
+ns_updrec *
+res_mkupdrec(int section, const char *dname,
+ u_int class, u_int type, u_long ttl) {
+ ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
+
+ if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
+ if (rrecp)
+ free((char *)rrecp);
+ return (NULL);
+ }
+ INIT_LINK(rrecp, r_link);
+ INIT_LINK(rrecp, r_glink);
+ rrecp->r_class = (ns_class)class;
+ rrecp->r_type = (ns_type)type;
+ rrecp->r_ttl = ttl;
+ rrecp->r_section = (ns_sect)section;
+ return (rrecp);
+}
+
+/*%
+ * Free a resource record buffer created by res_mkupdrec.
+ */
+void
+res_freeupdrec(ns_updrec *rrecp) {
+ /* Note: freeing r_dp is the caller's responsibility. */
+ if (rrecp->r_dname != NULL)
+ free(rrecp->r_dname);
+ free(rrecp);
+}
+
+struct valuelist {
+ struct valuelist * next;
+ struct valuelist * prev;
+ char * name;
+ char * proto;
+ int port;
+};
+static struct valuelist *servicelist, *protolist;
+
+static void
+res_buildservicelist() {
+ struct servent *sp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setservent(0);
+#else
+ setservent(1);
+#endif
+ while ((sp = getservent()) != NULL) {
+ slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+ if (!slp)
+ break;
+ slp->name = strdup(sp->s_name);
+ slp->proto = strdup(sp->s_proto);
+ if ((slp->name == NULL) || (slp->proto == NULL)) {
+ if (slp->name) free(slp->name);
+ if (slp->proto) free(slp->proto);
+ free(slp);
+ break;
+ }
+ slp->port = ntohs((u_int16_t)sp->s_port); /*%< host byt order */
+ slp->next = servicelist;
+ slp->prev = NULL;
+ if (servicelist)
+ servicelist->prev = slp;
+ servicelist = slp;
+ }
+ endservent();
+}
+
+void
+res_destroyservicelist() {
+ struct valuelist *slp, *slp_next;
+
+ for (slp = servicelist; slp != NULL; slp = slp_next) {
+ slp_next = slp->next;
+ free(slp->name);
+ free(slp->proto);
+ free(slp);
+ }
+ servicelist = (struct valuelist *)0;
+}
+
+void
+res_buildprotolist(void) {
+ struct protoent *pp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setprotoent(0);
+#else
+ setprotoent(1);
+#endif
+ while ((pp = getprotoent()) != NULL) {
+ slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+ if (!slp)
+ break;
+ slp->name = strdup(pp->p_name);
+ if (slp->name == NULL) {
+ free(slp);
+ break;
+ }
+ slp->port = pp->p_proto; /*%< host byte order */
+ slp->next = protolist;
+ slp->prev = NULL;
+ if (protolist)
+ protolist->prev = slp;
+ protolist = slp;
+ }
+ endprotoent();
+}
+
+void
+res_destroyprotolist(void) {
+ struct valuelist *plp, *plp_next;
+
+ for (plp = protolist; plp != NULL; plp = plp_next) {
+ plp_next = plp->next;
+ free(plp->name);
+ free(plp);
+ }
+ protolist = (struct valuelist *)0;
+}
+
+static int
+findservice(const char *s, struct valuelist **list) {
+ struct valuelist *lp = *list;
+ int n;
+
+ for (; lp != NULL; lp = lp->next)
+ if (strcasecmp(lp->name, s) == 0) {
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ return (lp->port); /*%< host byte order */
+ }
+ if (sscanf(s, "%d", &n) != 1 || n <= 0)
+ n = -1;
+ return (n);
+}
+
+/*%
+ * Convert service name or (ascii) number to int.
+ */
+int
+res_servicenumber(const char *p) {
+ if (servicelist == (struct valuelist *)0)
+ res_buildservicelist();
+ return (findservice(p, &servicelist));
+}
+
+/*%
+ * Convert protocol name or (ascii) number to int.
+ */
+int
+res_protocolnumber(const char *p) {
+ if (protolist == (struct valuelist *)0)
+ res_buildprotolist();
+ return (findservice(p, &protolist));
+}
+
+static struct servent *
+cgetservbyport(u_int16_t port, const char *proto) { /*%< Host byte order. */
+ struct valuelist **list = &servicelist;
+ struct valuelist *lp = *list;
+ static struct servent serv;
+
+ port = ntohs(port);
+ for (; lp != NULL; lp = lp->next) {
+ if (port != (u_int16_t)lp->port) /*%< Host byte order. */
+ continue;
+ if (strcasecmp(lp->proto, proto) == 0) {
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ serv.s_name = lp->name;
+ serv.s_port = htons((u_int16_t)lp->port);
+ serv.s_proto = lp->proto;
+ return (&serv);
+ }
+ }
+ return (0);
+}
+
+static struct protoent *
+cgetprotobynumber(int proto) { /*%< Host byte order. */
+ struct valuelist **list = &protolist;
+ struct valuelist *lp = *list;
+ static struct protoent prot;
+
+ for (; lp != NULL; lp = lp->next)
+ if (lp->port == proto) { /*%< Host byte order. */
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ prot.p_name = lp->name;
+ prot.p_proto = lp->port; /*%< Host byte order. */
+ return (&prot);
+ }
+ return (0);
+}
+
+const char *
+res_protocolname(int num) {
+ static char number[8];
+ struct protoent *pp;
+
+ if (protolist == (struct valuelist *)0)
+ res_buildprotolist();
+ pp = cgetprotobynumber(num);
+ if (pp == 0) {
+ (void) sprintf(number, "%d", num);
+ return (number);
+ }
+ return (pp->p_name);
+}
+
+const char *
+res_servicename(u_int16_t port, const char *proto) { /*%< Host byte order. */
+ static char number[8];
+ struct servent *ss;
+
+ if (servicelist == (struct valuelist *)0)
+ res_buildservicelist();
+ ss = cgetservbyport(htons(port), proto);
+ if (ss == 0) {
+ (void) sprintf(number, "%d", port);
+ return (number);
+ }
+ return (ss->s_name);
+}
diff --git a/lib/bind/resolv/res_mkupdate.h b/lib/bind/resolv/res_mkupdate.h
new file mode 100644
index 0000000..96c452d
--- /dev/null
+++ b/lib/bind/resolv/res_mkupdate.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#ifndef _RES_MKUPDATE_H_
+#define _RES_MKUPDATE_H_
+
+__BEGIN_DECLS
+__END_DECLS
+
+#endif /* _RES_MKUPDATE_H_ */
+/*! \file */
diff --git a/lib/bind/resolv/res_private.h b/lib/bind/resolv/res_private.h
new file mode 100644
index 0000000..4e98157
--- /dev/null
+++ b/lib/bind/resolv/res_private.h
@@ -0,0 +1,22 @@
+#ifndef res_private_h
+#define res_private_h
+
+struct __res_state_ext {
+ union res_sockaddr_union nsaddrs[MAXNS];
+ struct sort_list {
+ int af;
+ union {
+ struct in_addr ina;
+ struct in6_addr in6a;
+ } addr, mask;
+ } sort_list[MAXRESOLVSORT];
+ char nsuffix[64];
+ char nsuffix2[64];
+};
+
+extern int
+res_ourserver_p(const res_state statp, const struct sockaddr *sa);
+
+#endif
+
+/*! \file */
diff --git a/lib/bind/resolv/res_query.c b/lib/bind/resolv/res_query.c
new file mode 100644
index 0000000..c160e93
--- /dev/null
+++ b/lib/bind/resolv/res_query.c
@@ -0,0 +1,432 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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_query.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_query.c,v 1.7.18.1 2005/04/27 05:01:11 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "port_after.h"
+
+/* Options. Leave them on. */
+#define DEBUG
+
+#if PACKETSZ > 1024
+#define MAXPACKET PACKETSZ
+#else
+#define MAXPACKET 1024
+#endif
+
+/*%
+ * Formulate a normal query, send, and await answer.
+ * Returned answer is placed in supplied buffer "answer".
+ * Perform preliminary check of answer, returning success only
+ * if no error is indicated and the answer count is nonzero.
+ * Return the size of the response on success, -1 on error.
+ * Error number is left in H_ERRNO.
+ *
+ * Caller must parse answer and determine whether it answers the question.
+ */
+int
+res_nquery(res_state statp,
+ const char *name, /*%< domain name */
+ int class, int type, /*%< class and type of query */
+ u_char *answer, /*%< buffer to put answer */
+ int anslen) /*%< size of answer buffer */
+{
+ u_char buf[MAXPACKET];
+ HEADER *hp = (HEADER *) answer;
+ int n;
+ u_int oflags;
+
+ oflags = statp->_flags;
+
+again:
+ hp->rcode = NOERROR; /*%< default */
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_query(%s, %d, %d)\n", name, class, type);
+#endif
+
+ n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
+ buf, sizeof(buf));
+#ifdef RES_USE_EDNS0
+ if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 &&
+ (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U)
+ n = res_nopt(statp, n, buf, sizeof(buf), anslen);
+#endif
+ if (n <= 0) {
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_query: mkquery failed\n");
+#endif
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (n);
+ }
+ n = res_nsend(statp, buf, n, answer, anslen);
+ if (n < 0) {
+#ifdef RES_USE_EDNS0
+ /* if the query choked with EDNS0, retry without EDNS0 */
+ if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U &&
+ ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
+ statp->_flags |= RES_F_EDNS0ERR;
+ if (statp->options & RES_DEBUG)
+ printf(";; res_nquery: retry without EDNS0\n");
+ goto again;
+ }
+#endif
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_query: send error\n");
+#endif
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (n);
+ }
+
+ if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; rcode = (%s), counts = an:%d ns:%d ar:%d\n",
+ p_rcode(hp->rcode),
+ ntohs(hp->ancount),
+ ntohs(hp->nscount),
+ ntohs(hp->arcount));
+#endif
+ switch (hp->rcode) {
+ case NXDOMAIN:
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ break;
+ case SERVFAIL:
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ break;
+ case NOERROR:
+ RES_SET_H_ERRNO(statp, NO_DATA);
+ break;
+ case FORMERR:
+ case NOTIMP:
+ case REFUSED:
+ default:
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ break;
+ }
+ return (-1);
+ }
+ return (n);
+}
+
+/*%
+ * Formulate a normal query, send, and retrieve answer in supplied buffer.
+ * Return the size of the response on success, -1 on error.
+ * If enabled, implement search rules until answer or unrecoverable failure
+ * is detected. Error code, if any, is left in H_ERRNO.
+ */
+int
+res_nsearch(res_state statp,
+ const char *name, /*%< domain name */
+ int class, int type, /*%< class and type of query */
+ u_char *answer, /*%< buffer to put answer */
+ int anslen) /*%< size of answer */
+{
+ const char *cp, * const *domain;
+ HEADER *hp = (HEADER *) answer;
+ char tmp[NS_MAXDNAME];
+ u_int dots;
+ int trailing_dot, ret, saved_herrno;
+ int got_nodata = 0, got_servfail = 0, root_on_list = 0;
+ int tried_as_is = 0;
+ int searched = 0;
+
+ errno = 0;
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /*%< True if we never query. */
+ dots = 0;
+ for (cp = name; *cp != '\0'; cp++)
+ dots += (*cp == '.');
+ trailing_dot = 0;
+ if (cp > name && *--cp == '.')
+ trailing_dot++;
+
+ /* If there aren't any dots, it could be a user-level alias. */
+ if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
+ return (res_nquery(statp, cp, class, type, answer, anslen));
+
+ /*
+ * If there are enough dots in the name, let's just give it a
+ * try 'as is'. The threshold can be set with the "ndots" option.
+ * Also, query 'as is', if there is a trailing dot in the name.
+ */
+ saved_herrno = -1;
+ if (dots >= statp->ndots || trailing_dot) {
+ ret = res_nquerydomain(statp, name, NULL, class, type,
+ answer, anslen);
+ if (ret > 0 || trailing_dot)
+ return (ret);
+ saved_herrno = statp->res_h_errno;
+ tried_as_is++;
+ }
+
+ /*
+ * We do at least one level of search if
+ * - there is no dot and RES_DEFNAME is set, or
+ * - there is at least one dot, there is no trailing dot,
+ * and RES_DNSRCH is set.
+ */
+ if ((!dots && (statp->options & RES_DEFNAMES) != 0U) ||
+ (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0U)) {
+ int done = 0;
+
+ for (domain = (const char * const *)statp->dnsrch;
+ *domain && !done;
+ domain++) {
+ searched = 1;
+
+ if (domain[0][0] == '\0' ||
+ (domain[0][0] == '.' && domain[0][1] == '\0'))
+ root_on_list++;
+
+ ret = res_nquerydomain(statp, name, *domain,
+ class, type,
+ answer, anslen);
+ if (ret > 0)
+ return (ret);
+
+ /*
+ * If no server present, give up.
+ * If name isn't found in this domain,
+ * keep trying higher domains in the search list
+ * (if that's enabled).
+ * On a NO_DATA error, keep trying, otherwise
+ * a wildcard entry of another type could keep us
+ * from finding this entry higher in the domain.
+ * If we get some other error (negative answer or
+ * server failure), then stop searching up,
+ * but try the input name below in case it's
+ * fully-qualified.
+ */
+ if (errno == ECONNREFUSED) {
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (-1);
+ }
+
+ switch (statp->res_h_errno) {
+ case NO_DATA:
+ got_nodata++;
+ /* FALLTHROUGH */
+ case HOST_NOT_FOUND:
+ /* keep trying */
+ break;
+ case TRY_AGAIN:
+ if (hp->rcode == SERVFAIL) {
+ /* try next search element, if any */
+ got_servfail++;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ /* anything else implies that we're done */
+ done++;
+ }
+
+ /* if we got here for some reason other than DNSRCH,
+ * we only wanted one iteration of the loop, so stop.
+ */
+ if ((statp->options & RES_DNSRCH) == 0U)
+ done++;
+ }
+ }
+
+ /*
+ * If the query has not already been tried as is then try it
+ * unless RES_NOTLDQUERY is set and there were no dots.
+ */
+ if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0U) &&
+ !(tried_as_is || root_on_list)) {
+ ret = res_nquerydomain(statp, name, NULL, class, type,
+ answer, anslen);
+ if (ret > 0)
+ return (ret);
+ }
+
+ /* if we got here, we didn't satisfy the search.
+ * if we did an initial full query, return that query's H_ERRNO
+ * (note that we wouldn't be here if that query had succeeded).
+ * else if we ever got a nodata, send that back as the reason.
+ * else send back meaningless H_ERRNO, that being the one from
+ * the last DNSRCH we did.
+ */
+ if (saved_herrno != -1)
+ RES_SET_H_ERRNO(statp, saved_herrno);
+ else if (got_nodata)
+ RES_SET_H_ERRNO(statp, NO_DATA);
+ else if (got_servfail)
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (-1);
+}
+
+/*%
+ * Perform a call on res_query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+int
+res_nquerydomain(res_state statp,
+ const char *name,
+ const char *domain,
+ int class, int type, /*%< class and type of query */
+ u_char *answer, /*%< buffer to put answer */
+ int anslen) /*%< size of answer */
+{
+ char nbuf[MAXDNAME];
+ const char *longname = nbuf;
+ int n, d;
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
+ name, domain?domain:"<Nil>", class, type);
+#endif
+ if (domain == NULL) {
+ /*
+ * Check for trailing '.';
+ * copy without '.' if present.
+ */
+ n = strlen(name);
+ if (n >= MAXDNAME) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ n--;
+ if (n >= 0 && name[n] == '.') {
+ strncpy(nbuf, name, n);
+ nbuf[n] = '\0';
+ } else
+ longname = name;
+ } else {
+ n = strlen(name);
+ d = strlen(domain);
+ if (n + d + 1 >= MAXDNAME) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ sprintf(nbuf, "%s.%s", name, domain);
+ }
+ return (res_nquery(statp, longname, class, type, answer, anslen));
+}
+
+const char *
+res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
+ char *file, *cp1, *cp2;
+ char buf[BUFSIZ];
+ FILE *fp;
+
+ if (statp->options & RES_NOALIASES)
+ return (NULL);
+ file = getenv("HOSTALIASES");
+ if (file == NULL || (fp = fopen(file, "r")) == NULL)
+ return (NULL);
+ setbuf(fp, NULL);
+ buf[sizeof(buf) - 1] = '\0';
+ while (fgets(buf, sizeof(buf), fp)) {
+ for (cp1 = buf; *cp1 && !isspace((unsigned char)*cp1); ++cp1)
+ ;
+ if (!*cp1)
+ break;
+ *cp1 = '\0';
+ if (ns_samename(buf, name) == 1) {
+ while (isspace((unsigned char)*++cp1))
+ ;
+ if (!*cp1)
+ break;
+ for (cp2 = cp1 + 1; *cp2 &&
+ !isspace((unsigned char)*cp2); ++cp2)
+ ;
+ *cp2 = '\0';
+ strncpy(dst, cp1, siz - 1);
+ dst[siz - 1] = '\0';
+ fclose(fp);
+ return (dst);
+ }
+ }
+ fclose(fp);
+ return (NULL);
+}
+
+/*! \file */
diff --git a/lib/bind/resolv/res_send.c b/lib/bind/resolv/res_send.c
new file mode 100644
index 0000000..39dc998
--- /dev/null
+++ b/lib/bind/resolv/res_send.c
@@ -0,0 +1,1094 @@
+/*
+ * Copyright (c) 1985, 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.
+ */
+
+/*
+ * 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) 2005 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_send.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_send.c,v 1.9.18.8 2006/10/16 23:00:58 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*! \file
+ * \brief
+ * Send query to name server and wait for reply.
+ */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+
+#include "port_after.h"
+
+#ifdef USE_POLL
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+#include <poll.h>
+#endif /* USE_POLL */
+
+/* Options. Leave them on. */
+#define DEBUG
+#include "res_debug.h"
+#include "res_private.h"
+
+#define EXT(res) ((res)->_u._ext)
+
+#ifndef USE_POLL
+static const int highestFD = FD_SETSIZE - 1;
+#else
+static int highestFD = 0;
+#endif
+
+/* Forward. */
+
+static int get_salen __P((const struct sockaddr *));
+static struct sockaddr * get_nsaddr __P((res_state, size_t));
+static int send_vc(res_state, const u_char *, int,
+ u_char *, int, int *, int);
+static int send_dg(res_state, const u_char *, int,
+ u_char *, int, int *, int, int,
+ int *, int *);
+static void Aerror(const res_state, FILE *, const char *, int,
+ const struct sockaddr *, int);
+static void Perror(const res_state, FILE *, const char *, int);
+static int sock_eq(struct sockaddr *, struct sockaddr *);
+#if defined(NEED_PSELECT) && !defined(USE_POLL)
+static int pselect(int, void *, void *, void *,
+ struct timespec *,
+ const sigset_t *);
+#endif
+void res_pquery(const res_state, const u_char *, int, FILE *);
+
+static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
+
+/* Public. */
+
+/*%
+ * looks up "ina" in _res.ns_addr_list[]
+ *
+ * returns:
+ *\li 0 : not found
+ *\li >0 : found
+ *
+ * author:
+ *\li paul vixie, 29may94
+ */
+int
+res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
+ const struct sockaddr_in *inp, *srv;
+ const struct sockaddr_in6 *in6p, *srv6;
+ int ns;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ inp = (const struct sockaddr_in *)sa;
+ for (ns = 0; ns < statp->nscount; ns++) {
+ srv = (struct sockaddr_in *)get_nsaddr(statp, ns);
+ if (srv->sin_family == inp->sin_family &&
+ srv->sin_port == inp->sin_port &&
+ (srv->sin_addr.s_addr == INADDR_ANY ||
+ srv->sin_addr.s_addr == inp->sin_addr.s_addr))
+ return (1);
+ }
+ break;
+ case AF_INET6:
+ if (EXT(statp).ext == NULL)
+ break;
+ in6p = (const struct sockaddr_in6 *)sa;
+ for (ns = 0; ns < statp->nscount; ns++) {
+ srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns);
+ if (srv6->sin6_family == in6p->sin6_family &&
+ srv6->sin6_port == in6p->sin6_port &&
+#ifdef HAVE_SIN6_SCOPE_ID
+ (srv6->sin6_scope_id == 0 ||
+ srv6->sin6_scope_id == in6p->sin6_scope_id) &&
+#endif
+ (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
+ IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
+ return (1);
+ }
+ break;
+ default:
+ break;
+ }
+ return (0);
+}
+
+/*%
+ * look for (name,type,class) in the query section of packet (buf,eom)
+ *
+ * requires:
+ *\li buf + HFIXEDSZ <= eom
+ *
+ * returns:
+ *\li -1 : format error
+ *\li 0 : not found
+ *\li >0 : found
+ *
+ * author:
+ *\li paul vixie, 29may94
+ */
+int
+res_nameinquery(const char *name, int type, int class,
+ const u_char *buf, const u_char *eom)
+{
+ const u_char *cp = buf + HFIXEDSZ;
+ int qdcount = ntohs(((const HEADER*)buf)->qdcount);
+
+ while (qdcount-- > 0) {
+ char tname[MAXDNAME+1];
+ int n, ttype, tclass;
+
+ n = dn_expand(buf, eom, cp, tname, sizeof tname);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ if (cp + 2 * INT16SZ > eom)
+ return (-1);
+ ttype = ns_get16(cp); cp += INT16SZ;
+ tclass = ns_get16(cp); cp += INT16SZ;
+ if (ttype == type && tclass == class &&
+ ns_samename(tname, name) == 1)
+ return (1);
+ }
+ return (0);
+}
+
+/*%
+ * is there a 1:1 mapping of (name,type,class)
+ * in (buf1,eom1) and (buf2,eom2)?
+ *
+ * returns:
+ *\li -1 : format error
+ *\li 0 : not a 1:1 mapping
+ *\li >0 : is a 1:1 mapping
+ *
+ * author:
+ *\li paul vixie, 29may94
+ */
+int
+res_queriesmatch(const u_char *buf1, const u_char *eom1,
+ const u_char *buf2, const u_char *eom2)
+{
+ const u_char *cp = buf1 + HFIXEDSZ;
+ int qdcount = ntohs(((const HEADER*)buf1)->qdcount);
+
+ if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
+ return (-1);
+
+ /*
+ * Only header section present in replies to
+ * dynamic update packets.
+ */
+ if ((((const HEADER *)buf1)->opcode == ns_o_update) &&
+ (((const HEADER *)buf2)->opcode == ns_o_update))
+ return (1);
+
+ if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
+ return (0);
+ while (qdcount-- > 0) {
+ char tname[MAXDNAME+1];
+ int n, ttype, tclass;
+
+ n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ if (cp + 2 * INT16SZ > eom1)
+ return (-1);
+ ttype = ns_get16(cp); cp += INT16SZ;
+ tclass = ns_get16(cp); cp += INT16SZ;
+ if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
+ return (0);
+ }
+ return (1);
+}
+
+int
+res_nsend(res_state statp,
+ const u_char *buf, int buflen, u_char *ans, int anssiz)
+{
+ int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
+ char abuf[NI_MAXHOST];
+
+#ifdef USE_POLL
+ highestFD = sysconf(_SC_OPEN_MAX) - 1;
+#endif
+
+ /* No name servers or res_init() failure */
+ if (statp->nscount == 0 || EXT(statp).ext == NULL) {
+ errno = ESRCH;
+ return (-1);
+ }
+ if (anssiz < HFIXEDSZ) {
+ errno = EINVAL;
+ return (-1);
+ }
+ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
+ (stdout, ";; res_send()\n"), buf, buflen);
+ v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
+ gotsomewhere = 0;
+ terrno = ETIMEDOUT;
+
+ /*
+ * If the ns_addr_list in the resolver context has changed, then
+ * invalidate our cached copy and the associated timing data.
+ */
+ if (EXT(statp).nscount != 0) {
+ int needclose = 0;
+ struct sockaddr_storage peer;
+ ISC_SOCKLEN_T peerlen;
+
+ if (EXT(statp).nscount != statp->nscount)
+ needclose++;
+ else
+ for (ns = 0; ns < statp->nscount; ns++) {
+ if (statp->nsaddr_list[ns].sin_family &&
+ !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns],
+ (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) {
+ needclose++;
+ break;
+ }
+
+ if (EXT(statp).nssocks[ns] == -1)
+ continue;
+ peerlen = sizeof(peer);
+ if (getsockname(EXT(statp).nssocks[ns],
+ (struct sockaddr *)&peer, &peerlen) < 0) {
+ needclose++;
+ break;
+ }
+ if (!sock_eq((struct sockaddr *)&peer,
+ get_nsaddr(statp, ns))) {
+ needclose++;
+ break;
+ }
+ }
+ if (needclose) {
+ res_nclose(statp);
+ EXT(statp).nscount = 0;
+ }
+ }
+
+ /*
+ * Maybe initialize our private copy of the ns_addr_list.
+ */
+ if (EXT(statp).nscount == 0) {
+ for (ns = 0; ns < statp->nscount; ns++) {
+ EXT(statp).nstimes[ns] = RES_MAXTIME;
+ EXT(statp).nssocks[ns] = -1;
+ if (!statp->nsaddr_list[ns].sin_family)
+ continue;
+ EXT(statp).ext->nsaddrs[ns].sin =
+ statp->nsaddr_list[ns];
+ }
+ EXT(statp).nscount = statp->nscount;
+ }
+
+ /*
+ * Some resolvers want to even out the load on their nameservers.
+ * Note that RES_BLAST overrides RES_ROTATE.
+ */
+ if ((statp->options & RES_ROTATE) != 0U &&
+ (statp->options & RES_BLAST) == 0U) {
+ union res_sockaddr_union inu;
+ struct sockaddr_in ina;
+ int lastns = statp->nscount - 1;
+ int fd;
+ u_int16_t nstime;
+
+ if (EXT(statp).ext != NULL)
+ inu = EXT(statp).ext->nsaddrs[0];
+ ina = statp->nsaddr_list[0];
+ fd = EXT(statp).nssocks[0];
+ nstime = EXT(statp).nstimes[0];
+ for (ns = 0; ns < lastns; ns++) {
+ if (EXT(statp).ext != NULL)
+ EXT(statp).ext->nsaddrs[ns] =
+ EXT(statp).ext->nsaddrs[ns + 1];
+ statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
+ EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
+ EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
+ }
+ if (EXT(statp).ext != NULL)
+ EXT(statp).ext->nsaddrs[lastns] = inu;
+ statp->nsaddr_list[lastns] = ina;
+ EXT(statp).nssocks[lastns] = fd;
+ EXT(statp).nstimes[lastns] = nstime;
+ }
+
+ /*
+ * Send request, RETRY times, or until successful.
+ */
+ for (try = 0; try < statp->retry; try++) {
+ for (ns = 0; ns < statp->nscount; ns++) {
+ struct sockaddr *nsap;
+ int nsaplen;
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+ statp->_flags &= ~RES_F_LASTMASK;
+ statp->_flags |= (ns << RES_F_LASTSHIFT);
+ same_ns:
+ if (statp->qhook) {
+ int done = 0, loops = 0;
+
+ do {
+ res_sendhookact act;
+
+ act = (*statp->qhook)(&nsap, &buf, &buflen,
+ ans, anssiz, &resplen);
+ switch (act) {
+ case res_goahead:
+ done = 1;
+ break;
+ case res_nextns:
+ res_nclose(statp);
+ goto next_ns;
+ case res_done:
+ return (resplen);
+ case res_modified:
+ /* give the hook another try */
+ if (++loops < 42) /*doug adams*/
+ break;
+ /*FALLTHROUGH*/
+ case res_error:
+ /*FALLTHROUGH*/
+ default:
+ goto fail;
+ }
+ } while (!done);
+ }
+
+ Dprint(((statp->options & RES_DEBUG) &&
+ getnameinfo(nsap, nsaplen, abuf, sizeof(abuf),
+ NULL, 0, niflags) == 0),
+ (stdout, ";; Querying server (# %d) address = %s\n",
+ ns + 1, abuf));
+
+
+ if (v_circuit) {
+ /* Use VC; at most one attempt per server. */
+ try = statp->retry;
+ n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
+ ns);
+ if (n < 0)
+ goto fail;
+ if (n == 0)
+ goto next_ns;
+ resplen = n;
+ } else {
+ /* Use datagrams. */
+ n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
+ ns, try, &v_circuit, &gotsomewhere);
+ if (n < 0)
+ goto fail;
+ if (n == 0)
+ goto next_ns;
+ if (v_circuit)
+ goto same_ns;
+ resplen = n;
+ }
+
+ Dprint((statp->options & RES_DEBUG) ||
+ ((statp->pfcode & RES_PRF_REPLY) &&
+ (statp->pfcode & RES_PRF_HEAD1)),
+ (stdout, ";; got answer:\n"));
+
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, "%s", ""),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+
+ /*
+ * If we have temporarily opened a virtual circuit,
+ * or if we haven't been asked to keep a socket open,
+ * close the socket.
+ */
+ if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
+ (statp->options & RES_STAYOPEN) == 0U) {
+ res_nclose(statp);
+ }
+ if (statp->rhook) {
+ int done = 0, loops = 0;
+
+ do {
+ res_sendhookact act;
+
+ act = (*statp->rhook)(nsap, buf, buflen,
+ ans, anssiz, &resplen);
+ switch (act) {
+ case res_goahead:
+ case res_done:
+ done = 1;
+ break;
+ case res_nextns:
+ res_nclose(statp);
+ goto next_ns;
+ case res_modified:
+ /* give the hook another try */
+ if (++loops < 42) /*doug adams*/
+ break;
+ /*FALLTHROUGH*/
+ case res_error:
+ /*FALLTHROUGH*/
+ default:
+ goto fail;
+ }
+ } while (!done);
+
+ }
+ return (resplen);
+ next_ns: ;
+ } /*foreach ns*/
+ } /*foreach retry*/
+ res_nclose(statp);
+ if (!v_circuit) {
+ if (!gotsomewhere)
+ errno = ECONNREFUSED; /*%< no nameservers found */
+ else
+ errno = ETIMEDOUT; /*%< no answer obtained */
+ } else
+ errno = terrno;
+ return (-1);
+ fail:
+ res_nclose(statp);
+ return (-1);
+}
+
+/* Private */
+
+static int
+get_salen(sa)
+ const struct sockaddr *sa;
+{
+
+#ifdef HAVE_SA_LEN
+ /* There are people do not set sa_len. Be forgiving to them. */
+ if (sa->sa_len)
+ return (sa->sa_len);
+#endif
+
+ if (sa->sa_family == AF_INET)
+ return (sizeof(struct sockaddr_in));
+ else if (sa->sa_family == AF_INET6)
+ return (sizeof(struct sockaddr_in6));
+ else
+ return (0); /*%< unknown, die on connect */
+}
+
+/*%
+ * pick appropriate nsaddr_list for use. see res_init() for initialization.
+ */
+static struct sockaddr *
+get_nsaddr(statp, n)
+ res_state statp;
+ size_t n;
+{
+
+ if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
+ /*
+ * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
+ * than struct sockaddr, and
+ * - user code did not update statp->nsaddr_list[n].
+ */
+ return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
+ } else {
+ /*
+ * - user code updated statp->nsaddr_list[n], or
+ * - statp->nsaddr_list[n] has the same content as
+ * EXT(statp).ext->nsaddrs[n].
+ */
+ return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
+ }
+}
+
+static int
+send_vc(res_state statp,
+ const u_char *buf, int buflen, u_char *ans, int anssiz,
+ int *terrno, int ns)
+{
+ const HEADER *hp = (const HEADER *) buf;
+ HEADER *anhp = (HEADER *) ans;
+ struct sockaddr *nsap;
+ int nsaplen;
+ int truncating, connreset, resplen, n;
+ struct iovec iov[2];
+ u_short len;
+ u_char *cp;
+ void *tmp;
+
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+
+ connreset = 0;
+ same_ns:
+ truncating = 0;
+
+ /* Are we still talking to whom we want to talk to? */
+ if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
+ struct sockaddr_storage peer;
+ ISC_SOCKLEN_T size = sizeof peer;
+
+ if (getpeername(statp->_vcsock,
+ (struct sockaddr *)&peer, &size) < 0 ||
+ !sock_eq((struct sockaddr *)&peer, nsap)) {
+ res_nclose(statp);
+ statp->_flags &= ~RES_F_VC;
+ }
+ }
+
+ if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
+ if (statp->_vcsock >= 0)
+ res_nclose(statp);
+
+ statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
+ if (statp->_vcsock > highestFD) {
+ res_nclose(statp);
+ errno = ENOTSOCK;
+ }
+ if (statp->_vcsock < 0) {
+ switch (errno) {
+ case EPROTONOSUPPORT:
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT:
+#endif
+ case EAFNOSUPPORT:
+ Perror(statp, stderr, "socket(vc)", errno);
+ return (0);
+ default:
+ *terrno = errno;
+ Perror(statp, stderr, "socket(vc)", errno);
+ return (-1);
+ }
+ }
+ errno = 0;
+ if (connect(statp->_vcsock, nsap, nsaplen) < 0) {
+ *terrno = errno;
+ Aerror(statp, stderr, "connect/vc", errno, nsap,
+ nsaplen);
+ res_nclose(statp);
+ return (0);
+ }
+ statp->_flags |= RES_F_VC;
+ }
+
+ /*
+ * Send length & message
+ */
+ ns_put16((u_short)buflen, (u_char*)&len);
+ iov[0] = evConsIovec(&len, INT16SZ);
+ DE_CONST(buf, tmp);
+ iov[1] = evConsIovec(tmp, buflen);
+ if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
+ *terrno = errno;
+ Perror(statp, stderr, "write failed", errno);
+ res_nclose(statp);
+ return (0);
+ }
+ /*
+ * Receive length & response
+ */
+ read_len:
+ cp = ans;
+ len = INT16SZ;
+ while ((n = read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
+ cp += n;
+ if ((len -= n) == 0)
+ break;
+ }
+ if (n <= 0) {
+ *terrno = errno;
+ Perror(statp, stderr, "read failed", errno);
+ res_nclose(statp);
+ /*
+ * A long running process might get its TCP
+ * connection reset if the remote server was
+ * restarted. Requery the server instead of
+ * trying a new one. When there is only one
+ * server, this means that a query might work
+ * instead of failing. We only allow one reset
+ * per query to prevent looping.
+ */
+ if (*terrno == ECONNRESET && !connreset) {
+ connreset = 1;
+ res_nclose(statp);
+ goto same_ns;
+ }
+ res_nclose(statp);
+ return (0);
+ }
+ resplen = ns_get16(ans);
+ if (resplen > anssiz) {
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; response truncated\n")
+ );
+ truncating = 1;
+ len = anssiz;
+ } else
+ len = resplen;
+ if (len < HFIXEDSZ) {
+ /*
+ * Undersized message.
+ */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; undersized: %d\n", len));
+ *terrno = EMSGSIZE;
+ res_nclose(statp);
+ return (0);
+ }
+ cp = ans;
+ while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
+ cp += n;
+ len -= n;
+ }
+ if (n <= 0) {
+ *terrno = errno;
+ Perror(statp, stderr, "read(vc)", errno);
+ res_nclose(statp);
+ return (0);
+ }
+ if (truncating) {
+ /*
+ * Flush rest of answer so connection stays in synch.
+ */
+ anhp->tc = 1;
+ len = resplen - anssiz;
+ while (len != 0) {
+ char junk[PACKETSZ];
+
+ n = read(statp->_vcsock, junk,
+ (len > sizeof junk) ? sizeof junk : len);
+ if (n > 0)
+ len -= n;
+ else
+ break;
+ }
+ }
+ /*
+ * If the calling applicating has bailed out of
+ * a previous call and failed to arrange to have
+ * the circuit closed or the server has got
+ * itself confused, then drop the packet and
+ * wait for the correct one.
+ */
+ if (hp->id != anhp->id) {
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; old answer (unexpected):\n"),
+ ans, (resplen > anssiz) ? anssiz: resplen);
+ goto read_len;
+ }
+
+ /*
+ * All is well, or the error is fatal. Signal that the
+ * next nameserver ought not be tried.
+ */
+ return (resplen);
+}
+
+static int
+send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans,
+ int anssiz, int *terrno, int ns, int try, int *v_circuit,
+ int *gotsomewhere)
+{
+ const HEADER *hp = (const HEADER *) buf;
+ HEADER *anhp = (HEADER *) ans;
+ const struct sockaddr *nsap;
+ int nsaplen;
+ struct timespec now, timeout, finish;
+ struct sockaddr_storage from;
+ ISC_SOCKLEN_T fromlen;
+ int resplen, seconds, n, s;
+#ifdef USE_POLL
+ int polltimeout;
+ struct pollfd pollfd;
+#else
+ fd_set dsmask;
+#endif
+
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+ if (EXT(statp).nssocks[ns] == -1) {
+ EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
+ if (EXT(statp).nssocks[ns] > highestFD) {
+ res_nclose(statp);
+ errno = ENOTSOCK;
+ }
+ if (EXT(statp).nssocks[ns] < 0) {
+ switch (errno) {
+ case EPROTONOSUPPORT:
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT:
+#endif
+ case EAFNOSUPPORT:
+ Perror(statp, stderr, "socket(dg)", errno);
+ return (0);
+ default:
+ *terrno = errno;
+ Perror(statp, stderr, "socket(dg)", errno);
+ return (-1);
+ }
+ }
+#ifndef CANNOT_CONNECT_DGRAM
+ /*
+ * On a 4.3BSD+ machine (client and server,
+ * actually), sending to a nameserver datagram
+ * port with no nameserver will cause an
+ * ICMP port unreachable message to be returned.
+ * If our datagram socket is "connected" to the
+ * server, we get an ECONNREFUSED error on the next
+ * socket operation, and select returns if the
+ * error message is received. We can thus detect
+ * the absence of a nameserver without timing out.
+ */
+ if (connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
+ Aerror(statp, stderr, "connect(dg)", errno, nsap,
+ nsaplen);
+ res_nclose(statp);
+ return (0);
+ }
+#endif /* !CANNOT_CONNECT_DGRAM */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; new DG socket\n"))
+ }
+ s = EXT(statp).nssocks[ns];
+#ifndef CANNOT_CONNECT_DGRAM
+ if (send(s, (const char*)buf, buflen, 0) != buflen) {
+ Perror(statp, stderr, "send", errno);
+ res_nclose(statp);
+ return (0);
+ }
+#else /* !CANNOT_CONNECT_DGRAM */
+ if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
+ {
+ Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
+ res_nclose(statp);
+ return (0);
+ }
+#endif /* !CANNOT_CONNECT_DGRAM */
+
+ /*
+ * Wait for reply.
+ */
+ seconds = (statp->retrans << try);
+ if (ns > 0)
+ seconds /= statp->nscount;
+ if (seconds <= 0)
+ seconds = 1;
+ now = evNowTime();
+ timeout = evConsTime(seconds, 0);
+ finish = evAddTime(now, timeout);
+ goto nonow;
+ wait:
+ now = evNowTime();
+ nonow:
+#ifndef USE_POLL
+ FD_ZERO(&dsmask);
+ FD_SET(s, &dsmask);
+ if (evCmpTime(finish, now) > 0)
+ timeout = evSubTime(finish, now);
+ else
+ timeout = evConsTime(0, 0);
+ n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
+#else
+ timeout = evSubTime(finish, now);
+ if (timeout.tv_sec < 0)
+ timeout = evConsTime(0, 0);
+ polltimeout = 1000*timeout.tv_sec +
+ timeout.tv_nsec/1000000;
+ pollfd.fd = s;
+ pollfd.events = POLLRDNORM;
+ n = poll(&pollfd, 1, polltimeout);
+#endif /* USE_POLL */
+
+ if (n == 0) {
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
+ *gotsomewhere = 1;
+ return (0);
+ }
+ if (n < 0) {
+ if (errno == EINTR)
+ goto wait;
+#ifndef USE_POLL
+ Perror(statp, stderr, "select", errno);
+#else
+ Perror(statp, stderr, "poll", errno);
+#endif /* USE_POLL */
+ res_nclose(statp);
+ return (0);
+ }
+ errno = 0;
+ fromlen = sizeof(from);
+ resplen = recvfrom(s, (char*)ans, anssiz,0,
+ (struct sockaddr *)&from, &fromlen);
+ if (resplen <= 0) {
+ Perror(statp, stderr, "recvfrom", errno);
+ res_nclose(statp);
+ return (0);
+ }
+ *gotsomewhere = 1;
+ if (resplen < HFIXEDSZ) {
+ /*
+ * Undersized message.
+ */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; undersized: %d\n",
+ resplen));
+ *terrno = EMSGSIZE;
+ res_nclose(statp);
+ return (0);
+ }
+ if (hp->id != anhp->id) {
+ /*
+ * response from old query, ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; old answer:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ goto wait;
+ }
+ if (!(statp->options & RES_INSECURE1) &&
+ !res_ourserver_p(statp, (struct sockaddr *)&from)) {
+ /*
+ * response from wrong server? ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; not our server:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ goto wait;
+ }
+#ifdef RES_USE_EDNS0
+ if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
+ /*
+ * Do not retry if the server do not understand EDNS0.
+ * The case has to be captured here, as FORMERR packet do not
+ * carry query section, hence res_queriesmatch() returns 0.
+ */
+ DprintQ(statp->options & RES_DEBUG,
+ (stdout, "server rejected query with EDNS0:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ /* record the error */
+ statp->_flags |= RES_F_EDNS0ERR;
+ res_nclose(statp);
+ return (0);
+ }
+#endif
+ if (!(statp->options & RES_INSECURE2) &&
+ !res_queriesmatch(buf, buf + buflen,
+ ans, ans + anssiz)) {
+ /*
+ * response contains wrong query? ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; wrong query name:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ goto wait;
+ }
+ if (anhp->rcode == SERVFAIL ||
+ anhp->rcode == NOTIMP ||
+ anhp->rcode == REFUSED) {
+ DprintQ(statp->options & RES_DEBUG,
+ (stdout, "server rejected query:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ res_nclose(statp);
+ /* don't retry if called from dig */
+ if (!statp->pfcode)
+ return (0);
+ }
+ if (!(statp->options & RES_IGNTC) && anhp->tc) {
+ /*
+ * To get the rest of answer,
+ * use TCP with same server.
+ */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; truncated answer\n"));
+ *v_circuit = 1;
+ res_nclose(statp);
+ return (1);
+ }
+ /*
+ * All is well, or the error is fatal. Signal that the
+ * next nameserver ought not be tried.
+ */
+ return (resplen);
+}
+
+static void
+Aerror(const res_state statp, FILE *file, const char *string, int error,
+ const struct sockaddr *address, int alen)
+{
+ int save = errno;
+ char hbuf[NI_MAXHOST];
+ char sbuf[NI_MAXSERV];
+
+ alen = alen;
+
+ if ((statp->options & RES_DEBUG) != 0U) {
+ if (getnameinfo(address, alen, hbuf, sizeof(hbuf),
+ sbuf, sizeof(sbuf), niflags)) {
+ strncpy(hbuf, "?", sizeof(hbuf) - 1);
+ hbuf[sizeof(hbuf) - 1] = '\0';
+ strncpy(sbuf, "?", sizeof(sbuf) - 1);
+ sbuf[sizeof(sbuf) - 1] = '\0';
+ }
+ fprintf(file, "res_send: %s ([%s].%s): %s\n",
+ string, hbuf, sbuf, strerror(error));
+ }
+ errno = save;
+}
+
+static void
+Perror(const res_state statp, FILE *file, const char *string, int error) {
+ int save = errno;
+
+ if ((statp->options & RES_DEBUG) != 0U)
+ fprintf(file, "res_send: %s: %s\n",
+ string, strerror(error));
+ errno = save;
+}
+
+static int
+sock_eq(struct sockaddr *a, struct sockaddr *b) {
+ struct sockaddr_in *a4, *b4;
+ struct sockaddr_in6 *a6, *b6;
+
+ if (a->sa_family != b->sa_family)
+ return 0;
+ switch (a->sa_family) {
+ case AF_INET:
+ a4 = (struct sockaddr_in *)a;
+ b4 = (struct sockaddr_in *)b;
+ return a4->sin_port == b4->sin_port &&
+ a4->sin_addr.s_addr == b4->sin_addr.s_addr;
+ case AF_INET6:
+ a6 = (struct sockaddr_in6 *)a;
+ b6 = (struct sockaddr_in6 *)b;
+ return a6->sin6_port == b6->sin6_port &&
+#ifdef HAVE_SIN6_SCOPE_ID
+ a6->sin6_scope_id == b6->sin6_scope_id &&
+#endif
+ IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
+ default:
+ return 0;
+ }
+}
+
+#if defined(NEED_PSELECT) && !defined(USE_POLL)
+/* XXX needs to move to the porting library. */
+static int
+pselect(int nfds, void *rfds, void *wfds, void *efds,
+ struct timespec *tsp, const sigset_t *sigmask)
+{
+ struct timeval tv, *tvp;
+ sigset_t sigs;
+ int n;
+
+ 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/lib/bind/resolv/res_sendsigned.c b/lib/bind/resolv/res_sendsigned.c
new file mode 100644
index 0000000..63ae07c
--- /dev/null
+++ b/lib/bind/resolv/res_sendsigned.c
@@ -0,0 +1,170 @@
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <isc/dst.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+#define DEBUG
+#include "res_debug.h"
+
+
+/*% res_nsendsigned */
+int
+res_nsendsigned(res_state statp, const u_char *msg, int msglen,
+ ns_tsig_key *key, u_char *answer, int anslen)
+{
+ res_state nstatp;
+ DST_KEY *dstkey;
+ int usingTCP = 0;
+ u_char *newmsg;
+ int newmsglen, bufsize, siglen;
+ u_char sig[64];
+ HEADER *hp;
+ time_t tsig_time;
+ int ret;
+ int len;
+
+ dst_init();
+
+ nstatp = (res_state) malloc(sizeof(*statp));
+ if (nstatp == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memcpy(nstatp, statp, sizeof(*statp));
+
+ bufsize = msglen + 1024;
+ newmsg = (u_char *) malloc(bufsize);
+ if (newmsg == NULL) {
+ free(nstatp);
+ errno = ENOMEM;
+ return (-1);
+ }
+ memcpy(newmsg, msg, msglen);
+ newmsglen = msglen;
+
+ if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+ dstkey = NULL;
+ else
+ dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
+ NS_KEY_TYPE_AUTH_ONLY,
+ NS_KEY_PROT_ANY,
+ key->data, key->len);
+ if (dstkey == NULL) {
+ errno = EINVAL;
+ free(nstatp);
+ free(newmsg);
+ return (-1);
+ }
+
+ nstatp->nscount = 1;
+ siglen = sizeof(sig);
+ ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0,
+ sig, &siglen, 0);
+ if (ret < 0) {
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ if (ret == NS_TSIG_ERROR_NO_SPACE)
+ errno = EMSGSIZE;
+ else if (ret == -1)
+ errno = EINVAL;
+ return (ret);
+ }
+
+ if (newmsglen > PACKETSZ || nstatp->options & RES_USEVC)
+ usingTCP = 1;
+ if (usingTCP == 0)
+ nstatp->options |= RES_IGNTC;
+ else
+ nstatp->options |= RES_USEVC;
+ /*
+ * Stop res_send printing the answer.
+ */
+ nstatp->options &= ~RES_DEBUG;
+ nstatp->pfcode &= ~RES_PRF_REPLY;
+
+retry:
+
+ len = res_nsend(nstatp, newmsg, newmsglen, answer, anslen);
+ if (len < 0) {
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ return (len);
+ }
+
+ ret = ns_verify(answer, &len, dstkey, sig, siglen,
+ NULL, NULL, &tsig_time, nstatp->options & RES_KEEPTSIG);
+ if (ret != 0) {
+ Dprint((statp->options & RES_DEBUG) ||
+ ((statp->pfcode & RES_PRF_REPLY) &&
+ (statp->pfcode & RES_PRF_HEAD1)),
+ (stdout, ";; got answer:\n"));
+
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, "%s", ""),
+ answer, (anslen > len) ? len : anslen);
+
+ if (ret > 0) {
+ Dprint(statp->pfcode & RES_PRF_REPLY,
+ (stdout, ";; server rejected TSIG (%s)\n",
+ p_rcode(ret)));
+ } else {
+ Dprint(statp->pfcode & RES_PRF_REPLY,
+ (stdout, ";; TSIG invalid (%s)\n",
+ p_rcode(-ret)));
+ }
+
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ if (ret == -1)
+ errno = EINVAL;
+ else
+ errno = ENOTTY;
+ return (-1);
+ }
+
+ hp = (HEADER *) answer;
+ if (hp->tc && !usingTCP && (statp->options & RES_IGNTC) == 0U) {
+ nstatp->options &= ~RES_IGNTC;
+ usingTCP = 1;
+ goto retry;
+ }
+ Dprint((statp->options & RES_DEBUG) ||
+ ((statp->pfcode & RES_PRF_REPLY) &&
+ (statp->pfcode & RES_PRF_HEAD1)),
+ (stdout, ";; got answer:\n"));
+
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, "%s", ""),
+ answer, (anslen > len) ? len : anslen);
+
+ Dprint(statp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n"));
+
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ return (len);
+}
+
+/*! \file */
diff --git a/lib/bind/resolv/res_update.c b/lib/bind/resolv/res_update.c
new file mode 100644
index 0000000..483e19d
--- /dev/null
+++ b/lib/bind/resolv/res_update.c
@@ -0,0 +1,213 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_update.c,v 1.12.18.1 2005/04/27 05:01:12 sra Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file
+ * \brief
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * &lt;viraj_bais@ccm.fm.intel.com>
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <res_update.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/list.h>
+#include <resolv.h>
+
+#include "port_after.h"
+#include "res_private.h"
+
+/*%
+ * Separate a linked list of records into groups so that all records
+ * in a group will belong to a single zone on the nameserver.
+ * Create a dynamic update packet for each zone and send it to the
+ * nameservers for that zone, and await answer.
+ * Abort if error occurs in updating any zone.
+ * Return the number of zones updated on success, < 0 on error.
+ *
+ * On error, caller must deal with the unsynchronized zones
+ * eg. an A record might have been successfully added to the forward
+ * zone but the corresponding PTR record would be missing if error
+ * was encountered while updating the reverse zone.
+ */
+
+struct zonegrp {
+ char z_origin[MAXDNAME];
+ ns_class z_class;
+ union res_sockaddr_union z_nsaddrs[MAXNS];
+ int z_nscount;
+ int z_flags;
+ LIST(ns_updrec) z_rrlist;
+ LINK(struct zonegrp) z_link;
+};
+
+#define ZG_F_ZONESECTADDED 0x0001
+
+/* Forward. */
+
+static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2);
+
+/* Macros. */
+
+#define DPRINTF(x) do {\
+ int save_errno = errno; \
+ if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \
+ errno = save_errno; \
+ } while (0)
+
+/* Public. */
+
+int
+res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
+ ns_updrec *rrecp;
+ u_char answer[PACKETSZ];
+ u_char *packet;
+ struct zonegrp *zptr, tgrp;
+ LIST(struct zonegrp) zgrps;
+ int nzones = 0, nscount = 0, n;
+ union res_sockaddr_union nsaddrs[MAXNS];
+
+ packet = malloc(NS_MAXMSG);
+ if (packet == NULL) {
+ DPRINTF(("malloc failed"));
+ return (0);
+ }
+ /* Thread all of the updates onto a list of groups. */
+ INIT_LIST(zgrps);
+ memset(&tgrp, 0, sizeof (tgrp));
+ for (rrecp = rrecp_in; rrecp;
+ rrecp = LINKED(rrecp, r_link) ? NEXT(rrecp, r_link) : NULL) {
+ int nscnt;
+ /* Find the origin for it if there is one. */
+ tgrp.z_class = rrecp->r_class;
+ nscnt = res_findzonecut2(statp, rrecp->r_dname, tgrp.z_class,
+ RES_EXHAUSTIVE, tgrp.z_origin,
+ sizeof tgrp.z_origin,
+ tgrp.z_nsaddrs, MAXNS);
+ if (nscnt <= 0) {
+ DPRINTF(("res_findzonecut failed (%d)", nscnt));
+ goto done;
+ }
+ tgrp.z_nscount = nscnt;
+ /* Find the group for it if there is one. */
+ for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link))
+ if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 &&
+ tgrp.z_class == zptr->z_class)
+ break;
+ /* Make a group for it if there isn't one. */
+ if (zptr == NULL) {
+ zptr = malloc(sizeof *zptr);
+ if (zptr == NULL) {
+ DPRINTF(("malloc failed"));
+ goto done;
+ }
+ *zptr = tgrp;
+ zptr->z_flags = 0;
+ INIT_LINK(zptr, z_link);
+ INIT_LIST(zptr->z_rrlist);
+ APPEND(zgrps, zptr, z_link);
+ }
+ /* Thread this rrecp onto the right group. */
+ APPEND(zptr->z_rrlist, rrecp, r_glink);
+ }
+
+ for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) {
+ /* Construct zone section and prepend it. */
+ rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
+ zptr->z_class, ns_t_soa, 0);
+ if (rrecp == NULL) {
+ DPRINTF(("res_mkupdrec failed"));
+ goto done;
+ }
+ PREPEND(zptr->z_rrlist, rrecp, r_glink);
+ zptr->z_flags |= ZG_F_ZONESECTADDED;
+
+ /* Marshall the update message. */
+ n = res_nmkupdate(statp, HEAD(zptr->z_rrlist),
+ packet, NS_MAXMSG);
+ DPRINTF(("res_mkupdate -> %d", n));
+ if (n < 0)
+ goto done;
+
+ /* Temporarily replace the resolver's nameserver set. */
+ nscount = res_getservers(statp, nsaddrs, MAXNS);
+ res_setservers(statp, zptr->z_nsaddrs, zptr->z_nscount);
+
+ /* Send the update and remember the result. */
+ if (key != NULL)
+ n = res_nsendsigned(statp, packet, n, key,
+ answer, sizeof answer);
+ else
+ n = res_nsend(statp, packet, n, answer, sizeof answer);
+ if (n < 0) {
+ DPRINTF(("res_nsend: send error, n=%d (%s)\n",
+ n, strerror(errno)));
+ goto done;
+ }
+ if (((HEADER *)answer)->rcode == NOERROR)
+ nzones++;
+
+ /* Restore resolver's nameserver set. */
+ res_setservers(statp, nsaddrs, nscount);
+ nscount = 0;
+ }
+ done:
+ while (!EMPTY(zgrps)) {
+ zptr = HEAD(zgrps);
+ if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0)
+ res_freeupdrec(HEAD(zptr->z_rrlist));
+ UNLINK(zgrps, zptr, z_link);
+ free(zptr);
+ }
+ if (nscount != 0)
+ res_setservers(statp, nsaddrs, nscount);
+
+ free(packet);
+ return (nzones);
+}
+
+/* Private. */
+
+static void
+res_dprintf(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ fputs(";; res_nupdate: ", stderr);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+}
diff --git a/lib/bind9/Makefile.in b/lib/bind9/Makefile.in
new file mode 100644
index 0000000..270e9ae
--- /dev/null
+++ b/lib/bind9/Makefile.in
@@ -0,0 +1,84 @@
+# 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: Makefile.in,v 1.4.18.5 2004/12/10 00:11:50 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+@LIBBIND9_API@
+
+@BIND9_MAKE_INCLUDES@
+
+CINCLUDES = -I. ${BIND9_INCLUDES} ${DNS_INCLUDES} ${ISC_INCLUDES} \
+ ${ISCCFG_INCLUDES}
+
+CDEFINES =
+CWARNINGS =
+
+ISCLIBS = ../../lib/isc/libisc.@A@
+ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@
+DNSLIBS = ../../lib/dns/libdns.@A@
+
+ISCDEPLIBS = ../../lib/isc/libisc.@A@
+ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@
+DNSDEPLIBS = ../../lib/dns/libdns.@A@
+
+LIBS = @LIBS@
+
+SUBDIRS = include
+
+# Alphabetically
+OBJS = check.@O@ getaddresses.@O@ version.@O@
+
+# Alphabetically
+SRCS = check.c getaddresses.c version.c
+
+TARGETS = timestamp
+
+@BIND9_MAKE_RULES@
+
+version.@O@: version.c
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \
+ -DVERSION=\"${VERSION}\" \
+ -DLIBINTERFACE=${LIBINTERFACE} \
+ -DLIBREVISION=${LIBREVISION} \
+ -DLIBAGE=${LIBAGE} \
+ -c ${srcdir}/version.c
+
+libbind9.@SA@: ${OBJS}
+ ${AR} ${ARFLAGS} $@ ${OBJS}
+ ${RANLIB} $@
+
+libbind9.la: ${OBJS} ${ISCCFGDEPLIBS} ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} \
+ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libbind9.la -rpath ${libdir} \
+ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ ${OBJS} ${DNSLIBS} ${ISCCFGLIBS} ${ISCLIBS} ${LIBS}
+
+timestamp: libbind9.@A@
+ touch timestamp
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+
+install:: timestamp installdirs
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libbind9.@A@ ${DESTDIR}${libdir}
+
+clean distclean::
+ rm -f libbind9.@A@ timestamp
diff --git a/lib/bind9/api b/lib/bind9/api
new file mode 100644
index 0000000..93632d1
--- /dev/null
+++ b/lib/bind9/api
@@ -0,0 +1,3 @@
+LIBINTERFACE = 31
+LIBREVISION = 0
+LIBAGE = 1
diff --git a/lib/bind9/check.c b/lib/bind9/check.c
new file mode 100644
index 0000000..6cfdc93
--- /dev/null
+++ b/lib/bind9/check.c
@@ -0,0 +1,2043 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: check.c,v 1.44.18.35 2007/09/13 05:04:01 each Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/netaddr.h>
+#include <isc/parseint.h>
+#include <isc/region.h>
+#include <isc/result.h>
+#include <isc/sockaddr.h>
+#include <isc/string.h>
+#include <isc/symtab.h>
+#include <isc/util.h>
+
+#include <dns/acl.h>
+#include <dns/fixedname.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatatype.h>
+#include <dns/secalg.h>
+
+#include <isccfg/aclconf.h>
+#include <isccfg/cfg.h>
+
+#include <bind9/check.h>
+
+#ifndef DNS_RDATASET_FIXED
+#define DNS_RDATASET_FIXED 1
+#endif
+
+static void
+freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
+ UNUSED(type);
+ UNUSED(value);
+ isc_mem_free(userarg, key);
+}
+
+static isc_result_t
+check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+ isc_textregion_t r;
+ dns_fixedname_t fixed;
+ const cfg_obj_t *obj;
+ dns_rdataclass_t rdclass;
+ dns_rdatatype_t rdtype;
+ isc_buffer_t b;
+ const char *str;
+
+ dns_fixedname_init(&fixed);
+ obj = cfg_tuple_get(ent, "class");
+ if (cfg_obj_isstring(obj)) {
+
+ DE_CONST(cfg_obj_asstring(obj), r.base);
+ r.length = strlen(r.base);
+ tresult = dns_rdataclass_fromtext(&rdclass, &r);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "rrset-order: invalid class '%s'",
+ r.base);
+ result = ISC_R_FAILURE;
+ }
+ }
+
+ obj = cfg_tuple_get(ent, "type");
+ if (cfg_obj_isstring(obj)) {
+
+ DE_CONST(cfg_obj_asstring(obj), r.base);
+ r.length = strlen(r.base);
+ tresult = dns_rdatatype_fromtext(&rdtype, &r);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "rrset-order: invalid type '%s'",
+ r.base);
+ result = ISC_R_FAILURE;
+ }
+ }
+
+ obj = cfg_tuple_get(ent, "name");
+ if (cfg_obj_isstring(obj)) {
+ str = cfg_obj_asstring(obj);
+ isc_buffer_init(&b, str, strlen(str));
+ isc_buffer_add(&b, strlen(str));
+ tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
+ dns_rootname, ISC_FALSE, NULL);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "rrset-order: invalid name '%s'", str);
+ result = ISC_R_FAILURE;
+ }
+ }
+
+ obj = cfg_tuple_get(ent, "order");
+ if (!cfg_obj_isstring(obj) ||
+ strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
+ cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
+ "rrset-order: keyword 'order' missing");
+ result = ISC_R_FAILURE;
+ }
+
+ obj = cfg_tuple_get(ent, "ordering");
+ if (!cfg_obj_isstring(obj)) {
+ cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
+ "rrset-order: missing ordering");
+ result = ISC_R_FAILURE;
+ } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
+#if !DNS_RDATASET_FIXED
+ cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
+ "rrset-order: order 'fixed' not fully implemented");
+#endif
+ } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
+ strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "rrset-order: invalid order '%s'",
+ cfg_obj_asstring(obj));
+ result = ISC_R_FAILURE;
+ }
+ return (result);
+}
+
+static isc_result_t
+check_order(const cfg_obj_t *options, isc_log_t *logctx) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+ const cfg_listelt_t *element;
+ const cfg_obj_t *obj = NULL;
+
+ if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
+ return (result);
+
+ for (element = cfg_list_first(obj);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ tresult = check_orderent(cfg_listelt_value(element), logctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ }
+ return (result);
+}
+
+static isc_result_t
+check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
+ const cfg_listelt_t *element;
+ const cfg_obj_t *alternates = NULL;
+ const cfg_obj_t *value;
+ const cfg_obj_t *obj;
+ const char *str;
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+ isc_buffer_t buffer;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+
+ (void)cfg_map_get(options, "dual-stack-servers", &alternates);
+
+ if (alternates == NULL)
+ return (ISC_R_SUCCESS);
+
+ obj = cfg_tuple_get(alternates, "port");
+ if (cfg_obj_isuint32(obj)) {
+ isc_uint32_t val = cfg_obj_asuint32(obj);
+ if (val > ISC_UINT16_MAX) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "port '%u' out of range", val);
+ result = ISC_R_FAILURE;
+ }
+ }
+ obj = cfg_tuple_get(alternates, "addresses");
+ for (element = cfg_list_first(obj);
+ element != NULL;
+ element = cfg_list_next(element)) {
+ value = cfg_listelt_value(element);
+ if (cfg_obj_issockaddr(value))
+ continue;
+ obj = cfg_tuple_get(value, "name");
+ str = cfg_obj_asstring(obj);
+ isc_buffer_init(&buffer, str, strlen(str));
+ isc_buffer_add(&buffer, strlen(str));
+ dns_fixedname_init(&fixed);
+ name = dns_fixedname_name(&fixed);
+ tresult = dns_name_fromtext(name, &buffer, dns_rootname,
+ ISC_FALSE, NULL);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "bad name '%s'", str);
+ result = ISC_R_FAILURE;
+ }
+ obj = cfg_tuple_get(value, "port");
+ if (cfg_obj_isuint32(obj)) {
+ isc_uint32_t val = cfg_obj_asuint32(obj);
+ if (val > ISC_UINT16_MAX) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "port '%u' out of range", val);
+ result = ISC_R_FAILURE;
+ }
+ }
+ }
+ return (result);
+}
+
+static isc_result_t
+check_forward(const cfg_obj_t *options, isc_log_t *logctx) {
+ const cfg_obj_t *forward = NULL;
+ const cfg_obj_t *forwarders = NULL;
+
+ (void)cfg_map_get(options, "forward", &forward);
+ (void)cfg_map_get(options, "forwarders", &forwarders);
+
+ if (forward != NULL && forwarders == NULL) {
+ cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
+ "no matching 'forwarders' statement");
+ return (ISC_R_FAILURE);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+ const cfg_listelt_t *element;
+ const char *str;
+ isc_buffer_t b;
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+ const cfg_obj_t *obj;
+
+ dns_fixedname_init(&fixed);
+ name = dns_fixedname_name(&fixed);
+ obj = cfg_tuple_get(disabled, "name");
+ str = cfg_obj_asstring(obj);
+ isc_buffer_init(&b, str, strlen(str));
+ isc_buffer_add(&b, strlen(str));
+ tresult = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "bad domain name '%s'", str);
+ result = tresult;
+ }
+
+ obj = cfg_tuple_get(disabled, "algorithms");
+
+ for (element = cfg_list_first(obj);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ isc_textregion_t r;
+ dns_secalg_t alg;
+ isc_result_t tresult;
+
+ DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
+ r.length = strlen(r.base);
+
+ tresult = dns_secalg_fromtext(&alg, &r);
+ if (tresult != ISC_R_SUCCESS) {
+ isc_uint8_t ui;
+ result = isc_parse_uint8(&ui, r.base, 10);
+ }
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(cfg_listelt_value(element), logctx,
+ ISC_LOG_ERROR, "invalid algorithm '%s'",
+ r.base);
+ result = tresult;
+ }
+ }
+ return (result);
+}
+
+static isc_result_t
+nameexist(const cfg_obj_t *obj, const char *name, int value,
+ isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
+ isc_mem_t *mctx)
+{
+ char *key;
+ const char *file;
+ unsigned int line;
+ isc_result_t result;
+ isc_symvalue_t symvalue;
+
+ key = isc_mem_strdup(mctx, name);
+ if (key == NULL)
+ return (ISC_R_NOMEMORY);
+ symvalue.as_cpointer = obj;
+ result = isc_symtab_define(symtab, key, value, symvalue,
+ isc_symexists_reject);
+ if (result == ISC_R_EXISTS) {
+ RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
+ &symvalue) == ISC_R_SUCCESS);
+ file = cfg_obj_file(symvalue.as_cpointer);
+ line = cfg_obj_line(symvalue.as_cpointer);
+
+ if (file == NULL)
+ file = "<unknown file>";
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
+ isc_mem_free(mctx, key);
+ result = ISC_R_EXISTS;
+ } else if (result != ISC_R_SUCCESS) {
+ isc_mem_free(mctx, key);
+ }
+ return (result);
+}
+
+static isc_result_t
+mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
+ isc_mem_t *mctx)
+{
+ const cfg_obj_t *obj;
+ char namebuf[DNS_NAME_FORMATSIZE];
+ const char *str;
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+ isc_buffer_t b;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ dns_fixedname_init(&fixed);
+ name = dns_fixedname_name(&fixed);
+ obj = cfg_tuple_get(secure, "name");
+ str = cfg_obj_asstring(obj);
+ isc_buffer_init(&b, str, strlen(str));
+ isc_buffer_add(&b, strlen(str));
+ result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
+ if (result != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "bad domain name '%s'", str);
+ } else {
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ result = nameexist(secure, namebuf, 1, symtab,
+ "dnssec-must-be-secure '%s': already "
+ "exists previous definition: %s:%u",
+ logctx, mctx);
+ }
+ return (result);
+}
+
+static isc_result_t
+checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
+ const cfg_obj_t *voptions, const cfg_obj_t *config,
+ isc_log_t *logctx, isc_mem_t *mctx)
+{
+ isc_result_t result;
+ const cfg_obj_t *aclobj = NULL;
+ const cfg_obj_t *options;
+ dns_acl_t *acl = NULL;
+
+ if (zconfig != NULL) {
+ options = cfg_tuple_get(zconfig, "options");
+ cfg_map_get(options, aclname, &aclobj);
+ }
+ if (voptions != NULL && aclobj == NULL)
+ cfg_map_get(voptions, aclname, &aclobj);
+ if (config != NULL && aclobj == NULL) {
+ options = NULL;
+ cfg_map_get(config, "options", &options);
+ if (options != NULL)
+ cfg_map_get(options, aclname, &aclobj);
+ }
+ if (aclobj == NULL)
+ return (ISC_R_SUCCESS);
+ result = cfg_acl_fromconfig(aclobj, config, logctx, actx, mctx, &acl);
+ if (acl != NULL)
+ dns_acl_detach(&acl);
+ return (result);
+}
+
+static isc_result_t
+check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
+ const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
+{
+ isc_result_t result = ISC_R_SUCCESS, tresult;
+ int i = 0;
+
+ static const char *acls[] = { "allow-query", "allow-query-cache",
+ "allow-recursion", "blackhole", "match-clients",
+ "match-destinations", "sortlist", NULL };
+
+ while (acls[i] != NULL) {
+ tresult = checkacl(acls[i++], actx, NULL, voptions, config,
+ logctx, mctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ }
+ return (result);
+}
+
+typedef struct {
+ const char *name;
+ unsigned int scale;
+ unsigned int max;
+} intervaltable;
+
+static isc_result_t
+check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+ unsigned int i;
+ const cfg_obj_t *obj = NULL;
+ const cfg_listelt_t *element;
+ isc_symtab_t *symtab = NULL;
+ dns_fixedname_t fixed;
+ const char *str;
+ dns_name_t *name;
+ isc_buffer_t b;
+
+ static intervaltable intervals[] = {
+ { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
+ { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
+ { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
+ { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
+ { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
+ { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
+ { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
+ { "sig-validity-interval", 86400, 10 * 366 }, /* 10 years */
+ { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
+ };
+
+ /*
+ * Check that fields specified in units of time other than seconds
+ * have reasonable values.
+ */
+ for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
+ isc_uint32_t val;
+ obj = NULL;
+ (void)cfg_map_get(options, intervals[i].name, &obj);
+ if (obj == NULL)
+ continue;
+ val = cfg_obj_asuint32(obj);
+ if (val > intervals[i].max) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "%s '%u' is out of range (0..%u)",
+ intervals[i].name, val,
+ intervals[i].max);
+ result = ISC_R_RANGE;
+ } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "%s '%d' is out of range",
+ intervals[i].name, val);
+ result = ISC_R_RANGE;
+ }
+ }
+ obj = NULL;
+ (void)cfg_map_get(options, "preferred-glue", &obj);
+ if (obj != NULL) {
+ const char *str;
+ str = cfg_obj_asstring(obj);
+ if (strcasecmp(str, "a") != 0 &&
+ strcasecmp(str, "aaaa") != 0 &&
+ strcasecmp(str, "none") != 0)
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "preferred-glue unexpected value '%s'",
+ str);
+ }
+ obj = NULL;
+ (void)cfg_map_get(options, "root-delegation-only", &obj);
+ if (obj != NULL) {
+ if (!cfg_obj_isvoid(obj)) {
+ const cfg_listelt_t *element;
+ const cfg_obj_t *exclude;
+ const char *str;
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+ isc_buffer_t b;
+
+ 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));
+ tresult = dns_name_fromtext(name, &b,
+ dns_rootname,
+ ISC_FALSE, NULL);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "bad domain name '%s'",
+ str);
+ result = tresult;
+ }
+ }
+ }
+ }
+
+ /*
+ * Set supported DNSSEC algorithms.
+ */
+ obj = NULL;
+ (void)cfg_map_get(options, "disable-algorithms", &obj);
+ if (obj != NULL) {
+ for (element = cfg_list_first(obj);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ obj = cfg_listelt_value(element);
+ tresult = disabled_algorithms(obj, logctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ }
+ }
+
+ dns_fixedname_init(&fixed);
+ name = dns_fixedname_name(&fixed);
+
+ /*
+ * Check the DLV zone name.
+ */
+ obj = NULL;
+ (void)cfg_map_get(options, "dnssec-lookaside", &obj);
+ if (obj != NULL) {
+ tresult = isc_symtab_create(mctx, 100, freekey, mctx,
+ ISC_TRUE, &symtab);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ for (element = cfg_list_first(obj);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ const char *dlv;
+
+ obj = cfg_listelt_value(element);
+
+ dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain"));
+ isc_buffer_init(&b, dlv, strlen(dlv));
+ isc_buffer_add(&b, strlen(dlv));
+ tresult = dns_name_fromtext(name, &b, dns_rootname,
+ ISC_TRUE, NULL);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "bad domain name '%s'", dlv);
+ result = tresult;
+ }
+ if (symtab != NULL) {
+ tresult = nameexist(obj, dlv, 1, symtab,
+ "dnssec-lookaside '%s': "
+ "already exists previous "
+ "definition: %s:%u",
+ logctx, mctx);
+ if (tresult != ISC_R_SUCCESS &&
+ result == ISC_R_SUCCESS)
+ result = tresult;
+ }
+ /*
+ * XXXMPA to be removed when multiple lookaside
+ * namespaces are supported.
+ */
+ if (!dns_name_equal(dns_rootname, name)) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "dnssec-lookaside '%s': "
+ "non-root not yet supported", dlv);
+ if (result == ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ }
+ dlv = cfg_obj_asstring(cfg_tuple_get(obj,
+ "trust-anchor"));
+ isc_buffer_init(&b, dlv, strlen(dlv));
+ isc_buffer_add(&b, strlen(dlv));
+ tresult = dns_name_fromtext(name, &b, dns_rootname,
+ ISC_TRUE, NULL);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "bad domain name '%s'", dlv);
+ if (result == ISC_R_SUCCESS)
+ result = tresult;
+ }
+ }
+ if (symtab != NULL)
+ isc_symtab_destroy(&symtab);
+ }
+
+ /*
+ * Check dnssec-must-be-secure.
+ */
+ obj = NULL;
+ (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
+ if (obj != NULL) {
+ isc_symtab_t *symtab = NULL;
+ tresult = isc_symtab_create(mctx, 100, freekey, mctx,
+ ISC_FALSE, &symtab);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ for (element = cfg_list_first(obj);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ obj = cfg_listelt_value(element);
+ tresult = mustbesecure(obj, symtab, logctx, mctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ }
+ if (symtab != NULL)
+ isc_symtab_destroy(&symtab);
+ }
+
+ /*
+ * Check empty zone configuration.
+ */
+ obj = NULL;
+ (void)cfg_map_get(options, "empty-server", &obj);
+ if (obj != NULL) {
+ str = cfg_obj_asstring(obj);
+ isc_buffer_init(&b, str, strlen(str));
+ isc_buffer_add(&b, strlen(str));
+ tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
+ dns_rootname, ISC_FALSE, NULL);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "empty-server: invalid name '%s'", str);
+ result = ISC_R_FAILURE;
+ }
+ }
+
+ obj = NULL;
+ (void)cfg_map_get(options, "empty-contact", &obj);
+ if (obj != NULL) {
+ str = cfg_obj_asstring(obj);
+ isc_buffer_init(&b, str, strlen(str));
+ isc_buffer_add(&b, strlen(str));
+ tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
+ dns_rootname, ISC_FALSE, NULL);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "empty-contact: invalid name '%s'", str);
+ result = ISC_R_FAILURE;
+ }
+ }
+
+ obj = NULL;
+ (void)cfg_map_get(options, "disable-empty-zone", &obj);
+ for (element = cfg_list_first(obj);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ obj = cfg_listelt_value(element);
+ str = cfg_obj_asstring(obj);
+ isc_buffer_init(&b, str, strlen(str));
+ isc_buffer_add(&b, strlen(str));
+ tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
+ dns_rootname, ISC_FALSE, NULL);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "disable-empty-zone: invalid name '%s'",
+ str);
+ result = ISC_R_FAILURE;
+ }
+ }
+
+ return (result);
+}
+
+static isc_result_t
+get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
+ isc_result_t result;
+ const cfg_obj_t *masters = NULL;
+ const cfg_listelt_t *elt;
+
+ result = cfg_map_get(cctx, "masters", &masters);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ for (elt = cfg_list_first(masters);
+ elt != NULL;
+ elt = cfg_list_next(elt)) {
+ const cfg_obj_t *list;
+ const char *listname;
+
+ list = cfg_listelt_value(elt);
+ listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
+
+ if (strcasecmp(listname, name) == 0) {
+ *ret = list;
+ return (ISC_R_SUCCESS);
+ }
+ }
+ return (ISC_R_NOTFOUND);
+}
+
+static isc_result_t
+validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
+ isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+ isc_uint32_t count = 0;
+ isc_symtab_t *symtab = NULL;
+ isc_symvalue_t symvalue;
+ const cfg_listelt_t *element;
+ const cfg_listelt_t **stack = NULL;
+ isc_uint32_t stackcount = 0, pushed = 0;
+ const cfg_obj_t *list;
+
+ REQUIRE(countp != NULL);
+ result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
+ if (result != ISC_R_SUCCESS) {
+ *countp = count;
+ return (result);
+ }
+
+ newlist:
+ list = cfg_tuple_get(obj, "addresses");
+ element = cfg_list_first(list);
+ resume:
+ for ( ;
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ const char *listname;
+ const cfg_obj_t *addr;
+ const cfg_obj_t *key;
+
+ addr = cfg_tuple_get(cfg_listelt_value(element),
+ "masterselement");
+ key = cfg_tuple_get(cfg_listelt_value(element), "key");
+
+ if (cfg_obj_issockaddr(addr)) {
+ count++;
+ continue;
+ }
+ if (!cfg_obj_isvoid(key)) {
+ cfg_obj_log(key, logctx, ISC_LOG_ERROR,
+ "unexpected token '%s'",
+ cfg_obj_asstring(key));
+ if (result == ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ }
+ listname = cfg_obj_asstring(addr);
+ symvalue.as_cpointer = addr;
+ tresult = isc_symtab_define(symtab, listname, 1, symvalue,
+ isc_symexists_reject);
+ if (tresult == ISC_R_EXISTS)
+ continue;
+ tresult = get_masters_def(config, listname, &obj);
+ if (tresult != ISC_R_SUCCESS) {
+ if (result == ISC_R_SUCCESS)
+ result = tresult;
+ cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
+ "unable to find masters list '%s'",
+ listname);
+ continue;
+ }
+ /* Grow stack? */
+ if (stackcount == pushed) {
+ void * new;
+ isc_uint32_t newlen = stackcount + 16;
+ size_t newsize, oldsize;
+
+ newsize = newlen * sizeof(*stack);
+ oldsize = stackcount * sizeof(*stack);
+ new = isc_mem_get(mctx, newsize);
+ if (new == NULL)
+ goto cleanup;
+ if (stackcount != 0) {
+ memcpy(new, stack, oldsize);
+ isc_mem_put(mctx, stack, oldsize);
+ }
+ stack = new;
+ stackcount = newlen;
+ }
+ stack[pushed++] = cfg_list_next(element);
+ goto newlist;
+ }
+ if (pushed != 0) {
+ element = stack[--pushed];
+ goto resume;
+ }
+ cleanup:
+ if (stack != NULL)
+ isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
+ isc_symtab_destroy(&symtab);
+ *countp = count;
+ return (result);
+}
+
+static isc_result_t
+check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+ const cfg_listelt_t *element;
+ const cfg_listelt_t *element2;
+ dns_fixedname_t fixed;
+ const char *str;
+ isc_buffer_t b;
+
+ for (element = cfg_list_first(policy);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ const cfg_obj_t *stmt = cfg_listelt_value(element);
+ const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
+ const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
+ const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
+ const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
+
+ dns_fixedname_init(&fixed);
+ str = cfg_obj_asstring(identity);
+ isc_buffer_init(&b, str, strlen(str));
+ isc_buffer_add(&b, strlen(str));
+ tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
+ dns_rootname, ISC_FALSE, NULL);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
+ "'%s' is not a valid name", str);
+ result = tresult;
+ }
+
+ dns_fixedname_init(&fixed);
+ str = cfg_obj_asstring(dname);
+ isc_buffer_init(&b, str, strlen(str));
+ isc_buffer_add(&b, strlen(str));
+ tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
+ dns_rootname, ISC_FALSE, NULL);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
+ "'%s' is not a valid name", str);
+ result = tresult;
+ }
+ if (tresult == ISC_R_SUCCESS &&
+ strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
+ !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
+ cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
+ "'%s' is not a wildcard", str);
+ result = ISC_R_FAILURE;
+ }
+
+ for (element2 = cfg_list_first(typelist);
+ element2 != NULL;
+ element2 = cfg_list_next(element2))
+ {
+ const cfg_obj_t *typeobj;
+ isc_textregion_t r;
+ dns_rdatatype_t type;
+
+ typeobj = cfg_listelt_value(element2);
+ DE_CONST(cfg_obj_asstring(typeobj), r.base);
+ r.length = strlen(r.base);
+
+ tresult = dns_rdatatype_fromtext(&type, &r);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
+ "'%s' is not a valid type", r.base);
+ result = tresult;
+ }
+ }
+ }
+ return (result);
+}
+
+#define MASTERZONE 1
+#define SLAVEZONE 2
+#define STUBZONE 4
+#define HINTZONE 8
+#define FORWARDZONE 16
+#define DELEGATIONZONE 32
+#define CHECKACL 64
+
+typedef struct {
+ const char *name;
+ int allowed;
+} optionstable;
+
+static isc_result_t
+check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
+ const cfg_obj_t *config, isc_symtab_t *symtab,
+ dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
+ isc_log_t *logctx, isc_mem_t *mctx)
+{
+ const char *zname;
+ const char *typestr;
+ unsigned int ztype;
+ const cfg_obj_t *zoptions;
+ const cfg_obj_t *obj = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+ unsigned int i;
+ dns_rdataclass_t zclass;
+ dns_fixedname_t fixedname;
+ isc_buffer_t b;
+
+ static optionstable options[] = {
+ { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL },
+ { "allow-notify", SLAVEZONE | CHECKACL },
+ { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
+ { "notify", MASTERZONE | SLAVEZONE },
+ { "also-notify", MASTERZONE | SLAVEZONE },
+ { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
+ { "delegation-only", HINTZONE | STUBZONE },
+ { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
+ { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
+ { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
+ { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
+ { "notify-source", MASTERZONE | SLAVEZONE },
+ { "notify-source-v6", MASTERZONE | SLAVEZONE },
+ { "transfer-source", SLAVEZONE | STUBZONE },
+ { "transfer-source-v6", SLAVEZONE | STUBZONE },
+ { "max-transfer-time-in", SLAVEZONE | STUBZONE },
+ { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
+ { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
+ { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
+ { "max-retry-time", SLAVEZONE | STUBZONE },
+ { "min-retry-time", SLAVEZONE | STUBZONE },
+ { "max-refresh-time", SLAVEZONE | STUBZONE },
+ { "min-refresh-time", SLAVEZONE | STUBZONE },
+ { "sig-validity-interval", MASTERZONE },
+ { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE },
+ { "allow-update", MASTERZONE | CHECKACL },
+ { "allow-update-forwarding", SLAVEZONE | CHECKACL },
+ { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
+ { "journal", MASTERZONE | SLAVEZONE },
+ { "ixfr-base", MASTERZONE | SLAVEZONE },
+ { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
+ { "masters", SLAVEZONE | STUBZONE },
+ { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
+ { "update-policy", MASTERZONE },
+ { "database", MASTERZONE | SLAVEZONE | STUBZONE },
+ { "key-directory", MASTERZONE },
+ { "check-wildcard", MASTERZONE },
+ { "check-mx", MASTERZONE },
+ { "integrity-check", MASTERZONE },
+ { "check-mx-cname", MASTERZONE },
+ { "check-srv-cname", MASTERZONE },
+ { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
+ { "update-check-ksk", MASTERZONE },
+ };
+
+ static optionstable dialups[] = {
+ { "notify", MASTERZONE | SLAVEZONE },
+ { "notify-passive", SLAVEZONE },
+ { "refresh", SLAVEZONE | STUBZONE },
+ { "passive", SLAVEZONE | STUBZONE },
+ };
+
+ zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
+
+ zoptions = cfg_tuple_get(zconfig, "options");
+
+ obj = NULL;
+ (void)cfg_map_get(zoptions, "type", &obj);
+ if (obj == NULL) {
+ cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
+ "zone '%s': type not present", zname);
+ return (ISC_R_FAILURE);
+ }
+
+ typestr = cfg_obj_asstring(obj);
+ if (strcasecmp(typestr, "master") == 0)
+ ztype = MASTERZONE;
+ else if (strcasecmp(typestr, "slave") == 0)
+ ztype = SLAVEZONE;
+ else if (strcasecmp(typestr, "stub") == 0)
+ ztype = STUBZONE;
+ else if (strcasecmp(typestr, "forward") == 0)
+ ztype = FORWARDZONE;
+ else if (strcasecmp(typestr, "hint") == 0)
+ ztype = HINTZONE;
+ else if (strcasecmp(typestr, "delegation-only") == 0)
+ ztype = DELEGATIONZONE;
+ else {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "zone '%s': invalid type %s",
+ zname, typestr);
+ return (ISC_R_FAILURE);
+ }
+
+ obj = cfg_tuple_get(zconfig, "class");
+ if (cfg_obj_isstring(obj)) {
+ isc_textregion_t r;
+
+ DE_CONST(cfg_obj_asstring(obj), r.base);
+ r.length = strlen(r.base);
+ result = dns_rdataclass_fromtext(&zclass, &r);
+ if (result != ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "zone '%s': invalid class %s",
+ zname, r.base);
+ return (ISC_R_FAILURE);
+ }
+ if (zclass != defclass) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "zone '%s': class '%s' does not "
+ "match view/default class",
+ zname, r.base);
+ return (ISC_R_FAILURE);
+ }
+ }
+
+ /*
+ * Look for an already existing zone.
+ * We need to make this cannonical as isc_symtab_define()
+ * deals with strings.
+ */
+ dns_fixedname_init(&fixedname);
+ isc_buffer_init(&b, zname, strlen(zname));
+ isc_buffer_add(&b, strlen(zname));
+ tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
+ dns_rootname, ISC_TRUE, NULL);
+ if (result != ISC_R_SUCCESS) {
+ cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
+ "zone '%s': is not a valid name", zname);
+ tresult = ISC_R_FAILURE;
+ } else {
+ char namebuf[DNS_NAME_FORMATSIZE];
+
+ dns_name_format(dns_fixedname_name(&fixedname),
+ namebuf, sizeof(namebuf));
+ tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
+ symtab, "zone '%s': already exists "
+ "previous definition: %s:%u", logctx, mctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ }
+
+ /*
+ * Look for inappropriate options for the given zone type.
+ * Check that ACLs expand correctly.
+ */
+ for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
+ obj = NULL;
+ if ((options[i].allowed & ztype) == 0 &&
+ cfg_map_get(zoptions, options[i].name, &obj) ==
+ ISC_R_SUCCESS)
+ {
+ if (strcmp(options[i].name, "allow-update") != 0 ||
+ ztype != SLAVEZONE) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "option '%s' is not allowed "
+ "in '%s' zone '%s'",
+ options[i].name, typestr, zname);
+ result = ISC_R_FAILURE;
+ } else
+ cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
+ "option '%s' is not allowed "
+ "in '%s' zone '%s'",
+ options[i].name, typestr, zname);
+ }
+ obj = NULL;
+ if ((options[i].allowed & ztype) != 0 &&
+ (options[i].allowed & CHECKACL) != 0) {
+
+ tresult = checkacl(options[i].name, actx, zconfig,
+ voptions, config, logctx, mctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ }
+
+ }
+
+ /*
+ * Slave & stub zones must have a "masters" field.
+ */
+ if (ztype == SLAVEZONE || ztype == STUBZONE) {
+ obj = NULL;
+ if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
+ cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
+ "zone '%s': missing 'masters' entry",
+ zname);
+ result = ISC_R_FAILURE;
+ } else {
+ isc_uint32_t count;
+ tresult = validate_masters(obj, config, &count,
+ logctx, mctx);
+ if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
+ result = tresult;
+ if (tresult == ISC_R_SUCCESS && count == 0) {
+ cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
+ "zone '%s': empty 'masters' entry",
+ zname);
+ result = ISC_R_FAILURE;
+ }
+ }
+ }
+
+ /*
+ * Master zones can't have both "allow-update" and "update-policy".
+ */
+ if (ztype == MASTERZONE) {
+ isc_result_t res1, res2;
+ obj = NULL;
+ res1 = cfg_map_get(zoptions, "allow-update", &obj);
+ obj = NULL;
+ res2 = cfg_map_get(zoptions, "update-policy", &obj);
+ if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "zone '%s': 'allow-update' is ignored "
+ "when 'update-policy' is present",
+ zname);
+ result = ISC_R_FAILURE;
+ } else if (res2 == ISC_R_SUCCESS &&
+ check_update_policy(obj, logctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ }
+
+ /*
+ * Check the excessively complicated "dialup" option.
+ */
+ if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
+ const cfg_obj_t *dialup = NULL;
+ (void)cfg_map_get(zoptions, "dialup", &dialup);
+ if (dialup != NULL && cfg_obj_isstring(dialup)) {
+ const char *str = cfg_obj_asstring(dialup);
+ for (i = 0;
+ i < sizeof(dialups) / sizeof(dialups[0]);
+ i++)
+ {
+ if (strcasecmp(dialups[i].name, str) != 0)
+ continue;
+ if ((dialups[i].allowed & ztype) == 0) {
+ cfg_obj_log(obj, logctx,
+ ISC_LOG_ERROR,
+ "dialup type '%s' is not "
+ "allowed in '%s' "
+ "zone '%s'",
+ str, typestr, zname);
+ result = ISC_R_FAILURE;
+ }
+ break;
+ }
+ if (i == sizeof(dialups) / sizeof(dialups[0])) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "invalid dialup type '%s' in zone "
+ "'%s'", str, zname);
+ result = ISC_R_FAILURE;
+ }
+ }
+ }
+
+ /*
+ * Check that forwarding is reasonable.
+ */
+ if (check_forward(zoptions, logctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+
+ /*
+ * Check various options.
+ */
+ tresult = check_options(zoptions, logctx, mctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+
+ /*
+ * If the zone type is rbt/rbt64 then master/hint zones
+ * require file clauses.
+ */
+ obj = NULL;
+ tresult = cfg_map_get(zoptions, "database", &obj);
+ if (tresult == ISC_R_NOTFOUND ||
+ (tresult == ISC_R_SUCCESS &&
+ (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
+ strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
+ obj = NULL;
+ tresult = cfg_map_get(zoptions, "file", &obj);
+ if (tresult != ISC_R_SUCCESS &&
+ (ztype == MASTERZONE || ztype == HINTZONE)) {
+ cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
+ "zone '%s': missing 'file' entry",
+ zname);
+ result = tresult;
+ }
+ }
+
+ return (result);
+}
+
+
+typedef struct keyalgorithms {
+ const char *name;
+ isc_uint16_t size;
+} algorithmtable;
+
+isc_result_t
+bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
+ const cfg_obj_t *algobj = NULL;
+ const cfg_obj_t *secretobj = NULL;
+ const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
+ const char *algorithm;
+ int i;
+ size_t len = 0;
+ static const algorithmtable algorithms[] = {
+ { "hmac-md5", 128 },
+ { "hmac-md5.sig-alg.reg.int", 0 },
+ { "hmac-md5.sig-alg.reg.int.", 0 },
+ { "hmac-sha1", 160 },
+ { "hmac-sha224", 224 },
+ { "hmac-sha256", 256 },
+ { "hmac-sha384", 384 },
+ { "hmac-sha512", 512 },
+ { NULL, 0 }
+ };
+
+ (void)cfg_map_get(key, "algorithm", &algobj);
+ (void)cfg_map_get(key, "secret", &secretobj);
+ if (secretobj == NULL || algobj == NULL) {
+ cfg_obj_log(key, logctx, ISC_LOG_ERROR,
+ "key '%s' must have both 'secret' and "
+ "'algorithm' defined",
+ keyname);
+ return (ISC_R_FAILURE);
+ }
+
+ algorithm = cfg_obj_asstring(algobj);
+ for (i = 0; algorithms[i].name != NULL; i++) {
+ len = strlen(algorithms[i].name);
+ if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
+ (algorithm[len] == '\0' ||
+ (algorithms[i].size != 0 && algorithm[len] == '-')))
+ break;
+ }
+ if (algorithms[i].name == NULL) {
+ cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
+ "unknown algorithm '%s'", algorithm);
+ return (ISC_R_NOTFOUND);
+ }
+ if (algorithm[len] == '-') {
+ isc_uint16_t digestbits;
+ isc_result_t result;
+ result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
+ if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
+ if (result == ISC_R_RANGE ||
+ digestbits > algorithms[i].size) {
+ cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
+ "key '%s' digest-bits too large "
+ "[%u..%u]", keyname,
+ algorithms[i].size / 2,
+ algorithms[i].size);
+ return (ISC_R_RANGE);
+ }
+ if ((digestbits % 8) != 0) {
+ cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
+ "key '%s' digest-bits not multiple"
+ " of 8", keyname);
+ return (ISC_R_RANGE);
+ }
+ /*
+ * Recommended minima for hmac algorithms.
+ */
+ if ((digestbits < (algorithms[i].size / 2U) ||
+ (digestbits < 80U)))
+ cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
+ "key '%s' digest-bits too small "
+ "[<%u]", keyname,
+ algorithms[i].size/2);
+ } else {
+ cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
+ "key '%s': unable to parse digest-bits",
+ keyname);
+ return (result);
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab, isc_log_t *logctx) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+ const cfg_listelt_t *element;
+
+ for (element = cfg_list_first(keys);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ const cfg_obj_t *key = cfg_listelt_value(element);
+ const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
+ isc_symvalue_t symvalue;
+
+ tresult = bind9_check_key(key, logctx);
+ if (tresult != ISC_R_SUCCESS)
+ return (tresult);
+
+ symvalue.as_cpointer = key;
+ tresult = isc_symtab_define(symtab, keyname, 1,
+ symvalue, isc_symexists_reject);
+ if (tresult == ISC_R_EXISTS) {
+ const char *file;
+ unsigned int line;
+
+ RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
+ 1, &symvalue) == ISC_R_SUCCESS);
+ file = cfg_obj_file(symvalue.as_cpointer);
+ line = cfg_obj_line(symvalue.as_cpointer);
+
+ if (file == NULL)
+ file = "<unknown file>";
+ cfg_obj_log(key, logctx, ISC_LOG_ERROR,
+ "key '%s': already exists "
+ "previous definition: %s:%u",
+ keyname, file, line);
+ result = tresult;
+ } else if (tresult != ISC_R_SUCCESS)
+ return (tresult);
+ }
+ return (result);
+}
+
+static struct {
+ const char *v4;
+ const char *v6;
+} sources[] = {
+ { "transfer-source", "transfer-source-v6" },
+ { "notify-source", "notify-source-v6" },
+ { "query-source", "query-source-v6" },
+ { NULL, NULL }
+};
+
+static isc_result_t
+check_servers(const cfg_obj_t *servers, isc_log_t *logctx) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+ const cfg_listelt_t *e1, *e2;
+ const cfg_obj_t *v1, *v2;
+ isc_netaddr_t n1, n2;
+ unsigned int p1, p2;
+ const cfg_obj_t *obj;
+ char buf[ISC_NETADDR_FORMATSIZE];
+ const char *xfr;
+ int source;
+
+ for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
+ v1 = cfg_listelt_value(e1);
+ cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
+ /*
+ * Check that unused bits are zero.
+ */
+ tresult = isc_netaddr_prefixok(&n1, p1);
+ if (tresult != ISC_R_SUCCESS) {
+ INSIST(tresult == ISC_R_FAILURE);
+ isc_netaddr_format(&n1, buf, sizeof(buf));
+ cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
+ "server '%s/%u': invalid prefix "
+ "(extra bits specified)", buf, p1);
+ result = tresult;
+ }
+ source = 0;
+ do {
+ obj = NULL;
+ if (n1.family == AF_INET)
+ xfr = sources[source].v6;
+ else
+ xfr = sources[source].v4;
+ (void)cfg_map_get(v1, xfr, &obj);
+ if (obj != NULL) {
+ isc_netaddr_format(&n1, buf, sizeof(buf));
+ cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
+ "server '%s': %s not legal",
+ buf, xfr);
+ result = ISC_R_FAILURE;
+ }
+ } while (sources[++source].v4 != NULL);
+ e2 = e1;
+ while ((e2 = cfg_list_next(e2)) != NULL) {
+ v2 = cfg_listelt_value(e2);
+ cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
+ if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
+ const char *file = cfg_obj_file(v1);
+ unsigned int line = cfg_obj_line(v1);
+
+ if (file == NULL)
+ file = "<unknown file>";
+
+ isc_netaddr_format(&n2, buf, sizeof(buf));
+ cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
+ "server '%s/%u': already exists "
+ "previous definition: %s:%u",
+ buf, p2, file, line);
+ result = ISC_R_FAILURE;
+ }
+ }
+ }
+ return (result);
+}
+
+static isc_result_t
+check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
+ dns_rdataclass_t vclass, isc_log_t *logctx, isc_mem_t *mctx)
+{
+ const cfg_obj_t *servers = NULL;
+ const cfg_obj_t *zones = NULL;
+ const cfg_obj_t *keys = NULL;
+ const cfg_listelt_t *element;
+ isc_symtab_t *symtab = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult = ISC_R_SUCCESS;
+ cfg_aclconfctx_t actx;
+ const cfg_obj_t *obj;
+ isc_boolean_t enablednssec, enablevalidation;
+
+ /*
+ * Check that all zone statements are syntactically correct and
+ * there are no duplicate zones.
+ */
+ tresult = isc_symtab_create(mctx, 100, freekey, mctx,
+ ISC_FALSE, &symtab);
+ if (tresult != ISC_R_SUCCESS)
+ return (ISC_R_NOMEMORY);
+
+ cfg_aclconfctx_init(&actx);
+
+ if (voptions != NULL)
+ (void)cfg_map_get(voptions, "zone", &zones);
+ else
+ (void)cfg_map_get(config, "zone", &zones);
+
+ for (element = cfg_list_first(zones);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ isc_result_t tresult;
+ const cfg_obj_t *zone = cfg_listelt_value(element);
+
+ tresult = check_zoneconf(zone, voptions, config, symtab,
+ vclass, &actx, logctx, mctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ }
+
+ isc_symtab_destroy(&symtab);
+
+ /*
+ * Check that all key statements are syntactically correct and
+ * there are no duplicate keys.
+ */
+ tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
+ if (tresult != ISC_R_SUCCESS)
+ return (ISC_R_NOMEMORY);
+
+ (void)cfg_map_get(config, "key", &keys);
+ tresult = check_keylist(keys, symtab, logctx);
+ if (tresult == ISC_R_EXISTS)
+ result = ISC_R_FAILURE;
+ else if (tresult != ISC_R_SUCCESS) {
+ isc_symtab_destroy(&symtab);
+ return (tresult);
+ }
+
+ if (voptions != NULL) {
+ keys = NULL;
+ (void)cfg_map_get(voptions, "key", &keys);
+ tresult = check_keylist(keys, symtab, logctx);
+ if (tresult == ISC_R_EXISTS)
+ result = ISC_R_FAILURE;
+ else if (tresult != ISC_R_SUCCESS) {
+ isc_symtab_destroy(&symtab);
+ return (tresult);
+ }
+ }
+
+ isc_symtab_destroy(&symtab);
+
+ /*
+ * Check that forwarding is reasonable.
+ */
+ if (voptions == NULL) {
+ const cfg_obj_t *options = NULL;
+ (void)cfg_map_get(config, "options", &options);
+ if (options != NULL)
+ if (check_forward(options, logctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ } else {
+ if (check_forward(voptions, logctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ }
+ /*
+ * Check that dual-stack-servers is reasonable.
+ */
+ if (voptions == NULL) {
+ const cfg_obj_t *options = NULL;
+ (void)cfg_map_get(config, "options", &options);
+ if (options != NULL)
+ if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ } else {
+ if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ }
+
+ /*
+ * Check that rrset-order is reasonable.
+ */
+ if (voptions != NULL) {
+ if (check_order(voptions, logctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ }
+
+ if (voptions != NULL) {
+ (void)cfg_map_get(voptions, "server", &servers);
+ if (servers != NULL &&
+ check_servers(servers, logctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ }
+
+ /*
+ * Check that dnssec-enable/dnssec-validation are sensible.
+ */
+ obj = NULL;
+ if (voptions != NULL)
+ (void)cfg_map_get(voptions, "dnssec-enable", &obj);
+ if (obj == NULL)
+ (void)cfg_map_get(config, "dnssec-enable", &obj);
+ if (obj == NULL)
+ enablednssec = ISC_TRUE;
+ else
+ enablednssec = cfg_obj_asboolean(obj);
+
+ obj = NULL;
+ if (voptions != NULL)
+ (void)cfg_map_get(voptions, "dnssec-validation", &obj);
+ if (obj == NULL)
+ (void)cfg_map_get(config, "dnssec-validation", &obj);
+ if (obj == NULL)
+ enablevalidation = ISC_FALSE; /* XXXMPA Change for 9.5. */
+ else
+ enablevalidation = cfg_obj_asboolean(obj);
+
+ if (enablevalidation && !enablednssec)
+ cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
+ "'dnssec-validation yes;' and 'dnssec-enable no;'");
+
+ if (voptions != NULL)
+ tresult = check_options(voptions, logctx, mctx);
+ else
+ tresult = check_options(config, logctx, mctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+
+ tresult = check_viewacls(&actx, voptions, config, logctx, mctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+
+ cfg_aclconfctx_destroy(&actx);
+
+ return (result);
+}
+
+static const char *
+default_channels[] = {
+ "default_syslog",
+ "default_stderr",
+ "default_debug",
+ "null",
+ NULL
+};
+
+static isc_result_t
+bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
+ isc_mem_t *mctx)
+{
+ const cfg_obj_t *categories = NULL;
+ const cfg_obj_t *category;
+ const cfg_obj_t *channels = NULL;
+ const cfg_obj_t *channel;
+ const cfg_listelt_t *element;
+ const cfg_listelt_t *delement;
+ const char *channelname;
+ const char *catname;
+ const cfg_obj_t *fileobj = NULL;
+ const cfg_obj_t *syslogobj = NULL;
+ const cfg_obj_t *nullobj = NULL;
+ const cfg_obj_t *stderrobj = NULL;
+ const cfg_obj_t *logobj = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+ isc_symtab_t *symtab = NULL;
+ isc_symvalue_t symvalue;
+ int i;
+
+ (void)cfg_map_get(config, "logging", &logobj);
+ if (logobj == NULL)
+ return (ISC_R_SUCCESS);
+
+ result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ symvalue.as_cpointer = NULL;
+ for (i = 0; default_channels[i] != NULL; i++) {
+ tresult = isc_symtab_define(symtab, default_channels[i], 1,
+ symvalue, isc_symexists_replace);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ }
+
+ cfg_map_get(logobj, "channel", &channels);
+
+ for (element = cfg_list_first(channels);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ channel = cfg_listelt_value(element);
+ channelname = cfg_obj_asstring(cfg_map_getname(channel));
+ fileobj = syslogobj = nullobj = stderrobj = NULL;
+ (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, logctx, ISC_LOG_ERROR,
+ "channel '%s': exactly one of file, syslog, "
+ "null, and stderr must be present",
+ channelname);
+ result = ISC_R_FAILURE;
+ }
+ tresult = isc_symtab_define(symtab, channelname, 1,
+ symvalue, isc_symexists_replace);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ }
+
+ cfg_map_get(logobj, "category", &categories);
+
+ for (element = cfg_list_first(categories);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ category = cfg_listelt_value(element);
+ catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
+ if (isc_log_categorybyname(logctx, catname) == NULL) {
+ cfg_obj_log(category, logctx, ISC_LOG_ERROR,
+ "undefined category: '%s'", catname);
+ result = ISC_R_FAILURE;
+ }
+ channels = cfg_tuple_get(category, "destinations");
+ for (delement = cfg_list_first(channels);
+ delement != NULL;
+ delement = cfg_list_next(delement))
+ {
+ channel = cfg_listelt_value(delement);
+ channelname = cfg_obj_asstring(channel);
+ tresult = isc_symtab_lookup(symtab, channelname, 1,
+ &symvalue);
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
+ "undefined channel: '%s'",
+ channelname);
+ result = tresult;
+ }
+ }
+ }
+ isc_symtab_destroy(&symtab);
+ return (result);
+}
+
+static isc_result_t
+key_exists(const cfg_obj_t *keylist, const char *keyname) {
+ const cfg_listelt_t *element;
+ const char *str;
+ const cfg_obj_t *obj;
+
+ if (keylist == NULL)
+ return (ISC_R_NOTFOUND);
+ 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)
+ return (ISC_R_SUCCESS);
+ }
+ return (ISC_R_NOTFOUND);
+}
+
+static isc_result_t
+bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
+ isc_log_t *logctx)
+{
+ isc_result_t result = ISC_R_SUCCESS, tresult;
+ const cfg_obj_t *control_keylist;
+ const cfg_listelt_t *element;
+ const cfg_obj_t *key;
+
+ control_keylist = cfg_tuple_get(control, "keys");
+ if (cfg_obj_isvoid(control_keylist))
+ return (ISC_R_SUCCESS);
+
+ for (element = cfg_list_first(control_keylist);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ key = cfg_listelt_value(element);
+ tresult = key_exists(keylist, cfg_obj_asstring(key));
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(key, logctx, ISC_LOG_ERROR,
+ "unknown key '%s'", cfg_obj_asstring(key));
+ result = tresult;
+ }
+ }
+ return (result);
+}
+
+static isc_result_t
+bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
+ isc_mem_t *mctx)
+{
+ isc_result_t result = ISC_R_SUCCESS, tresult;
+ cfg_aclconfctx_t actx;
+ const cfg_listelt_t *element, *element2;
+ const cfg_obj_t *allow;
+ const cfg_obj_t *control;
+ const cfg_obj_t *controls;
+ const cfg_obj_t *controlslist = NULL;
+ const cfg_obj_t *inetcontrols;
+ const cfg_obj_t *unixcontrols;
+ const cfg_obj_t *keylist = NULL;
+ const char *path;
+ isc_uint32_t perm, mask;
+ dns_acl_t *acl = NULL;
+ isc_sockaddr_t addr;
+ int i;
+
+ (void)cfg_map_get(config, "controls", &controlslist);
+ if (controlslist == NULL)
+ return (ISC_R_SUCCESS);
+
+ (void)cfg_map_get(config, "key", &keylist);
+
+ cfg_aclconfctx_init(&actx);
+
+ /*
+ * INET: Check allow clause.
+ * UNIX: Check "perm" for sanity, check path length.
+ */
+ for (element = cfg_list_first(controlslist);
+ element != NULL;
+ element = cfg_list_next(element)) {
+ controls = cfg_listelt_value(element);
+ unixcontrols = NULL;
+ inetcontrols = NULL;
+ (void)cfg_map_get(controls, "unix", &unixcontrols);
+ (void)cfg_map_get(controls, "inet", &inetcontrols);
+ for (element2 = cfg_list_first(inetcontrols);
+ element2 != NULL;
+ element2 = cfg_list_next(element2)) {
+ control = cfg_listelt_value(element2);
+ allow = cfg_tuple_get(control, "allow");
+ tresult = cfg_acl_fromconfig(allow, config, logctx,
+ &actx, mctx, &acl);
+ if (acl != NULL)
+ dns_acl_detach(&acl);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ tresult = bind9_check_controlskeys(control, keylist,
+ logctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ }
+ for (element2 = cfg_list_first(unixcontrols);
+ element2 != NULL;
+ element2 = cfg_list_next(element2)) {
+ control = cfg_listelt_value(element2);
+ path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
+ tresult = isc_sockaddr_frompath(&addr, path);
+ if (tresult == ISC_R_NOSPACE) {
+ cfg_obj_log(control, logctx, ISC_LOG_ERROR,
+ "unix control '%s': path too long",
+ path);
+ result = ISC_R_NOSPACE;
+ }
+ perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
+ for (i = 0; i < 3; i++) {
+#ifdef NEED_SECURE_DIRECTORY
+ mask = (0x1 << (i*3)); /* SEARCH */
+#else
+ mask = (0x6 << (i*3)); /* READ + WRITE */
+#endif
+ if ((perm & mask) == mask)
+ break;
+ }
+ if (i == 0) {
+ cfg_obj_log(control, logctx, ISC_LOG_WARNING,
+ "unix control '%s' allows access "
+ "to everyone", path);
+ } else if (i == 3) {
+ cfg_obj_log(control, logctx, ISC_LOG_WARNING,
+ "unix control '%s' allows access "
+ "to nobody", path);
+ }
+ tresult = bind9_check_controlskeys(control, keylist,
+ logctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ }
+ }
+ cfg_aclconfctx_destroy(&actx);
+ return (result);
+}
+
+isc_result_t
+bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
+ isc_mem_t *mctx)
+{
+ const cfg_obj_t *options = NULL;
+ const cfg_obj_t *servers = NULL;
+ const cfg_obj_t *views = NULL;
+ const cfg_obj_t *acls = NULL;
+ const cfg_obj_t *kals = NULL;
+ const cfg_obj_t *obj;
+ const cfg_listelt_t *velement;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult;
+ isc_symtab_t *symtab = NULL;
+
+ static const char *builtin[] = { "localhost", "localnets",
+ "any", "none"};
+
+ (void)cfg_map_get(config, "options", &options);
+
+ if (options != NULL &&
+ check_options(options, logctx, mctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+
+ (void)cfg_map_get(config, "server", &servers);
+ if (servers != NULL &&
+ check_servers(servers, logctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+
+ if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+
+ if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+
+ if (options != NULL &&
+ check_order(options, logctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+
+ (void)cfg_map_get(config, "view", &views);
+
+ if (views != NULL && options != NULL)
+ if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+
+ if (views == NULL) {
+ if (check_viewconf(config, NULL, dns_rdataclass_in,
+ logctx, mctx) != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ } else {
+ const cfg_obj_t *zones = NULL;
+
+ (void)cfg_map_get(config, "zone", &zones);
+ if (zones != NULL) {
+ cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
+ "when using 'view' statements, "
+ "all zones must be in views");
+ result = ISC_R_FAILURE;
+ }
+ }
+
+ tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ for (velement = cfg_list_first(views);
+ velement != NULL;
+ velement = cfg_list_next(velement))
+ {
+ const cfg_obj_t *view = cfg_listelt_value(velement);
+ const cfg_obj_t *vname = cfg_tuple_get(view, "name");
+ const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
+ const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
+ dns_rdataclass_t vclass = dns_rdataclass_in;
+ isc_result_t tresult = ISC_R_SUCCESS;
+ const char *key = cfg_obj_asstring(vname);
+ isc_symvalue_t symvalue;
+
+ if (cfg_obj_isstring(vclassobj)) {
+ isc_textregion_t r;
+
+ DE_CONST(cfg_obj_asstring(vclassobj), r.base);
+ r.length = strlen(r.base);
+ tresult = dns_rdataclass_fromtext(&vclass, &r);
+ if (tresult != ISC_R_SUCCESS)
+ cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
+ "view '%s': invalid class %s",
+ cfg_obj_asstring(vname), r.base);
+ }
+ if (tresult == ISC_R_SUCCESS && symtab != NULL) {
+ symvalue.as_cpointer = view;
+ tresult = isc_symtab_define(symtab, key, vclass,
+ symvalue,
+ isc_symexists_reject);
+ if (tresult == ISC_R_EXISTS) {
+ const char *file;
+ unsigned int line;
+ RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
+ vclass, &symvalue) == ISC_R_SUCCESS);
+ file = cfg_obj_file(symvalue.as_cpointer);
+ line = cfg_obj_line(symvalue.as_cpointer);
+ cfg_obj_log(view, logctx, ISC_LOG_ERROR,
+ "view '%s': already exists "
+ "previous definition: %s:%u",
+ key, file, line);
+ result = tresult;
+ } else if (result != ISC_R_SUCCESS) {
+ result = tresult;
+ } else if ((strcasecmp(key, "_bind") == 0 &&
+ vclass == dns_rdataclass_ch) ||
+ (strcasecmp(key, "_default") == 0 &&
+ vclass == dns_rdataclass_in)) {
+ cfg_obj_log(view, logctx, ISC_LOG_ERROR,
+ "attempt to redefine builtin view "
+ "'%s'", key);
+ result = ISC_R_EXISTS;
+ }
+ }
+ if (tresult == ISC_R_SUCCESS)
+ tresult = check_viewconf(config, voptions,
+ vclass, logctx, mctx);
+ if (tresult != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ }
+ if (symtab != NULL)
+ isc_symtab_destroy(&symtab);
+
+ if (views != NULL && options != NULL) {
+ obj = NULL;
+ tresult = cfg_map_get(options, "cache-file", &obj);
+ if (tresult == ISC_R_SUCCESS) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "'cache-file' cannot be a global "
+ "option if views are present");
+ result = ISC_R_FAILURE;
+ }
+ }
+
+ tresult = cfg_map_get(config, "acl", &acls);
+ if (tresult == ISC_R_SUCCESS) {
+ const cfg_listelt_t *elt;
+ const cfg_listelt_t *elt2;
+ const char *aclname;
+
+ for (elt = cfg_list_first(acls);
+ elt != NULL;
+ elt = cfg_list_next(elt)) {
+ const cfg_obj_t *acl = cfg_listelt_value(elt);
+ unsigned int i;
+
+ aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
+ for (i = 0;
+ i < sizeof(builtin) / sizeof(builtin[0]);
+ i++)
+ if (strcasecmp(aclname, builtin[i]) == 0) {
+ cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
+ "attempt to redefine "
+ "builtin acl '%s'",
+ aclname);
+ result = ISC_R_FAILURE;
+ break;
+ }
+
+ for (elt2 = cfg_list_next(elt);
+ elt2 != NULL;
+ elt2 = cfg_list_next(elt2)) {
+ const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
+ const char *name;
+ name = cfg_obj_asstring(cfg_tuple_get(acl2,
+ "name"));
+ if (strcasecmp(aclname, name) == 0) {
+ const char *file = cfg_obj_file(acl);
+ unsigned int line = cfg_obj_line(acl);
+
+ if (file == NULL)
+ file = "<unknown file>";
+
+ cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
+ "attempt to redefine "
+ "acl '%s' previous "
+ "definition: %s:%u",
+ name, file, line);
+ result = ISC_R_FAILURE;
+ }
+ }
+ }
+ }
+
+ tresult = cfg_map_get(config, "kal", &kals);
+ if (tresult == ISC_R_SUCCESS) {
+ const cfg_listelt_t *elt;
+ const cfg_listelt_t *elt2;
+ const char *aclname;
+
+ for (elt = cfg_list_first(kals);
+ elt != NULL;
+ elt = cfg_list_next(elt)) {
+ const cfg_obj_t *acl = cfg_listelt_value(elt);
+
+ aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
+
+ for (elt2 = cfg_list_next(elt);
+ elt2 != NULL;
+ elt2 = cfg_list_next(elt2)) {
+ const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
+ const char *name;
+ name = cfg_obj_asstring(cfg_tuple_get(acl2,
+ "name"));
+ if (strcasecmp(aclname, name) == 0) {
+ const char *file = cfg_obj_file(acl);
+ unsigned int line = cfg_obj_line(acl);
+
+ if (file == NULL)
+ file = "<unknown file>";
+
+ cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
+ "attempt to redefine "
+ "kal '%s' previous "
+ "definition: %s:%u",
+ name, file, line);
+ result = ISC_R_FAILURE;
+ }
+ }
+ }
+ }
+
+ return (result);
+}
diff --git a/lib/bind9/getaddresses.c b/lib/bind9/getaddresses.c
new file mode 100644
index 0000000..b6edce0
--- /dev/null
+++ b/lib/bind9/getaddresses.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2004, 2005 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: getaddresses.c,v 1.15.18.5 2005/10/14 01:28:24 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+#include <string.h>
+
+#include <isc/net.h>
+#include <isc/netaddr.h>
+#include <isc/netdb.h>
+#include <isc/netscope.h>
+#include <isc/result.h>
+#include <isc/sockaddr.h>
+#include <isc/util.h>
+
+#include <bind9/getaddresses.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
+
+isc_result_t
+bind9_getaddresses(const char *hostname, in_port_t port,
+ isc_sockaddr_t *addrs, int addrsize, int *addrcount)
+{
+ struct in_addr in4;
+ struct in6_addr in6;
+ isc_boolean_t have_ipv4, have_ipv6;
+ int i;
+
+#ifdef USE_GETADDRINFO
+ struct addrinfo *ai = NULL, *tmpai, hints;
+ int result;
+#else
+ struct hostent *he;
+#endif
+
+ REQUIRE(hostname != NULL);
+ REQUIRE(addrs != NULL);
+ REQUIRE(addrcount != NULL);
+ REQUIRE(addrsize > 0);
+
+ have_ipv4 = ISC_TF((isc_net_probeipv4() == ISC_R_SUCCESS));
+ have_ipv6 = ISC_TF((isc_net_probeipv6() == ISC_R_SUCCESS));
+
+ /*
+ * Try IPv4, then IPv6. In order to handle the extended format
+ * for IPv6 scoped addresses (address%scope_ID), we'll use a local
+ * working buffer of 128 bytes. The length is an ad-hoc value, but
+ * should be enough for this purpose; the buffer can contain a string
+ * of at least 80 bytes for scope_ID in addition to any IPv6 numeric
+ * addresses (up to 46 bytes), the delimiter character and the
+ * terminating NULL character.
+ */
+ if (inet_pton(AF_INET, hostname, &in4) == 1) {
+ if (have_ipv4)
+ isc_sockaddr_fromin(&addrs[0], &in4, port);
+ else
+ isc_sockaddr_v6fromin(&addrs[0], &in4, port);
+ *addrcount = 1;
+ return (ISC_R_SUCCESS);
+ } else if (strlen(hostname) <= 127U) {
+ char tmpbuf[128], *d;
+ isc_uint32_t zone = 0;
+
+ strcpy(tmpbuf, hostname);
+ d = strchr(tmpbuf, '%');
+ if (d != NULL)
+ *d = '\0';
+
+ if (inet_pton(AF_INET6, tmpbuf, &in6) == 1) {
+ isc_netaddr_t na;
+
+ if (!have_ipv6)
+ return (ISC_R_FAMILYNOSUPPORT);
+
+ if (d != NULL) {
+#ifdef ISC_PLATFORM_HAVESCOPEID
+ isc_result_t result;
+
+ result = isc_netscope_pton(AF_INET6, d + 1,
+ &in6, &zone);
+
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#else
+ /*
+ * The extended format is specified while the
+ * system does not provide the ability to use
+ * it. Throw an explicit error instead of
+ * ignoring the specified value.
+ */
+ return (ISC_R_BADADDRESSFORM);
+#endif
+ }
+
+ isc_netaddr_fromin6(&na, &in6);
+ isc_netaddr_setzone(&na, zone);
+ isc_sockaddr_fromnetaddr(&addrs[0],
+ (const isc_netaddr_t *)&na,
+ port);
+
+ *addrcount = 1;
+ return (ISC_R_SUCCESS);
+
+ }
+ }
+#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
+ }
+ hints.ai_socktype = SOCK_STREAM;
+#ifdef AI_ADDRCONFIG
+ again:
+#endif
+ result = getaddrinfo(hostname, NULL, &hints, &ai);
+ switch (result) {
+ case 0:
+ break;
+ case EAI_NONAME:
+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
+ case EAI_NODATA:
+#endif
+ return (ISC_R_NOTFOUND);
+#ifdef AI_ADDRCONFIG
+ case EAI_BADFLAGS:
+ if ((hints.ai_flags & AI_ADDRCONFIG) != 0) {
+ hints.ai_flags &= ~AI_ADDRCONFIG;
+ goto again;
+ }
+#endif
+ default:
+ return (ISC_R_FAILURE);
+ }
+ for (tmpai = ai, i = 0;
+ tmpai != NULL && i < addrsize;
+ tmpai = tmpai->ai_next)
+ {
+ if (tmpai->ai_family != AF_INET &&
+ tmpai->ai_family != AF_INET6)
+ continue;
+ if (tmpai->ai_family == AF_INET) {
+ struct sockaddr_in *sin;
+ sin = (struct sockaddr_in *)tmpai->ai_addr;
+ isc_sockaddr_fromin(&addrs[i], &sin->sin_addr, port);
+ } else {
+ struct sockaddr_in6 *sin6;
+ sin6 = (struct sockaddr_in6 *)tmpai->ai_addr;
+ isc_sockaddr_fromin6(&addrs[i], &sin6->sin6_addr,
+ port);
+ }
+ i++;
+
+ }
+ freeaddrinfo(ai);
+ *addrcount = i;
+#else
+ he = gethostbyname(hostname);
+ if (he == NULL) {
+ switch (h_errno) {
+ case HOST_NOT_FOUND:
+#ifdef NO_DATA
+ case NO_DATA:
+#endif
+#if defined(NO_ADDRESS) && (!defined(NO_DATA) || (NO_DATA != NO_ADDRESS))
+ case NO_ADDRESS:
+#endif
+ return (ISC_R_NOTFOUND);
+ default:
+ return (ISC_R_FAILURE);
+ }
+ }
+ if (he->h_addrtype != AF_INET && he->h_addrtype != AF_INET6)
+ return (ISC_R_NOTFOUND);
+ for (i = 0; i < addrsize; i++) {
+ if (he->h_addrtype == AF_INET) {
+ struct in_addr *inp;
+ inp = (struct in_addr *)(he->h_addr_list[i]);
+ if (inp == NULL)
+ break;
+ isc_sockaddr_fromin(&addrs[i], inp, port);
+ } else {
+ struct in6_addr *in6p;
+ in6p = (struct in6_addr *)(he->h_addr_list[i]);
+ if (in6p == NULL)
+ break;
+ isc_sockaddr_fromin6(&addrs[i], in6p, port);
+ }
+ }
+ *addrcount = i;
+#endif
+ if (*addrcount == 0)
+ return (ISC_R_NOTFOUND);
+ else
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/bind9/include/Makefile.in b/lib/bind9/include/Makefile.in
new file mode 100644
index 0000000..6c6611e
--- /dev/null
+++ b/lib/bind9/include/Makefile.in
@@ -0,0 +1,25 @@
+# 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: Makefile.in,v 1.2 2004/03/05 05:09:08 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = bind9
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind9/include/bind9/Makefile.in b/lib/bind9/include/bind9/Makefile.in
new file mode 100644
index 0000000..8ef5c32
--- /dev/null
+++ b/lib/bind9/include/bind9/Makefile.in
@@ -0,0 +1,42 @@
+# 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: Makefile.in,v 1.6 2004/03/05 05:09:10 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+#
+# Only list headers that are to be installed and are not
+# machine generated. The latter are handled specially in the
+# install target below.
+#
+HEADERS = check.h getaddresses.h version.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/bind9
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/bind9 ; \
+ done
diff --git a/lib/bind9/include/bind9/check.h b/lib/bind9/include/bind9/check.h
new file mode 100644
index 0000000..25a8e0c
--- /dev/null
+++ b/lib/bind9/include/bind9/check.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2004-2006 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: check.h,v 1.2.18.4 2006/03/02 00:37:21 marka Exp $ */
+
+#ifndef BIND9_CHECK_H
+#define BIND9_CHECK_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#include <isccfg/cfg.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
+ isc_mem_t *mctx);
+/*%<
+ * Check the syntactic validity of a configuration parse tree generated from
+ * a named.conf file.
+ *
+ * Requires:
+ *\li config is a valid parse tree
+ *
+ *\li logctx is a valid logging context.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_FAILURE
+ */
+
+isc_result_t
+bind9_check_key(const cfg_obj_t *config, isc_log_t *logctx);
+/*%<
+ * Same as bind9_check_namedconf(), but for a single 'key' statement.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* BIND9_CHECK_H */
diff --git a/lib/bind9/include/bind9/getaddresses.h b/lib/bind9/include/bind9/getaddresses.h
new file mode 100644
index 0000000..e6d030d
--- /dev/null
+++ b/lib/bind9/include/bind9/getaddresses.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2004, 2005 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: getaddresses.h,v 1.3.18.2 2005/04/29 00:15:48 marka Exp $ */
+
+#ifndef BIND9_GETADDRESSES_H
+#define BIND9_GETADDRESSES_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#include <isc/net.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+bind9_getaddresses(const char *hostname, in_port_t port,
+ isc_sockaddr_t *addrs, int addrsize, int *addrcount);
+/*%<
+ * Use the system resolver to get the addresses associated with a hostname.
+ * If successful, the number of addresses found is returned in 'addrcount'.
+ * If a hostname lookup is performed and addresses of an unknown family is
+ * seen, it is ignored. If more than 'addrsize' addresses are seen, the
+ * first 'addrsize' are returned and the remainder silently truncated.
+ *
+ * This routine may block. If called by a program using the isc_app
+ * framework, it should be surounded by isc_app_block()/isc_app_unblock().
+ *
+ * Requires:
+ *\li 'hostname' is not NULL.
+ *\li 'addrs' is not NULL.
+ *\li 'addrsize' > 0
+ *\li 'addrcount' is not NULL.
+ *
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOTFOUND
+ *\li #ISC_R_NOFAMILYSUPPORT - 'hostname' is an IPv6 address, and IPv6 is
+ * not supported.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* BIND9_GETADDRESSES_H */
diff --git a/lib/bind9/include/bind9/version.h b/lib/bind9/include/bind9/version.h
new file mode 100644
index 0000000..154e240d
--- /dev/null
+++ b/lib/bind9/include/bind9/version.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005 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: version.h,v 1.3.18.2 2005/04/29 00:15:48 marka Exp $ */
+
+/*! \file */
+
+#include <isc/platform.h>
+
+LIBBIND9_EXTERNAL_DATA extern const char bind9_version[];
+
+LIBBIND9_EXTERNAL_DATA extern const unsigned int bind9_libinterface;
+LIBBIND9_EXTERNAL_DATA extern const unsigned int bind9_librevision;
+LIBBIND9_EXTERNAL_DATA extern const unsigned int bind9_libage;
diff --git a/lib/bind9/version.c b/lib/bind9/version.c
new file mode 100644
index 0000000..2cc17da
--- /dev/null
+++ b/lib/bind9/version.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005 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: version.c,v 1.4.18.2 2005/04/29 00:15:47 marka Exp $ */
+
+/*! \file */
+
+#include <bind9/version.h>
+
+const char bind9_version[] = VERSION;
+
+const unsigned int bind9_libinterface = LIBINTERFACE;
+const unsigned int bind9_librevision = LIBREVISION;
+const unsigned int bind9_libage = LIBAGE;
diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in
new file mode 100644
index 0000000..286a5f9
--- /dev/null
+++ b/lib/dns/Makefile.in
@@ -0,0 +1,171 @@
+# Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-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.144.18.10 2006/01/06 00:01:43 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+# Attempt to disable parallel processing.
+.NOTPARALLEL:
+.NO_PARALLEL:
+
+@BIND9_VERSION@
+
+@LIBDNS_API@
+
+@BIND9_MAKE_INCLUDES@
+
+CINCLUDES = -I. -Iinclude ${DNS_INCLUDES} \
+ ${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@
+
+CDEFINES = -DUSE_MD5 @USE_OPENSSL@ @USE_GSSAPI@
+CWARNINGS =
+
+ISCLIBS = ../../lib/isc/libisc.@A@
+
+ISCDEPLIBS = ../../lib/isc/libisc.@A@
+
+LIBS = @LIBS@
+
+# Alphabetically
+
+DSTOBJS = dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \
+ gssapi_link.@O@ gssapictx.@O@ hmac_link.@O@ key.@O@ \
+ openssl_link.@O@ openssldh_link.@O@ openssldsa_link.@O@ \
+ opensslrsa_link.@O@
+
+# Alphabetically
+DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
+ cache.@O@ callbacks.@O@ compress.@O@ \
+ db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \
+ dlz.@O@ dnssec.@O@ ds.@O@ forward.@O@ journal.@O@ keytable.@O@ \
+ lib.@O@ log.@O@ lookup.@O@ \
+ master.@O@ masterdump.@O@ message.@O@ \
+ name.@O@ ncache.@O@ nsec.@O@ order.@O@ peer.@O@ portlist.@O@ \
+ rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \
+ rdatalist.@O@ \
+ rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ request.@O@ \
+ resolver.@O@ result.@O@ rootns.@O@ sdb.@O@ sdlz.@O@ \
+ soa.@O@ ssu.@O@ \
+ stats.@O@ tcpmsg.@O@ time.@O@ timer.@O@ tkey.@O@ \
+ tsig.@O@ ttl.@O@ validator.@O@ \
+ version.@O@ view.@O@ xfrin.@O@ zone.@O@ zonekey.@O@ zt.@O@
+
+OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS}
+
+# Alphabetically
+DSTSRCS = dst_api.c dst_lib.c dst_parse.c \
+ dst_result.c gssapi_link.c gssapictx.c \
+ hmac_link.c key.c \
+ openssl_link.c openssldh_link.c \
+ openssldsa_link.c opensslrsa_link.c
+
+DNSSRCS = acache.c acl.c adb.c byaddr.c \
+ cache.c callbacks.c compress.c \
+ db.c dbiterator.c dbtable.c diff.c dispatch.c \
+ dlz.c dnssec.c ds.c forward.c journal.c keytable.c \
+ lib.c log.c lookup.c \
+ master.c masterdump.c message.c \
+ name.c ncache.c nsec.c order.c peer.c portlist.c \
+ rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c \
+ rdatalist.c \
+ rdataset.c rdatasetiter.c rdataslab.c request.c \
+ resolver.c result.c rootns.c sdb.c sdlz.c \
+ soa.c ssu.c \
+ stats.c tcpmsg.c time.c timer.c tkey.c \
+ tsig.c ttl.c validator.c \
+ version.c view.c xfrin.c zone.c zonekey.c zt.c ${OTHERSRCS}
+SRCS = ${DSTSRCS} ${DNSSRCS}
+
+SUBDIRS = include
+TARGETS = include/dns/enumtype.h include/dns/enumclass.h \
+ include/dns/rdatastruct.h timestamp
+
+DEPENDEXTRA = ./gen -F include/dns/rdatastruct.h \
+ -s ${srcdir} -d >> Makefile ;
+
+@BIND9_MAKE_RULES@
+
+version.@O@: version.c
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \
+ -DVERSION=\"${VERSION}\" \
+ -DLIBINTERFACE=${LIBINTERFACE} \
+ -DLIBREVISION=${LIBREVISION} \
+ -DLIBAGE=${LIBAGE} \
+ -c ${srcdir}/version.c
+
+libdns.@SA@: ${OBJS}
+ ${AR} ${ARFLAGS} $@ ${OBJS}
+ ${RANLIB} $@
+
+libdns.la: ${OBJS}
+ ${LIBTOOL_MODE_LINK} \
+ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns.la -rpath ${libdir} \
+ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ ${OBJS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ ${LIBS}
+
+timestamp: libdns.@A@
+ touch timestamp
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+
+install:: timestamp installdirs
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libdns.@A@ ${DESTDIR}${libdir}
+
+clean distclean::
+ rm -f libdns.@A@ timestamp
+ rm -f gen code.h include/dns/enumtype.h include/dns/enumclass.h
+ rm -f include/dns/rdatastruct.h
+
+newrr::
+ rm -f code.h include/dns/enumtype.h include/dns/enumclass.h
+ rm -f include/dns/rdatastruct.h
+
+include: include/dns/enumtype.h include/dns/enumclass.h \
+ include/dns/rdatastruct.h
+
+rdata.@O@: code.h
+
+include/dns/enumtype.h: gen
+ ./gen -s ${srcdir} -t > $@
+
+include/dns/enumclass.h: gen
+ ./gen -s ${srcdir} -c > $@
+
+include/dns/rdatastruct.h: gen \
+ ${srcdir}/rdata/rdatastructpre.h \
+ ${srcdir}/rdata/rdatastructsuf.h
+ ./gen -s ${srcdir} -i \
+ -P ${srcdir}/rdata/rdatastructpre.h \
+ -S ${srcdir}/rdata/rdatastructsuf.h > $@
+
+code.h: gen
+ ./gen -s ${srcdir} > code.h
+
+gen: gen.c
+ ${BUILD_CC} ${BUILD_CFLAGS} -I${top_srcdir}/lib/isc/include \
+ ${BUILD_CPPFLAGS} ${BUILD_LDFLAGS} -o $@ ${srcdir}/gen.c ${BUILD_LIBS}
+
+rbtdb64.@O@: rbtdb.c
+
+depend: include/dns/enumtype.h include/dns/enumclass.h \
+ include/dns/rdatastruct.h code.h
+subdirs: include/dns/enumtype.h include/dns/enumclass.h \
+ include/dns/rdatastruct.h code.h
+${OBJS}: include/dns/enumtype.h include/dns/enumclass.h \
+ include/dns/rdatastruct.h
diff --git a/lib/dns/acache.c b/lib/dns/acache.c
new file mode 100644
index 0000000..5787a5a
--- /dev/null
+++ b/lib/dns/acache.c
@@ -0,0 +1,1778 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: acache.c,v 1.3.2.16 2006/07/19 00:34:56 marka Exp $ */
+
+#include <config.h>
+
+#include <isc/atomic.h>
+#include <isc/event.h>
+#include <isc/hash.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/mutex.h>
+#include <isc/random.h>
+#include <isc/refcount.h>
+#include <isc/rwlock.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+
+#include <dns/acache.h>
+#include <dns/db.h>
+#include <dns/events.h>
+#include <dns/log.h>
+#include <dns/message.h>
+#include <dns/name.h>
+#include <dns/rdataset.h>
+#include <dns/result.h>
+#include <dns/zone.h>
+
+#define ACACHE_MAGIC ISC_MAGIC('A', 'C', 'H', 'E')
+#define DNS_ACACHE_VALID(acache) ISC_MAGIC_VALID(acache, ACACHE_MAGIC)
+
+#define ACACHEENTRY_MAGIC ISC_MAGIC('A', 'C', 'E', 'T')
+#define DNS_ACACHEENTRY_VALID(entry) ISC_MAGIC_VALID(entry, ACACHEENTRY_MAGIC)
+
+#define DBBUCKETS 67
+
+#if 0
+#define ATRACE(m) isc_log_write(dns_lctx, \
+ DNS_LOGCATEGORY_DATABASE, \
+ DNS_LOGMODULE_ACACHE, \
+ ISC_LOG_DEBUG(3), \
+ "acache %p: %s", acache, (m))
+#define AATRACE(a,m) isc_log_write(dns_lctx, \
+ DNS_LOGCATEGORY_DATABASE, \
+ DNS_LOGMODULE_ACACHE, \
+ ISC_LOG_DEBUG(3), \
+ "acache %p: %s", (a), (m))
+#else
+#define ATRACE(m)
+#define AATRACE(a, m)
+#endif
+
+/*
+ * The following variables control incremental cleaning.
+ * MINSIZE is how many bytes is the floor for dns_acache_setcachesize().
+ * CLEANERINCREMENT is how many entries are examined in one pass.
+ * (XXX simply derived from definitions in cache.c There may be better
+ * constants here.)
+ */
+#define DNS_ACACHE_MINSIZE 2097152 /* Bytes. 2097152 = 2 MB */
+#define DNS_ACACHE_CLEANERINCREMENT 1000 /* Number of entries. */
+
+#define DEFAULT_ACACHE_ENTRY_LOCK_COUNT 1009 /*%< Should be prime. */
+
+#if defined(ISC_RWLOCK_USEATOMIC) && defined(ISC_PLATFORM_HAVEATOMICSTORE)
+#define ACACHE_USE_RWLOCK 1
+#endif
+
+#ifdef ACACHE_USE_RWLOCK
+#define ACACHE_INITLOCK(l) isc_rwlock_init((l), 0, 0)
+#define ACACHE_DESTROYLOCK(l) isc_rwlock_destroy(l)
+#define ACACHE_LOCK(l, t) RWLOCK((l), (t))
+#define ACACHE_UNLOCK(l, t) RWUNLOCK((l), (t))
+
+#define acache_storetime(entry, t) \
+ (isc_atomic_store((isc_int32_t *)&(entry)->lastused, (t)))
+#else
+#define ACACHE_INITLOCK(l) isc_mutex_init(l)
+#define ACACHE_DESTROYLOCK(l) DESTROYLOCK(l)
+#define ACACHE_LOCK(l, t) LOCK(l)
+#define ACACHE_UNLOCK(l, t) UNLOCK(l)
+
+#define acache_storetime(entry, t) ((entry)->lastused = (t))
+#endif
+
+/* Locked by acache lock */
+typedef struct dbentry {
+ ISC_LINK(struct dbentry) link;
+
+ dns_db_t *db;
+ ISC_LIST(dns_acacheentry_t) originlist;
+ ISC_LIST(dns_acacheentry_t) referlist;
+} dbentry_t;
+
+typedef ISC_LIST(dbentry_t) dbentrylist_t;
+
+typedef struct acache_cleaner acache_cleaner_t;
+
+typedef enum {
+ cleaner_s_idle, /* Waiting for cleaning-interval to expire. */
+ cleaner_s_busy, /* Currently cleaning. */
+ cleaner_s_done /* Freed enough memory after being overmem. */
+} cleaner_state_t;
+
+/*
+ * Convenience macros for comprehensive assertion checking.
+ */
+#define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle && \
+ (c)->resched_event != NULL)
+#define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy && \
+ (c)->resched_event == NULL)
+
+struct acache_cleaner {
+ isc_mutex_t lock;
+ /*
+ * Locks overmem_event, overmem. (See cache.c)
+ */
+
+ dns_acache_t *acache;
+ unsigned int cleaning_interval; /* The cleaning-interval
+ from named.conf,
+ in seconds. */
+
+ isc_stdtime_t last_cleanup_time; /* The time when the last
+ cleanup task completed */
+
+ isc_timer_t *cleaning_timer;
+ isc_event_t *resched_event; /* Sent by cleaner task to
+ itself to reschedule */
+ isc_event_t *overmem_event;
+
+ dns_acacheentry_t *current_entry; /* The bookmark entry to
+ restart the cleaning.
+ Locked by acache lock. */
+ int increment; /* Number of entries to
+ clean in one increment */
+
+ unsigned long ncleaned; /* Number of entries cleaned
+ up (for logging purposes) */
+ cleaner_state_t state; /* Idle/Busy/Done. */
+ isc_boolean_t overmem; /* The acache is in an overmem
+ state. */
+};
+
+struct dns_acachestats {
+ unsigned int hits;
+ unsigned int queries;
+ unsigned int misses;
+ unsigned int adds;
+ unsigned int deleted;
+ unsigned int cleaned;
+ unsigned int cleaner_runs;
+ unsigned int overmem;
+ unsigned int overmem_nocreates;
+ unsigned int nomem;
+};
+
+/*
+ * The actual acache object.
+ */
+
+struct dns_acache {
+ unsigned int magic;
+
+ isc_mem_t *mctx;
+ isc_refcount_t refs;
+
+#ifdef ACACHE_USE_RWLOCK
+ isc_rwlock_t *entrylocks;
+#else
+ isc_mutex_t *entrylocks;
+#endif
+
+ isc_mutex_t lock;
+
+ int live_cleaners;
+ acache_cleaner_t cleaner;
+ ISC_LIST(dns_acacheentry_t) entries;
+ unsigned int dbentries;
+ dbentrylist_t dbbucket[DBBUCKETS];
+
+ isc_boolean_t shutting_down;
+
+ isc_task_t *task;
+ isc_event_t cevent;
+ isc_boolean_t cevent_sent;
+
+ dns_acachestats_t stats;
+};
+
+struct dns_acacheentry {
+ unsigned int magic;
+
+ unsigned int locknum;
+ isc_refcount_t references;
+
+ dns_acache_t *acache;
+
+ /* Data for Management of cache entries */
+ ISC_LINK(dns_acacheentry_t) link;
+ ISC_LINK(dns_acacheentry_t) olink;
+ ISC_LINK(dns_acacheentry_t) rlink;
+
+ dns_db_t *origdb; /* reference to the DB
+ holding this entry */
+
+ /* Cache data */
+ dns_zone_t *zone; /* zone this entry
+ belongs to */
+ dns_db_t *db; /* DB this entry belongs to */
+ dns_dbversion_t *version; /* the version of the DB */
+ dns_dbnode_t *node; /* node this entry
+ belongs to */
+ dns_name_t *foundname; /* corresponding DNS name
+ and rdataset */
+
+ /* Callback function and its argument */
+ void (*callback)(dns_acacheentry_t *, void **);
+ void *cbarg;
+
+ /* Timestamp of the last time this entry is referred to */
+ isc_stdtime32_t lastused;
+};
+
+/*
+ * Internal functions (and prototypes).
+ */
+static inline isc_boolean_t check_noentry(dns_acache_t *acache);
+static void destroy(dns_acache_t *acache);
+static void shutdown_entries(dns_acache_t *acache);
+static void shutdown_buckets(dns_acache_t *acache);
+static void destroy_entry(dns_acacheentry_t *ent);
+static inline void unlink_dbentries(dns_acache_t *acache,
+ dns_acacheentry_t *ent);
+static inline isc_result_t finddbent(dns_acache_t *acache,
+ dns_db_t *db, dbentry_t **dbentryp);
+static inline void clear_entry(dns_acache_t *acache, dns_acacheentry_t *entry);
+static isc_result_t acache_cleaner_init(dns_acache_t *acache,
+ isc_timermgr_t *timermgr,
+ acache_cleaner_t *cleaner);
+static void acache_cleaning_timer_action(isc_task_t *task, isc_event_t *event);
+static void acache_incremental_cleaning_action(isc_task_t *task,
+ isc_event_t *event);
+static void acache_overmem_cleaning_action(isc_task_t *task,
+ isc_event_t *event);
+static void acache_cleaner_shutdown_action(isc_task_t *task,
+ isc_event_t *event);
+
+/*
+ * acache should be locked. If it is not, the stats can get out of whack,
+ * which is not a big deal for us since this is for debugging / stats
+ */
+static void
+reset_stats(dns_acache_t *acache) {
+ acache->stats.hits = 0;
+ acache->stats.queries = 0;
+ acache->stats.misses = 0;
+ acache->stats.adds = 0;
+ acache->stats.deleted = 0;
+ acache->stats.cleaned = 0;
+ acache->stats.overmem = 0;
+ acache->stats.overmem_nocreates = 0;
+ acache->stats.nomem = 0;
+}
+
+/*
+ * The acache must be locked before calling.
+ */
+static inline isc_boolean_t
+check_noentry(dns_acache_t *acache) {
+ if (ISC_LIST_EMPTY(acache->entries) && acache->dbentries == 0) {
+ return (ISC_TRUE);
+ }
+
+ return (ISC_FALSE);
+}
+
+/*
+ * The acache must be locked before calling.
+ */
+static void
+shutdown_entries(dns_acache_t *acache) {
+ dns_acacheentry_t *entry, *entry_next;
+
+ REQUIRE(DNS_ACACHE_VALID(acache));
+ INSIST(acache->shutting_down);
+
+ /*
+ * Release the dependency of all entries, and detach them.
+ */
+ for (entry = ISC_LIST_HEAD(acache->entries);
+ entry != NULL;
+ entry = entry_next) {
+ entry_next = ISC_LIST_NEXT(entry, link);
+
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
+
+ /*
+ * If the cleaner holds this entry, it will be unlinked and
+ * freed in the cleaner later.
+ */
+ if (acache->cleaner.current_entry != entry)
+ ISC_LIST_UNLINK(acache->entries, entry, link);
+ unlink_dbentries(acache, entry);
+ if (entry->callback != NULL) {
+ (entry->callback)(entry, &entry->cbarg);
+ entry->callback = NULL;
+ }
+
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
+
+ if (acache->cleaner.current_entry != entry)
+ dns_acache_detachentry(&entry);
+ }
+}
+
+/*
+ * The acache must be locked before calling.
+ */
+static void
+shutdown_buckets(dns_acache_t *acache) {
+ int i;
+ dbentry_t *dbent;
+
+ REQUIRE(DNS_ACACHE_VALID(acache));
+ INSIST(acache->shutting_down);
+
+ for (i = 0; i < DBBUCKETS; i++) {
+ while ((dbent = ISC_LIST_HEAD(acache->dbbucket[i])) != NULL) {
+ INSIST(ISC_LIST_EMPTY(dbent->originlist) &&
+ ISC_LIST_EMPTY(dbent->referlist));
+ ISC_LIST_UNLINK(acache->dbbucket[i], dbent, link);
+
+ dns_db_detach(&dbent->db);
+
+ isc_mem_put(acache->mctx, dbent, sizeof(*dbent));
+
+ acache->dbentries--;
+ }
+ }
+
+ INSIST(acache->dbentries == 0);
+}
+
+static void
+shutdown_task(isc_task_t *task, isc_event_t *ev) {
+ dns_acache_t *acache;
+
+ UNUSED(task);
+
+ acache = ev->ev_arg;
+ INSIST(DNS_ACACHE_VALID(acache));
+
+ isc_event_free(&ev);
+
+ LOCK(&acache->lock);
+
+ shutdown_entries(acache);
+ shutdown_buckets(acache);
+
+ UNLOCK(&acache->lock);
+
+ dns_acache_detach(&acache);
+}
+
+/* The acache and the entry must be locked before calling. */
+static inline void
+unlink_dbentries(dns_acache_t *acache, dns_acacheentry_t *ent) {
+ isc_result_t result;
+ dbentry_t *dbent;
+
+ if (ISC_LINK_LINKED(ent, olink)) {
+ INSIST(ent->origdb != NULL);
+ dbent = NULL;
+ result = finddbent(acache, ent->origdb, &dbent);
+ INSIST(result == ISC_R_SUCCESS);
+
+ ISC_LIST_UNLINK(dbent->originlist, ent, olink);
+ }
+ if (ISC_LINK_LINKED(ent, rlink)) {
+ INSIST(ent->db != NULL);
+ dbent = NULL;
+ result = finddbent(acache, ent->db, &dbent);
+ INSIST(result == ISC_R_SUCCESS);
+
+ ISC_LIST_UNLINK(dbent->referlist, ent, rlink);
+ }
+}
+
+/* There must not be a reference to this entry. */
+static void
+destroy_entry(dns_acacheentry_t *entry) {
+ dns_acache_t *acache;
+
+ REQUIRE(DNS_ACACHEENTRY_VALID(entry));
+
+ acache = entry->acache;
+ REQUIRE(DNS_ACACHE_VALID(acache));
+
+ /*
+ * Since there is no reference to this entry, it is safe to call
+ * clear_entry() here.
+ */
+ clear_entry(acache, entry);
+
+ isc_mem_put(acache->mctx, entry, sizeof(*entry));
+
+ dns_acache_detach(&acache);
+}
+
+static void
+destroy(dns_acache_t *acache) {
+ int i;
+
+ REQUIRE(DNS_ACACHE_VALID(acache));
+
+ ATRACE("destroy");
+
+ isc_mem_setwater(acache->mctx, NULL, NULL, 0, 0);
+
+ if (acache->cleaner.overmem_event != NULL)
+ isc_event_free(&acache->cleaner.overmem_event);
+
+ if (acache->cleaner.resched_event != NULL)
+ isc_event_free(&acache->cleaner.resched_event);
+
+ if (acache->task != NULL)
+ isc_task_detach(&acache->task);
+
+ for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++)
+ ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
+ isc_mem_put(acache->mctx, acache->entrylocks,
+ sizeof(*acache->entrylocks) *
+ DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+
+ DESTROYLOCK(&acache->cleaner.lock);
+
+ DESTROYLOCK(&acache->lock);
+ acache->magic = 0;
+
+ isc_mem_putanddetach(&acache->mctx, acache, sizeof(*acache));
+}
+
+static inline isc_result_t
+finddbent(dns_acache_t *acache, dns_db_t *db, dbentry_t **dbentryp) {
+ int bucket;
+ dbentry_t *dbentry;
+
+ REQUIRE(DNS_ACACHE_VALID(acache));
+ REQUIRE(db != NULL);
+ REQUIRE(dbentryp != NULL && *dbentryp == NULL);
+
+ /*
+ * The caller must be holding the acache lock.
+ */
+
+ bucket = isc_hash_calc((const unsigned char *)&db,
+ sizeof(db), ISC_TRUE) % DBBUCKETS;
+
+ for (dbentry = ISC_LIST_HEAD(acache->dbbucket[bucket]);
+ dbentry != NULL;
+ dbentry = ISC_LIST_NEXT(dbentry, link)) {
+ if (dbentry->db == db)
+ break;
+ }
+
+ *dbentryp = dbentry;
+
+ if (dbentry == NULL)
+ return (ISC_R_NOTFOUND);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+clear_entry(dns_acache_t *acache, dns_acacheentry_t *entry) {
+ REQUIRE(DNS_ACACHE_VALID(acache));
+ REQUIRE(DNS_ACACHEENTRY_VALID(entry));
+
+ /*
+ * The caller must be holing the entry lock.
+ */
+
+ if (entry->foundname) {
+ dns_rdataset_t *rdataset, *rdataset_next;
+
+ for (rdataset = ISC_LIST_HEAD(entry->foundname->list);
+ rdataset != NULL;
+ rdataset = rdataset_next) {
+ rdataset_next = ISC_LIST_NEXT(rdataset, link);
+ ISC_LIST_UNLINK(entry->foundname->list,
+ rdataset, link);
+ dns_rdataset_disassociate(rdataset);
+ isc_mem_put(acache->mctx, rdataset, sizeof(*rdataset));
+ }
+ if (dns_name_dynamic(entry->foundname))
+ dns_name_free(entry->foundname, acache->mctx);
+ isc_mem_put(acache->mctx, entry->foundname,
+ sizeof(*entry->foundname));
+ entry->foundname = NULL;
+ }
+
+ if (entry->node != NULL) {
+ INSIST(entry->db != NULL);
+ dns_db_detachnode(entry->db, &entry->node);
+ }
+ if (entry->version != NULL) {
+ INSIST(entry->db != NULL);
+ dns_db_closeversion(entry->db, &entry->version, ISC_FALSE);
+ }
+ if (entry->db != NULL)
+ dns_db_detach(&entry->db);
+ if (entry->zone != NULL)
+ dns_zone_detach(&entry->zone);
+
+ if (entry->origdb != NULL)
+ dns_db_detach(&entry->origdb);
+}
+
+static isc_result_t
+acache_cleaner_init(dns_acache_t *acache, isc_timermgr_t *timermgr,
+ acache_cleaner_t *cleaner)
+{
+ int result;
+
+ ATRACE("acache cleaner init");
+
+ result = isc_mutex_init(&cleaner->lock);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+
+ cleaner->increment = DNS_ACACHE_CLEANERINCREMENT;
+ cleaner->state = cleaner_s_idle;
+ cleaner->acache = acache;
+ cleaner->overmem = ISC_FALSE;
+
+ cleaner->cleaning_timer = NULL;
+ cleaner->resched_event = NULL;
+ cleaner->overmem_event = NULL;
+ cleaner->current_entry = NULL;
+
+ if (timermgr != NULL) {
+ cleaner->acache->live_cleaners++;
+
+ result = isc_task_onshutdown(acache->task,
+ acache_cleaner_shutdown_action,
+ acache);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "acache cleaner: "
+ "isc_task_onshutdown() failed: %s",
+ dns_result_totext(result));
+ goto cleanup;
+ }
+
+ cleaner->cleaning_interval = 0; /* Initially turned off. */
+ isc_stdtime_get(&cleaner->last_cleanup_time);
+ result = isc_timer_create(timermgr, isc_timertype_inactive,
+ NULL, NULL,
+ acache->task,
+ acache_cleaning_timer_action,
+ cleaner, &cleaner->cleaning_timer);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_timer_create() failed: %s",
+ dns_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+
+ cleaner->resched_event =
+ isc_event_allocate(acache->mctx, cleaner,
+ DNS_EVENT_ACACHECLEAN,
+ acache_incremental_cleaning_action,
+ cleaner, sizeof(isc_event_t));
+ if (cleaner->resched_event == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ cleaner->overmem_event =
+ isc_event_allocate(acache->mctx, cleaner,
+ DNS_EVENT_ACACHEOVERMEM,
+ acache_overmem_cleaning_action,
+ cleaner, sizeof(isc_event_t));
+ if (cleaner->overmem_event == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ }
+
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (cleaner->overmem_event != NULL)
+ isc_event_free(&cleaner->overmem_event);
+ if (cleaner->resched_event != NULL)
+ isc_event_free(&cleaner->resched_event);
+ if (cleaner->cleaning_timer != NULL)
+ isc_timer_detach(&cleaner->cleaning_timer);
+ cleaner->acache->live_cleaners--;
+ DESTROYLOCK(&cleaner->lock);
+ fail:
+ return (result);
+}
+
+static void
+begin_cleaning(acache_cleaner_t *cleaner) {
+ dns_acacheentry_t *head;
+ dns_acache_t *acache = cleaner->acache;
+
+ /*
+ * This function does not have to lock the cleaner, since critical
+ * parameters (except current_entry, which is locked by acache lock,)
+ * are only used in a single task context.
+ */
+
+ REQUIRE(CLEANER_IDLE(cleaner));
+ INSIST(DNS_ACACHE_VALID(acache));
+ INSIST(cleaner->current_entry == NULL);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_ACACHE, ISC_LOG_DEBUG(1),
+ "begin acache cleaning, mem inuse %lu",
+ (unsigned long)isc_mem_inuse(cleaner->acache->mctx));
+
+ LOCK(&acache->lock);
+
+ head = ISC_LIST_HEAD(acache->entries);
+ if (head != NULL)
+ dns_acache_attachentry(head, &cleaner->current_entry);
+
+ UNLOCK(&acache->lock);
+
+ if (cleaner->current_entry != NULL) {
+ cleaner->ncleaned = 0;
+ cleaner->state = cleaner_s_busy;
+ isc_task_send(acache->task, &cleaner->resched_event);
+ }
+
+ return;
+}
+
+static void
+end_cleaning(acache_cleaner_t *cleaner, isc_event_t *event) {
+ dns_acache_t *acache = cleaner->acache;
+
+ REQUIRE(CLEANER_BUSY(cleaner));
+ REQUIRE(event != NULL);
+ REQUIRE(DNS_ACACHEENTRY_VALID(cleaner->current_entry));
+
+ /* No need to lock the cleaner (see begin_cleaning()). */
+
+ LOCK(&acache->lock);
+
+ /*
+ * Even if the cleaner has the last reference to the entry, which means
+ * the entry has been unused, it may still be linked if unlinking the
+ * entry has been delayed due to the reference.
+ */
+ if (isc_refcount_current(&cleaner->current_entry->references) == 1) {
+ INSIST(cleaner->current_entry->callback == NULL);
+
+ if (ISC_LINK_LINKED(cleaner->current_entry, link)) {
+ ISC_LIST_UNLINK(acache->entries,
+ cleaner->current_entry, link);
+ }
+ }
+ dns_acache_detachentry(&cleaner->current_entry);
+
+ if (cleaner->overmem)
+ acache->stats.overmem++;
+ acache->stats.cleaned += cleaner->ncleaned;
+ acache->stats.cleaner_runs++;
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
+ ISC_LOG_NOTICE,
+ "acache %p stats: hits=%d misses=%d queries=%d "
+ "adds=%d deleted=%d "
+ "cleaned=%d cleaner_runs=%d overmem=%d "
+ "overmem_nocreates=%d nomem=%d",
+ acache,
+ acache->stats.hits, acache->stats.misses,
+ acache->stats.queries,
+ acache->stats.adds, acache->stats.deleted,
+ acache->stats.cleaned, acache->stats.cleaner_runs,
+ acache->stats.overmem, acache->stats.overmem_nocreates,
+ acache->stats.nomem);
+ reset_stats(acache);
+
+ isc_stdtime_get(&cleaner->last_cleanup_time);
+
+ UNLOCK(&acache->lock);
+
+ dns_acache_setcleaninginterval(cleaner->acache,
+ cleaner->cleaning_interval);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
+ ISC_LOG_DEBUG(1), "end acache cleaning, "
+ "%lu entries cleaned, mem inuse %lu",
+ cleaner->ncleaned,
+ (unsigned long)isc_mem_inuse(cleaner->acache->mctx));
+
+ if (cleaner->overmem) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_ACACHE, ISC_LOG_NOTICE,
+ "acache is still in overmem state "
+ "after cleaning");
+ }
+
+ cleaner->ncleaned = 0;
+ cleaner->state = cleaner_s_idle;
+ cleaner->resched_event = event;
+}
+
+/*
+ * This is run once for every acache-cleaning-interval as defined
+ * in named.conf.
+ */
+static void
+acache_cleaning_timer_action(isc_task_t *task, isc_event_t *event) {
+ acache_cleaner_t *cleaner = event->ev_arg;
+
+ UNUSED(task);
+
+ INSIST(event->ev_type == ISC_TIMEREVENT_TICK);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
+ ISC_LOG_DEBUG(1), "acache cleaning timer fired, "
+ "cleaner state = %d", cleaner->state);
+
+ if (cleaner->state == cleaner_s_idle)
+ begin_cleaning(cleaner);
+
+ isc_event_free(&event);
+}
+
+/* The caller must hold entry lock. */
+static inline isc_boolean_t
+entry_stale(acache_cleaner_t *cleaner, dns_acacheentry_t *entry,
+ isc_stdtime32_t now32, unsigned int interval)
+{
+ /*
+ * If the callback has been canceled, we definitely do not need the
+ * entry.
+ */
+ if (entry->callback == NULL)
+ return (ISC_TRUE);
+
+ if (interval > cleaner->cleaning_interval)
+ interval = cleaner->cleaning_interval;
+
+ if (entry->lastused + interval < now32)
+ return (ISC_TRUE);
+
+ /*
+ * If the acache is in the overmem state, probabilistically decide if
+ * the entry should be purged, based on the time passed from its last
+ * use and the cleaning interval.
+ */
+ if (cleaner->overmem) {
+ unsigned int passed =
+ now32 - entry->lastused; /* <= interval */
+ isc_uint32_t val;
+
+ if (passed > interval / 2)
+ return (ISC_TRUE);
+ isc_random_get(&val);
+ if (passed > interval / 4)
+ return (ISC_TF(val % 4 == 0));
+ return (ISC_TF(val % 8 == 0));
+ }
+
+ return (ISC_FALSE);
+}
+
+/*
+ * Do incremental cleaning.
+ */
+static void
+acache_incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
+ acache_cleaner_t *cleaner = event->ev_arg;
+ dns_acache_t *acache = cleaner->acache;
+ dns_acacheentry_t *entry, *next = NULL;
+ int n_entries;
+ isc_stdtime32_t now32, last32;
+ isc_stdtime_t now;
+ unsigned int interval;
+
+ INSIST(DNS_ACACHE_VALID(acache));
+ INSIST(task == acache->task);
+ INSIST(event->ev_type == DNS_EVENT_ACACHECLEAN);
+
+ if (cleaner->state == cleaner_s_done) {
+ cleaner->state = cleaner_s_busy;
+ end_cleaning(cleaner, event);
+ return;
+ }
+
+ INSIST(CLEANER_BUSY(cleaner));
+
+ n_entries = cleaner->increment;
+
+ isc_stdtime_get(&now);
+ isc_stdtime_convert32(now, &now32);
+
+ LOCK(&acache->lock);
+
+ entry = cleaner->current_entry;
+ isc_stdtime_convert32(cleaner->last_cleanup_time, &last32);
+ INSIST(now32 > last32);
+ interval = now32 - last32;
+
+ while (n_entries-- > 0) {
+ isc_boolean_t is_stale = ISC_FALSE;
+
+ INSIST(entry != NULL);
+
+ next = ISC_LIST_NEXT(entry, link);
+
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
+
+ is_stale = entry_stale(cleaner, entry, now32, interval);
+ if (is_stale) {
+ ISC_LIST_UNLINK(acache->entries, entry, link);
+ unlink_dbentries(acache, entry);
+ if (entry->callback != NULL)
+ (entry->callback)(entry, &entry->cbarg);
+ entry->callback = NULL;
+
+ cleaner->ncleaned++;
+ }
+
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
+
+ if (is_stale)
+ dns_acache_detachentry(&entry);
+
+ if (next == NULL) {
+ if (cleaner->overmem) {
+ entry = ISC_LIST_HEAD(acache->entries);
+ if (entry != NULL) {
+ /*
+ * If we are still in the overmem
+ * state, keep cleaning.
+ */
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_ACACHE,
+ ISC_LOG_DEBUG(1),
+ "acache cleaner: "
+ "still overmem, "
+ "reset and try again");
+ continue;
+ }
+ }
+
+ UNLOCK(&acache->lock);
+ end_cleaning(cleaner, event);
+ return;
+ }
+
+ entry = next;
+ }
+
+ /*
+ * We have successfully performed a cleaning increment but have
+ * not gone through the entire cache. Remember the entry that will
+ * be the starting point in the next clean-up, and reschedule another
+ * batch. If it fails, just try to continue anyway.
+ */
+ INSIST(next != NULL && next != cleaner->current_entry);
+ dns_acache_detachentry(&cleaner->current_entry);
+ dns_acache_attachentry(next, &cleaner->current_entry);
+
+ UNLOCK(&acache->lock);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
+ ISC_LOG_DEBUG(1), "acache cleaner: checked %d entries, "
+ "mem inuse %lu, sleeping", cleaner->increment,
+ (unsigned long)isc_mem_inuse(cleaner->acache->mctx));
+
+ isc_task_send(task, &event);
+ INSIST(CLEANER_BUSY(cleaner));
+
+ return;
+}
+
+/*
+ * This is called when the acache either surpasses its upper limit
+ * or shrinks beyond its lower limit.
+ */
+static void
+acache_overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
+ acache_cleaner_t *cleaner = event->ev_arg;
+ isc_boolean_t want_cleaning = ISC_FALSE;
+
+ UNUSED(task);
+
+ INSIST(event->ev_type == DNS_EVENT_ACACHEOVERMEM);
+ INSIST(cleaner->overmem_event == NULL);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
+ ISC_LOG_DEBUG(1), "overmem_cleaning_action called, "
+ "overmem = %d, state = %d", cleaner->overmem,
+ cleaner->state);
+
+ LOCK(&cleaner->lock);
+
+ if (cleaner->overmem) {
+ if (cleaner->state == cleaner_s_idle)
+ want_cleaning = ISC_TRUE;
+ } else {
+ if (cleaner->state == cleaner_s_busy)
+ /*
+ * end_cleaning() can't be called here because
+ * then both cleaner->overmem_event and
+ * cleaner->resched_event will point to this
+ * event. Set the state to done, and then
+ * when the acache_incremental_cleaning_action() event
+ * is posted, it will handle the end_cleaning.
+ */
+ cleaner->state = cleaner_s_done;
+ }
+
+ cleaner->overmem_event = event;
+
+ UNLOCK(&cleaner->lock);
+
+ if (want_cleaning)
+ begin_cleaning(cleaner);
+}
+
+static void
+water(void *arg, int mark) {
+ dns_acache_t *acache = arg;
+ isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
+
+ REQUIRE(DNS_ACACHE_VALID(acache));
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_ACACHE, ISC_LOG_DEBUG(1),
+ "acache memory reaches %s watermark, mem inuse %lu",
+ overmem ? "high" : "low",
+ (unsigned long)isc_mem_inuse(acache->mctx));
+
+ LOCK(&acache->cleaner.lock);
+
+ acache->cleaner.overmem = overmem;
+
+ if (acache->cleaner.overmem_event != NULL)
+ isc_task_send(acache->task, &acache->cleaner.overmem_event);
+
+ UNLOCK(&acache->cleaner.lock);
+}
+
+/*
+ * The cleaner task is shutting down; do the necessary cleanup.
+ */
+static void
+acache_cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
+ dns_acache_t *acache = event->ev_arg;
+ isc_boolean_t should_free = ISC_FALSE;
+
+ INSIST(task == acache->task);
+ INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
+ INSIST(DNS_ACACHE_VALID(acache));
+
+ ATRACE("acache cleaner shutdown");
+
+ if (CLEANER_BUSY(&acache->cleaner))
+ end_cleaning(&acache->cleaner, event);
+ else
+ isc_event_free(&event);
+
+ LOCK(&acache->lock);
+
+ acache->live_cleaners--;
+ INSIST(acache->live_cleaners == 0);
+
+ if (isc_refcount_current(&acache->refs) == 0) {
+ INSIST(check_noentry(acache) == ISC_TRUE);
+ should_free = ISC_TRUE;
+ }
+
+ /*
+ * By detaching the timer in the context of its task,
+ * we are guaranteed that there will be no further timer
+ * events.
+ */
+ if (acache->cleaner.cleaning_timer != NULL)
+ isc_timer_detach(&acache->cleaner.cleaning_timer);
+
+ /* Make sure we don't reschedule anymore. */
+ (void)isc_task_purge(task, NULL, DNS_EVENT_ACACHECLEAN, NULL);
+
+ UNLOCK(&acache->lock);
+
+ if (should_free)
+ destroy(acache);
+}
+
+/*
+ * Public functions.
+ */
+
+isc_result_t
+dns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx,
+ isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr)
+{
+ int i;
+ isc_result_t result;
+ dns_acache_t *acache;
+
+ REQUIRE(acachep != NULL && *acachep == NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(taskmgr != NULL);
+
+ acache = isc_mem_get(mctx, sizeof(*acache));
+ if (acache == NULL)
+ return (ISC_R_NOMEMORY);
+
+ ATRACE("create");
+
+ result = isc_refcount_init(&acache->refs, 1);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, acache, sizeof(*acache));
+ return (result);
+ }
+
+ result = isc_mutex_init(&acache->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_refcount_decrement(&acache->refs, NULL);
+ isc_refcount_destroy(&acache->refs);
+ isc_mem_put(mctx, acache, sizeof(*acache));
+ return (result);
+ }
+
+ acache->mctx = NULL;
+ isc_mem_attach(mctx, &acache->mctx);
+ ISC_LIST_INIT(acache->entries);
+
+ acache->shutting_down = ISC_FALSE;
+
+ acache->task = NULL;
+ acache->entrylocks = NULL;
+
+ result = isc_task_create(taskmgr, 1, &acache->task);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_task_create() failed(): %s",
+ dns_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+ isc_task_setname(acache->task, "acachetask", acache);
+ ISC_EVENT_INIT(&acache->cevent, sizeof(acache->cevent), 0, NULL,
+ DNS_EVENT_ACACHECONTROL, shutdown_task, NULL,
+ NULL, NULL, NULL);
+ acache->cevent_sent = ISC_FALSE;
+
+ acache->dbentries = 0;
+ for (i = 0; i < DBBUCKETS; i++)
+ ISC_LIST_INIT(acache->dbbucket[i]);
+
+ acache->entrylocks = isc_mem_get(mctx, sizeof(*acache->entrylocks) *
+ DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+ if (acache->entrylocks == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++) {
+ result = ACACHE_INITLOCK(&acache->entrylocks[i]);
+ if (result != ISC_R_SUCCESS) {
+ while (i-- > 0)
+ ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
+ isc_mem_put(mctx, acache->entrylocks,
+ sizeof(*acache->entrylocks) *
+ DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+ acache->entrylocks = NULL;
+ goto cleanup;
+ }
+ }
+
+ acache->live_cleaners = 0;
+ result = acache_cleaner_init(acache, timermgr, &acache->cleaner);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ acache->stats.cleaner_runs = 0;
+ reset_stats(acache);
+
+ acache->magic = ACACHE_MAGIC;
+
+ *acachep = acache;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (acache->task != NULL)
+ isc_task_detach(&acache->task);
+ DESTROYLOCK(&acache->lock);
+ isc_refcount_decrement(&acache->refs, NULL);
+ isc_refcount_destroy(&acache->refs);
+ if (acache->entrylocks != NULL) {
+ for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++)
+ ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
+ isc_mem_put(mctx, acache->entrylocks,
+ sizeof(*acache->entrylocks) *
+ DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+ }
+ isc_mem_put(mctx, acache, sizeof(*acache));
+ isc_mem_detach(&mctx);
+
+ return (result);
+}
+
+void
+dns_acache_attach(dns_acache_t *source, dns_acache_t **targetp) {
+ REQUIRE(DNS_ACACHE_VALID(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ AATRACE(source, "attach");
+
+ isc_refcount_increment(&source->refs, NULL);
+
+ *targetp = source;
+}
+
+void
+dns_acache_countquerymiss(dns_acache_t *acache) {
+ acache->stats.misses++; /* XXXSK danger: unlocked! */
+ acache->stats.queries++; /* XXXSK danger: unlocked! */
+}
+
+void
+dns_acache_detach(dns_acache_t **acachep) {
+ dns_acache_t *acache;
+ unsigned int refs;
+ isc_boolean_t should_free = ISC_FALSE;
+
+ REQUIRE(acachep != NULL && DNS_ACACHE_VALID(*acachep));
+ acache = *acachep;
+
+ ATRACE("detach");
+
+ isc_refcount_decrement(&acache->refs, &refs);
+ if (refs == 0) {
+ INSIST(check_noentry(acache) == ISC_TRUE);
+ should_free = ISC_TRUE;
+ }
+
+ *acachep = NULL;
+
+ /*
+ * If we're exiting and the cleaner task exists, let it free the cache.
+ */
+ if (should_free && acache->live_cleaners > 0) {
+ isc_task_shutdown(acache->task);
+ should_free = ISC_FALSE;
+ }
+
+ if (should_free)
+ destroy(acache);
+}
+
+void
+dns_acache_shutdown(dns_acache_t *acache) {
+ REQUIRE(DNS_ACACHE_VALID(acache));
+
+ LOCK(&acache->lock);
+
+ ATRACE("shutdown");
+
+ if (!acache->shutting_down) {
+ isc_event_t *event;
+ dns_acache_t *acache_evarg = NULL;
+
+ INSIST(!acache->cevent_sent);
+
+ acache->shutting_down = ISC_TRUE;
+
+ isc_mem_setwater(acache->mctx, NULL, NULL, 0, 0);
+
+ /*
+ * Self attach the object in order to prevent it from being
+ * destroyed while waiting for the event.
+ */
+ dns_acache_attach(acache, &acache_evarg);
+ event = &acache->cevent;
+ event->ev_arg = acache_evarg;
+ isc_task_send(acache->task, &event);
+ acache->cevent_sent = ISC_TRUE;
+ }
+
+ UNLOCK(&acache->lock);
+}
+
+isc_result_t
+dns_acache_setdb(dns_acache_t *acache, dns_db_t *db) {
+ int bucket;
+ dbentry_t *dbentry;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(DNS_ACACHE_VALID(acache));
+ REQUIRE(db != NULL);
+
+ ATRACE("setdb");
+
+ LOCK(&acache->lock);
+
+ dbentry = NULL;
+ result = finddbent(acache, db, &dbentry);
+ if (result == ISC_R_SUCCESS) {
+ result = ISC_R_EXISTS;
+ goto end;
+ }
+ result = ISC_R_SUCCESS;
+
+ dbentry = isc_mem_get(acache->mctx, sizeof(*dbentry));
+ if (dbentry == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto end;
+ }
+
+ ISC_LINK_INIT(dbentry, link);
+ ISC_LIST_INIT(dbentry->originlist);
+ ISC_LIST_INIT(dbentry->referlist);
+
+ dbentry->db = NULL;
+ dns_db_attach(db, &dbentry->db);
+
+ bucket = isc_hash_calc((const unsigned char *)&db,
+ sizeof(db), ISC_TRUE) % DBBUCKETS;
+
+ ISC_LIST_APPEND(acache->dbbucket[bucket], dbentry, link);
+
+ acache->dbentries++;
+
+ end:
+ UNLOCK(&acache->lock);
+
+ return (result);
+}
+
+isc_result_t
+dns_acache_putdb(dns_acache_t *acache, dns_db_t *db) {
+ int bucket;
+ isc_result_t result;
+ dbentry_t *dbentry;
+ dns_acacheentry_t *entry;
+
+ REQUIRE(DNS_ACACHE_VALID(acache));
+ REQUIRE(db != NULL);
+
+ ATRACE("putdb");
+
+ LOCK(&acache->lock);
+
+ dbentry = NULL;
+ result = finddbent(acache, db, &dbentry);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * The entry may have not been created due to memory shortage.
+ */
+ UNLOCK(&acache->lock);
+ return (ISC_R_NOTFOUND);
+ }
+
+ /*
+ * Release corresponding cache entries: for each entry, release all
+ * links the entry has, and then callback to the entry holder (if any).
+ * If no other external references exist (this can happen if the
+ * original holder has canceled callback,) destroy it here.
+ */
+ while ((entry = ISC_LIST_HEAD(dbentry->originlist)) != NULL) {
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
+
+ /*
+ * Releasing olink first would avoid finddbent() in
+ * unlink_dbentries().
+ */
+ ISC_LIST_UNLINK(dbentry->originlist, entry, olink);
+ if (acache->cleaner.current_entry != entry)
+ ISC_LIST_UNLINK(acache->entries, entry, link);
+ unlink_dbentries(acache, entry);
+
+ if (entry->callback != NULL)
+ (entry->callback)(entry, &entry->cbarg);
+ entry->callback = NULL;
+
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
+
+ if (acache->cleaner.current_entry != entry)
+ dns_acache_detachentry(&entry);
+ }
+ while ((entry = ISC_LIST_HEAD(dbentry->referlist)) != NULL) {
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
+
+ ISC_LIST_UNLINK(dbentry->referlist, entry, rlink);
+ if (acache->cleaner.current_entry != entry)
+ ISC_LIST_UNLINK(acache->entries, entry, link);
+ unlink_dbentries(acache, entry);
+
+ if (entry->callback != NULL)
+ (entry->callback)(entry, &entry->cbarg);
+ entry->callback = NULL;
+
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
+
+ if (acache->cleaner.current_entry != entry)
+ dns_acache_detachentry(&entry);
+ }
+
+ INSIST(ISC_LIST_EMPTY(dbentry->originlist) &&
+ ISC_LIST_EMPTY(dbentry->referlist));
+
+ bucket = isc_hash_calc((const unsigned char *)&db,
+ sizeof(db), ISC_TRUE) % DBBUCKETS;
+ ISC_LIST_UNLINK(acache->dbbucket[bucket], dbentry, link);
+ dns_db_detach(&dbentry->db);
+
+ isc_mem_put(acache->mctx, dbentry, sizeof(*dbentry));
+
+ acache->dbentries--;
+
+ acache->stats.deleted++;
+
+ UNLOCK(&acache->lock);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb,
+ void (*callback)(dns_acacheentry_t *, void **),
+ void *cbarg, dns_acacheentry_t **entryp)
+{
+ dns_acacheentry_t *newentry;
+ isc_result_t result;
+ isc_uint32_t r;
+
+ REQUIRE(DNS_ACACHE_VALID(acache));
+ REQUIRE(entryp != NULL && *entryp == NULL);
+ REQUIRE(origdb != NULL);
+
+ /*
+ * Should we exceed our memory limit for some reason (for
+ * example, if the cleaner does not run aggressively enough),
+ * then we will not create additional entries.
+ *
+ * XXXSK: It might be better to lock the acache->cleaner->lock,
+ * but locking may be an expensive bottleneck. If we misread
+ * the value, we will occasionally refuse to create a few
+ * cache entries, or create a few that we should not. I do not
+ * expect this to happen often, and it will not have very bad
+ * effects when it does. So no lock for now.
+ */
+ if (acache->cleaner.overmem) {
+ acache->stats.overmem_nocreates++; /* XXXSK danger: unlocked! */
+ return (ISC_R_NORESOURCES);
+ }
+
+ newentry = isc_mem_get(acache->mctx, sizeof(*newentry));
+ if (newentry == NULL) {
+ acache->stats.nomem++; /* XXXMLG danger: unlocked! */
+ return (ISC_R_NOMEMORY);
+ }
+
+ isc_random_get(&r);
+ newentry->locknum = r % DEFAULT_ACACHE_ENTRY_LOCK_COUNT;
+
+ result = isc_refcount_init(&newentry->references, 1);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(acache->mctx, newentry, sizeof(*newentry));
+ return (result);
+ };
+
+ ISC_LINK_INIT(newentry, link);
+ ISC_LINK_INIT(newentry, olink);
+ ISC_LINK_INIT(newentry, rlink);
+
+ newentry->acache = NULL;
+ dns_acache_attach(acache, &newentry->acache);
+
+ newentry->zone = NULL;
+ newentry->db = NULL;
+ newentry->version = NULL;
+ newentry->node = NULL;
+ newentry->foundname = NULL;
+
+ newentry->callback = callback;
+ newentry->cbarg = cbarg;
+ newentry->origdb = NULL;
+ dns_db_attach(origdb, &newentry->origdb);
+
+ isc_stdtime_get(&newentry->lastused);
+
+ newentry->magic = ACACHEENTRY_MAGIC;
+
+ *entryp = newentry;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep,
+ dns_db_t **dbp, dns_dbversion_t **versionp,
+ dns_dbnode_t **nodep, dns_name_t *fname,
+ dns_message_t *msg, isc_stdtime_t now)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_rdataset_t *erdataset;
+ isc_stdtime32_t now32;
+ dns_acache_t *acache;
+ int locknum;
+
+ REQUIRE(DNS_ACACHEENTRY_VALID(entry));
+ REQUIRE(zonep == NULL || *zonep == NULL);
+ REQUIRE(dbp != NULL && *dbp == NULL);
+ REQUIRE(versionp != NULL && *versionp == NULL);
+ REQUIRE(nodep != NULL && *nodep == NULL);
+ REQUIRE(fname != NULL);
+ REQUIRE(msg != NULL);
+ acache = entry->acache;
+ REQUIRE(DNS_ACACHE_VALID(acache));
+
+ locknum = entry->locknum;
+ ACACHE_LOCK(&acache->entrylocks[locknum], isc_rwlocktype_read);
+
+ isc_stdtime_convert32(now, &now32);
+ acache_storetime(entry, now32);
+
+ if (entry->zone != NULL && zonep != NULL)
+ dns_zone_attach(entry->zone, zonep);
+
+ if (entry->db == NULL) {
+ *dbp = NULL;
+ *versionp = NULL;
+ } else {
+ dns_db_attach(entry->db, dbp);
+ dns_db_attachversion(entry->db, entry->version, versionp);
+ }
+ if (entry->node == NULL)
+ *nodep = NULL;
+ else {
+ dns_db_attachnode(entry->db, entry->node, nodep);
+
+ INSIST(entry->foundname != NULL);
+ dns_name_copy(entry->foundname, fname, NULL);
+ for (erdataset = ISC_LIST_HEAD(entry->foundname->list);
+ erdataset != NULL;
+ erdataset = ISC_LIST_NEXT(erdataset, link)) {
+ dns_rdataset_t *ardataset;
+
+ ardataset = NULL;
+ result = dns_message_gettemprdataset(msg, &ardataset);
+ if (result != ISC_R_SUCCESS) {
+ ACACHE_UNLOCK(&acache->entrylocks[locknum],
+ isc_rwlocktype_read);
+ goto fail;
+ }
+
+ /*
+ * XXXJT: if we simply clone the rdataset, we'll get
+ * lost wrt cyclic ordering. We'll need an additional
+ * trick to get the latest counter from the original
+ * header.
+ */
+ dns_rdataset_init(ardataset);
+ dns_rdataset_clone(erdataset, ardataset);
+ ISC_LIST_APPEND(fname->list, ardataset, link);
+ }
+ }
+
+ entry->acache->stats.hits++; /* XXXMLG danger: unlocked! */
+ entry->acache->stats.queries++;
+
+ ACACHE_UNLOCK(&acache->entrylocks[locknum], isc_rwlocktype_read);
+
+ return (result);
+
+ fail:
+ while ((erdataset = ISC_LIST_HEAD(fname->list)) != NULL) {
+ ISC_LIST_UNLINK(fname->list, erdataset, link);
+ dns_rdataset_disassociate(erdataset);
+ dns_message_puttemprdataset(msg, &erdataset);
+ }
+ if (*nodep != NULL)
+ dns_db_detachnode(*dbp, nodep);
+ if (*versionp != NULL)
+ dns_db_closeversion(*dbp, versionp, ISC_FALSE);
+ if (*dbp != NULL)
+ dns_db_detach(dbp);
+ if (zonep != NULL && *zonep != NULL)
+ dns_zone_detach(zonep);
+
+ return (result);
+}
+
+isc_result_t
+dns_acache_setentry(dns_acache_t *acache, dns_acacheentry_t *entry,
+ dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
+ dns_dbnode_t *node, dns_name_t *fname)
+{
+ isc_result_t result;
+ dbentry_t *odbent;
+ dbentry_t *rdbent = NULL;
+ isc_boolean_t close_version = ISC_FALSE;
+ dns_acacheentry_t *dummy_entry = NULL;
+
+ REQUIRE(DNS_ACACHE_VALID(acache));
+ REQUIRE(DNS_ACACHEENTRY_VALID(entry));
+
+ LOCK(&acache->lock); /* XXX: need to lock it here for ordering */
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write);
+
+ /* Set zone */
+ if (zone != NULL)
+ dns_zone_attach(zone, &entry->zone);
+ /* Set DB */
+ if (db != NULL)
+ dns_db_attach(db, &entry->db);
+ /*
+ * Set DB version. If the version is not given by the caller,
+ * which is the case for glue or cache DBs, use the current version.
+ */
+ if (version == NULL) {
+ if (db != NULL) {
+ dns_db_currentversion(db, &version);
+ close_version = ISC_TRUE;
+ }
+ }
+ if (version != NULL) {
+ INSIST(db != NULL);
+ dns_db_attachversion(db, version, &entry->version);
+ }
+ if (close_version)
+ dns_db_closeversion(db, &version, ISC_FALSE);
+ /* Set DB node. */
+ if (node != NULL) {
+ INSIST(db != NULL);
+ dns_db_attachnode(db, node, &entry->node);
+ }
+
+ /*
+ * Set list of the corresponding rdatasets, if given.
+ * To minimize the overhead and memory consumption, we'll do this for
+ * positive cache only, in which case the DB node is non NULL.
+ * We do not want to cache incomplete information, so give up the
+ * entire entry when a memory shortage happen during the process.
+ */
+ if (node != NULL) {
+ dns_rdataset_t *ardataset, *crdataset;
+
+ entry->foundname = isc_mem_get(acache->mctx,
+ sizeof(*entry->foundname));
+
+ if (entry->foundname == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto fail;
+ }
+ dns_name_init(entry->foundname, NULL);
+ result = dns_name_dup(fname, acache->mctx,
+ entry->foundname);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+
+ for (ardataset = ISC_LIST_HEAD(fname->list);
+ ardataset != NULL;
+ ardataset = ISC_LIST_NEXT(ardataset, link)) {
+ crdataset = isc_mem_get(acache->mctx,
+ sizeof(*crdataset));
+ if (crdataset == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto fail;
+ }
+
+ dns_rdataset_init(crdataset);
+ dns_rdataset_clone(ardataset, crdataset);
+ ISC_LIST_APPEND(entry->foundname->list, crdataset,
+ link);
+ }
+ }
+
+ odbent = NULL;
+ result = finddbent(acache, entry->origdb, &odbent);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+ if (db != NULL) {
+ rdbent = NULL;
+ result = finddbent(acache, db, &rdbent);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+ }
+
+ ISC_LIST_APPEND(acache->entries, entry, link);
+ ISC_LIST_APPEND(odbent->originlist, entry, olink);
+ if (rdbent != NULL)
+ ISC_LIST_APPEND(rdbent->referlist, entry, rlink);
+
+ /*
+ * The additional cache needs an implicit reference to entries in its
+ * link.
+ */
+ dns_acache_attachentry(entry, &dummy_entry);
+
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
+
+ acache->stats.adds++;
+ UNLOCK(&acache->lock);
+
+ return (ISC_R_SUCCESS);
+
+ fail:
+ clear_entry(acache, entry);
+
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
+ UNLOCK(&acache->lock);
+
+ return (result);
+}
+
+void
+dns_acache_cancelentry(dns_acacheentry_t *entry) {
+ dns_acache_t *acache = entry->acache;
+
+ REQUIRE(DNS_ACACHEENTRY_VALID(entry));
+ INSIST(DNS_ACACHE_VALID(acache));
+
+ LOCK(&acache->lock);
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write);
+
+ /*
+ * Release dependencies stored in this entry as much as possible.
+ * The main link cannot be released, since the acache object has
+ * a reference to this entry; the empty entry will be released in
+ * the next cleaning action.
+ */
+ unlink_dbentries(acache, entry);
+ clear_entry(entry->acache, entry);
+
+ entry->callback = NULL;
+ entry->cbarg = NULL;
+
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
+ UNLOCK(&acache->lock);
+}
+
+void
+dns_acache_attachentry(dns_acacheentry_t *source,
+ dns_acacheentry_t **targetp)
+{
+ REQUIRE(DNS_ACACHEENTRY_VALID(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ isc_refcount_increment(&source->references, NULL);
+
+ *targetp = source;
+}
+
+void
+dns_acache_detachentry(dns_acacheentry_t **entryp) {
+ dns_acacheentry_t *entry;
+ unsigned int refs;
+
+ REQUIRE(entryp != NULL && DNS_ACACHEENTRY_VALID(*entryp));
+ entry = *entryp;
+
+ isc_refcount_decrement(&entry->references, &refs);
+
+ /*
+ * If there are no references to the entry, the entry must have been
+ * unlinked and can be destroyed safely.
+ */
+ if (refs == 0) {
+ INSIST(!ISC_LINK_LINKED(entry, link));
+ (*entryp)->acache->stats.deleted++;
+ destroy_entry(entry);
+ }
+
+ *entryp = NULL;
+}
+
+void
+dns_acache_setcleaninginterval(dns_acache_t *acache, unsigned int t) {
+ isc_interval_t interval;
+ isc_result_t result;
+
+ REQUIRE(DNS_ACACHE_VALID(acache));
+
+ ATRACE("dns_acache_setcleaninginterval");
+
+ LOCK(&acache->lock);
+
+ /*
+ * It may be the case that the acache has already shut down.
+ * If so, it has no timer. (Not sure if this can really happen.)
+ */
+ if (acache->cleaner.cleaning_timer == NULL)
+ goto unlock;
+
+ acache->cleaner.cleaning_interval = t;
+
+ if (t == 0) {
+ result = isc_timer_reset(acache->cleaner.cleaning_timer,
+ isc_timertype_inactive,
+ NULL, NULL, ISC_TRUE);
+ } else {
+ isc_interval_set(&interval, acache->cleaner.cleaning_interval,
+ 0);
+ result = isc_timer_reset(acache->cleaner.cleaning_timer,
+ isc_timertype_ticker,
+ NULL, &interval, ISC_FALSE);
+ }
+ if (result != ISC_R_SUCCESS)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_ACACHE, ISC_LOG_WARNING,
+ "could not set acache cleaning interval: %s",
+ isc_result_totext(result));
+ else
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_ACACHE, ISC_LOG_NOTICE,
+ "acache %p cleaning interval set to %d.",
+ acache, t);
+
+ unlock:
+ UNLOCK(&acache->lock);
+}
+
+/*
+ * This function was derived from cache.c:dns_cache_setcachesize(). See the
+ * function for more details about the logic.
+ */
+void
+dns_acache_setcachesize(dns_acache_t *acache, isc_uint32_t size) {
+ isc_uint32_t lowater;
+ isc_uint32_t hiwater;
+
+ REQUIRE(DNS_ACACHE_VALID(acache));
+
+ if (size != 0 && size < DNS_ACACHE_MINSIZE)
+ size = DNS_ACACHE_MINSIZE;
+
+ hiwater = size - (size >> 3);
+ lowater = size - (size >> 2);
+
+ if (size == 0 || hiwater == 0 || lowater == 0)
+ isc_mem_setwater(acache->mctx, water, acache, 0, 0);
+ else
+ isc_mem_setwater(acache->mctx, water, acache,
+ hiwater, lowater);
+}
diff --git a/lib/dns/acl.c b/lib/dns/acl.c
new file mode 100644
index 0000000..844c132
--- /dev/null
+++ b/lib/dns/acl.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2004-2006 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: acl.c,v 1.25.18.5 2006/03/02 00:37:21 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/acl.h>
+
+isc_result_t
+dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) {
+ isc_result_t result;
+ dns_acl_t *acl;
+
+ /*
+ * Work around silly limitation of isc_mem_get().
+ */
+ if (n == 0)
+ n = 1;
+
+ acl = isc_mem_get(mctx, sizeof(*acl));
+ if (acl == NULL)
+ return (ISC_R_NOMEMORY);
+ acl->mctx = mctx;
+ acl->name = NULL;
+ result = isc_refcount_init(&acl->refcount, 1);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, acl, sizeof(*acl));
+ return (result);
+ }
+ acl->elements = NULL;
+ acl->alloc = 0;
+ acl->length = 0;
+
+ ISC_LINK_INIT(acl, nextincache);
+ /*
+ * Must set magic early because we use dns_acl_detach() to clean up.
+ */
+ acl->magic = DNS_ACL_MAGIC;
+
+ acl->elements = isc_mem_get(mctx, n * sizeof(dns_aclelement_t));
+ if (acl->elements == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ acl->alloc = n;
+ memset(acl->elements, 0, n * sizeof(dns_aclelement_t));
+ *target = acl;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ dns_acl_detach(&acl);
+ return (result);
+}
+
+isc_result_t
+dns_acl_appendelement(dns_acl_t *acl, const dns_aclelement_t *elt) {
+ if (acl->length + 1 > acl->alloc) {
+ /*
+ * Resize the ACL.
+ */
+ unsigned int newalloc;
+ void *newmem;
+
+ newalloc = acl->alloc * 2;
+ if (newalloc < 4)
+ newalloc = 4;
+ newmem = isc_mem_get(acl->mctx,
+ newalloc * sizeof(dns_aclelement_t));
+ if (newmem == NULL)
+ return (ISC_R_NOMEMORY);
+ memcpy(newmem, acl->elements,
+ acl->length * sizeof(dns_aclelement_t));
+ isc_mem_put(acl->mctx, acl->elements,
+ acl->alloc * sizeof(dns_aclelement_t));
+ acl->elements = newmem;
+ acl->alloc = newalloc;
+ }
+ /*
+ * Append the new element.
+ */
+ acl->elements[acl->length++] = *elt;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dns_acl_anyornone(isc_mem_t *mctx, isc_boolean_t neg, dns_acl_t **target) {
+ isc_result_t result;
+ dns_acl_t *acl = NULL;
+ result = dns_acl_create(mctx, 1, &acl);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ acl->elements[0].negative = neg;
+ acl->elements[0].type = dns_aclelementtype_any;
+ acl->length = 1;
+ *target = acl;
+ return (result);
+}
+
+isc_result_t
+dns_acl_any(isc_mem_t *mctx, dns_acl_t **target) {
+ return (dns_acl_anyornone(mctx, ISC_FALSE, target));
+}
+
+isc_result_t
+dns_acl_none(isc_mem_t *mctx, dns_acl_t **target) {
+ return (dns_acl_anyornone(mctx, ISC_TRUE, target));
+}
+
+isc_result_t
+dns_acl_match(const isc_netaddr_t *reqaddr,
+ const dns_name_t *reqsigner,
+ const dns_acl_t *acl,
+ const dns_aclenv_t *env,
+ int *match,
+ dns_aclelement_t const**matchelt)
+{
+ unsigned int i;
+
+ REQUIRE(reqaddr != NULL);
+ REQUIRE(matchelt == NULL || *matchelt == NULL);
+
+ for (i = 0; i < acl->length; i++) {
+ dns_aclelement_t *e = &acl->elements[i];
+
+ if (dns_aclelement_match(reqaddr, reqsigner,
+ e, env, matchelt)) {
+ *match = e->negative ? -((int)i+1) : ((int)i+1);
+ return (ISC_R_SUCCESS);
+ }
+ }
+ /* No match. */
+ *match = 0;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_acl_elementmatch(const dns_acl_t *acl,
+ const dns_aclelement_t *elt,
+ const dns_aclelement_t **matchelt)
+{
+ unsigned int i;
+
+ REQUIRE(elt != NULL);
+ REQUIRE(matchelt == NULL || *matchelt == NULL);
+
+ for (i = 0; i < acl->length; i++) {
+ dns_aclelement_t *e = &acl->elements[i];
+
+ if (dns_aclelement_equal(e, elt) == ISC_TRUE) {
+ if (matchelt != NULL)
+ *matchelt = e;
+ return (ISC_R_SUCCESS);
+ }
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+isc_boolean_t
+dns_aclelement_match(const isc_netaddr_t *reqaddr,
+ const dns_name_t *reqsigner,
+ const dns_aclelement_t *e,
+ const dns_aclenv_t *env,
+ const dns_aclelement_t **matchelt)
+{
+ dns_acl_t *inner = NULL;
+ const isc_netaddr_t *addr;
+ isc_netaddr_t v4addr;
+ int indirectmatch;
+ isc_result_t result;
+
+ switch (e->type) {
+ case dns_aclelementtype_ipprefix:
+ if (env == NULL ||
+ env->match_mapped == ISC_FALSE ||
+ reqaddr->family != AF_INET6 ||
+ !IN6_IS_ADDR_V4MAPPED(&reqaddr->type.in6))
+ addr = reqaddr;
+ else {
+ isc_netaddr_fromv4mapped(&v4addr, reqaddr);
+ addr = &v4addr;
+ }
+
+ if (isc_netaddr_eqprefix(addr,
+ &e->u.ip_prefix.address,
+ e->u.ip_prefix.prefixlen))
+ goto matched;
+ break;
+
+ case dns_aclelementtype_keyname:
+ if (reqsigner != NULL &&
+ dns_name_equal(reqsigner, &e->u.keyname))
+ goto matched;
+ break;
+
+ case dns_aclelementtype_nestedacl:
+ inner = e->u.nestedacl;
+ nested:
+ result = dns_acl_match(reqaddr, reqsigner,
+ inner,
+ env,
+ &indirectmatch, matchelt);
+ INSIST(result == ISC_R_SUCCESS);
+
+ /*
+ * Treat negative matches in indirect ACLs as
+ * "no match".
+ * That way, a negated indirect ACL will never become
+ * a surprise positive match through double negation.
+ * XXXDCL this should be documented.
+ */
+ if (indirectmatch > 0)
+ goto matchelt_set;
+
+ /*
+ * A negative indirect match may have set *matchelt,
+ * but we don't want it set when we return.
+ */
+ if (matchelt != NULL)
+ *matchelt = NULL;
+ break;
+
+ case dns_aclelementtype_any:
+ matched:
+ if (matchelt != NULL)
+ *matchelt = e;
+ matchelt_set:
+ return (ISC_TRUE);
+
+ case dns_aclelementtype_localhost:
+ if (env != NULL && env->localhost != NULL) {
+ inner = env->localhost;
+ goto nested;
+ } else {
+ break;
+ }
+
+ case dns_aclelementtype_localnets:
+ if (env != NULL && env->localnets != NULL) {
+ inner = env->localnets;
+ goto nested;
+ } else {
+ break;
+ }
+
+ default:
+ INSIST(0);
+ break;
+ }
+
+ return (ISC_FALSE);
+}
+
+void
+dns_acl_attach(dns_acl_t *source, dns_acl_t **target) {
+ REQUIRE(DNS_ACL_VALID(source));
+ isc_refcount_increment(&source->refcount, NULL);
+ *target = source;
+}
+
+static void
+destroy(dns_acl_t *dacl) {
+ unsigned int i;
+ for (i = 0; i < dacl->length; i++) {
+ dns_aclelement_t *de = &dacl->elements[i];
+ switch (de->type) {
+ case dns_aclelementtype_keyname:
+ dns_name_free(&de->u.keyname, dacl->mctx);
+ break;
+ case dns_aclelementtype_nestedacl:
+ dns_acl_detach(&de->u.nestedacl);
+ break;
+ default:
+ break;
+ }
+ }
+ if (dacl->elements != NULL)
+ isc_mem_put(dacl->mctx, dacl->elements,
+ dacl->alloc * sizeof(dns_aclelement_t));
+ if (dacl->name != NULL)
+ isc_mem_free(dacl->mctx, dacl->name);
+ isc_refcount_destroy(&dacl->refcount);
+ dacl->magic = 0;
+ isc_mem_put(dacl->mctx, dacl, sizeof(*dacl));
+}
+
+void
+dns_acl_detach(dns_acl_t **aclp) {
+ dns_acl_t *acl = *aclp;
+ unsigned int refs;
+ REQUIRE(DNS_ACL_VALID(acl));
+ isc_refcount_decrement(&acl->refcount, &refs);
+ if (refs == 0)
+ destroy(acl);
+ *aclp = NULL;
+}
+
+isc_boolean_t
+dns_aclelement_equal(const dns_aclelement_t *ea, const dns_aclelement_t *eb) {
+ if (ea->type != eb->type)
+ return (ISC_FALSE);
+ switch (ea->type) {
+ case dns_aclelementtype_ipprefix:
+ if (ea->u.ip_prefix.prefixlen !=
+ eb->u.ip_prefix.prefixlen)
+ return (ISC_FALSE);
+ return (isc_netaddr_eqprefix(&ea->u.ip_prefix.address,
+ &eb->u.ip_prefix.address,
+ ea->u.ip_prefix.prefixlen));
+ case dns_aclelementtype_keyname:
+ return (dns_name_equal(&ea->u.keyname, &eb->u.keyname));
+ case dns_aclelementtype_nestedacl:
+ return (dns_acl_equal(ea->u.nestedacl, eb->u.nestedacl));
+ case dns_aclelementtype_localhost:
+ case dns_aclelementtype_localnets:
+ case dns_aclelementtype_any:
+ return (ISC_TRUE);
+ default:
+ INSIST(0);
+ return (ISC_FALSE);
+ }
+}
+
+isc_boolean_t
+dns_acl_equal(const dns_acl_t *a, const dns_acl_t *b) {
+ unsigned int i;
+ if (a == b)
+ return (ISC_TRUE);
+ if (a->length != b->length)
+ return (ISC_FALSE);
+ for (i = 0; i < a->length; i++) {
+ if (! dns_aclelement_equal(&a->elements[i],
+ &b->elements[i]))
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+static isc_boolean_t
+is_loopback(const dns_aclipprefix_t *p) {
+ switch (p->address.family) {
+ case AF_INET:
+ if (p->prefixlen == 32 &&
+ htonl(p->address.type.in.s_addr) == INADDR_LOOPBACK)
+ return (ISC_TRUE);
+ break;
+ case AF_INET6:
+ if (p->prefixlen == 128 &&
+ IN6_IS_ADDR_LOOPBACK(&p->address.type.in6))
+ return (ISC_TRUE);
+ break;
+ default:
+ break;
+ }
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_acl_isinsecure(const dns_acl_t *a) {
+ unsigned int i;
+ for (i = 0; i < a->length; i++) {
+ dns_aclelement_t *e = &a->elements[i];
+
+ /* A negated match can never be insecure. */
+ if (e->negative)
+ continue;
+
+ switch (e->type) {
+ case dns_aclelementtype_ipprefix:
+ /* The loopback address is considered secure. */
+ if (! is_loopback(&e->u.ip_prefix))
+ return (ISC_TRUE);
+ continue;
+
+ case dns_aclelementtype_keyname:
+ case dns_aclelementtype_localhost:
+ continue;
+
+ case dns_aclelementtype_nestedacl:
+ if (dns_acl_isinsecure(e->u.nestedacl))
+ return (ISC_TRUE);
+ continue;
+
+ case dns_aclelementtype_localnets:
+ case dns_aclelementtype_any:
+ return (ISC_TRUE);
+
+ default:
+ INSIST(0);
+ return (ISC_TRUE);
+ }
+ }
+ /* No insecure elements were found. */
+ return (ISC_FALSE);
+}
+
+isc_result_t
+dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env) {
+ isc_result_t result;
+ env->localhost = NULL;
+ env->localnets = NULL;
+ result = dns_acl_create(mctx, 0, &env->localhost);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_nothing;
+ result = dns_acl_create(mctx, 0, &env->localnets);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_localhost;
+ env->match_mapped = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+
+ cleanup_localhost:
+ dns_acl_detach(&env->localhost);
+ cleanup_nothing:
+ return (result);
+}
+
+void
+dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s) {
+ dns_acl_detach(&t->localhost);
+ dns_acl_attach(s->localhost, &t->localhost);
+ dns_acl_detach(&t->localnets);
+ dns_acl_attach(s->localnets, &t->localnets);
+ t->match_mapped = s->match_mapped;
+}
+
+void
+dns_aclenv_destroy(dns_aclenv_t *env) {
+ dns_acl_detach(&env->localhost);
+ dns_acl_detach(&env->localnets);
+}
diff --git a/lib/dns/adb.c b/lib/dns/adb.c
new file mode 100644
index 0000000..c65c474
--- /dev/null
+++ b/lib/dns/adb.c
@@ -0,0 +1,3610 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: adb.c,v 1.215.18.17 2007/09/11 02:23:26 marka Exp $ */
+
+/*! \file
+ *
+ * \note
+ * In finds, if task == NULL, no events will be generated, and no events
+ * have been sent. If task != NULL but taskaction == NULL, an event has been
+ * posted but not yet freed. If neither are NULL, no event was posted.
+ *
+ */
+
+/*%
+ * After we have cleaned all buckets, dump the database contents.
+ */
+#if 0
+#define DUMP_ADB_AFTER_CLEANING
+#endif
+
+#include <config.h>
+
+#include <limits.h>
+
+#include <isc/mutexblock.h>
+#include <isc/netaddr.h>
+#include <isc/random.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/adb.h>
+#include <dns/db.h>
+#include <dns/events.h>
+#include <dns/log.h>
+#include <dns/rdata.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/rdatatype.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+
+#define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b')
+#define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
+#define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N')
+#define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
+#define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H')
+#define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
+#define DNS_ADBLAMEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z')
+#define DNS_ADBLAMEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC)
+#define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E')
+#define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
+#define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4')
+#define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
+#define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6')
+#define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
+
+/*!
+ * The number of buckets needs to be a prime (for good hashing).
+ *
+ * XXXRTH How many buckets do we need?
+ */
+#define NBUCKETS 1009 /*%< how many buckets for names/addrs */
+
+/*!
+ * For type 3 negative cache entries, we will remember that the address is
+ * broken for this long. XXXMLG This is also used for actual addresses, too.
+ * The intent is to keep us from constantly asking about A/AAAA records
+ * if the zone has extremely low TTLs.
+ */
+#define ADB_CACHE_MINIMUM 10 /*%< seconds */
+#define ADB_CACHE_MAXIMUM 86400 /*%< seconds (86400 = 24 hours) */
+#define ADB_ENTRY_WINDOW 1800 /*%< seconds */
+
+/*%
+ * Wake up every CLEAN_SECONDS and clean CLEAN_BUCKETS buckets, so that all
+ * buckets are cleaned in CLEAN_PERIOD seconds.
+ */
+#define CLEAN_PERIOD 3600
+/*% See #CLEAN_PERIOD */
+#define CLEAN_SECONDS 30
+/*% See #CLEAN_PERIOD */
+#define CLEAN_BUCKETS ((NBUCKETS * CLEAN_SECONDS) / CLEAN_PERIOD)
+
+#define FREE_ITEMS 64 /*%< free count for memory pools */
+#define FILL_COUNT 16 /*%< fill count for memory pools */
+
+#define DNS_ADB_INVALIDBUCKET (-1) /*%< invalid bucket address */
+
+#define DNS_ADB_MINADBSIZE (1024*1024) /*%< 1 Megabyte */
+
+typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
+typedef struct dns_adbnamehook dns_adbnamehook_t;
+typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
+typedef struct dns_adblameinfo dns_adblameinfo_t;
+typedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
+typedef struct dns_adbfetch dns_adbfetch_t;
+typedef struct dns_adbfetch6 dns_adbfetch6_t;
+
+/*% dns adb structure */
+struct dns_adb {
+ unsigned int magic;
+
+ isc_mutex_t lock;
+ isc_mutex_t reflock; /*%< Covers irefcnt, erefcnt */
+ isc_mem_t *mctx;
+ dns_view_t *view;
+ isc_timermgr_t *timermgr;
+ isc_timer_t *timer;
+ isc_taskmgr_t *taskmgr;
+ isc_task_t *task;
+ isc_boolean_t overmem;
+
+ isc_interval_t tick_interval;
+ int next_cleanbucket;
+
+ unsigned int irefcnt;
+ unsigned int erefcnt;
+
+ isc_mutex_t mplock;
+ isc_mempool_t *nmp; /*%< dns_adbname_t */
+ isc_mempool_t *nhmp; /*%< dns_adbnamehook_t */
+ isc_mempool_t *limp; /*%< dns_adblameinfo_t */
+ isc_mempool_t *emp; /*%< dns_adbentry_t */
+ isc_mempool_t *ahmp; /*%< dns_adbfind_t */
+ isc_mempool_t *aimp; /*%< dns_adbaddrinfo_t */
+ isc_mempool_t *afmp; /*%< dns_adbfetch_t */
+
+ /*!
+ * Bucketized locks and lists for names.
+ *
+ * XXXRTH Have a per-bucket structure that contains all of these?
+ */
+ dns_adbnamelist_t names[NBUCKETS];
+ /*% See dns_adbnamelist_t */
+ isc_mutex_t namelocks[NBUCKETS];
+ /*% See dns_adbnamelist_t */
+ isc_boolean_t name_sd[NBUCKETS];
+ /*% See dns_adbnamelist_t */
+ unsigned int name_refcnt[NBUCKETS];
+
+ /*!
+ * Bucketized locks for entries.
+ *
+ * XXXRTH Have a per-bucket structure that contains all of these?
+ */
+ dns_adbentrylist_t entries[NBUCKETS];
+ isc_mutex_t entrylocks[NBUCKETS];
+ isc_boolean_t entry_sd[NBUCKETS]; /*%< shutting down */
+ unsigned int entry_refcnt[NBUCKETS];
+
+ isc_event_t cevent;
+ isc_boolean_t cevent_sent;
+ isc_boolean_t shutting_down;
+ isc_eventlist_t whenshutdown;
+};
+
+/*
+ * XXXMLG Document these structures.
+ */
+
+/*% dns_adbname structure */
+struct dns_adbname {
+ unsigned int magic;
+ dns_name_t name;
+ dns_adb_t *adb;
+ unsigned int partial_result;
+ unsigned int flags;
+ int lock_bucket;
+ dns_name_t target;
+ isc_stdtime_t expire_target;
+ isc_stdtime_t expire_v4;
+ isc_stdtime_t expire_v6;
+ unsigned int chains;
+ dns_adbnamehooklist_t v4;
+ dns_adbnamehooklist_t v6;
+ dns_adbfetch_t *fetch_a;
+ dns_adbfetch_t *fetch_aaaa;
+ unsigned int fetch_err;
+ unsigned int fetch6_err;
+ dns_adbfindlist_t finds;
+ ISC_LINK(dns_adbname_t) plink;
+};
+
+/*% The adbfetch structure */
+struct dns_adbfetch {
+ unsigned int magic;
+ dns_adbnamehook_t *namehook;
+ dns_adbentry_t *entry;
+ dns_fetch_t *fetch;
+ dns_rdataset_t rdataset;
+};
+
+/*%
+ * This is a small widget that dangles off a dns_adbname_t. It contains a
+ * pointer to the address information about this host, and a link to the next
+ * namehook that will contain the next address this host has.
+ */
+struct dns_adbnamehook {
+ unsigned int magic;
+ dns_adbentry_t *entry;
+ ISC_LINK(dns_adbnamehook_t) plink;
+};
+
+/*%
+ * This is a small widget that holds qname-specific information about an
+ * address. Currently limited to lameness, but could just as easily be
+ * extended to other types of information about zones.
+ */
+struct dns_adblameinfo {
+ unsigned int magic;
+
+ dns_name_t qname;
+ dns_rdatatype_t qtype;
+ isc_stdtime_t lame_timer;
+
+ ISC_LINK(dns_adblameinfo_t) plink;
+};
+
+/*%
+ * An address entry. It holds quite a bit of information about addresses,
+ * including edns state (in "flags"), rtt, and of course the address of
+ * the host.
+ */
+struct dns_adbentry {
+ unsigned int magic;
+
+ int lock_bucket;
+ unsigned int refcnt;
+
+ unsigned int flags;
+ unsigned int srtt;
+ isc_sockaddr_t sockaddr;
+
+ isc_stdtime_t expires;
+ /*%<
+ * A nonzero 'expires' field indicates that the entry should
+ * persist until that time. This allows entries found
+ * using dns_adb_findaddrinfo() to persist for a limited time
+ * even though they are not necessarily associated with a
+ * name.
+ */
+
+ ISC_LIST(dns_adblameinfo_t) lameinfo;
+ ISC_LINK(dns_adbentry_t) plink;
+};
+
+/*
+ * Internal functions (and prototypes).
+ */
+static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
+static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
+static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
+ dns_adbentry_t *);
+static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
+static inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *,
+ dns_rdatatype_t);
+static inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **);
+static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
+static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
+static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
+static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
+static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
+ in_port_t);
+static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
+static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
+static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
+ unsigned int, int *);
+static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
+ isc_sockaddr_t *, int *);
+static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t);
+static void print_dns_name(FILE *, dns_name_t *);
+static void print_namehook_list(FILE *, const char *legend,
+ dns_adbnamehooklist_t *list,
+ isc_boolean_t debug,
+ isc_stdtime_t now);
+static void print_find_list(FILE *, dns_adbname_t *);
+static void print_fetch_list(FILE *, dns_adbname_t *);
+static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
+static inline void inc_adb_irefcnt(dns_adb_t *);
+static inline void inc_adb_erefcnt(dns_adb_t *);
+static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
+ isc_boolean_t);
+static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
+ isc_boolean_t);
+static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
+static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
+static void clean_target(dns_adb_t *, dns_name_t *);
+static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
+ unsigned int);
+static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t,
+ isc_boolean_t);
+static void cancel_fetches_at_name(dns_adbname_t *);
+static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
+ dns_rdatatype_t);
+static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
+ dns_rdatatype_t);
+static inline void check_exit(dns_adb_t *);
+static void timer_cleanup(isc_task_t *, isc_event_t *);
+static void destroy(dns_adb_t *);
+static isc_boolean_t shutdown_names(dns_adb_t *);
+static isc_boolean_t shutdown_entries(dns_adb_t *);
+static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
+static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
+static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
+static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
+static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
+static void water(void *, int);
+static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t);
+
+/*
+ * MUST NOT overlap DNS_ADBFIND_* flags!
+ */
+#define FIND_EVENT_SENT 0x40000000
+#define FIND_EVENT_FREED 0x80000000
+#define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0)
+#define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0)
+
+#define NAME_NEEDS_POKE 0x80000000
+#define NAME_IS_DEAD 0x40000000
+#define NAME_HINT_OK DNS_ADBFIND_HINTOK
+#define NAME_GLUE_OK DNS_ADBFIND_GLUEOK
+#define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE
+#define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0)
+#define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0)
+#define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0)
+#define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0)
+
+/*
+ * To the name, address classes are all that really exist. If it has a
+ * V6 address it doesn't care if it came from a AAAA query.
+ */
+#define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4))
+#define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6))
+#define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n))
+
+/*
+ * Fetches are broken out into A and AAAA types. In some cases,
+ * however, it makes more sense to test for a particular class of fetches,
+ * like V4 or V6 above.
+ * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA
+ * are now equal to FETCH_V4 and FETCH_V6, respectively.
+ */
+#define NAME_FETCH_A(n) ((n)->fetch_a != NULL)
+#define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL)
+#define NAME_FETCH_V4(n) (NAME_FETCH_A(n))
+#define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n))
+#define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
+
+/*
+ * Find options and tests to see if there are addresses on the list.
+ */
+#define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
+#define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
+#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
+ != 0)
+#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \
+ != 0)
+#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
+#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
+#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list))
+#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
+
+/*
+ * These are currently used on simple unsigned ints, so they are
+ * not really associated with any particular type.
+ */
+#define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0)
+#define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0)
+
+#define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now))
+
+/*
+ * Find out if the flags on a name (nf) indicate if it is a hint or
+ * glue, and compare this to the appropriate bits set in o, to see if
+ * this is ok.
+ */
+#define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0))
+#define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0))
+#define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o))
+#define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
+ ((o) & DNS_ADBFIND_STARTATZONE))
+
+#define ENTER_LEVEL ISC_LOG_DEBUG(50)
+#define EXIT_LEVEL ENTER_LEVEL
+#define CLEAN_LEVEL ISC_LOG_DEBUG(100)
+#define DEF_LEVEL ISC_LOG_DEBUG(5)
+#define NCACHE_LEVEL ISC_LOG_DEBUG(20)
+
+#define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \
+ (r) == DNS_R_NCACHENXRRSET)
+#define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \
+ (r) == DNS_R_NXRRSET)
+#define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \
+ (r) == DNS_R_NCACHENXDOMAIN)
+#define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \
+ (r) == DNS_R_NXRRSET || \
+ (r) == DNS_R_HINTNXRRSET)
+
+/*
+ * Error state rankings.
+ */
+
+#define FIND_ERR_SUCCESS 0 /* highest rank */
+#define FIND_ERR_CANCELED 1
+#define FIND_ERR_FAILURE 2
+#define FIND_ERR_NXDOMAIN 3
+#define FIND_ERR_NXRRSET 4
+#define FIND_ERR_UNEXPECTED 5
+#define FIND_ERR_NOTFOUND 6
+#define FIND_ERR_MAX 7
+
+static const char *errnames[] = {
+ "success",
+ "canceled",
+ "failure",
+ "nxdomain",
+ "nxrrset",
+ "unexpected",
+ "not_found"
+};
+
+#define NEWERR(old, new) (ISC_MIN((old), (new)))
+
+static isc_result_t find_err_map[FIND_ERR_MAX] = {
+ ISC_R_SUCCESS,
+ ISC_R_CANCELED,
+ ISC_R_FAILURE,
+ DNS_R_NXDOMAIN,
+ DNS_R_NXRRSET,
+ ISC_R_UNEXPECTED,
+ ISC_R_NOTFOUND /* not YET found */
+};
+
+static void
+DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
+
+static void
+DP(int level, const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ isc_log_vwrite(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
+ level, format, args);
+ va_end(args);
+}
+
+static inline dns_ttl_t
+ttlclamp(dns_ttl_t ttl) {
+ if (ttl < ADB_CACHE_MINIMUM)
+ ttl = ADB_CACHE_MINIMUM;
+ if (ttl > ADB_CACHE_MAXIMUM)
+ ttl = ADB_CACHE_MAXIMUM;
+
+ return (ttl);
+}
+
+/*
+ * Requires the adbname bucket be locked and that no entry buckets be locked.
+ *
+ * This code handles A and AAAA rdatasets only.
+ */
+static isc_result_t
+import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
+ isc_stdtime_t now)
+{
+ isc_result_t result;
+ dns_adb_t *adb;
+ dns_adbnamehook_t *nh;
+ dns_adbnamehook_t *anh;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ struct in_addr ina;
+ struct in6_addr in6a;
+ isc_sockaddr_t sockaddr;
+ dns_adbentry_t *foundentry; /* NO CLEAN UP! */
+ int addr_bucket;
+ isc_boolean_t new_addresses_added;
+ dns_rdatatype_t rdtype;
+ unsigned int findoptions;
+
+ INSIST(DNS_ADBNAME_VALID(adbname));
+ adb = adbname->adb;
+ INSIST(DNS_ADB_VALID(adb));
+
+ rdtype = rdataset->type;
+ INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
+ if (rdtype == dns_rdatatype_a)
+ findoptions = DNS_ADBFIND_INET;
+ else
+ findoptions = DNS_ADBFIND_INET6;
+
+ addr_bucket = DNS_ADB_INVALIDBUCKET;
+ new_addresses_added = ISC_FALSE;
+
+ nh = NULL;
+ result = dns_rdataset_first(rdataset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdata_reset(&rdata);
+ dns_rdataset_current(rdataset, &rdata);
+ if (rdtype == dns_rdatatype_a) {
+ INSIST(rdata.length == 4);
+ memcpy(&ina.s_addr, rdata.data, 4);
+ isc_sockaddr_fromin(&sockaddr, &ina, 0);
+ } else {
+ INSIST(rdata.length == 16);
+ memcpy(in6a.s6_addr, rdata.data, 16);
+ isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
+ }
+
+ INSIST(nh == NULL);
+ nh = new_adbnamehook(adb, NULL);
+ if (nh == NULL) {
+ adbname->partial_result |= findoptions;
+ result = ISC_R_NOMEMORY;
+ goto fail;
+ }
+
+ foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket);
+ if (foundentry == NULL) {
+ dns_adbentry_t *entry;
+
+ entry = new_adbentry(adb);
+ if (entry == NULL) {
+ adbname->partial_result |= findoptions;
+ result = ISC_R_NOMEMORY;
+ goto fail;
+ }
+
+ entry->sockaddr = sockaddr;
+ entry->refcnt = 1;
+
+ nh->entry = entry;
+
+ link_entry(adb, addr_bucket, entry);
+ } else {
+ for (anh = ISC_LIST_HEAD(adbname->v4);
+ anh != NULL;
+ anh = ISC_LIST_NEXT(anh, plink))
+ if (anh->entry == foundentry)
+ break;
+ if (anh == NULL) {
+ foundentry->refcnt++;
+ nh->entry = foundentry;
+ } else
+ free_adbnamehook(adb, &nh);
+ }
+
+ new_addresses_added = ISC_TRUE;
+ if (nh != NULL) {
+ if (rdtype == dns_rdatatype_a)
+ ISC_LIST_APPEND(adbname->v4, nh, plink);
+ else
+ ISC_LIST_APPEND(adbname->v6, nh, plink);
+ }
+ nh = NULL;
+ result = dns_rdataset_next(rdataset);
+ }
+
+ fail:
+ if (nh != NULL)
+ free_adbnamehook(adb, &nh);
+
+ if (addr_bucket != DNS_ADB_INVALIDBUCKET)
+ UNLOCK(&adb->entrylocks[addr_bucket]);
+
+ if (rdataset->trust == dns_trust_glue ||
+ rdataset->trust == dns_trust_additional)
+ rdataset->ttl = ADB_CACHE_MINIMUM;
+ else
+ rdataset->ttl = ttlclamp(rdataset->ttl);
+
+ if (rdtype == dns_rdatatype_a) {
+ DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
+ adbname->expire_v4, now + rdataset->ttl);
+ adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
+ now + rdataset->ttl);
+ } else {
+ DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
+ adbname->expire_v6, now + rdataset->ttl);
+ adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
+ now + rdataset->ttl);
+ }
+
+ if (new_addresses_added) {
+ /*
+ * Lie a little here. This is more or less so code that cares
+ * can find out if any new information was added or not.
+ */
+ return (ISC_R_SUCCESS);
+ }
+
+ return (result);
+}
+
+/*
+ * Requires the name's bucket be locked.
+ */
+static isc_boolean_t
+kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
+ dns_adbname_t *name;
+ isc_boolean_t result = ISC_FALSE;
+ isc_boolean_t result4, result6;
+ dns_adb_t *adb;
+
+ INSIST(n != NULL);
+ name = *n;
+ *n = NULL;
+ INSIST(DNS_ADBNAME_VALID(name));
+ adb = name->adb;
+ INSIST(DNS_ADB_VALID(adb));
+
+ DP(DEF_LEVEL, "killing name %p", name);
+
+ /*
+ * If we're dead already, just check to see if we should go
+ * away now or not.
+ */
+ if (NAME_DEAD(name) && !NAME_FETCH(name)) {
+ result = unlink_name(adb, name);
+ free_adbname(adb, &name);
+ if (result)
+ result = dec_adb_irefcnt(adb);
+ return (result);
+ }
+
+ /*
+ * Clean up the name's various lists. These two are destructive
+ * in that they will always empty the list.
+ */
+ clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
+ result4 = clean_namehooks(adb, &name->v4);
+ result6 = clean_namehooks(adb, &name->v6);
+ clean_target(adb, &name->target);
+ result = ISC_TF(result4 || result6);
+
+ /*
+ * If fetches are running, cancel them. If none are running, we can
+ * just kill the name here.
+ */
+ if (!NAME_FETCH(name)) {
+ INSIST(result == ISC_FALSE);
+ result = unlink_name(adb, name);
+ free_adbname(adb, &name);
+ if (result)
+ result = dec_adb_irefcnt(adb);
+ } else {
+ name->flags |= NAME_IS_DEAD;
+ cancel_fetches_at_name(name);
+ }
+ return (result);
+}
+
+/*
+ * Requires the name's bucket be locked and no entry buckets be locked.
+ */
+static isc_boolean_t
+check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now,
+ isc_boolean_t overmem)
+{
+ dns_adb_t *adb;
+ isc_boolean_t expire;
+ isc_boolean_t result4 = ISC_FALSE;
+ isc_boolean_t result6 = ISC_FALSE;
+
+ INSIST(DNS_ADBNAME_VALID(name));
+ adb = name->adb;
+ INSIST(DNS_ADB_VALID(adb));
+
+ if (overmem) {
+ isc_uint32_t val;
+
+ isc_random_get(&val);
+
+ expire = ISC_TF((val % 4) == 0);
+ } else
+ expire = ISC_FALSE;
+
+ /*
+ * Check to see if we need to remove the v4 addresses
+ */
+ if (!NAME_FETCH_V4(name) &&
+ (expire || EXPIRE_OK(name->expire_v4, now))) {
+ if (NAME_HAS_V4(name)) {
+ DP(DEF_LEVEL, "expiring v4 for name %p", name);
+ result4 = clean_namehooks(adb, &name->v4);
+ name->partial_result &= ~DNS_ADBFIND_INET;
+ }
+ name->expire_v4 = INT_MAX;
+ name->fetch_err = FIND_ERR_UNEXPECTED;
+ }
+
+ /*
+ * Check to see if we need to remove the v6 addresses
+ */
+ if (!NAME_FETCH_V6(name) &&
+ (expire || EXPIRE_OK(name->expire_v6, now))) {
+ if (NAME_HAS_V6(name)) {
+ DP(DEF_LEVEL, "expiring v6 for name %p", name);
+ result6 = clean_namehooks(adb, &name->v6);
+ name->partial_result &= ~DNS_ADBFIND_INET6;
+ }
+ name->expire_v6 = INT_MAX;
+ name->fetch6_err = FIND_ERR_UNEXPECTED;
+ }
+
+ /*
+ * Check to see if we need to remove the alias target.
+ */
+ if (expire || EXPIRE_OK(name->expire_target, now)) {
+ clean_target(adb, &name->target);
+ name->expire_target = INT_MAX;
+ }
+ return (ISC_TF(result4 || result6));
+}
+
+/*
+ * Requires the name's bucket be locked.
+ */
+static inline void
+link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
+ INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
+
+ ISC_LIST_PREPEND(adb->names[bucket], name, plink);
+ name->lock_bucket = bucket;
+ adb->name_refcnt[bucket]++;
+}
+
+/*
+ * Requires the name's bucket be locked.
+ */
+static inline isc_boolean_t
+unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
+ int bucket;
+ isc_boolean_t result = ISC_FALSE;
+
+ bucket = name->lock_bucket;
+ INSIST(bucket != DNS_ADB_INVALIDBUCKET);
+
+ ISC_LIST_UNLINK(adb->names[bucket], name, plink);
+ name->lock_bucket = DNS_ADB_INVALIDBUCKET;
+ INSIST(adb->name_refcnt[bucket] > 0);
+ adb->name_refcnt[bucket]--;
+ if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
+ result = ISC_TRUE;
+ return (result);
+}
+
+/*
+ * Requires the entry's bucket be locked.
+ */
+static inline void
+link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
+ ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
+ entry->lock_bucket = bucket;
+ adb->entry_refcnt[bucket]++;
+}
+
+/*
+ * Requires the entry's bucket be locked.
+ */
+static inline isc_boolean_t
+unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
+ int bucket;
+ isc_boolean_t result = ISC_FALSE;
+
+ bucket = entry->lock_bucket;
+ INSIST(bucket != DNS_ADB_INVALIDBUCKET);
+
+ ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
+ entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
+ INSIST(adb->entry_refcnt[bucket] > 0);
+ adb->entry_refcnt[bucket]--;
+ if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
+ result = ISC_TRUE;
+ return (result);
+}
+
+static inline void
+violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
+ if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
+ UNLOCK(have);
+ LOCK(want);
+ LOCK(have);
+ }
+}
+
+/*
+ * The ADB _MUST_ be locked before calling. Also, exit conditions must be
+ * checked after calling this function.
+ */
+static isc_boolean_t
+shutdown_names(dns_adb_t *adb) {
+ int bucket;
+ isc_boolean_t result = ISC_FALSE;
+ dns_adbname_t *name;
+ dns_adbname_t *next_name;
+
+ for (bucket = 0; bucket < NBUCKETS; bucket++) {
+ LOCK(&adb->namelocks[bucket]);
+ adb->name_sd[bucket] = ISC_TRUE;
+
+ name = ISC_LIST_HEAD(adb->names[bucket]);
+ if (name == NULL) {
+ /*
+ * This bucket has no names. We must decrement the
+ * irefcnt ourselves, since it will not be
+ * automatically triggered by a name being unlinked.
+ */
+ INSIST(result == ISC_FALSE);
+ result = dec_adb_irefcnt(adb);
+ } else {
+ /*
+ * Run through the list. For each name, clean up finds
+ * found there, and cancel any fetches running. When
+ * all the fetches are canceled, the name will destroy
+ * itself.
+ */
+ while (name != NULL) {
+ next_name = ISC_LIST_NEXT(name, plink);
+ INSIST(result == ISC_FALSE);
+ result = kill_name(&name,
+ DNS_EVENT_ADBSHUTDOWN);
+ name = next_name;
+ }
+ }
+
+ UNLOCK(&adb->namelocks[bucket]);
+ }
+ return (result);
+}
+
+/*
+ * The ADB _MUST_ be locked before calling. Also, exit conditions must be
+ * checked after calling this function.
+ */
+static isc_boolean_t
+shutdown_entries(dns_adb_t *adb) {
+ int bucket;
+ isc_boolean_t result = ISC_FALSE;
+ dns_adbentry_t *entry;
+ dns_adbentry_t *next_entry;
+
+ for (bucket = 0; bucket < NBUCKETS; bucket++) {
+ LOCK(&adb->entrylocks[bucket]);
+ adb->entry_sd[bucket] = ISC_TRUE;
+
+ entry = ISC_LIST_HEAD(adb->entries[bucket]);
+ if (entry == NULL) {
+ /*
+ * This bucket has no entries. We must decrement the
+ * irefcnt ourselves, since it will not be
+ * automatically triggered by an entry being unlinked.
+ */
+ result = dec_adb_irefcnt(adb);
+ } else {
+ /*
+ * Run through the list. Cleanup any entries not
+ * associated with names, and which are not in use.
+ */
+ while (entry != NULL) {
+ next_entry = ISC_LIST_NEXT(entry, plink);
+ if (entry->refcnt == 0 &&
+ entry->expires != 0) {
+ result = unlink_entry(adb, entry);
+ free_adbentry(adb, &entry);
+ if (result)
+ result = dec_adb_irefcnt(adb);
+ }
+ entry = next_entry;
+ }
+ }
+
+ UNLOCK(&adb->entrylocks[bucket]);
+ }
+ return (result);
+}
+
+/*
+ * Name bucket must be locked
+ */
+static void
+cancel_fetches_at_name(dns_adbname_t *name) {
+ if (NAME_FETCH_A(name))
+ dns_resolver_cancelfetch(name->fetch_a->fetch);
+
+ if (NAME_FETCH_AAAA(name))
+ dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
+}
+
+/*
+ * Assumes the name bucket is locked.
+ */
+static isc_boolean_t
+clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
+ dns_adbentry_t *entry;
+ dns_adbnamehook_t *namehook;
+ int addr_bucket;
+ isc_boolean_t result = ISC_FALSE;
+
+ addr_bucket = DNS_ADB_INVALIDBUCKET;
+ namehook = ISC_LIST_HEAD(*namehooks);
+ while (namehook != NULL) {
+ INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
+
+ /*
+ * Clean up the entry if needed.
+ */
+ entry = namehook->entry;
+ if (entry != NULL) {
+ INSIST(DNS_ADBENTRY_VALID(entry));
+
+ if (addr_bucket != entry->lock_bucket) {
+ if (addr_bucket != DNS_ADB_INVALIDBUCKET)
+ UNLOCK(&adb->entrylocks[addr_bucket]);
+ addr_bucket = entry->lock_bucket;
+ LOCK(&adb->entrylocks[addr_bucket]);
+ }
+
+ result = dec_entry_refcnt(adb, entry, ISC_FALSE);
+ }
+
+ /*
+ * Free the namehook
+ */
+ namehook->entry = NULL;
+ ISC_LIST_UNLINK(*namehooks, namehook, plink);
+ free_adbnamehook(adb, &namehook);
+
+ namehook = ISC_LIST_HEAD(*namehooks);
+ }
+
+ if (addr_bucket != DNS_ADB_INVALIDBUCKET)
+ UNLOCK(&adb->entrylocks[addr_bucket]);
+ return (result);
+}
+
+static void
+clean_target(dns_adb_t *adb, dns_name_t *target) {
+ if (dns_name_countlabels(target) > 0) {
+ dns_name_free(target, adb->mctx);
+ dns_name_init(target, NULL);
+ }
+}
+
+static isc_result_t
+set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
+ dns_rdataset_t *rdataset, dns_name_t *target)
+{
+ isc_result_t result;
+ dns_namereln_t namereln;
+ unsigned int nlabels;
+ int order;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_fixedname_t fixed1, fixed2;
+ dns_name_t *prefix, *new_target;
+
+ REQUIRE(dns_name_countlabels(target) == 0);
+
+ if (rdataset->type == dns_rdatatype_cname) {
+ dns_rdata_cname_t cname;
+
+ /*
+ * Copy the CNAME's target into the target name.
+ */
+ result = dns_rdataset_first(rdataset);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &cname, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dns_name_dup(&cname.cname, adb->mctx, target);
+ dns_rdata_freestruct(&cname);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else {
+ dns_rdata_dname_t dname;
+
+ INSIST(rdataset->type == dns_rdatatype_dname);
+ namereln = dns_name_fullcompare(name, fname, &order, &nlabels);
+ INSIST(namereln == dns_namereln_subdomain);
+ /*
+ * Get the target name of the DNAME.
+ */
+ result = dns_rdataset_first(rdataset);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &dname, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ /*
+ * Construct the new target name.
+ */
+ dns_fixedname_init(&fixed1);
+ prefix = dns_fixedname_name(&fixed1);
+ dns_fixedname_init(&fixed2);
+ new_target = dns_fixedname_name(&fixed2);
+ dns_name_split(name, nlabels, prefix, NULL);
+ result = dns_name_concatenate(prefix, &dname.dname, new_target,
+ NULL);
+ dns_rdata_freestruct(&dname);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dns_name_dup(new_target, adb->mctx, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Assumes nothing is locked, since this is called by the client.
+ */
+static void
+event_free(isc_event_t *event) {
+ dns_adbfind_t *find;
+
+ INSIST(event != NULL);
+ find = event->ev_destroy_arg;
+ INSIST(DNS_ADBFIND_VALID(find));
+
+ LOCK(&find->lock);
+ find->flags |= FIND_EVENT_FREED;
+ event->ev_destroy_arg = NULL;
+ UNLOCK(&find->lock);
+}
+
+/*
+ * Assumes the name bucket is locked.
+ */
+static void
+clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
+ unsigned int addrs)
+{
+ isc_event_t *ev;
+ isc_task_t *task;
+ dns_adbfind_t *find;
+ dns_adbfind_t *next_find;
+ isc_boolean_t process;
+ unsigned int wanted, notify;
+
+ DP(ENTER_LEVEL,
+ "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
+ name, evtype, addrs);
+
+ find = ISC_LIST_HEAD(name->finds);
+ while (find != NULL) {
+ LOCK(&find->lock);
+ next_find = ISC_LIST_NEXT(find, plink);
+
+ process = ISC_FALSE;
+ wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
+ notify = wanted & addrs;
+
+ switch (evtype) {
+ case DNS_EVENT_ADBMOREADDRESSES:
+ DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
+ if ((notify) != 0) {
+ find->flags &= ~addrs;
+ process = ISC_TRUE;
+ }
+ break;
+ case DNS_EVENT_ADBNOMOREADDRESSES:
+ DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
+ find->flags &= ~addrs;
+ wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
+ if (wanted == 0)
+ process = ISC_TRUE;
+ break;
+ default:
+ find->flags &= ~addrs;
+ process = ISC_TRUE;
+ }
+
+ if (process) {
+ DP(DEF_LEVEL, "cfan: processing find %p", find);
+ /*
+ * Unlink the find from the name, letting the caller
+ * call dns_adb_destroyfind() on it to clean it up
+ * later.
+ */
+ ISC_LIST_UNLINK(name->finds, find, plink);
+ find->adbname = NULL;
+ find->name_bucket = DNS_ADB_INVALIDBUCKET;
+
+ INSIST(!FIND_EVENTSENT(find));
+
+ ev = &find->event;
+ task = ev->ev_sender;
+ ev->ev_sender = find;
+ find->result_v4 = find_err_map[name->fetch_err];
+ find->result_v6 = find_err_map[name->fetch6_err];
+ ev->ev_type = evtype;
+ ev->ev_destroy = event_free;
+ ev->ev_destroy_arg = find;
+
+ DP(DEF_LEVEL,
+ "sending event %p to task %p for find %p",
+ ev, task, find);
+
+ isc_task_sendanddetach(&task, (isc_event_t **)&ev);
+ } else {
+ DP(DEF_LEVEL, "cfan: skipping find %p", find);
+ }
+
+ UNLOCK(&find->lock);
+ find = next_find;
+ }
+
+ DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
+}
+
+static inline void
+check_exit(dns_adb_t *adb) {
+ isc_event_t *event;
+ /*
+ * The caller must be holding the adb lock.
+ */
+ if (adb->shutting_down) {
+ /*
+ * If there aren't any external references either, we're
+ * done. Send the control event to initiate shutdown.
+ */
+ INSIST(!adb->cevent_sent); /* Sanity check. */
+ event = &adb->cevent;
+ isc_task_send(adb->task, &event);
+ adb->cevent_sent = ISC_TRUE;
+ }
+}
+
+static inline isc_boolean_t
+dec_adb_irefcnt(dns_adb_t *adb) {
+ isc_event_t *event;
+ isc_task_t *etask;
+ isc_boolean_t result = ISC_FALSE;
+
+ LOCK(&adb->reflock);
+
+ INSIST(adb->irefcnt > 0);
+ adb->irefcnt--;
+
+ if (adb->irefcnt == 0) {
+ event = ISC_LIST_HEAD(adb->whenshutdown);
+ while (event != NULL) {
+ ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
+ etask = event->ev_sender;
+ event->ev_sender = adb;
+ isc_task_sendanddetach(&etask, &event);
+ event = ISC_LIST_HEAD(adb->whenshutdown);
+ }
+ }
+
+ if (adb->irefcnt == 0 && adb->erefcnt == 0)
+ result = ISC_TRUE;
+ UNLOCK(&adb->reflock);
+ return (result);
+}
+
+static inline void
+inc_adb_irefcnt(dns_adb_t *adb) {
+ LOCK(&adb->reflock);
+ adb->irefcnt++;
+ UNLOCK(&adb->reflock);
+}
+
+static inline void
+inc_adb_erefcnt(dns_adb_t *adb) {
+ LOCK(&adb->reflock);
+ adb->erefcnt++;
+ UNLOCK(&adb->reflock);
+}
+
+static inline void
+inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
+ int bucket;
+
+ bucket = entry->lock_bucket;
+
+ if (lock)
+ LOCK(&adb->entrylocks[bucket]);
+
+ entry->refcnt++;
+
+ if (lock)
+ UNLOCK(&adb->entrylocks[bucket]);
+}
+
+static inline isc_boolean_t
+dec_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
+ int bucket;
+ isc_boolean_t destroy_entry;
+ isc_boolean_t result = ISC_FALSE;
+
+ bucket = entry->lock_bucket;
+
+ if (lock)
+ LOCK(&adb->entrylocks[bucket]);
+
+ INSIST(entry->refcnt > 0);
+ entry->refcnt--;
+
+ destroy_entry = ISC_FALSE;
+ if (entry->refcnt == 0 &&
+ (adb->entry_sd[bucket] || entry->expires == 0)) {
+ destroy_entry = ISC_TRUE;
+ result = unlink_entry(adb, entry);
+ }
+
+ if (lock)
+ UNLOCK(&adb->entrylocks[bucket]);
+
+ if (!destroy_entry)
+ return (result);
+
+ entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
+
+ free_adbentry(adb, &entry);
+ if (result)
+ result =dec_adb_irefcnt(adb);
+
+ return (result);
+}
+
+static inline dns_adbname_t *
+new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
+ dns_adbname_t *name;
+
+ name = isc_mempool_get(adb->nmp);
+ if (name == NULL)
+ return (NULL);
+
+ dns_name_init(&name->name, NULL);
+ if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
+ isc_mempool_put(adb->nmp, name);
+ return (NULL);
+ }
+ dns_name_init(&name->target, NULL);
+ name->magic = DNS_ADBNAME_MAGIC;
+ name->adb = adb;
+ name->partial_result = 0;
+ name->flags = 0;
+ name->expire_v4 = INT_MAX;
+ name->expire_v6 = INT_MAX;
+ name->expire_target = INT_MAX;
+ name->chains = 0;
+ name->lock_bucket = DNS_ADB_INVALIDBUCKET;
+ ISC_LIST_INIT(name->v4);
+ ISC_LIST_INIT(name->v6);
+ name->fetch_a = NULL;
+ name->fetch_aaaa = NULL;
+ name->fetch_err = FIND_ERR_UNEXPECTED;
+ name->fetch6_err = FIND_ERR_UNEXPECTED;
+ ISC_LIST_INIT(name->finds);
+ ISC_LINK_INIT(name, plink);
+
+ return (name);
+}
+
+static inline void
+free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
+ dns_adbname_t *n;
+
+ INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
+ n = *name;
+ *name = NULL;
+
+ INSIST(!NAME_HAS_V4(n));
+ INSIST(!NAME_HAS_V6(n));
+ INSIST(!NAME_FETCH(n));
+ INSIST(ISC_LIST_EMPTY(n->finds));
+ INSIST(!ISC_LINK_LINKED(n, plink));
+ INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
+ INSIST(n->adb == adb);
+
+ n->magic = 0;
+ dns_name_free(&n->name, adb->mctx);
+
+ isc_mempool_put(adb->nmp, n);
+}
+
+static inline dns_adbnamehook_t *
+new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
+ dns_adbnamehook_t *nh;
+
+ nh = isc_mempool_get(adb->nhmp);
+ if (nh == NULL)
+ return (NULL);
+
+ nh->magic = DNS_ADBNAMEHOOK_MAGIC;
+ nh->entry = entry;
+ ISC_LINK_INIT(nh, plink);
+
+ return (nh);
+}
+
+static inline void
+free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
+ dns_adbnamehook_t *nh;
+
+ INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
+ nh = *namehook;
+ *namehook = NULL;
+
+ INSIST(nh->entry == NULL);
+ INSIST(!ISC_LINK_LINKED(nh, plink));
+
+ nh->magic = 0;
+ isc_mempool_put(adb->nhmp, nh);
+}
+
+static inline dns_adblameinfo_t *
+new_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) {
+ dns_adblameinfo_t *li;
+
+ li = isc_mempool_get(adb->limp);
+ if (li == NULL)
+ return (NULL);
+
+ dns_name_init(&li->qname, NULL);
+ if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) {
+ isc_mempool_put(adb->limp, li);
+ return (NULL);
+ }
+ li->magic = DNS_ADBLAMEINFO_MAGIC;
+ li->lame_timer = 0;
+ li->qtype = qtype;
+ ISC_LINK_INIT(li, plink);
+
+ return (li);
+}
+
+static inline void
+free_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) {
+ dns_adblameinfo_t *li;
+
+ INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo));
+ li = *lameinfo;
+ *lameinfo = NULL;
+
+ INSIST(!ISC_LINK_LINKED(li, plink));
+
+ dns_name_free(&li->qname, adb->mctx);
+
+ li->magic = 0;
+
+ isc_mempool_put(adb->limp, li);
+}
+
+static inline dns_adbentry_t *
+new_adbentry(dns_adb_t *adb) {
+ dns_adbentry_t *e;
+ isc_uint32_t r;
+
+ e = isc_mempool_get(adb->emp);
+ if (e == NULL)
+ return (NULL);
+
+ e->magic = DNS_ADBENTRY_MAGIC;
+ e->lock_bucket = DNS_ADB_INVALIDBUCKET;
+ e->refcnt = 0;
+ e->flags = 0;
+ isc_random_get(&r);
+ e->srtt = (r & 0x1f) + 1;
+ e->expires = 0;
+ ISC_LIST_INIT(e->lameinfo);
+ ISC_LINK_INIT(e, plink);
+
+ return (e);
+}
+
+static inline void
+free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
+ dns_adbentry_t *e;
+ dns_adblameinfo_t *li;
+
+ INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
+ e = *entry;
+ *entry = NULL;
+
+ INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
+ INSIST(e->refcnt == 0);
+ INSIST(!ISC_LINK_LINKED(e, plink));
+
+ e->magic = 0;
+
+ li = ISC_LIST_HEAD(e->lameinfo);
+ while (li != NULL) {
+ ISC_LIST_UNLINK(e->lameinfo, li, plink);
+ free_adblameinfo(adb, &li);
+ li = ISC_LIST_HEAD(e->lameinfo);
+ }
+
+ isc_mempool_put(adb->emp, e);
+}
+
+static inline dns_adbfind_t *
+new_adbfind(dns_adb_t *adb) {
+ dns_adbfind_t *h;
+ isc_result_t result;
+
+ h = isc_mempool_get(adb->ahmp);
+ if (h == NULL)
+ return (NULL);
+
+ /*
+ * Public members.
+ */
+ h->magic = 0;
+ h->adb = adb;
+ h->partial_result = 0;
+ h->options = 0;
+ h->flags = 0;
+ h->result_v4 = ISC_R_UNEXPECTED;
+ h->result_v6 = ISC_R_UNEXPECTED;
+ ISC_LINK_INIT(h, publink);
+ ISC_LINK_INIT(h, plink);
+ ISC_LIST_INIT(h->list);
+ h->adbname = NULL;
+ h->name_bucket = DNS_ADB_INVALIDBUCKET;
+
+ /*
+ * private members
+ */
+ result = isc_mutex_init(&h->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mempool_put(adb->ahmp, h);
+ return (NULL);
+ }
+
+ ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
+ NULL, NULL, h);
+
+ inc_adb_irefcnt(adb);
+ h->magic = DNS_ADBFIND_MAGIC;
+ return (h);
+}
+
+static inline dns_adbfetch_t *
+new_adbfetch(dns_adb_t *adb) {
+ dns_adbfetch_t *f;
+
+ f = isc_mempool_get(adb->afmp);
+ if (f == NULL)
+ return (NULL);
+
+ f->magic = 0;
+ f->namehook = NULL;
+ f->entry = NULL;
+ f->fetch = NULL;
+
+ f->namehook = new_adbnamehook(adb, NULL);
+ if (f->namehook == NULL)
+ goto err;
+
+ f->entry = new_adbentry(adb);
+ if (f->entry == NULL)
+ goto err;
+
+ dns_rdataset_init(&f->rdataset);
+
+ f->magic = DNS_ADBFETCH_MAGIC;
+
+ return (f);
+
+ err:
+ if (f->namehook != NULL)
+ free_adbnamehook(adb, &f->namehook);
+ if (f->entry != NULL)
+ free_adbentry(adb, &f->entry);
+ isc_mempool_put(adb->afmp, f);
+ return (NULL);
+}
+
+static inline void
+free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
+ dns_adbfetch_t *f;
+
+ INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
+ f = *fetch;
+ *fetch = NULL;
+
+ f->magic = 0;
+
+ if (f->namehook != NULL)
+ free_adbnamehook(adb, &f->namehook);
+ if (f->entry != NULL)
+ free_adbentry(adb, &f->entry);
+
+ if (dns_rdataset_isassociated(&f->rdataset))
+ dns_rdataset_disassociate(&f->rdataset);
+
+ isc_mempool_put(adb->afmp, f);
+}
+
+static inline isc_boolean_t
+free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
+ dns_adbfind_t *find;
+
+ INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
+ find = *findp;
+ *findp = NULL;
+
+ INSIST(!FIND_HAS_ADDRS(find));
+ INSIST(!ISC_LINK_LINKED(find, publink));
+ INSIST(!ISC_LINK_LINKED(find, plink));
+ INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
+ INSIST(find->adbname == NULL);
+
+ find->magic = 0;
+
+ DESTROYLOCK(&find->lock);
+ isc_mempool_put(adb->ahmp, find);
+ return (dec_adb_irefcnt(adb));
+}
+
+/*
+ * Copy bits from the entry into the newly allocated addrinfo. The entry
+ * must be locked, and the reference count must be bumped up by one
+ * if this function returns a valid pointer.
+ */
+static inline dns_adbaddrinfo_t *
+new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
+ dns_adbaddrinfo_t *ai;
+
+ ai = isc_mempool_get(adb->aimp);
+ if (ai == NULL)
+ return (NULL);
+
+ ai->magic = DNS_ADBADDRINFO_MAGIC;
+ ai->sockaddr = entry->sockaddr;
+ isc_sockaddr_setport(&ai->sockaddr, port);
+ ai->srtt = entry->srtt;
+ ai->flags = entry->flags;
+ ai->entry = entry;
+ ISC_LINK_INIT(ai, publink);
+
+ return (ai);
+}
+
+static inline void
+free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
+ dns_adbaddrinfo_t *ai;
+
+ INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
+ ai = *ainfo;
+ *ainfo = NULL;
+
+ INSIST(ai->entry == NULL);
+ INSIST(!ISC_LINK_LINKED(ai, publink));
+
+ ai->magic = 0;
+
+ isc_mempool_put(adb->aimp, ai);
+}
+
+/*
+ * Search for the name. NOTE: The bucket is kept locked on both
+ * success and failure, so it must always be unlocked by the caller!
+ *
+ * On the first call to this function, *bucketp must be set to
+ * DNS_ADB_INVALIDBUCKET.
+ */
+static inline dns_adbname_t *
+find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
+ unsigned int options, int *bucketp)
+{
+ dns_adbname_t *adbname;
+ int bucket;
+
+ bucket = dns_name_fullhash(name, ISC_FALSE) % NBUCKETS;
+
+ if (*bucketp == DNS_ADB_INVALIDBUCKET) {
+ LOCK(&adb->namelocks[bucket]);
+ *bucketp = bucket;
+ } else if (*bucketp != bucket) {
+ UNLOCK(&adb->namelocks[*bucketp]);
+ LOCK(&adb->namelocks[bucket]);
+ *bucketp = bucket;
+ }
+
+ adbname = ISC_LIST_HEAD(adb->names[bucket]);
+ while (adbname != NULL) {
+ if (!NAME_DEAD(adbname)) {
+ if (dns_name_equal(name, &adbname->name)
+ && GLUEHINT_OK(adbname, options)
+ && STARTATZONE_MATCHES(adbname, options))
+ return (adbname);
+ }
+ adbname = ISC_LIST_NEXT(adbname, plink);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Search for the address. NOTE: The bucket is kept locked on both
+ * success and failure, so it must always be unlocked by the caller.
+ *
+ * On the first call to this function, *bucketp must be set to
+ * DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On
+ * later calls (within the same "lock path") it can be left alone, so
+ * if this function is called multiple times locking is only done if
+ * the bucket changes.
+ */
+static inline dns_adbentry_t *
+find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp) {
+ dns_adbentry_t *entry;
+ int bucket;
+
+ bucket = isc_sockaddr_hash(addr, ISC_TRUE) % NBUCKETS;
+
+ if (*bucketp == DNS_ADB_INVALIDBUCKET) {
+ LOCK(&adb->entrylocks[bucket]);
+ *bucketp = bucket;
+ } else if (*bucketp != bucket) {
+ UNLOCK(&adb->entrylocks[*bucketp]);
+ LOCK(&adb->entrylocks[bucket]);
+ *bucketp = bucket;
+ }
+
+ entry = ISC_LIST_HEAD(adb->entries[bucket]);
+ while (entry != NULL) {
+ if (isc_sockaddr_equal(addr, &entry->sockaddr))
+ return (entry);
+ entry = ISC_LIST_NEXT(entry, plink);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Entry bucket MUST be locked!
+ */
+static isc_boolean_t
+entry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname,
+ dns_rdatatype_t qtype, isc_stdtime_t now)
+{
+ dns_adblameinfo_t *li, *next_li;
+ isc_boolean_t is_bad;
+
+ is_bad = ISC_FALSE;
+
+ li = ISC_LIST_HEAD(entry->lameinfo);
+ if (li == NULL)
+ return (ISC_FALSE);
+ while (li != NULL) {
+ next_li = ISC_LIST_NEXT(li, plink);
+
+ /*
+ * Has the entry expired?
+ */
+ if (li->lame_timer < now) {
+ ISC_LIST_UNLINK(entry->lameinfo, li, plink);
+ free_adblameinfo(adb, &li);
+ }
+
+ /*
+ * Order tests from least to most expensive.
+ *
+ * We do not break out of the main loop here as
+ * we use the loop for house keeping.
+ */
+ if (li != NULL && !is_bad && li->qtype == qtype &&
+ dns_name_equal(qname, &li->qname))
+ is_bad = ISC_TRUE;
+
+ li = next_li;
+ }
+
+ return (is_bad);
+}
+
+static void
+copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname,
+ dns_rdatatype_t qtype, dns_adbname_t *name,
+ isc_stdtime_t now)
+{
+ dns_adbnamehook_t *namehook;
+ dns_adbaddrinfo_t *addrinfo;
+ dns_adbentry_t *entry;
+ int bucket;
+
+ bucket = DNS_ADB_INVALIDBUCKET;
+
+ if (find->options & DNS_ADBFIND_INET) {
+ namehook = ISC_LIST_HEAD(name->v4);
+ while (namehook != NULL) {
+ entry = namehook->entry;
+ bucket = entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+
+ if (!FIND_RETURNLAME(find)
+ && entry_is_lame(adb, entry, qname, qtype, now)) {
+ find->options |= DNS_ADBFIND_LAMEPRUNED;
+ goto nextv4;
+ }
+ addrinfo = new_adbaddrinfo(adb, entry, find->port);
+ if (addrinfo == NULL) {
+ find->partial_result |= DNS_ADBFIND_INET;
+ goto out;
+ }
+ /*
+ * Found a valid entry. Add it to the find's list.
+ */
+ inc_entry_refcnt(adb, entry, ISC_FALSE);
+ ISC_LIST_APPEND(find->list, addrinfo, publink);
+ addrinfo = NULL;
+ nextv4:
+ UNLOCK(&adb->entrylocks[bucket]);
+ bucket = DNS_ADB_INVALIDBUCKET;
+ namehook = ISC_LIST_NEXT(namehook, plink);
+ }
+ }
+
+ if (find->options & DNS_ADBFIND_INET6) {
+ namehook = ISC_LIST_HEAD(name->v6);
+ while (namehook != NULL) {
+ entry = namehook->entry;
+ bucket = entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+
+ if (entry_is_lame(adb, entry, qname, qtype, now))
+ goto nextv6;
+ addrinfo = new_adbaddrinfo(adb, entry, find->port);
+ if (addrinfo == NULL) {
+ find->partial_result |= DNS_ADBFIND_INET6;
+ goto out;
+ }
+ /*
+ * Found a valid entry. Add it to the find's list.
+ */
+ inc_entry_refcnt(adb, entry, ISC_FALSE);
+ ISC_LIST_APPEND(find->list, addrinfo, publink);
+ addrinfo = NULL;
+ nextv6:
+ UNLOCK(&adb->entrylocks[bucket]);
+ bucket = DNS_ADB_INVALIDBUCKET;
+ namehook = ISC_LIST_NEXT(namehook, plink);
+ }
+ }
+
+ out:
+ if (bucket != DNS_ADB_INVALIDBUCKET)
+ UNLOCK(&adb->entrylocks[bucket]);
+}
+
+static void
+shutdown_task(isc_task_t *task, isc_event_t *ev) {
+ dns_adb_t *adb;
+
+ UNUSED(task);
+
+ adb = ev->ev_arg;
+ INSIST(DNS_ADB_VALID(adb));
+
+ /*
+ * Kill the timer, and then the ADB itself. Note that this implies
+ * that this task was the one scheduled to get timer events. If
+ * this is not true (and it is unfortunate there is no way to INSIST()
+ * this) badness will occur.
+ */
+ LOCK(&adb->lock);
+ isc_timer_detach(&adb->timer);
+ UNLOCK(&adb->lock);
+ isc_event_free(&ev);
+ destroy(adb);
+}
+
+/*
+ * Name bucket must be locked; adb may be locked; no other locks held.
+ */
+static isc_boolean_t
+check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
+ dns_adbname_t *name;
+ isc_boolean_t result = ISC_FALSE;
+
+ INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
+ name = *namep;
+
+ if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
+ return (result);
+ if (NAME_FETCH(name))
+ return (result);
+ if (!EXPIRE_OK(name->expire_v4, now))
+ return (result);
+ if (!EXPIRE_OK(name->expire_v6, now))
+ return (result);
+ if (!EXPIRE_OK(name->expire_target, now))
+ return (result);
+
+ /*
+ * The name is empty. Delete it.
+ */
+ result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
+ *namep = NULL;
+
+ /*
+ * Our caller, or one of its callers, will be calling check_exit() at
+ * some point, so we don't need to do it here.
+ */
+ return (result);
+}
+
+/*
+ * Entry bucket must be locked; adb may be locked; no other locks held.
+ */
+static isc_boolean_t
+check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
+{
+ dns_adbentry_t *entry;
+ isc_boolean_t expire;
+ isc_boolean_t result = ISC_FALSE;
+
+ INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
+ entry = *entryp;
+
+ if (entry->refcnt != 0)
+ return (result);
+
+ if (adb->overmem) {
+ isc_uint32_t val;
+
+ isc_random_get(&val);
+
+ expire = ISC_TF((val % 4) == 0);
+ } else
+ expire = ISC_FALSE;
+
+ if (entry->expires == 0 || (! expire && entry->expires > now))
+ return (result);
+
+ /*
+ * The entry is not in use. Delete it.
+ */
+ DP(DEF_LEVEL, "killing entry %p", entry);
+ INSIST(ISC_LINK_LINKED(entry, plink));
+ result = unlink_entry(adb, entry);
+ free_adbentry(adb, &entry);
+ if (result)
+ dec_adb_irefcnt(adb);
+ *entryp = NULL;
+ return (result);
+}
+
+/*
+ * ADB must be locked, and no other locks held.
+ */
+static isc_boolean_t
+cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
+ dns_adbname_t *name;
+ dns_adbname_t *next_name;
+ isc_boolean_t result = ISC_FALSE;
+
+ DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
+
+ LOCK(&adb->namelocks[bucket]);
+ if (adb->name_sd[bucket]) {
+ UNLOCK(&adb->namelocks[bucket]);
+ return (result);
+ }
+
+ name = ISC_LIST_HEAD(adb->names[bucket]);
+ while (name != NULL) {
+ next_name = ISC_LIST_NEXT(name, plink);
+ INSIST(result == ISC_FALSE);
+ result = check_expire_namehooks(name, now, adb->overmem);
+ if (!result)
+ result = check_expire_name(&name, now);
+ name = next_name;
+ }
+ UNLOCK(&adb->namelocks[bucket]);
+ return (result);
+}
+
+/*
+ * ADB must be locked, and no other locks held.
+ */
+static isc_boolean_t
+cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
+ dns_adbentry_t *entry, *next_entry;
+ isc_boolean_t result = ISC_FALSE;
+
+ DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
+
+ LOCK(&adb->entrylocks[bucket]);
+ entry = ISC_LIST_HEAD(adb->entries[bucket]);
+ while (entry != NULL) {
+ next_entry = ISC_LIST_NEXT(entry, plink);
+ INSIST(result == ISC_FALSE);
+ result = check_expire_entry(adb, &entry, now);
+ entry = next_entry;
+ }
+ UNLOCK(&adb->entrylocks[bucket]);
+ return (result);
+}
+
+static void
+timer_cleanup(isc_task_t *task, isc_event_t *ev) {
+ dns_adb_t *adb;
+ isc_stdtime_t now;
+ unsigned int i;
+ isc_interval_t interval;
+
+ UNUSED(task);
+
+ adb = ev->ev_arg;
+ INSIST(DNS_ADB_VALID(adb));
+
+ LOCK(&adb->lock);
+
+ isc_stdtime_get(&now);
+
+ for (i = 0; i < CLEAN_BUCKETS; i++) {
+ /*
+ * Call our cleanup routines.
+ */
+ RUNTIME_CHECK(cleanup_names(adb, adb->next_cleanbucket, now) ==
+ ISC_FALSE);
+ RUNTIME_CHECK(cleanup_entries(adb, adb->next_cleanbucket, now)
+ == ISC_FALSE);
+
+ /*
+ * Set the next bucket to be cleaned.
+ */
+ adb->next_cleanbucket++;
+ if (adb->next_cleanbucket >= NBUCKETS) {
+ adb->next_cleanbucket = 0;
+#ifdef DUMP_ADB_AFTER_CLEANING
+ dump_adb(adb, stdout, ISC_TRUE, now);
+#endif
+ }
+ }
+
+ /*
+ * Reset the timer.
+ * XXXDCL isc_timer_reset might return ISC_R_UNEXPECTED or
+ * ISC_R_NOMEMORY, but it isn't clear what could be done here
+ * if either one of those things happened.
+ */
+ interval = adb->tick_interval;
+ if (adb->overmem)
+ isc_interval_set(&interval, 0, 1);
+ (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
+ &interval, ISC_FALSE);
+
+ UNLOCK(&adb->lock);
+
+ isc_event_free(&ev);
+}
+
+static void
+destroy(dns_adb_t *adb) {
+ adb->magic = 0;
+
+ /*
+ * The timer is already dead, from the task's shutdown callback.
+ */
+ isc_task_detach(&adb->task);
+
+ isc_mempool_destroy(&adb->nmp);
+ isc_mempool_destroy(&adb->nhmp);
+ isc_mempool_destroy(&adb->limp);
+ isc_mempool_destroy(&adb->emp);
+ isc_mempool_destroy(&adb->ahmp);
+ isc_mempool_destroy(&adb->aimp);
+ isc_mempool_destroy(&adb->afmp);
+
+ DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
+ DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
+
+ DESTROYLOCK(&adb->reflock);
+ DESTROYLOCK(&adb->lock);
+ DESTROYLOCK(&adb->mplock);
+
+ isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
+}
+
+
+/*
+ * Public functions.
+ */
+
+isc_result_t
+dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
+ isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
+{
+ dns_adb_t *adb;
+ isc_result_t result;
+ int i;
+
+ REQUIRE(mem != NULL);
+ REQUIRE(view != NULL);
+ REQUIRE(timermgr != NULL);
+ REQUIRE(taskmgr != NULL);
+ REQUIRE(newadb != NULL && *newadb == NULL);
+
+ adb = isc_mem_get(mem, sizeof(dns_adb_t));
+ if (adb == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /*
+ * Initialize things here that cannot fail, and especially things
+ * that must be NULL for the error return to work properly.
+ */
+ adb->magic = 0;
+ adb->erefcnt = 1;
+ adb->irefcnt = 0;
+ adb->nmp = NULL;
+ adb->nhmp = NULL;
+ adb->limp = NULL;
+ adb->emp = NULL;
+ adb->ahmp = NULL;
+ adb->aimp = NULL;
+ adb->afmp = NULL;
+ adb->task = NULL;
+ adb->timer = NULL;
+ adb->mctx = NULL;
+ adb->view = view;
+ adb->timermgr = timermgr;
+ adb->taskmgr = taskmgr;
+ adb->next_cleanbucket = 0;
+ ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
+ DNS_EVENT_ADBCONTROL, shutdown_task, adb,
+ adb, NULL, NULL);
+ adb->cevent_sent = ISC_FALSE;
+ adb->shutting_down = ISC_FALSE;
+ adb->overmem = ISC_FALSE;
+ ISC_LIST_INIT(adb->whenshutdown);
+
+ isc_mem_attach(mem, &adb->mctx);
+
+ result = isc_mutex_init(&adb->lock);
+ if (result != ISC_R_SUCCESS)
+ goto fail0b;
+
+ result = isc_mutex_init(&adb->mplock);
+ if (result != ISC_R_SUCCESS)
+ goto fail0c;
+
+ result = isc_mutex_init(&adb->reflock);
+ if (result != ISC_R_SUCCESS)
+ goto fail0d;
+
+ /*
+ * Initialize the bucket locks for names and elements.
+ * May as well initialize the list heads, too.
+ */
+ result = isc_mutexblock_init(adb->namelocks, NBUCKETS);
+ if (result != ISC_R_SUCCESS)
+ goto fail1;
+ for (i = 0; i < NBUCKETS; i++) {
+ ISC_LIST_INIT(adb->names[i]);
+ adb->name_sd[i] = ISC_FALSE;
+ adb->name_refcnt[i] = 0;
+ adb->irefcnt++;
+ }
+ for (i = 0; i < NBUCKETS; i++) {
+ ISC_LIST_INIT(adb->entries[i]);
+ adb->entry_sd[i] = ISC_FALSE;
+ adb->entry_refcnt[i] = 0;
+ adb->irefcnt++;
+ }
+ result = isc_mutexblock_init(adb->entrylocks, NBUCKETS);
+ if (result != ISC_R_SUCCESS)
+ goto fail2;
+
+ /*
+ * Memory pools
+ */
+#define MPINIT(t, p, n) do { \
+ result = isc_mempool_create(mem, sizeof(t), &(p)); \
+ if (result != ISC_R_SUCCESS) \
+ goto fail3; \
+ isc_mempool_setfreemax((p), FREE_ITEMS); \
+ isc_mempool_setfillcount((p), FILL_COUNT); \
+ isc_mempool_setname((p), n); \
+ isc_mempool_associatelock((p), &adb->mplock); \
+} while (0)
+
+ MPINIT(dns_adbname_t, adb->nmp, "adbname");
+ MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
+ MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo");
+ MPINIT(dns_adbentry_t, adb->emp, "adbentry");
+ MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
+ MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
+ MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
+
+#undef MPINIT
+
+ /*
+ * Allocate a timer and a task for our periodic cleanup.
+ */
+ result = isc_task_create(adb->taskmgr, 0, &adb->task);
+ if (result != ISC_R_SUCCESS)
+ goto fail3;
+ isc_task_setname(adb->task, "ADB", adb);
+ /*
+ * XXXMLG When this is changed to be a config file option,
+ */
+ isc_interval_set(&adb->tick_interval, CLEAN_SECONDS, 0);
+ result = isc_timer_create(adb->timermgr, isc_timertype_once,
+ NULL, &adb->tick_interval, adb->task,
+ timer_cleanup, adb, &adb->timer);
+ if (result != ISC_R_SUCCESS)
+ goto fail3;
+
+ DP(ISC_LOG_DEBUG(5), "cleaning interval for adb: "
+ "%u buckets every %u seconds, %u buckets in system, %u cl.interval",
+ CLEAN_BUCKETS, CLEAN_SECONDS, NBUCKETS, CLEAN_PERIOD);
+
+ /*
+ * Normal return.
+ */
+ adb->magic = DNS_ADB_MAGIC;
+ *newadb = adb;
+ return (ISC_R_SUCCESS);
+
+ fail3:
+ if (adb->task != NULL)
+ isc_task_detach(&adb->task);
+ if (adb->timer != NULL)
+ isc_timer_detach(&adb->timer);
+
+ /* clean up entrylocks */
+ DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
+
+ fail2: /* clean up namelocks */
+ DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
+
+ fail1: /* clean up only allocated memory */
+ if (adb->nmp != NULL)
+ isc_mempool_destroy(&adb->nmp);
+ if (adb->nhmp != NULL)
+ isc_mempool_destroy(&adb->nhmp);
+ if (adb->limp != NULL)
+ isc_mempool_destroy(&adb->limp);
+ if (adb->emp != NULL)
+ isc_mempool_destroy(&adb->emp);
+ if (adb->ahmp != NULL)
+ isc_mempool_destroy(&adb->ahmp);
+ if (adb->aimp != NULL)
+ isc_mempool_destroy(&adb->aimp);
+ if (adb->afmp != NULL)
+ isc_mempool_destroy(&adb->afmp);
+
+ DESTROYLOCK(&adb->reflock);
+ fail0d:
+ DESTROYLOCK(&adb->mplock);
+ fail0c:
+ DESTROYLOCK(&adb->lock);
+ fail0b:
+ isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
+
+ return (result);
+}
+
+void
+dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(adbx != NULL && *adbx == NULL);
+
+ inc_adb_erefcnt(adb);
+ *adbx = adb;
+}
+
+void
+dns_adb_detach(dns_adb_t **adbx) {
+ dns_adb_t *adb;
+ isc_boolean_t need_exit_check;
+
+ REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
+
+ adb = *adbx;
+ *adbx = NULL;
+
+ INSIST(adb->erefcnt > 0);
+
+ LOCK(&adb->reflock);
+ adb->erefcnt--;
+ need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
+ UNLOCK(&adb->reflock);
+
+ if (need_exit_check) {
+ LOCK(&adb->lock);
+ INSIST(adb->shutting_down);
+ check_exit(adb);
+ UNLOCK(&adb->lock);
+ }
+}
+
+void
+dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
+ isc_task_t *clone;
+ isc_event_t *event;
+ isc_boolean_t zeroirefcnt = ISC_FALSE;
+
+ /*
+ * Send '*eventp' to 'task' when 'adb' has shutdown.
+ */
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(eventp != NULL);
+
+ event = *eventp;
+ *eventp = NULL;
+
+ LOCK(&adb->lock);
+
+ LOCK(&adb->reflock);
+ zeroirefcnt = ISC_TF(adb->irefcnt == 0);
+
+ if (adb->shutting_down && zeroirefcnt &&
+ isc_mempool_getallocated(adb->ahmp) == 0) {
+ /*
+ * We're already shutdown. Send the event.
+ */
+ event->ev_sender = adb;
+ isc_task_send(task, &event);
+ } else {
+ clone = NULL;
+ isc_task_attach(task, &clone);
+ event->ev_sender = clone;
+ ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
+ }
+
+ UNLOCK(&adb->reflock);
+ UNLOCK(&adb->lock);
+}
+
+void
+dns_adb_shutdown(dns_adb_t *adb) {
+ isc_boolean_t need_check_exit;
+
+ /*
+ * Shutdown 'adb'.
+ */
+
+ LOCK(&adb->lock);
+
+ if (!adb->shutting_down) {
+ adb->shutting_down = ISC_TRUE;
+ isc_mem_setwater(adb->mctx, water, adb, 0, 0);
+ need_check_exit = shutdown_names(adb);
+ if (!need_check_exit)
+ need_check_exit = shutdown_entries(adb);
+ if (need_check_exit)
+ check_exit(adb);
+ }
+
+ UNLOCK(&adb->lock);
+}
+
+isc_result_t
+dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
+ void *arg, dns_name_t *name, dns_name_t *qname,
+ dns_rdatatype_t qtype, unsigned int options,
+ isc_stdtime_t now, dns_name_t *target,
+ in_port_t port, dns_adbfind_t **findp)
+{
+ dns_adbfind_t *find;
+ dns_adbname_t *adbname;
+ int bucket;
+ isc_boolean_t want_event, start_at_zone, alias, have_address;
+ isc_result_t result;
+ unsigned int wanted_addresses;
+ unsigned int wanted_fetches;
+ unsigned int query_pending;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ if (task != NULL) {
+ REQUIRE(action != NULL);
+ }
+ REQUIRE(name != NULL);
+ REQUIRE(qname != NULL);
+ REQUIRE(findp != NULL && *findp == NULL);
+ REQUIRE(target == NULL || dns_name_hasbuffer(target));
+
+ REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
+
+ result = ISC_R_UNEXPECTED;
+ wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
+ wanted_fetches = 0;
+ query_pending = 0;
+ want_event = ISC_FALSE;
+ start_at_zone = ISC_FALSE;
+ alias = ISC_FALSE;
+
+ if (now == 0)
+ isc_stdtime_get(&now);
+
+ /*
+ * XXXMLG Move this comment somewhere else!
+ *
+ * Look up the name in our internal database.
+ *
+ * Possibilities: Note that these are not always exclusive.
+ *
+ * No name found. In this case, allocate a new name header and
+ * an initial namehook or two. If any of these allocations
+ * fail, clean up and return ISC_R_NOMEMORY.
+ *
+ * Name found, valid addresses present. Allocate one addrinfo
+ * structure for each found and append it to the linked list
+ * of addresses for this header.
+ *
+ * Name found, queries pending. In this case, if a task was
+ * passed in, allocate a job id, attach it to the name's job
+ * list and remember to tell the caller that there will be
+ * more info coming later.
+ */
+
+ find = new_adbfind(adb);
+ if (find == NULL)
+ return (ISC_R_NOMEMORY);
+
+ find->port = port;
+
+ /*
+ * Remember what types of addresses we are interested in.
+ */
+ find->options = options;
+ find->flags |= wanted_addresses;
+ if (FIND_WANTEVENT(find)) {
+ REQUIRE(task != NULL);
+ }
+
+ /*
+ * Try to see if we know anything about this name at all.
+ */
+ bucket = DNS_ADB_INVALIDBUCKET;
+ adbname = find_name_and_lock(adb, name, find->options, &bucket);
+ if (adb->name_sd[bucket]) {
+ DP(DEF_LEVEL,
+ "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
+ RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
+ result = ISC_R_SHUTTINGDOWN;
+ goto out;
+ }
+
+ /*
+ * Nothing found. Allocate a new adbname structure for this name.
+ */
+ if (adbname == NULL) {
+ adbname = new_adbname(adb, name);
+ if (adbname == NULL) {
+ RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
+ result = ISC_R_NOMEMORY;
+ goto out;
+ }
+ link_name(adb, bucket, adbname);
+ if (FIND_HINTOK(find))
+ adbname->flags |= NAME_HINT_OK;
+ if (FIND_GLUEOK(find))
+ adbname->flags |= NAME_GLUE_OK;
+ if (FIND_STARTATZONE(find))
+ adbname->flags |= NAME_STARTATZONE;
+ }
+
+ /*
+ * Expire old entries, etc.
+ */
+ RUNTIME_CHECK(check_expire_namehooks(adbname, now, adb->overmem) ==
+ ISC_FALSE);
+
+ /*
+ * Do we know that the name is an alias?
+ */
+ if (!EXPIRE_OK(adbname->expire_target, now)) {
+ /*
+ * Yes, it is.
+ */
+ DP(DEF_LEVEL,
+ "dns_adb_createfind: name %p is an alias (cached)",
+ adbname);
+ alias = ISC_TRUE;
+ goto post_copy;
+ }
+
+ /*
+ * Try to populate the name from the database and/or
+ * start fetches. First try looking for an A record
+ * in the database.
+ */
+ if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
+ && WANT_INET(wanted_addresses)) {
+ result = dbfind_name(adbname, now, dns_rdatatype_a);
+ if (result == ISC_R_SUCCESS) {
+ DP(DEF_LEVEL,
+ "dns_adb_createfind: found A for name %p in db",
+ adbname);
+ goto v6;
+ }
+
+ /*
+ * Did we get a CNAME or DNAME?
+ */
+ if (result == DNS_R_ALIAS) {
+ DP(DEF_LEVEL,
+ "dns_adb_createfind: name %p is an alias",
+ adbname);
+ alias = ISC_TRUE;
+ goto post_copy;
+ }
+
+ /*
+ * If the name doesn't exist at all, don't bother with
+ * v6 queries; they won't work.
+ *
+ * If the name does exist but we didn't get our data, go
+ * ahead and try AAAA.
+ *
+ * If the result is neither of these, try a fetch for A.
+ */
+ if (NXDOMAIN_RESULT(result))
+ goto fetch;
+ else if (NXRRSET_RESULT(result))
+ goto v6;
+
+ if (!NAME_FETCH_V4(adbname))
+ wanted_fetches |= DNS_ADBFIND_INET;
+ }
+
+ v6:
+ if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
+ && WANT_INET6(wanted_addresses)) {
+ result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
+ if (result == ISC_R_SUCCESS) {
+ DP(DEF_LEVEL,
+ "dns_adb_createfind: found AAAA for name %p",
+ adbname);
+ goto fetch;
+ }
+
+ /*
+ * Did we get a CNAME or DNAME?
+ */
+ if (result == DNS_R_ALIAS) {
+ DP(DEF_LEVEL,
+ "dns_adb_createfind: name %p is an alias",
+ adbname);
+ alias = ISC_TRUE;
+ goto post_copy;
+ }
+
+ /*
+ * Listen to negative cache hints, and don't start
+ * another query.
+ */
+ if (NCACHE_RESULT(result) || AUTH_NX(result))
+ goto fetch;
+
+ if (!NAME_FETCH_V6(adbname))
+ wanted_fetches |= DNS_ADBFIND_INET6;
+ }
+
+ fetch:
+ if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
+ (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
+ have_address = ISC_TRUE;
+ else
+ have_address = ISC_FALSE;
+ if (wanted_fetches != 0 &&
+ ! (FIND_AVOIDFETCHES(find) && have_address)) {
+ /*
+ * We're missing at least one address family. Either the
+ * caller hasn't instructed us to avoid fetches, or we don't
+ * know anything about any of the address families that would
+ * be acceptable so we have to launch fetches.
+ */
+
+ if (FIND_STARTATZONE(find))
+ start_at_zone = ISC_TRUE;
+
+ /*
+ * Start V4.
+ */
+ if (WANT_INET(wanted_fetches) &&
+ fetch_name(adbname, start_at_zone,
+ dns_rdatatype_a) == ISC_R_SUCCESS) {
+ DP(DEF_LEVEL,
+ "dns_adb_createfind: started A fetch for name %p",
+ adbname);
+ }
+
+ /*
+ * Start V6.
+ */
+ if (WANT_INET6(wanted_fetches) &&
+ fetch_name(adbname, start_at_zone,
+ dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
+ DP(DEF_LEVEL,
+ "dns_adb_createfind: "
+ "started AAAA fetch for name %p",
+ adbname);
+ }
+ }
+
+ /*
+ * Run through the name and copy out the bits we are
+ * interested in.
+ */
+ copy_namehook_lists(adb, find, qname, qtype, adbname, now);
+
+ post_copy:
+ if (NAME_FETCH_V4(adbname))
+ query_pending |= DNS_ADBFIND_INET;
+ if (NAME_FETCH_V6(adbname))
+ query_pending |= DNS_ADBFIND_INET6;
+
+ /*
+ * Attach to the name's query list if there are queries
+ * already running, and we have been asked to.
+ */
+ want_event = ISC_TRUE;
+ if (!FIND_WANTEVENT(find))
+ want_event = ISC_FALSE;
+ if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
+ want_event = ISC_FALSE;
+ if ((wanted_addresses & query_pending) == 0)
+ want_event = ISC_FALSE;
+ if (alias)
+ want_event = ISC_FALSE;
+ if (want_event) {
+ find->adbname = adbname;
+ find->name_bucket = bucket;
+ ISC_LIST_APPEND(adbname->finds, find, plink);
+ find->query_pending = (query_pending & wanted_addresses);
+ find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
+ find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
+ DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
+ find, adbname);
+ } else {
+ /*
+ * Remove the flag so the caller knows there will never
+ * be an event, and set internal flags to fake that
+ * the event was sent and freed, so dns_adb_destroyfind() will
+ * do the right thing.
+ */
+ find->query_pending = (query_pending & wanted_addresses);
+ find->options &= ~DNS_ADBFIND_WANTEVENT;
+ find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
+ find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
+ }
+
+ find->partial_result |= (adbname->partial_result & wanted_addresses);
+ if (alias) {
+ if (target != NULL) {
+ result = dns_name_copy(&adbname->target, target, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto out;
+ }
+ result = DNS_R_ALIAS;
+ } else
+ result = ISC_R_SUCCESS;
+
+ /*
+ * Copy out error flags from the name structure into the find.
+ */
+ find->result_v4 = find_err_map[adbname->fetch_err];
+ find->result_v6 = find_err_map[adbname->fetch6_err];
+
+ out:
+ if (find != NULL) {
+ *findp = find;
+
+ if (want_event) {
+ isc_task_t *taskp;
+
+ INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
+ taskp = NULL;
+ isc_task_attach(task, &taskp);
+ find->event.ev_sender = taskp;
+ find->event.ev_action = action;
+ find->event.ev_arg = arg;
+ }
+ }
+
+ UNLOCK(&adb->namelocks[bucket]);
+
+ return (result);
+}
+
+void
+dns_adb_destroyfind(dns_adbfind_t **findp) {
+ dns_adbfind_t *find;
+ dns_adbentry_t *entry;
+ dns_adbaddrinfo_t *ai;
+ int bucket;
+ dns_adb_t *adb;
+
+ REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
+ find = *findp;
+ *findp = NULL;
+
+ LOCK(&find->lock);
+
+ DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
+
+ adb = find->adb;
+ REQUIRE(DNS_ADB_VALID(adb));
+
+ REQUIRE(FIND_EVENTFREED(find));
+
+ bucket = find->name_bucket;
+ INSIST(bucket == DNS_ADB_INVALIDBUCKET);
+
+ UNLOCK(&find->lock);
+
+ /*
+ * The find doesn't exist on any list, and nothing is locked.
+ * Return the find to the memory pool, and decrement the adb's
+ * reference count.
+ */
+ ai = ISC_LIST_HEAD(find->list);
+ while (ai != NULL) {
+ ISC_LIST_UNLINK(find->list, ai, publink);
+ entry = ai->entry;
+ ai->entry = NULL;
+ INSIST(DNS_ADBENTRY_VALID(entry));
+ RUNTIME_CHECK(dec_entry_refcnt(adb, entry, ISC_TRUE) ==
+ ISC_FALSE);
+ free_adbaddrinfo(adb, &ai);
+ ai = ISC_LIST_HEAD(find->list);
+ }
+
+ /*
+ * WARNING: The find is freed with the adb locked. This is done
+ * to avoid a race condition where we free the find, some other
+ * thread tests to see if it should be destroyed, detects it should
+ * be, destroys it, and then we try to lock it for our check, but the
+ * lock is destroyed.
+ */
+ LOCK(&adb->lock);
+ if (free_adbfind(adb, &find))
+ check_exit(adb);
+ UNLOCK(&adb->lock);
+}
+
+void
+dns_adb_cancelfind(dns_adbfind_t *find) {
+ isc_event_t *ev;
+ isc_task_t *task;
+ dns_adb_t *adb;
+ int bucket;
+ int unlock_bucket;
+
+ LOCK(&find->lock);
+
+ DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
+
+ adb = find->adb;
+ REQUIRE(DNS_ADB_VALID(adb));
+
+ REQUIRE(!FIND_EVENTFREED(find));
+ REQUIRE(FIND_WANTEVENT(find));
+
+ bucket = find->name_bucket;
+ if (bucket == DNS_ADB_INVALIDBUCKET)
+ goto cleanup;
+
+ /*
+ * We need to get the adbname's lock to unlink the find.
+ */
+ unlock_bucket = bucket;
+ violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
+ bucket = find->name_bucket;
+ if (bucket != DNS_ADB_INVALIDBUCKET) {
+ ISC_LIST_UNLINK(find->adbname->finds, find, plink);
+ find->adbname = NULL;
+ find->name_bucket = DNS_ADB_INVALIDBUCKET;
+ }
+ UNLOCK(&adb->namelocks[unlock_bucket]);
+ bucket = DNS_ADB_INVALIDBUCKET;
+
+ cleanup:
+
+ if (!FIND_EVENTSENT(find)) {
+ ev = &find->event;
+ task = ev->ev_sender;
+ ev->ev_sender = find;
+ ev->ev_type = DNS_EVENT_ADBCANCELED;
+ ev->ev_destroy = event_free;
+ ev->ev_destroy_arg = find;
+ find->result_v4 = ISC_R_CANCELED;
+ find->result_v6 = ISC_R_CANCELED;
+
+ DP(DEF_LEVEL, "sending event %p to task %p for find %p",
+ ev, task, find);
+
+ isc_task_sendanddetach(&task, (isc_event_t **)&ev);
+ }
+
+ UNLOCK(&find->lock);
+}
+
+void
+dns_adb_dump(dns_adb_t *adb, FILE *f) {
+ int i;
+ isc_stdtime_t now;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(f != NULL);
+
+ /*
+ * Lock the adb itself, lock all the name buckets, then lock all
+ * the entry buckets. This should put the adb into a state where
+ * nothing can change, so we can iterate through everything and
+ * print at our leisure.
+ */
+
+ LOCK(&adb->lock);
+ isc_stdtime_get(&now);
+
+ for (i = 0; i < NBUCKETS; i++)
+ RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE);
+ for (i = 0; i < NBUCKETS; i++)
+ RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE);
+
+ dump_adb(adb, f, ISC_FALSE, now);
+ UNLOCK(&adb->lock);
+}
+
+static void
+dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
+ if (value == INT_MAX)
+ return;
+ fprintf(f, " [%s TTL %d]", legend, value - now);
+}
+
+static void
+dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
+ int i;
+ dns_adbname_t *name;
+ dns_adbentry_t *entry;
+
+ fprintf(f, ";\n; Address database dump\n;\n");
+ if (debug)
+ fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
+ adb, adb->erefcnt, adb->irefcnt,
+ isc_mempool_getallocated(adb->nhmp));
+
+ for (i = 0; i < NBUCKETS; i++)
+ LOCK(&adb->namelocks[i]);
+ for (i = 0; i < NBUCKETS; i++)
+ LOCK(&adb->entrylocks[i]);
+
+ /*
+ * Dump the names
+ */
+ for (i = 0; i < NBUCKETS; i++) {
+ name = ISC_LIST_HEAD(adb->names[i]);
+ if (name == NULL)
+ continue;
+ if (debug)
+ fprintf(f, "; bucket %d\n", i);
+ for (;
+ name != NULL;
+ name = ISC_LIST_NEXT(name, plink))
+ {
+ if (debug)
+ fprintf(f, "; name %p (flags %08x)\n",
+ name, name->flags);
+
+ fprintf(f, "; ");
+ print_dns_name(f, &name->name);
+ if (dns_name_countlabels(&name->target) > 0) {
+ fprintf(f, " alias ");
+ print_dns_name(f, &name->target);
+ }
+
+ dump_ttl(f, "v4", name->expire_v4, now);
+ dump_ttl(f, "v6", name->expire_v6, now);
+ dump_ttl(f, "target", name->expire_target, now);
+
+ fprintf(f, " [v4 %s] [v6 %s]",
+ errnames[name->fetch_err],
+ errnames[name->fetch6_err]);
+
+ fprintf(f, "\n");
+
+ print_namehook_list(f, "v4", &name->v4, debug, now);
+ print_namehook_list(f, "v6", &name->v6, debug, now);
+
+ if (debug)
+ print_fetch_list(f, name);
+ if (debug)
+ print_find_list(f, name);
+
+ }
+ }
+
+ fprintf(f, ";\n; Unassociated entries\n;\n");
+
+ for (i = 0; i < NBUCKETS; i++) {
+ entry = ISC_LIST_HEAD(adb->entries[i]);
+ while (entry != NULL) {
+ if (entry->refcnt == 0)
+ dump_entry(f, entry, debug, now);
+ entry = ISC_LIST_NEXT(entry, plink);
+ }
+ }
+
+ /*
+ * Unlock everything
+ */
+ for (i = 0; i < NBUCKETS; i++)
+ UNLOCK(&adb->entrylocks[i]);
+ for (i = 0; i < NBUCKETS; i++)
+ UNLOCK(&adb->namelocks[i]);
+}
+
+static void
+dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug,
+ isc_stdtime_t now)
+{
+ char addrbuf[ISC_NETADDR_FORMATSIZE];
+ char typebuf[DNS_RDATATYPE_FORMATSIZE];
+ isc_netaddr_t netaddr;
+ dns_adblameinfo_t *li;
+
+ isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
+ isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
+
+ if (debug)
+ fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
+
+ fprintf(f, ";\t%s [srtt %u] [flags %08x]",
+ addrbuf, entry->srtt, entry->flags);
+ if (entry->expires != 0)
+ fprintf(f, " [ttl %d]", entry->expires - now);
+ fprintf(f, "\n");
+ for (li = ISC_LIST_HEAD(entry->lameinfo);
+ li != NULL;
+ li = ISC_LIST_NEXT(li, plink)) {
+ fprintf(f, ";\t\t");
+ print_dns_name(f, &li->qname);
+ dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf));
+ fprintf(f, " %s [lame TTL %d]\n", typebuf,
+ li->lame_timer - now);
+ }
+}
+
+void
+dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
+ char tmp[512];
+ const char *tmpp;
+ dns_adbaddrinfo_t *ai;
+ isc_sockaddr_t *sa;
+
+ /*
+ * Not used currently, in the API Just In Case we
+ * want to dump out the name and/or entries too.
+ */
+
+ LOCK(&find->lock);
+
+ fprintf(f, ";Find %p\n", find);
+ fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
+ find->query_pending, find->partial_result,
+ find->options, find->flags);
+ fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
+ find->name_bucket, find->adbname, find->event.ev_sender);
+
+ ai = ISC_LIST_HEAD(find->list);
+ if (ai != NULL)
+ fprintf(f, "\tAddresses:\n");
+ while (ai != NULL) {
+ sa = &ai->sockaddr;
+ switch (sa->type.sa.sa_family) {
+ case AF_INET:
+ tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
+ tmp, sizeof(tmp));
+ break;
+ case AF_INET6:
+ tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
+ tmp, sizeof(tmp));
+ break;
+ default:
+ tmpp = "UnkFamily";
+ }
+
+ if (tmpp == NULL)
+ tmpp = "BadAddress";
+
+ fprintf(f, "\t\tentry %p, flags %08x"
+ " srtt %u addr %s\n",
+ ai->entry, ai->flags, ai->srtt, tmpp);
+
+ ai = ISC_LIST_NEXT(ai, publink);
+ }
+
+ UNLOCK(&find->lock);
+}
+
+static void
+print_dns_name(FILE *f, dns_name_t *name) {
+ char buf[DNS_NAME_FORMATSIZE];
+
+ INSIST(f != NULL);
+
+ dns_name_format(name, buf, sizeof(buf));
+ fprintf(f, "%s", buf);
+}
+
+static void
+print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list,
+ isc_boolean_t debug, isc_stdtime_t now)
+{
+ dns_adbnamehook_t *nh;
+
+ for (nh = ISC_LIST_HEAD(*list);
+ nh != NULL;
+ nh = ISC_LIST_NEXT(nh, plink))
+ {
+ if (debug)
+ fprintf(f, ";\tHook(%s) %p\n", legend, nh);
+ dump_entry(f, nh->entry, debug, now);
+ }
+}
+
+static inline void
+print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
+ fprintf(f, "\t\tFetch(%s): %p -> { nh %p, entry %p, fetch %p }\n",
+ type, ft, ft->namehook, ft->entry, ft->fetch);
+}
+
+static void
+print_fetch_list(FILE *f, dns_adbname_t *n) {
+ if (NAME_FETCH_A(n))
+ print_fetch(f, n->fetch_a, "A");
+ if (NAME_FETCH_AAAA(n))
+ print_fetch(f, n->fetch_aaaa, "AAAA");
+}
+
+static void
+print_find_list(FILE *f, dns_adbname_t *name) {
+ dns_adbfind_t *find;
+
+ find = ISC_LIST_HEAD(name->finds);
+ while (find != NULL) {
+ dns_adb_dumpfind(find, f);
+ find = ISC_LIST_NEXT(find, plink);
+ }
+}
+
+static isc_result_t
+dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
+{
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+ dns_adb_t *adb;
+ dns_fixedname_t foundname;
+ dns_name_t *fname;
+
+ INSIST(DNS_ADBNAME_VALID(adbname));
+ adb = adbname->adb;
+ INSIST(DNS_ADB_VALID(adb));
+ INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
+
+ dns_fixedname_init(&foundname);
+ fname = dns_fixedname_name(&foundname);
+ dns_rdataset_init(&rdataset);
+
+ if (rdtype == dns_rdatatype_a)
+ adbname->fetch_err = FIND_ERR_UNEXPECTED;
+ else
+ adbname->fetch6_err = FIND_ERR_UNEXPECTED;
+
+ result = dns_view_find(adb->view, &adbname->name, rdtype, now,
+ NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0,
+ ISC_TF(NAME_HINTOK(adbname)),
+ NULL, NULL, fname, &rdataset, NULL);
+
+ /* XXXVIX this switch statement is too sparse to gen a jump table. */
+ switch (result) {
+ case DNS_R_GLUE:
+ case DNS_R_HINT:
+ case ISC_R_SUCCESS:
+ /*
+ * Found in the database. Even if we can't copy out
+ * any information, return success, or else a fetch
+ * will be made, which will only make things worse.
+ */
+ if (rdtype == dns_rdatatype_a)
+ adbname->fetch_err = FIND_ERR_SUCCESS;
+ else
+ adbname->fetch6_err = FIND_ERR_SUCCESS;
+ result = import_rdataset(adbname, &rdataset, now);
+ break;
+ case DNS_R_NXDOMAIN:
+ case DNS_R_NXRRSET:
+ /*
+ * We're authoritative and the data doesn't exist.
+ * Make up a negative cache entry so we don't ask again
+ * for a while.
+ *
+ * XXXRTH What time should we use? I'm putting in 30 seconds
+ * for now.
+ */
+ if (rdtype == dns_rdatatype_a) {
+ adbname->expire_v4 = now + 30;
+ DP(NCACHE_LEVEL,
+ "adb name %p: Caching auth negative entry for A",
+ adbname);
+ if (result == DNS_R_NXDOMAIN)
+ adbname->fetch_err = FIND_ERR_NXDOMAIN;
+ else
+ adbname->fetch_err = FIND_ERR_NXRRSET;
+ } else {
+ DP(NCACHE_LEVEL,
+ "adb name %p: Caching auth negative entry for AAAA",
+ adbname);
+ adbname->expire_v6 = now + 30;
+ if (result == DNS_R_NXDOMAIN)
+ adbname->fetch6_err = FIND_ERR_NXDOMAIN;
+ else
+ adbname->fetch6_err = FIND_ERR_NXRRSET;
+ }
+ break;
+ case DNS_R_NCACHENXDOMAIN:
+ case DNS_R_NCACHENXRRSET:
+ /*
+ * We found a negative cache entry. Pull the TTL from it
+ * so we won't ask again for a while.
+ */
+ rdataset.ttl = ttlclamp(rdataset.ttl);
+ if (rdtype == dns_rdatatype_a) {
+ adbname->expire_v4 = rdataset.ttl + now;
+ if (result == DNS_R_NCACHENXDOMAIN)
+ adbname->fetch_err = FIND_ERR_NXDOMAIN;
+ else
+ adbname->fetch_err = FIND_ERR_NXRRSET;
+ DP(NCACHE_LEVEL,
+ "adb name %p: Caching negative entry for A (ttl %u)",
+ adbname, rdataset.ttl);
+ } else {
+ DP(NCACHE_LEVEL,
+ "adb name %p: Caching negative entry for AAAA (ttl %u)",
+ adbname, rdataset.ttl);
+ adbname->expire_v6 = rdataset.ttl + now;
+ if (result == DNS_R_NCACHENXDOMAIN)
+ adbname->fetch6_err = FIND_ERR_NXDOMAIN;
+ else
+ adbname->fetch6_err = FIND_ERR_NXRRSET;
+ }
+ break;
+ case DNS_R_CNAME:
+ case DNS_R_DNAME:
+ /*
+ * Clear the hint and glue flags, so this will match
+ * more often.
+ */
+ adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
+
+ rdataset.ttl = ttlclamp(rdataset.ttl);
+ clean_target(adb, &adbname->target);
+ adbname->expire_target = INT_MAX;
+ result = set_target(adb, &adbname->name, fname, &rdataset,
+ &adbname->target);
+ if (result == ISC_R_SUCCESS) {
+ result = DNS_R_ALIAS;
+ DP(NCACHE_LEVEL,
+ "adb name %p: caching alias target",
+ adbname);
+ adbname->expire_target = rdataset.ttl + now;
+ }
+ if (rdtype == dns_rdatatype_a)
+ adbname->fetch_err = FIND_ERR_SUCCESS;
+ else
+ adbname->fetch6_err = FIND_ERR_SUCCESS;
+ break;
+ }
+
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+
+ return (result);
+}
+
+static void
+fetch_callback(isc_task_t *task, isc_event_t *ev) {
+ dns_fetchevent_t *dev;
+ dns_adbname_t *name;
+ dns_adb_t *adb;
+ dns_adbfetch_t *fetch;
+ int bucket;
+ isc_eventtype_t ev_status;
+ isc_stdtime_t now;
+ isc_result_t result;
+ unsigned int address_type;
+ isc_boolean_t want_check_exit = ISC_FALSE;
+
+ UNUSED(task);
+
+ INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
+ dev = (dns_fetchevent_t *)ev;
+ name = ev->ev_arg;
+ INSIST(DNS_ADBNAME_VALID(name));
+ adb = name->adb;
+ INSIST(DNS_ADB_VALID(adb));
+
+ bucket = name->lock_bucket;
+ LOCK(&adb->namelocks[bucket]);
+
+ INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
+ address_type = 0;
+ if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
+ address_type = DNS_ADBFIND_INET;
+ fetch = name->fetch_a;
+ name->fetch_a = NULL;
+ } else if (NAME_FETCH_AAAA(name)
+ && (name->fetch_aaaa->fetch == dev->fetch)) {
+ address_type = DNS_ADBFIND_INET6;
+ fetch = name->fetch_aaaa;
+ name->fetch_aaaa = NULL;
+ }
+ INSIST(address_type != 0);
+
+ dns_resolver_destroyfetch(&fetch->fetch);
+ dev->fetch = NULL;
+
+ ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
+
+ /*
+ * Cleanup things we don't care about.
+ */
+ if (dev->node != NULL)
+ dns_db_detachnode(dev->db, &dev->node);
+ if (dev->db != NULL)
+ dns_db_detach(&dev->db);
+
+ /*
+ * If this name is marked as dead, clean up, throwing away
+ * potentially good data.
+ */
+ if (NAME_DEAD(name)) {
+ free_adbfetch(adb, &fetch);
+ isc_event_free(&ev);
+
+ want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
+
+ UNLOCK(&adb->namelocks[bucket]);
+
+ if (want_check_exit) {
+ LOCK(&adb->lock);
+ check_exit(adb);
+ UNLOCK(&adb->lock);
+ }
+
+ return;
+ }
+
+ isc_stdtime_get(&now);
+
+ /*
+ * If we got a negative cache response, remember it.
+ */
+ if (NCACHE_RESULT(dev->result)) {
+ dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
+ if (address_type == DNS_ADBFIND_INET) {
+ DP(NCACHE_LEVEL, "adb fetch name %p: "
+ "caching negative entry for A (ttl %u)",
+ name, dev->rdataset->ttl);
+ name->expire_v4 = ISC_MIN(name->expire_v4,
+ dev->rdataset->ttl + now);
+ if (dev->result == DNS_R_NCACHENXDOMAIN)
+ name->fetch_err = FIND_ERR_NXDOMAIN;
+ else
+ name->fetch_err = FIND_ERR_NXRRSET;
+ } else {
+ DP(NCACHE_LEVEL, "adb fetch name %p: "
+ "caching negative entry for AAAA (ttl %u)",
+ name, dev->rdataset->ttl);
+ name->expire_v6 = ISC_MIN(name->expire_v6,
+ dev->rdataset->ttl + now);
+ if (dev->result == DNS_R_NCACHENXDOMAIN)
+ name->fetch6_err = FIND_ERR_NXDOMAIN;
+ else
+ name->fetch6_err = FIND_ERR_NXRRSET;
+ }
+ goto out;
+ }
+
+ /*
+ * Handle CNAME/DNAME.
+ */
+ if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
+ dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
+ clean_target(adb, &name->target);
+ name->expire_target = INT_MAX;
+ result = set_target(adb, &name->name,
+ dns_fixedname_name(&dev->foundname),
+ dev->rdataset,
+ &name->target);
+ if (result == ISC_R_SUCCESS) {
+ DP(NCACHE_LEVEL,
+ "adb fetch name %p: caching alias target",
+ name);
+ name->expire_target = dev->rdataset->ttl + now;
+ }
+ goto check_result;
+ }
+
+ /*
+ * Did we get back junk? If so, and there are no more fetches
+ * sitting out there, tell all the finds about it.
+ */
+ if (dev->result != ISC_R_SUCCESS) {
+ char buf[DNS_NAME_FORMATSIZE];
+
+ dns_name_format(&name->name, buf, sizeof(buf));
+ DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
+ buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
+ dns_result_totext(dev->result));
+ /* XXXMLG Don't pound on bad servers. */
+ if (address_type == DNS_ADBFIND_INET) {
+ name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
+ name->fetch_err = FIND_ERR_FAILURE;
+ } else {
+ name->expire_v6 = ISC_MIN(name->expire_v6, now + 300);
+ name->fetch6_err = FIND_ERR_FAILURE;
+ }
+ goto out;
+ }
+
+ /*
+ * We got something potentially useful.
+ */
+ result = import_rdataset(name, &fetch->rdataset, now);
+
+ check_result:
+ if (result == ISC_R_SUCCESS) {
+ ev_status = DNS_EVENT_ADBMOREADDRESSES;
+ if (address_type == DNS_ADBFIND_INET)
+ name->fetch_err = FIND_ERR_SUCCESS;
+ else
+ name->fetch6_err = FIND_ERR_SUCCESS;
+ }
+
+ out:
+ free_adbfetch(adb, &fetch);
+ isc_event_free(&ev);
+
+ clean_finds_at_name(name, ev_status, address_type);
+
+ UNLOCK(&adb->namelocks[bucket]);
+}
+
+static isc_result_t
+fetch_name(dns_adbname_t *adbname,
+ isc_boolean_t start_at_zone,
+ dns_rdatatype_t type)
+{
+ isc_result_t result;
+ dns_adbfetch_t *fetch = NULL;
+ dns_adb_t *adb;
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+ dns_rdataset_t rdataset;
+ dns_rdataset_t *nameservers;
+ unsigned int options;
+
+ INSIST(DNS_ADBNAME_VALID(adbname));
+ adb = adbname->adb;
+ INSIST(DNS_ADB_VALID(adb));
+
+ INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
+ (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
+
+ adbname->fetch_err = FIND_ERR_NOTFOUND;
+
+ name = NULL;
+ nameservers = NULL;
+ dns_rdataset_init(&rdataset);
+
+ options = DNS_FETCHOPT_NOVALIDATE;
+ if (start_at_zone) {
+ DP(ENTER_LEVEL,
+ "fetch_name: starting at zone for name %p",
+ adbname);
+ dns_fixedname_init(&fixed);
+ name = dns_fixedname_name(&fixed);
+ result = dns_view_findzonecut2(adb->view, &adbname->name, name,
+ 0, 0, ISC_TRUE, ISC_FALSE,
+ &rdataset, NULL);
+ if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
+ goto cleanup;
+ nameservers = &rdataset;
+ options |= DNS_FETCHOPT_UNSHARED;
+ }
+
+ fetch = new_adbfetch(adb);
+ if (fetch == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
+ type, name, nameservers, NULL,
+ options, adb->task, fetch_callback,
+ adbname, &fetch->rdataset, NULL,
+ &fetch->fetch);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ if (type == dns_rdatatype_a)
+ adbname->fetch_a = fetch;
+ else
+ adbname->fetch_aaaa = fetch;
+ fetch = NULL; /* Keep us from cleaning this up below. */
+
+ cleanup:
+ if (fetch != NULL)
+ free_adbfetch(adb, &fetch);
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+
+ return (result);
+}
+
+/*
+ * XXXMLG Needs to take a find argument and an address info, no zone or adb,
+ * since these can be extracted from the find itself.
+ */
+isc_result_t
+dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname,
+ dns_rdatatype_t qtype, isc_stdtime_t expire_time)
+{
+ dns_adblameinfo_t *li;
+ int bucket;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+ REQUIRE(qname != NULL);
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+ li = ISC_LIST_HEAD(addr->entry->lameinfo);
+ while (li != NULL &&
+ (li->qtype != qtype || !dns_name_equal(qname, &li->qname)))
+ li = ISC_LIST_NEXT(li, plink);
+ if (li != NULL) {
+ if (expire_time > li->lame_timer)
+ li->lame_timer = expire_time;
+ goto unlock;
+ }
+ li = new_adblameinfo(adb, qname, qtype);
+ if (li == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto unlock;
+ }
+
+ li->lame_timer = expire_time;
+
+ ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink);
+ unlock:
+ UNLOCK(&adb->entrylocks[bucket]);
+
+ return (result);
+}
+
+void
+dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
+ unsigned int rtt, unsigned int factor)
+{
+ int bucket;
+ unsigned int new_srtt;
+ isc_stdtime_t now;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+ REQUIRE(factor <= 10);
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+
+ if (factor == DNS_ADB_RTTADJAGE)
+ new_srtt = addr->entry->srtt * 98 / 100;
+ else
+ new_srtt = (addr->entry->srtt / 10 * factor)
+ + (rtt / 10 * (10 - factor));
+
+ addr->entry->srtt = new_srtt;
+ addr->srtt = new_srtt;
+
+ isc_stdtime_get(&now);
+ addr->entry->expires = now + ADB_ENTRY_WINDOW;
+
+ UNLOCK(&adb->entrylocks[bucket]);
+}
+
+void
+dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
+ unsigned int bits, unsigned int mask)
+{
+ int bucket;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+
+ addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
+ /*
+ * Note that we do not update the other bits in addr->flags with
+ * the most recent values from addr->entry->flags.
+ */
+ addr->flags = (addr->flags & ~mask) | (bits & mask);
+
+ UNLOCK(&adb->entrylocks[bucket]);
+}
+
+isc_result_t
+dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
+ dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
+{
+ int bucket;
+ dns_adbentry_t *entry;
+ dns_adbaddrinfo_t *addr;
+ isc_result_t result;
+ in_port_t port;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(addrp != NULL && *addrp == NULL);
+
+ UNUSED(now);
+
+ result = ISC_R_SUCCESS;
+ bucket = DNS_ADB_INVALIDBUCKET;
+ entry = find_entry_and_lock(adb, sa, &bucket);
+ if (adb->entry_sd[bucket]) {
+ result = ISC_R_SHUTTINGDOWN;
+ goto unlock;
+ }
+ if (entry == NULL) {
+ /*
+ * We don't know anything about this address.
+ */
+ entry = new_adbentry(adb);
+ if (entry == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto unlock;
+ }
+ entry->sockaddr = *sa;
+ link_entry(adb, bucket, entry);
+ DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
+ } else
+ DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
+
+ port = isc_sockaddr_getport(sa);
+ addr = new_adbaddrinfo(adb, entry, port);
+ if (addr == NULL) {
+ result = ISC_R_NOMEMORY;
+ } else {
+ inc_entry_refcnt(adb, entry, ISC_FALSE);
+ *addrp = addr;
+ }
+
+ unlock:
+ UNLOCK(&adb->entrylocks[bucket]);
+
+ return (result);
+}
+
+void
+dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
+ dns_adbaddrinfo_t *addr;
+ dns_adbentry_t *entry;
+ int bucket;
+ isc_stdtime_t now;
+ isc_boolean_t want_check_exit = ISC_FALSE;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(addrp != NULL);
+ addr = *addrp;
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+ entry = addr->entry;
+ REQUIRE(DNS_ADBENTRY_VALID(entry));
+
+ isc_stdtime_get(&now);
+
+ *addrp = NULL;
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+
+ entry->expires = now + ADB_ENTRY_WINDOW;
+
+ want_check_exit = dec_entry_refcnt(adb, entry, ISC_FALSE);
+
+ UNLOCK(&adb->entrylocks[bucket]);
+
+ addr->entry = NULL;
+ free_adbaddrinfo(adb, &addr);
+
+ if (want_check_exit) {
+ LOCK(&adb->lock);
+ check_exit(adb);
+ UNLOCK(&adb->lock);
+ }
+}
+
+void
+dns_adb_flush(dns_adb_t *adb) {
+ unsigned int i;
+
+ INSIST(DNS_ADB_VALID(adb));
+
+ LOCK(&adb->lock);
+
+ /*
+ * Call our cleanup routines.
+ */
+ for (i = 0; i < NBUCKETS; i++)
+ RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
+ for (i = 0; i < NBUCKETS; i++)
+ RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
+
+#ifdef DUMP_ADB_AFTER_CLEANING
+ dump_adb(adb, stdout, ISC_TRUE, INT_MAX);
+#endif
+
+ UNLOCK(&adb->lock);
+}
+
+void
+dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
+ dns_adbname_t *adbname;
+ dns_adbname_t *nextname;
+ int bucket;
+
+ INSIST(DNS_ADB_VALID(adb));
+
+ LOCK(&adb->lock);
+ bucket = dns_name_hash(name, ISC_FALSE) % NBUCKETS;
+ LOCK(&adb->namelocks[bucket]);
+ adbname = ISC_LIST_HEAD(adb->names[bucket]);
+ while (adbname != NULL) {
+ nextname = ISC_LIST_NEXT(adbname, plink);
+ if (!NAME_DEAD(adbname) &&
+ dns_name_equal(name, &adbname->name)) {
+ RUNTIME_CHECK(kill_name(&adbname,
+ DNS_EVENT_ADBCANCELED) ==
+ ISC_FALSE);
+ }
+ adbname = nextname;
+ }
+ UNLOCK(&adb->namelocks[bucket]);
+ UNLOCK(&adb->lock);
+}
+
+static void
+water(void *arg, int mark) {
+ dns_adb_t *adb = arg;
+ isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
+ isc_interval_t interval;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+
+ DP(ISC_LOG_DEBUG(1),
+ "adb reached %s water mark", overmem ? "high" : "low");
+
+ adb->overmem = overmem;
+ if (overmem) {
+ isc_interval_set(&interval, 0, 1);
+ (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
+ &interval, ISC_TRUE);
+ }
+}
+
+void
+dns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size) {
+ isc_uint32_t hiwater;
+ isc_uint32_t lowater;
+
+ INSIST(DNS_ADB_VALID(adb));
+
+ if (size != 0 && size < DNS_ADB_MINADBSIZE)
+ size = DNS_ADB_MINADBSIZE;
+
+ hiwater = size - (size >> 3); /* Approximately 7/8ths. */
+ lowater = size - (size >> 2); /* Approximately 3/4ths. */
+
+ if (size == 0 || hiwater == 0 || lowater == 0)
+ isc_mem_setwater(adb->mctx, water, adb, 0, 0);
+ else
+ isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);
+}
diff --git a/lib/dns/api b/lib/dns/api
new file mode 100644
index 0000000..f830d6c
--- /dev/null
+++ b/lib/dns/api
@@ -0,0 +1,3 @@
+LIBINTERFACE = 34
+LIBREVISION = 2
+LIBAGE = 2
diff --git a/lib/dns/byaddr.c b/lib/dns/byaddr.c
new file mode 100644
index 0000000..38d6e8b
--- /dev/null
+++ b/lib/dns/byaddr.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2004, 2005 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: byaddr.c,v 1.34.18.3 2005/04/29 00:15:49 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/netaddr.h>
+#include <isc/print.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/task.h>
+#include <isc/util.h>
+
+#include <dns/byaddr.h>
+#include <dns/db.h>
+#include <dns/events.h>
+#include <dns/lookup.h>
+#include <dns/rdata.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+#include <dns/view.h>
+
+/*
+ * XXXRTH We could use a static event...
+ */
+
+struct dns_byaddr {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ isc_mutex_t lock;
+ dns_fixedname_t name;
+ /* Locked by lock. */
+ unsigned int options;
+ dns_lookup_t * lookup;
+ isc_task_t * task;
+ dns_byaddrevent_t * event;
+ isc_boolean_t canceled;
+};
+
+#define BYADDR_MAGIC ISC_MAGIC('B', 'y', 'A', 'd')
+#define VALID_BYADDR(b) ISC_MAGIC_VALID(b, BYADDR_MAGIC)
+
+#define MAX_RESTARTS 16
+
+static char hex_digits[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+};
+
+isc_result_t
+dns_byaddr_createptrname(isc_netaddr_t *address, isc_boolean_t nibble,
+ dns_name_t *name)
+{
+ /*
+ * We dropped bitstring labels, so all lookups will use nibbles.
+ */
+ UNUSED(nibble);
+
+ return (dns_byaddr_createptrname2(address,
+ DNS_BYADDROPT_IPV6INT, name));
+}
+
+isc_result_t
+dns_byaddr_createptrname2(isc_netaddr_t *address, unsigned int options,
+ dns_name_t *name)
+{
+ char textname[128];
+ unsigned char *bytes;
+ int i;
+ char *cp;
+ isc_buffer_t buffer;
+ unsigned int len;
+
+ REQUIRE(address != NULL);
+
+ /*
+ * We create the text representation and then convert to a
+ * dns_name_t. This is not maximally efficient, but it keeps all
+ * of the knowledge of wire format in the dns_name_ routines.
+ */
+
+ bytes = (unsigned char *)(&address->type);
+ if (address->family == AF_INET) {
+ (void)snprintf(textname, sizeof(textname),
+ "%u.%u.%u.%u.in-addr.arpa.",
+ (bytes[3] & 0xff),
+ (bytes[2] & 0xff),
+ (bytes[1] & 0xff),
+ (bytes[0] & 0xff));
+ } else if (address->family == AF_INET6) {
+ cp = textname;
+ for (i = 15; i >= 0; i--) {
+ *cp++ = hex_digits[bytes[i] & 0x0f];
+ *cp++ = '.';
+ *cp++ = hex_digits[(bytes[i] >> 4) & 0x0f];
+ *cp++ = '.';
+ }
+ if ((options & DNS_BYADDROPT_IPV6INT) != 0)
+ strcpy(cp, "ip6.int.");
+ else
+ strcpy(cp, "ip6.arpa.");
+ } else
+ return (ISC_R_NOTIMPLEMENTED);
+
+ len = (unsigned int)strlen(textname);
+ isc_buffer_init(&buffer, textname, len);
+ isc_buffer_add(&buffer, len);
+ return (dns_name_fromtext(name, &buffer, dns_rootname,
+ ISC_FALSE, NULL));
+}
+
+static inline isc_result_t
+copy_ptr_targets(dns_byaddr_t *byaddr, dns_rdataset_t *rdataset) {
+ isc_result_t result;
+ dns_name_t *name;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ /*
+ * The caller must be holding the byaddr's lock.
+ */
+
+ result = dns_rdataset_first(rdataset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdata_ptr_t ptr;
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &ptr, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ name = isc_mem_get(byaddr->mctx, sizeof(*name));
+ if (name == NULL) {
+ dns_rdata_freestruct(&ptr);
+ return (ISC_R_NOMEMORY);
+ }
+ dns_name_init(name, NULL);
+ result = dns_name_dup(&ptr.ptr, byaddr->mctx, name);
+ dns_rdata_freestruct(&ptr);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(byaddr->mctx, name, sizeof(*name));
+ return (ISC_R_NOMEMORY);
+ }
+ ISC_LIST_APPEND(byaddr->event->names, name, link);
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(rdataset);
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ return (result);
+}
+
+static void
+lookup_done(isc_task_t *task, isc_event_t *event) {
+ dns_byaddr_t *byaddr = event->ev_arg;
+ dns_lookupevent_t *levent;
+ isc_result_t result;
+
+ REQUIRE(event->ev_type == DNS_EVENT_LOOKUPDONE);
+ REQUIRE(VALID_BYADDR(byaddr));
+ REQUIRE(byaddr->task == task);
+
+ UNUSED(task);
+
+ levent = (dns_lookupevent_t *)event;
+
+ if (levent->result == ISC_R_SUCCESS) {
+ result = copy_ptr_targets(byaddr, levent->rdataset);
+ byaddr->event->result = result;
+ } else
+ byaddr->event->result = levent->result;
+ isc_event_free(&event);
+ isc_task_sendanddetach(&byaddr->task, (isc_event_t **)&byaddr->event);
+}
+
+static void
+bevent_destroy(isc_event_t *event) {
+ dns_byaddrevent_t *bevent;
+ dns_name_t *name, *next_name;
+ isc_mem_t *mctx;
+
+ REQUIRE(event->ev_type == DNS_EVENT_BYADDRDONE);
+ mctx = event->ev_destroy_arg;
+ bevent = (dns_byaddrevent_t *)event;
+
+ for (name = ISC_LIST_HEAD(bevent->names);
+ name != NULL;
+ name = next_name) {
+ next_name = ISC_LIST_NEXT(name, link);
+ ISC_LIST_UNLINK(bevent->names, name, link);
+ dns_name_free(name, mctx);
+ isc_mem_put(mctx, name, sizeof(*name));
+ }
+ isc_mem_put(mctx, event, event->ev_size);
+}
+
+isc_result_t
+dns_byaddr_create(isc_mem_t *mctx, isc_netaddr_t *address, dns_view_t *view,
+ unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg, dns_byaddr_t **byaddrp)
+{
+ isc_result_t result;
+ dns_byaddr_t *byaddr;
+ isc_event_t *ievent;
+
+ byaddr = isc_mem_get(mctx, sizeof(*byaddr));
+ if (byaddr == NULL)
+ return (ISC_R_NOMEMORY);
+ byaddr->mctx = mctx;
+ byaddr->options = options;
+
+ byaddr->event = isc_mem_get(mctx, sizeof(*byaddr->event));
+ if (byaddr->event == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_byaddr;
+ }
+ ISC_EVENT_INIT(byaddr->event, sizeof(*byaddr->event), 0, NULL,
+ DNS_EVENT_BYADDRDONE, action, arg, byaddr,
+ bevent_destroy, mctx);
+ byaddr->event->result = ISC_R_FAILURE;
+ ISC_LIST_INIT(byaddr->event->names);
+
+ byaddr->task = NULL;
+ isc_task_attach(task, &byaddr->task);
+
+ result = isc_mutex_init(&byaddr->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_event;
+
+ dns_fixedname_init(&byaddr->name);
+
+ result = dns_byaddr_createptrname2(address, options,
+ dns_fixedname_name(&byaddr->name));
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+
+ byaddr->lookup = NULL;
+ result = dns_lookup_create(mctx, dns_fixedname_name(&byaddr->name),
+ dns_rdatatype_ptr, view, 0, task,
+ lookup_done, byaddr, &byaddr->lookup);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+
+ byaddr->canceled = ISC_FALSE;
+ byaddr->magic = BYADDR_MAGIC;
+
+ *byaddrp = byaddr;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_lock:
+ DESTROYLOCK(&byaddr->lock);
+
+ cleanup_event:
+ ievent = (isc_event_t *)byaddr->event;
+ isc_event_free(&ievent);
+ byaddr->event = NULL;
+
+ isc_task_detach(&byaddr->task);
+
+ cleanup_byaddr:
+ isc_mem_put(mctx, byaddr, sizeof(*byaddr));
+
+ return (result);
+}
+
+void
+dns_byaddr_cancel(dns_byaddr_t *byaddr) {
+ REQUIRE(VALID_BYADDR(byaddr));
+
+ LOCK(&byaddr->lock);
+
+ if (!byaddr->canceled) {
+ byaddr->canceled = ISC_TRUE;
+ if (byaddr->lookup != NULL)
+ dns_lookup_cancel(byaddr->lookup);
+ }
+
+ UNLOCK(&byaddr->lock);
+}
+
+void
+dns_byaddr_destroy(dns_byaddr_t **byaddrp) {
+ dns_byaddr_t *byaddr;
+
+ REQUIRE(byaddrp != NULL);
+ byaddr = *byaddrp;
+ REQUIRE(VALID_BYADDR(byaddr));
+ REQUIRE(byaddr->event == NULL);
+ REQUIRE(byaddr->task == NULL);
+ dns_lookup_destroy(&byaddr->lookup);
+
+ DESTROYLOCK(&byaddr->lock);
+ byaddr->magic = 0;
+ isc_mem_put(byaddr->mctx, byaddr, sizeof(*byaddr));
+
+ *byaddrp = NULL;
+}
diff --git a/lib/dns/cache.c b/lib/dns/cache.c
new file mode 100644
index 0000000..011dbf7
--- /dev/null
+++ b/lib/dns/cache.c
@@ -0,0 +1,1154 @@
+/*
+ * Copyright (C) 2004-2006 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: cache.c,v 1.57.18.16 2006/08/01 01:06:48 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/cache.h>
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/events.h>
+#include <dns/lib.h>
+#include <dns/log.h>
+#include <dns/masterdump.h>
+#include <dns/rdata.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/result.h>
+
+#define CACHE_MAGIC ISC_MAGIC('$', '$', '$', '$')
+#define VALID_CACHE(cache) ISC_MAGIC_VALID(cache, CACHE_MAGIC)
+
+/*!
+ * Control incremental cleaning.
+ * DNS_CACHE_MINSIZE is how many bytes is the floor for dns_cache_setcachesize().
+ * See also DNS_CACHE_CLEANERINCREMENT
+ */
+#define DNS_CACHE_MINSIZE 2097152 /*%< Bytes. 2097152 = 2 MB */
+/*!
+ * Control incremental cleaning.
+ * CLEANERINCREMENT is how many nodes are examined in one pass.
+ * See also DNS_CACHE_MINSIZE
+ */
+#define DNS_CACHE_CLEANERINCREMENT 1000U /*%< Number of nodes. */
+
+/***
+ *** Types
+ ***/
+
+/*
+ * A cache_cleaner_t encapsulsates the state of the periodic
+ * cache cleaning.
+ */
+
+typedef struct cache_cleaner cache_cleaner_t;
+
+typedef enum {
+ cleaner_s_idle, /*%< Waiting for cleaning-interval to expire. */
+ cleaner_s_busy, /*%< Currently cleaning. */
+ cleaner_s_done /*%< Freed enough memory after being overmem. */
+} cleaner_state_t;
+
+/*
+ * Convenience macros for comprehensive assertion checking.
+ */
+#define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle && \
+ (c)->resched_event != NULL)
+#define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy && \
+ (c)->iterator != NULL && \
+ (c)->resched_event == NULL)
+
+/*%
+ * Accesses to a cache cleaner object are synchronized through
+ * task/event serialization, or locked from the cache object.
+ */
+struct cache_cleaner {
+ isc_mutex_t lock;
+ /*%<
+ * Locks overmem_event, overmem. Note: never allocate memory
+ * while holding this lock - that could lead to deadlock since
+ * the lock is take by water() which is called from the memory
+ * allocator.
+ */
+
+ dns_cache_t *cache;
+ isc_task_t *task;
+ unsigned int cleaning_interval; /*% The cleaning-interval from
+ named.conf, in seconds. */
+ isc_timer_t *cleaning_timer;
+ isc_event_t *resched_event; /*% Sent by cleaner task to
+ itself to reschedule */
+ isc_event_t *overmem_event;
+
+ dns_dbiterator_t *iterator;
+ unsigned int increment; /*% Number of names to
+ clean in one increment */
+ cleaner_state_t state; /*% Idle/Busy. */
+ isc_boolean_t overmem; /*% The cache is in an overmem state. */
+ isc_boolean_t replaceiterator;
+};
+
+/*%
+ * The actual cache object.
+ */
+
+struct dns_cache {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mutex_t lock;
+ isc_mutex_t filelock;
+ isc_mem_t *mctx;
+
+ /* Locked by 'lock'. */
+ int references;
+ int live_tasks;
+ dns_rdataclass_t rdclass;
+ dns_db_t *db;
+ cache_cleaner_t cleaner;
+ char *db_type;
+ int db_argc;
+ char **db_argv;
+
+ /* Locked by 'filelock'. */
+ char * filename;
+ /* Access to the on-disk cache file is also locked by 'filelock'. */
+};
+
+/***
+ *** Functions
+ ***/
+
+static isc_result_t
+cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
+ isc_timermgr_t *timermgr, cache_cleaner_t *cleaner);
+
+static void
+cleaning_timer_action(isc_task_t *task, isc_event_t *event);
+
+static void
+incremental_cleaning_action(isc_task_t *task, isc_event_t *event);
+
+static void
+cleaner_shutdown_action(isc_task_t *task, isc_event_t *event);
+
+static void
+overmem_cleaning_action(isc_task_t *task, isc_event_t *event);
+
+/*%
+ * Work out how many nodes can be cleaned in the time between two
+ * requests to the nameserver. Smooth the resulting number and use
+ * it as a estimate for the number of nodes to be cleaned in the next
+ * iteration.
+ */
+static void
+adjust_increment(cache_cleaner_t *cleaner, unsigned int remaining,
+ isc_time_t *start)
+{
+ isc_time_t end;
+ isc_uint64_t usecs;
+ isc_uint64_t new;
+ unsigned int pps = dns_pps;
+ unsigned int interval;
+ unsigned int names;
+
+ /*
+ * Tune for minumum of 100 packets per second (pps).
+ */
+ if (pps < 100)
+ pps = 100;
+
+ isc_time_now(&end);
+
+ interval = 1000000 / pps; /* Interval between packets in usecs. */
+ if (interval == 0)
+ interval = 1;
+
+ INSIST(cleaner->increment >= remaining);
+ names = cleaner->increment - remaining;
+ usecs = isc_time_microdiff(&end, start);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+ ISC_LOG_DEBUG(1), "adjust_increment interval=%u "
+ "names=%u usec=%" ISC_PLATFORM_QUADFORMAT "u",
+ interval, names, usecs);
+
+ if (usecs == 0) {
+ /*
+ * If we cleaned all the nodes in unmeasurable time
+ * double the number of nodes to be cleaned next time.
+ */
+ if (names == cleaner->increment) {
+ cleaner->increment *= 2;
+ if (cleaner->increment > DNS_CACHE_CLEANERINCREMENT)
+ cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+ "%p:new cleaner->increment = %u\n",
+ cleaner, cleaner->increment);
+ }
+ return;
+ }
+
+ new = (names * interval);
+ new /= (usecs * 2);
+ if (new == 0)
+ new = 1;
+
+ /* Smooth */
+ new = (new + cleaner->increment * 7) / 8;
+
+ if (new > DNS_CACHE_CLEANERINCREMENT)
+ new = DNS_CACHE_CLEANERINCREMENT;
+
+ cleaner->increment = (unsigned int)new;
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+ ISC_LOG_DEBUG(1), "%p:new cleaner->increment = %u\n",
+ cleaner, cleaner->increment);
+}
+
+static inline isc_result_t
+cache_create_db(dns_cache_t *cache, dns_db_t **db) {
+ return (dns_db_create(cache->mctx, cache->db_type, dns_rootname,
+ dns_dbtype_cache, cache->rdclass,
+ cache->db_argc, cache->db_argv, db));
+}
+
+isc_result_t
+dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
+ isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
+ const char *db_type, unsigned int db_argc, char **db_argv,
+ dns_cache_t **cachep)
+{
+ isc_result_t result;
+ dns_cache_t *cache;
+ int i;
+
+ REQUIRE(cachep != NULL);
+ REQUIRE(*cachep == NULL);
+ REQUIRE(mctx != NULL);
+
+ cache = isc_mem_get(mctx, sizeof(*cache));
+ if (cache == NULL)
+ return (ISC_R_NOMEMORY);
+
+ cache->mctx = NULL;
+ isc_mem_attach(mctx, &cache->mctx);
+
+ result = isc_mutex_init(&cache->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_mem;
+
+ result = isc_mutex_init(&cache->filelock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+
+ cache->references = 1;
+ cache->live_tasks = 0;
+ cache->rdclass = rdclass;
+
+ cache->db_type = isc_mem_strdup(mctx, db_type);
+ if (cache->db_type == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_filelock;
+ }
+
+ cache->db_argc = db_argc;
+ if (cache->db_argc == 0)
+ cache->db_argv = NULL;
+ else {
+ cache->db_argv = isc_mem_get(mctx,
+ cache->db_argc * sizeof(char *));
+ if (cache->db_argv == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_dbtype;
+ }
+ for (i = 0; i < cache->db_argc; i++)
+ cache->db_argv[i] = NULL;
+ for (i = 0; i < cache->db_argc; i++) {
+ cache->db_argv[i] = isc_mem_strdup(mctx, db_argv[i]);
+ if (cache->db_argv[i] == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_dbargv;
+ }
+ }
+ }
+
+ cache->db = NULL;
+ result = cache_create_db(cache, &cache->db);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_dbargv;
+
+ cache->filename = NULL;
+
+ cache->magic = CACHE_MAGIC;
+
+ result = cache_cleaner_init(cache, taskmgr, timermgr, &cache->cleaner);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_db;
+
+ *cachep = cache;
+ return (ISC_R_SUCCESS);
+
+ cleanup_db:
+ dns_db_detach(&cache->db);
+ cleanup_dbargv:
+ for (i = 0; i < cache->db_argc; i++)
+ if (cache->db_argv[i] != NULL)
+ isc_mem_free(mctx, cache->db_argv[i]);
+ if (cache->db_argv != NULL)
+ isc_mem_put(mctx, cache->db_argv,
+ cache->db_argc * sizeof(char *));
+ cleanup_dbtype:
+ isc_mem_free(mctx, cache->db_type);
+ cleanup_filelock:
+ DESTROYLOCK(&cache->filelock);
+ cleanup_lock:
+ DESTROYLOCK(&cache->lock);
+ cleanup_mem:
+ isc_mem_put(mctx, cache, sizeof(*cache));
+ isc_mem_detach(&mctx);
+ return (result);
+}
+
+static void
+cache_free(dns_cache_t *cache) {
+ isc_mem_t *mctx;
+ int i;
+
+ REQUIRE(VALID_CACHE(cache));
+ REQUIRE(cache->references == 0);
+
+ isc_mem_setwater(cache->mctx, NULL, NULL, 0, 0);
+
+ if (cache->cleaner.task != NULL)
+ isc_task_detach(&cache->cleaner.task);
+
+ if (cache->cleaner.overmem_event != NULL)
+ isc_event_free(&cache->cleaner.overmem_event);
+
+ if (cache->cleaner.resched_event != NULL)
+ isc_event_free(&cache->cleaner.resched_event);
+
+ if (cache->cleaner.iterator != NULL)
+ dns_dbiterator_destroy(&cache->cleaner.iterator);
+
+ DESTROYLOCK(&cache->cleaner.lock);
+
+ if (cache->filename) {
+ isc_mem_free(cache->mctx, cache->filename);
+ cache->filename = NULL;
+ }
+
+ if (cache->db != NULL)
+ dns_db_detach(&cache->db);
+
+ if (cache->db_argv != NULL) {
+ for (i = 0; i < cache->db_argc; i++)
+ if (cache->db_argv[i] != NULL)
+ isc_mem_free(cache->mctx, cache->db_argv[i]);
+ isc_mem_put(cache->mctx, cache->db_argv,
+ cache->db_argc * sizeof(char *));
+ }
+
+ if (cache->db_type != NULL)
+ isc_mem_free(cache->mctx, cache->db_type);
+
+ DESTROYLOCK(&cache->lock);
+ DESTROYLOCK(&cache->filelock);
+ cache->magic = 0;
+ mctx = cache->mctx;
+ isc_mem_put(cache->mctx, cache, sizeof(*cache));
+ isc_mem_detach(&mctx);
+}
+
+
+void
+dns_cache_attach(dns_cache_t *cache, dns_cache_t **targetp) {
+
+ REQUIRE(VALID_CACHE(cache));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ LOCK(&cache->lock);
+ cache->references++;
+ UNLOCK(&cache->lock);
+
+ *targetp = cache;
+}
+
+void
+dns_cache_detach(dns_cache_t **cachep) {
+ dns_cache_t *cache;
+ isc_boolean_t free_cache = ISC_FALSE;
+
+ REQUIRE(cachep != NULL);
+ cache = *cachep;
+ REQUIRE(VALID_CACHE(cache));
+
+ LOCK(&cache->lock);
+ REQUIRE(cache->references > 0);
+ cache->references--;
+ if (cache->references == 0) {
+ cache->cleaner.overmem = ISC_FALSE;
+ free_cache = ISC_TRUE;
+ }
+
+ *cachep = NULL;
+
+ if (free_cache) {
+ /*
+ * When the cache is shut down, dump it to a file if one is
+ * specified.
+ */
+ isc_result_t result = dns_cache_dump(cache);
+ if (result != ISC_R_SUCCESS)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
+ "error dumping cache: %s ",
+ isc_result_totext(result));
+
+ /*
+ * If the cleaner task exists, let it free the cache.
+ */
+ if (cache->live_tasks > 0) {
+ isc_task_shutdown(cache->cleaner.task);
+ free_cache = ISC_FALSE;
+ }
+ }
+
+ UNLOCK(&cache->lock);
+
+ if (free_cache)
+ cache_free(cache);
+}
+
+void
+dns_cache_attachdb(dns_cache_t *cache, dns_db_t **dbp) {
+ REQUIRE(VALID_CACHE(cache));
+ REQUIRE(dbp != NULL && *dbp == NULL);
+ REQUIRE(cache->db != NULL);
+
+ LOCK(&cache->lock);
+ dns_db_attach(cache->db, dbp);
+ UNLOCK(&cache->lock);
+
+}
+
+isc_result_t
+dns_cache_setfilename(dns_cache_t *cache, const char *filename) {
+ char *newname;
+
+ REQUIRE(VALID_CACHE(cache));
+ REQUIRE(filename != NULL);
+
+ newname = isc_mem_strdup(cache->mctx, filename);
+ if (newname == NULL)
+ return (ISC_R_NOMEMORY);
+
+ LOCK(&cache->filelock);
+ if (cache->filename)
+ isc_mem_free(cache->mctx, cache->filename);
+ cache->filename = newname;
+ UNLOCK(&cache->filelock);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_cache_load(dns_cache_t *cache) {
+ isc_result_t result;
+
+ REQUIRE(VALID_CACHE(cache));
+
+ if (cache->filename == NULL)
+ return (ISC_R_SUCCESS);
+
+ LOCK(&cache->filelock);
+ result = dns_db_load(cache->db, cache->filename);
+ UNLOCK(&cache->filelock);
+
+ return (result);
+}
+
+isc_result_t
+dns_cache_dump(dns_cache_t *cache) {
+ isc_result_t result;
+
+ REQUIRE(VALID_CACHE(cache));
+
+ if (cache->filename == NULL)
+ return (ISC_R_SUCCESS);
+
+ LOCK(&cache->filelock);
+ result = dns_master_dump(cache->mctx, cache->db, NULL,
+ &dns_master_style_cache, cache->filename);
+ UNLOCK(&cache->filelock);
+
+ return (result);
+}
+
+void
+dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int t) {
+ isc_interval_t interval;
+ isc_result_t result;
+
+ LOCK(&cache->lock);
+
+ /*
+ * It may be the case that the cache has already shut down.
+ * If so, it has no timer.
+ */
+ if (cache->cleaner.cleaning_timer == NULL)
+ goto unlock;
+
+ cache->cleaner.cleaning_interval = t;
+
+ if (t == 0) {
+ result = isc_timer_reset(cache->cleaner.cleaning_timer,
+ isc_timertype_inactive,
+ NULL, NULL, ISC_TRUE);
+ } else {
+ isc_interval_set(&interval, cache->cleaner.cleaning_interval,
+ 0);
+ result = isc_timer_reset(cache->cleaner.cleaning_timer,
+ isc_timertype_ticker,
+ NULL, &interval, ISC_FALSE);
+ }
+ if (result != ISC_R_SUCCESS)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
+ "could not set cache cleaning interval: %s",
+ isc_result_totext(result));
+
+ unlock:
+ UNLOCK(&cache->lock);
+}
+
+/*
+ * Initialize the cache cleaner object at *cleaner.
+ * Space for the object must be allocated by the caller.
+ */
+
+static isc_result_t
+cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
+ isc_timermgr_t *timermgr, cache_cleaner_t *cleaner)
+{
+ isc_result_t result;
+
+ result = isc_mutex_init(&cleaner->lock);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+
+ cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
+ cleaner->state = cleaner_s_idle;
+ cleaner->cache = cache;
+ cleaner->iterator = NULL;
+ cleaner->overmem = ISC_FALSE;
+ cleaner->replaceiterator = ISC_FALSE;
+
+ cleaner->task = NULL;
+ cleaner->cleaning_timer = NULL;
+ cleaner->resched_event = NULL;
+ cleaner->overmem_event = NULL;
+
+ result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
+ &cleaner->iterator);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ if (taskmgr != NULL && timermgr != NULL) {
+ result = isc_task_create(taskmgr, 1, &cleaner->task);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_task_create() failed: %s",
+ dns_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+ cleaner->cache->live_tasks++;
+ isc_task_setname(cleaner->task, "cachecleaner", cleaner);
+
+ result = isc_task_onshutdown(cleaner->task,
+ cleaner_shutdown_action, cache);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "cache cleaner: "
+ "isc_task_onshutdown() failed: %s",
+ dns_result_totext(result));
+ goto cleanup;
+ }
+
+ cleaner->cleaning_interval = 0; /* Initially turned off. */
+ result = isc_timer_create(timermgr, isc_timertype_inactive,
+ NULL, NULL,
+ cleaner->task,
+ cleaning_timer_action, cleaner,
+ &cleaner->cleaning_timer);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_timer_create() failed: %s",
+ dns_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+
+ cleaner->resched_event =
+ isc_event_allocate(cache->mctx, cleaner,
+ DNS_EVENT_CACHECLEAN,
+ incremental_cleaning_action,
+ cleaner, sizeof(isc_event_t));
+ if (cleaner->resched_event == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ cleaner->overmem_event =
+ isc_event_allocate(cache->mctx, cleaner,
+ DNS_EVENT_CACHEOVERMEM,
+ overmem_cleaning_action,
+ cleaner, sizeof(isc_event_t));
+ if (cleaner->overmem_event == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ }
+
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (cleaner->overmem_event != NULL)
+ isc_event_free(&cleaner->overmem_event);
+ if (cleaner->resched_event != NULL)
+ isc_event_free(&cleaner->resched_event);
+ if (cleaner->cleaning_timer != NULL)
+ isc_timer_detach(&cleaner->cleaning_timer);
+ if (cleaner->task != NULL)
+ isc_task_detach(&cleaner->task);
+ if (cleaner->iterator != NULL)
+ dns_dbiterator_destroy(&cleaner->iterator);
+ DESTROYLOCK(&cleaner->lock);
+ fail:
+ return (result);
+}
+
+static void
+begin_cleaning(cache_cleaner_t *cleaner) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(CLEANER_IDLE(cleaner));
+
+ /*
+ * Create an iterator, if it does not already exist, and
+ * position it at the beginning of the cache.
+ */
+ if (cleaner->iterator == NULL)
+ result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
+ &cleaner->iterator);
+ if (result != ISC_R_SUCCESS)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
+ "cache cleaner could not create "
+ "iterator: %s", isc_result_totext(result));
+ else {
+ dns_dbiterator_setcleanmode(cleaner->iterator, ISC_TRUE);
+ result = dns_dbiterator_first(cleaner->iterator);
+ }
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * If the result is ISC_R_NOMORE, the database is empty,
+ * so there is nothing to be cleaned.
+ */
+ if (result != ISC_R_NOMORE && cleaner->iterator != NULL) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "cache cleaner: "
+ "dns_dbiterator_first() failed: %s",
+ dns_result_totext(result));
+ dns_dbiterator_destroy(&cleaner->iterator);
+ } else if (cleaner->iterator != NULL) {
+ result = dns_dbiterator_pause(cleaner->iterator);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ }
+ } else {
+ /*
+ * Pause the iterator to free its lock.
+ */
+ result = dns_dbiterator_pause(cleaner->iterator);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+ "begin cache cleaning, mem inuse %lu",
+ (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
+ cleaner->state = cleaner_s_busy;
+ isc_task_send(cleaner->task, &cleaner->resched_event);
+ }
+
+ return;
+}
+
+static void
+end_cleaning(cache_cleaner_t *cleaner, isc_event_t *event) {
+ isc_result_t result;
+
+ REQUIRE(CLEANER_BUSY(cleaner));
+ REQUIRE(event != NULL);
+
+ result = dns_dbiterator_pause(cleaner->iterator);
+ if (result != ISC_R_SUCCESS)
+ dns_dbiterator_destroy(&cleaner->iterator);
+
+ dns_cache_setcleaninginterval(cleaner->cache,
+ cleaner->cleaning_interval);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+ ISC_LOG_DEBUG(1), "end cache cleaning, mem inuse %lu",
+ (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
+
+ cleaner->state = cleaner_s_idle;
+ cleaner->resched_event = event;
+}
+
+/*
+ * This is run once for every cache-cleaning-interval as defined in named.conf.
+ */
+static void
+cleaning_timer_action(isc_task_t *task, isc_event_t *event) {
+ cache_cleaner_t *cleaner = event->ev_arg;
+
+ UNUSED(task);
+
+ INSIST(task == cleaner->task);
+ INSIST(event->ev_type == ISC_TIMEREVENT_TICK);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+ ISC_LOG_DEBUG(1), "cache cleaning timer fired, "
+ "cleaner state = %d", cleaner->state);
+
+ if (cleaner->state == cleaner_s_idle)
+ begin_cleaning(cleaner);
+
+ isc_event_free(&event);
+}
+
+/*
+ * This is called when the cache either surpasses its upper limit
+ * or shrinks beyond its lower limit.
+ */
+static void
+overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
+ cache_cleaner_t *cleaner = event->ev_arg;
+ isc_boolean_t want_cleaning = ISC_FALSE;
+
+ UNUSED(task);
+
+ INSIST(task == cleaner->task);
+ INSIST(event->ev_type == DNS_EVENT_CACHEOVERMEM);
+ INSIST(cleaner->overmem_event == NULL);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+ ISC_LOG_DEBUG(1), "overmem_cleaning_action called, "
+ "overmem = %d, state = %d", cleaner->overmem,
+ cleaner->state);
+
+ LOCK(&cleaner->lock);
+
+ if (cleaner->overmem) {
+ if (cleaner->state == cleaner_s_idle)
+ want_cleaning = ISC_TRUE;
+ } else {
+ if (cleaner->state == cleaner_s_busy)
+ /*
+ * end_cleaning() can't be called here because
+ * then both cleaner->overmem_event and
+ * cleaner->resched_event will point to this
+ * event. Set the state to done, and then
+ * when the incremental_cleaning_action() event
+ * is posted, it will handle the end_cleaning.
+ */
+ cleaner->state = cleaner_s_done;
+ }
+
+ cleaner->overmem_event = event;
+
+ UNLOCK(&cleaner->lock);
+
+ if (want_cleaning)
+ begin_cleaning(cleaner);
+}
+
+/*
+ * Do incremental cleaning.
+ */
+static void
+incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
+ cache_cleaner_t *cleaner = event->ev_arg;
+ isc_result_t result;
+ unsigned int n_names;
+ isc_time_t start;
+
+ UNUSED(task);
+
+ INSIST(task == cleaner->task);
+ INSIST(event->ev_type == DNS_EVENT_CACHECLEAN);
+
+ if (cleaner->state == cleaner_s_done) {
+ cleaner->state = cleaner_s_busy;
+ end_cleaning(cleaner, event);
+ LOCK(&cleaner->cache->lock);
+ LOCK(&cleaner->lock);
+ if (cleaner->replaceiterator) {
+ dns_dbiterator_destroy(&cleaner->iterator);
+ (void) dns_db_createiterator(cleaner->cache->db,
+ ISC_FALSE,
+ &cleaner->iterator);
+ cleaner->replaceiterator = ISC_FALSE;
+ }
+ UNLOCK(&cleaner->lock);
+ UNLOCK(&cleaner->cache->lock);
+ return;
+ }
+
+ INSIST(CLEANER_BUSY(cleaner));
+
+ n_names = cleaner->increment;
+
+ REQUIRE(DNS_DBITERATOR_VALID(cleaner->iterator));
+
+ isc_time_now(&start);
+ while (n_names-- > 0) {
+ dns_dbnode_t *node = NULL;
+
+ result = dns_dbiterator_current(cleaner->iterator, &node,
+ NULL);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "cache cleaner: dns_dbiterator_current() "
+ "failed: %s", dns_result_totext(result));
+
+ adjust_increment(cleaner, n_names, &start);
+ end_cleaning(cleaner, event);
+ return;
+ }
+
+ /*
+ * The node was not needed, but was required by
+ * dns_dbiterator_current(). Give up its reference.
+ */
+ dns_db_detachnode(cleaner->cache->db, &node);
+
+ /*
+ * Step to the next node.
+ */
+ result = dns_dbiterator_next(cleaner->iterator);
+
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * Either the end was reached (ISC_R_NOMORE) or
+ * some error was signaled. If the cache is still
+ * overmem and no error was encountered,
+ * keep trying to clean it, otherwise stop cleaning.
+ */
+ if (result != ISC_R_NOMORE)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "cache cleaner: "
+ "dns_dbiterator_next() "
+ "failed: %s",
+ dns_result_totext(result));
+ else if (cleaner->overmem) {
+ result = dns_dbiterator_first(cleaner->
+ iterator);
+ if (result == ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE,
+ ISC_LOG_DEBUG(1),
+ "cache cleaner: "
+ "still overmem, "
+ "reset and try again");
+ continue;
+ }
+ }
+
+ adjust_increment(cleaner, n_names, &start);
+ end_cleaning(cleaner, event);
+ return;
+ }
+ }
+
+ adjust_increment(cleaner, 0U, &start);
+
+ /*
+ * We have successfully performed a cleaning increment but have
+ * not gone through the entire cache. Free the iterator locks
+ * and reschedule another batch. If it fails, just try to continue
+ * anyway.
+ */
+ result = dns_dbiterator_pause(cleaner->iterator);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+ ISC_LOG_DEBUG(1), "cache cleaner: checked %u nodes, "
+ "mem inuse %lu, sleeping", cleaner->increment,
+ (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
+
+ isc_task_send(task, &event);
+ INSIST(CLEANER_BUSY(cleaner));
+ return;
+}
+
+/*
+ * Do immediate cleaning.
+ */
+isc_result_t
+dns_cache_clean(dns_cache_t *cache, isc_stdtime_t now) {
+ isc_result_t result;
+ dns_dbiterator_t *iterator = NULL;
+
+ REQUIRE(VALID_CACHE(cache));
+
+ result = dns_db_createiterator(cache->db, ISC_FALSE, &iterator);
+ if (result != ISC_R_SUCCESS)
+ return result;
+
+ result = dns_dbiterator_first(iterator);
+
+ while (result == ISC_R_SUCCESS) {
+ dns_dbnode_t *node = NULL;
+ result = dns_dbiterator_current(iterator, &node,
+ (dns_name_t *)NULL);
+ if (result != ISC_R_SUCCESS)
+ break;
+
+ /*
+ * Check TTLs, mark expired rdatasets stale.
+ */
+ result = dns_db_expirenode(cache->db, node, now);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "cache cleaner: dns_db_expirenode() "
+ "failed: %s",
+ dns_result_totext(result));
+ /*
+ * Continue anyway.
+ */
+ }
+
+ /*
+ * This is where the actual freeing takes place.
+ */
+ dns_db_detachnode(cache->db, &node);
+
+ result = dns_dbiterator_next(iterator);
+ }
+
+ dns_dbiterator_destroy(&iterator);
+
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ return (result);
+}
+
+static void
+water(void *arg, int mark) {
+ dns_cache_t *cache = arg;
+ isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
+
+ REQUIRE(VALID_CACHE(cache));
+
+ LOCK(&cache->cleaner.lock);
+
+ dns_db_overmem(cache->db, overmem);
+ cache->cleaner.overmem = overmem;
+
+ if (cache->cleaner.overmem_event != NULL)
+ isc_task_send(cache->cleaner.task,
+ &cache->cleaner.overmem_event);
+
+ UNLOCK(&cache->cleaner.lock);
+}
+
+void
+dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size) {
+ isc_uint32_t lowater;
+ isc_uint32_t hiwater;
+
+ REQUIRE(VALID_CACHE(cache));
+
+ /*
+ * Impose a minumum cache size; pathological things happen if there
+ * is too little room.
+ */
+ if (size != 0 && size < DNS_CACHE_MINSIZE)
+ size = DNS_CACHE_MINSIZE;
+
+ hiwater = size - (size >> 3); /* Approximately 7/8ths. */
+ lowater = size - (size >> 2); /* Approximately 3/4ths. */
+
+ /*
+ * If the cache was overmem and cleaning, but now with the new limits
+ * it is no longer in an overmem condition, then the next
+ * isc_mem_put for cache memory will do the right thing and trigger
+ * water().
+ */
+
+ if (size == 0 || hiwater == 0 || lowater == 0)
+ /*
+ * Disable cache memory limiting.
+ */
+ isc_mem_setwater(cache->mctx, water, cache, 0, 0);
+ else
+ /*
+ * Establish new cache memory limits (either for the first
+ * time, or replacing other limits).
+ */
+ isc_mem_setwater(cache->mctx, water, cache, hiwater, lowater);
+}
+
+/*
+ * The cleaner task is shutting down; do the necessary cleanup.
+ */
+static void
+cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
+ dns_cache_t *cache = event->ev_arg;
+ isc_boolean_t should_free = ISC_FALSE;
+
+ UNUSED(task);
+
+ INSIST(task == cache->cleaner.task);
+ INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
+
+ if (CLEANER_BUSY(&cache->cleaner))
+ end_cleaning(&cache->cleaner, event);
+ else
+ isc_event_free(&event);
+
+ LOCK(&cache->lock);
+
+ cache->live_tasks--;
+ INSIST(cache->live_tasks == 0);
+
+ if (cache->references == 0)
+ should_free = ISC_TRUE;
+
+ /*
+ * By detaching the timer in the context of its task,
+ * we are guaranteed that there will be no further timer
+ * events.
+ */
+ if (cache->cleaner.cleaning_timer != NULL)
+ isc_timer_detach(&cache->cleaner.cleaning_timer);
+
+ /* Make sure we don't reschedule anymore. */
+ (void)isc_task_purge(task, NULL, DNS_EVENT_CACHECLEAN, NULL);
+
+ UNLOCK(&cache->lock);
+
+ if (should_free)
+ cache_free(cache);
+}
+
+isc_result_t
+dns_cache_flush(dns_cache_t *cache) {
+ dns_db_t *db = NULL;
+ isc_result_t result;
+
+ result = cache_create_db(cache, &db);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ LOCK(&cache->lock);
+ LOCK(&cache->cleaner.lock);
+ if (cache->cleaner.state == cleaner_s_idle) {
+ if (cache->cleaner.iterator != NULL)
+ dns_dbiterator_destroy(&cache->cleaner.iterator);
+ (void) dns_db_createiterator(db, ISC_FALSE,
+ &cache->cleaner.iterator);
+ } else {
+ if (cache->cleaner.state == cleaner_s_busy)
+ cache->cleaner.state = cleaner_s_done;
+ cache->cleaner.replaceiterator = ISC_TRUE;
+ }
+ dns_db_detach(&cache->db);
+ cache->db = db;
+ UNLOCK(&cache->cleaner.lock);
+ UNLOCK(&cache->lock);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_cache_flushname(dns_cache_t *cache, dns_name_t *name) {
+ isc_result_t result;
+ dns_rdatasetiter_t *iter = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_db_t *db = NULL;
+
+ LOCK(&cache->lock);
+ if (cache->db != NULL)
+ dns_db_attach(cache->db, &db);
+ UNLOCK(&cache->lock);
+ if (db == NULL)
+ return (ISC_R_SUCCESS);
+ result = dns_db_findnode(cache->db, name, ISC_FALSE, &node);
+ if (result == ISC_R_NOTFOUND) {
+ result = ISC_R_SUCCESS;
+ goto cleanup_db;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_db;
+
+ result = dns_db_allrdatasets(cache->db, node, NULL,
+ (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 = dns_db_deleterdataset(cache->db, node, NULL,
+ rdataset.type, rdataset.covers);
+ dns_rdataset_disassociate(&rdataset);
+ if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED)
+ break;
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ dns_rdatasetiter_destroy(&iter);
+
+ cleanup_node:
+ dns_db_detachnode(cache->db, &node);
+
+ cleanup_db:
+ dns_db_detach(&db);
+ return (result);
+}
diff --git a/lib/dns/callbacks.c b/lib/dns/callbacks.c
new file mode 100644
index 0000000..a487ed0
--- /dev/null
+++ b/lib/dns/callbacks.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2004, 2005 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: callbacks.c,v 1.13.18.2 2005/04/29 00:15:49 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/util.h>
+
+#include <dns/callbacks.h>
+#include <dns/log.h>
+
+static void
+stdio_error_warn_callback(dns_rdatacallbacks_t *, const char *, ...)
+ ISC_FORMAT_PRINTF(2, 3);
+
+static void
+isclog_error_callback(dns_rdatacallbacks_t *callbacks, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(2, 3);
+
+static void
+isclog_warn_callback(dns_rdatacallbacks_t *callbacks, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(2, 3);
+
+/*
+ * Private
+ */
+
+static void
+stdio_error_warn_callback(dns_rdatacallbacks_t *callbacks,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ UNUSED(callbacks);
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void
+isclog_error_callback(dns_rdatacallbacks_t *callbacks, const char *fmt, ...) {
+ va_list ap;
+
+ UNUSED(callbacks);
+
+ va_start(ap, fmt);
+ isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTER, /* XXX */
+ ISC_LOG_ERROR, fmt, ap);
+ va_end(ap);
+}
+
+static void
+isclog_warn_callback(dns_rdatacallbacks_t *callbacks, const char *fmt, ...) {
+ va_list ap;
+
+ UNUSED(callbacks);
+
+ va_start(ap, fmt);
+
+ isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTER, /* XXX */
+ ISC_LOG_WARNING, fmt, ap);
+ va_end(ap);
+}
+
+static void
+dns_rdatacallbacks_initcommon(dns_rdatacallbacks_t *callbacks) {
+ REQUIRE(callbacks != NULL);
+
+ callbacks->add = NULL;
+ callbacks->add_private = NULL;
+ callbacks->error_private = NULL;
+ callbacks->warn_private = NULL;
+}
+
+/*
+ * Public.
+ */
+
+void
+dns_rdatacallbacks_init(dns_rdatacallbacks_t *callbacks) {
+ dns_rdatacallbacks_initcommon(callbacks);
+ callbacks->error = isclog_error_callback;
+ callbacks->warn = isclog_warn_callback;
+}
+
+void
+dns_rdatacallbacks_init_stdio(dns_rdatacallbacks_t *callbacks) {
+ dns_rdatacallbacks_initcommon(callbacks);
+ callbacks->error = stdio_error_warn_callback;
+ callbacks->warn = stdio_error_warn_callback;
+}
+
diff --git a/lib/dns/compress.c b/lib/dns/compress.c
new file mode 100644
index 0000000..2103767
--- /dev/null
+++ b/lib/dns/compress.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2004-2006 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: compress.c,v 1.52.18.5 2006/03/02 00:37:21 marka Exp $ */
+
+/*! \file */
+
+#define DNS_NAME_USEINLINE 1
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/compress.h>
+#include <dns/fixedname.h>
+#include <dns/rbt.h>
+#include <dns/result.h>
+
+#define CCTX_MAGIC ISC_MAGIC('C', 'C', 'T', 'X')
+#define VALID_CCTX(x) ISC_MAGIC_VALID(x, CCTX_MAGIC)
+
+#define DCTX_MAGIC ISC_MAGIC('D', 'C', 'T', 'X')
+#define VALID_DCTX(x) ISC_MAGIC_VALID(x, DCTX_MAGIC)
+
+/***
+ *** Compression
+ ***/
+
+isc_result_t
+dns_compress_init(dns_compress_t *cctx, int edns, isc_mem_t *mctx) {
+ unsigned int i;
+
+ REQUIRE(cctx != NULL);
+ REQUIRE(mctx != NULL); /* See: rdataset.c:towiresorted(). */
+
+ cctx->allowed = 0;
+ cctx->edns = edns;
+ for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++)
+ cctx->table[i] = NULL;
+ cctx->mctx = mctx;
+ cctx->count = 0;
+ cctx->magic = CCTX_MAGIC;
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_compress_invalidate(dns_compress_t *cctx) {
+ dns_compressnode_t *node;
+ unsigned int i;
+
+ REQUIRE(VALID_CCTX(cctx));
+
+ cctx->magic = 0;
+ for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) {
+ while (cctx->table[i] != NULL) {
+ node = cctx->table[i];
+ cctx->table[i] = cctx->table[i]->next;
+ if (node->count < DNS_COMPRESS_INITIALNODES)
+ continue;
+ isc_mem_put(cctx->mctx, node, sizeof(*node));
+ }
+ }
+ cctx->allowed = 0;
+ cctx->edns = -1;
+}
+
+void
+dns_compress_setmethods(dns_compress_t *cctx, unsigned int allowed) {
+ REQUIRE(VALID_CCTX(cctx));
+
+ cctx->allowed &= ~DNS_COMPRESS_ALL;
+ cctx->allowed |= (allowed & DNS_COMPRESS_ALL);
+}
+
+unsigned int
+dns_compress_getmethods(dns_compress_t *cctx) {
+ REQUIRE(VALID_CCTX(cctx));
+ return (cctx->allowed & DNS_COMPRESS_ALL);
+}
+
+void
+dns_compress_setsensitive(dns_compress_t *cctx, isc_boolean_t sensitive) {
+ REQUIRE(VALID_CCTX(cctx));
+
+ if (sensitive)
+ cctx->allowed |= DNS_COMPRESS_CASESENSITIVE;
+ else
+ cctx->allowed &= ~DNS_COMPRESS_CASESENSITIVE;
+}
+
+isc_boolean_t
+dns_compress_getsensitive(dns_compress_t *cctx) {
+ REQUIRE(VALID_CCTX(cctx));
+
+ return (ISC_TF((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0));
+}
+
+int
+dns_compress_getedns(dns_compress_t *cctx) {
+ REQUIRE(VALID_CCTX(cctx));
+ return (cctx->edns);
+}
+
+#define NODENAME(node, name) \
+do { \
+ (name)->length = (node)->r.length; \
+ (name)->labels = (node)->labels; \
+ (name)->ndata = (node)->r.base; \
+ (name)->attributes = DNS_NAMEATTR_ABSOLUTE; \
+} while (0)
+
+/*
+ * Find the longest match of name in the table.
+ * If match is found return ISC_TRUE. prefix, suffix and offset are updated.
+ * If no match is found return ISC_FALSE.
+ */
+isc_boolean_t
+dns_compress_findglobal(dns_compress_t *cctx, const dns_name_t *name,
+ dns_name_t *prefix, isc_uint16_t *offset)
+{
+ dns_name_t tname, nname;
+ dns_compressnode_t *node = NULL;
+ unsigned int labels, hash, n;
+
+ REQUIRE(VALID_CCTX(cctx));
+ REQUIRE(dns_name_isabsolute(name) == ISC_TRUE);
+ REQUIRE(offset != NULL);
+
+ if (cctx->count == 0)
+ return (ISC_FALSE);
+
+ labels = dns_name_countlabels(name);
+ INSIST(labels > 0);
+
+ dns_name_init(&tname, NULL);
+ dns_name_init(&nname, NULL);
+
+ for (n = 0; n < labels - 1; n++) {
+ dns_name_getlabelsequence(name, n, labels - n, &tname);
+ hash = dns_name_hash(&tname, ISC_FALSE) %
+ DNS_COMPRESS_TABLESIZE;
+ for (node = cctx->table[hash]; node != NULL; node = node->next)
+ {
+ NODENAME(node, &nname);
+ if ((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0) {
+ if (dns_name_caseequal(&nname, &tname))
+ break;
+ } else {
+ if (dns_name_equal(&nname, &tname))
+ break;
+ }
+ }
+ if (node != NULL)
+ break;
+ }
+
+ /*
+ * If node == NULL, we found no match at all.
+ */
+ if (node == NULL)
+ return (ISC_FALSE);
+
+ if (n == 0)
+ dns_name_reset(prefix);
+ else
+ dns_name_getlabelsequence(name, 0, n, prefix);
+
+ *offset = node->offset;
+ return (ISC_TRUE);
+}
+
+static inline unsigned int
+name_length(const dns_name_t *name) {
+ isc_region_t r;
+ dns_name_toregion(name, &r);
+ return (r.length);
+}
+
+void
+dns_compress_add(dns_compress_t *cctx, const dns_name_t *name,
+ const dns_name_t *prefix, isc_uint16_t offset)
+{
+ dns_name_t tname;
+ unsigned int start;
+ unsigned int n;
+ unsigned int count;
+ unsigned int hash;
+ dns_compressnode_t *node;
+ unsigned int length;
+ unsigned int tlength;
+ isc_uint16_t toffset;
+
+ REQUIRE(VALID_CCTX(cctx));
+ REQUIRE(dns_name_isabsolute(name));
+
+ dns_name_init(&tname, NULL);
+
+ n = dns_name_countlabels(name);
+ count = dns_name_countlabels(prefix);
+ if (dns_name_isabsolute(prefix))
+ count--;
+ start = 0;
+ length = name_length(name);
+ while (count > 0) {
+ if (offset >= 0x4000)
+ break;
+ dns_name_getlabelsequence(name, start, n, &tname);
+ hash = dns_name_hash(&tname, ISC_FALSE) %
+ DNS_COMPRESS_TABLESIZE;
+ tlength = name_length(&tname);
+ toffset = (isc_uint16_t)(offset + (length - tlength));
+ /*
+ * Create a new node and add it.
+ */
+ if (cctx->count < DNS_COMPRESS_INITIALNODES)
+ node = &cctx->initialnodes[cctx->count];
+ else {
+ node = isc_mem_get(cctx->mctx,
+ sizeof(dns_compressnode_t));
+ if (node == NULL)
+ return;
+ }
+ node->count = cctx->count++;
+ node->offset = toffset;
+ dns_name_toregion(&tname, &node->r);
+ node->labels = (isc_uint8_t)dns_name_countlabels(&tname);
+ node->next = cctx->table[hash];
+ cctx->table[hash] = node;
+ start++;
+ n--;
+ count--;
+ }
+}
+
+void
+dns_compress_rollback(dns_compress_t *cctx, isc_uint16_t offset) {
+ unsigned int i;
+ dns_compressnode_t *node;
+
+ REQUIRE(VALID_CCTX(cctx));
+
+ for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) {
+ node = cctx->table[i];
+ /*
+ * This relies on nodes with greater offsets being
+ * closer to the beginning of the list, and the
+ * items with the greatest offsets being at the end
+ * of the initialnodes[] array.
+ */
+ while (node != NULL && node->offset >= offset) {
+ cctx->table[i] = node->next;
+ if (node->count >= DNS_COMPRESS_INITIALNODES)
+ isc_mem_put(cctx->mctx, node, sizeof(*node));
+ cctx->count--;
+ node = cctx->table[i];
+ }
+ }
+}
+
+/***
+ *** Decompression
+ ***/
+
+void
+dns_decompress_init(dns_decompress_t *dctx, int edns,
+ dns_decompresstype_t type) {
+
+ REQUIRE(dctx != NULL);
+ REQUIRE(edns >= -1 && edns <= 255);
+
+ dctx->allowed = DNS_COMPRESS_NONE;
+ dctx->edns = edns;
+ dctx->type = type;
+ dctx->magic = DCTX_MAGIC;
+}
+
+void
+dns_decompress_invalidate(dns_decompress_t *dctx) {
+
+ REQUIRE(VALID_DCTX(dctx));
+
+ dctx->magic = 0;
+}
+
+void
+dns_decompress_setmethods(dns_decompress_t *dctx, unsigned int allowed) {
+
+ REQUIRE(VALID_DCTX(dctx));
+
+ switch (dctx->type) {
+ case DNS_DECOMPRESS_ANY:
+ dctx->allowed = DNS_COMPRESS_ALL;
+ break;
+ case DNS_DECOMPRESS_NONE:
+ dctx->allowed = DNS_COMPRESS_NONE;
+ break;
+ case DNS_DECOMPRESS_STRICT:
+ dctx->allowed = allowed;
+ break;
+ }
+}
+
+unsigned int
+dns_decompress_getmethods(dns_decompress_t *dctx) {
+
+ REQUIRE(VALID_DCTX(dctx));
+
+ return (dctx->allowed);
+}
+
+int
+dns_decompress_edns(dns_decompress_t *dctx) {
+
+ REQUIRE(VALID_DCTX(dctx));
+
+ return (dctx->edns);
+}
+
+dns_decompresstype_t
+dns_decompress_type(dns_decompress_t *dctx) {
+
+ REQUIRE(VALID_DCTX(dctx));
+
+ return (dctx->type);
+}
diff --git a/lib/dns/db.c b/lib/dns/db.c
new file mode 100644
index 0000000..32ff6ae
--- /dev/null
+++ b/lib/dns/db.c
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2004, 2005 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: db.c,v 1.74.18.6 2005/10/13 02:12:24 marka Exp $ */
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <config.h>
+
+#include <isc/buffer.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/rwlock.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/callbacks.h>
+#include <dns/db.h>
+#include <dns/log.h>
+#include <dns/master.h>
+#include <dns/rdata.h>
+#include <dns/rdataset.h>
+#include <dns/result.h>
+
+/***
+ *** Private Types
+ ***/
+
+struct dns_dbimplementation {
+ const char * name;
+ dns_dbcreatefunc_t create;
+ isc_mem_t * mctx;
+ void * driverarg;
+ ISC_LINK(dns_dbimplementation_t) link;
+};
+
+/***
+ *** Supported DB Implementations Registry
+ ***/
+
+/*
+ * Built in database implementations are registered here.
+ */
+
+#include "rbtdb.h"
+#include "rbtdb64.h"
+
+static ISC_LIST(dns_dbimplementation_t) implementations;
+static isc_rwlock_t implock;
+static isc_once_t once = ISC_ONCE_INIT;
+
+static dns_dbimplementation_t rbtimp;
+static dns_dbimplementation_t rbt64imp;
+
+static void
+initialize(void) {
+ RUNTIME_CHECK(isc_rwlock_init(&implock, 0, 0) == ISC_R_SUCCESS);
+
+ rbtimp.name = "rbt";
+ rbtimp.create = dns_rbtdb_create;
+ rbtimp.mctx = NULL;
+ rbtimp.driverarg = NULL;
+ ISC_LINK_INIT(&rbtimp, link);
+
+ rbt64imp.name = "rbt64";
+ rbt64imp.create = dns_rbtdb64_create;
+ rbt64imp.mctx = NULL;
+ rbt64imp.driverarg = NULL;
+ ISC_LINK_INIT(&rbt64imp, link);
+
+ ISC_LIST_INIT(implementations);
+ ISC_LIST_APPEND(implementations, &rbtimp, link);
+ ISC_LIST_APPEND(implementations, &rbt64imp, link);
+}
+
+static inline dns_dbimplementation_t *
+impfind(const char *name) {
+ dns_dbimplementation_t *imp;
+
+ for (imp = ISC_LIST_HEAD(implementations);
+ imp != NULL;
+ imp = ISC_LIST_NEXT(imp, link))
+ if (strcasecmp(name, imp->name) == 0)
+ return (imp);
+ return (NULL);
+}
+
+
+/***
+ *** Basic DB Methods
+ ***/
+
+isc_result_t
+dns_db_create(isc_mem_t *mctx, const char *db_type, dns_name_t *origin,
+ dns_dbtype_t type, dns_rdataclass_t rdclass,
+ unsigned int argc, char *argv[], dns_db_t **dbp)
+{
+ dns_dbimplementation_t *impinfo;
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
+
+ /*
+ * Create a new database using implementation 'db_type'.
+ */
+
+ REQUIRE(dbp != NULL && *dbp == NULL);
+ REQUIRE(dns_name_isabsolute(origin));
+
+ RWLOCK(&implock, isc_rwlocktype_read);
+ impinfo = impfind(db_type);
+ if (impinfo != NULL) {
+ isc_result_t result;
+ result = ((impinfo->create)(mctx, origin, type,
+ rdclass, argc, argv,
+ impinfo->driverarg, dbp));
+ RWUNLOCK(&implock, isc_rwlocktype_read);
+ return (result);
+ }
+
+ RWUNLOCK(&implock, isc_rwlocktype_read);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DB, ISC_LOG_ERROR,
+ "unsupported database type '%s'", db_type);
+
+ return (ISC_R_NOTFOUND);
+}
+
+void
+dns_db_attach(dns_db_t *source, dns_db_t **targetp) {
+
+ /*
+ * Attach *targetp to source.
+ */
+
+ REQUIRE(DNS_DB_VALID(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ (source->methods->attach)(source, targetp);
+
+ ENSURE(*targetp == source);
+}
+
+void
+dns_db_detach(dns_db_t **dbp) {
+
+ /*
+ * Detach *dbp from its database.
+ */
+
+ REQUIRE(dbp != NULL);
+ REQUIRE(DNS_DB_VALID(*dbp));
+
+ ((*dbp)->methods->detach)(dbp);
+
+ ENSURE(*dbp == NULL);
+}
+
+isc_result_t
+dns_db_ondestroy(dns_db_t *db, isc_task_t *task, isc_event_t **eventp)
+{
+ REQUIRE(DNS_DB_VALID(db));
+
+ return (isc_ondestroy_register(&db->ondest, task, eventp));
+}
+
+
+isc_boolean_t
+dns_db_iscache(dns_db_t *db) {
+
+ /*
+ * Does 'db' have cache semantics?
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+
+ if ((db->attributes & DNS_DBATTR_CACHE) != 0)
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_db_iszone(dns_db_t *db) {
+
+ /*
+ * Does 'db' have zone semantics?
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+
+ if ((db->attributes & (DNS_DBATTR_CACHE|DNS_DBATTR_STUB)) == 0)
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_db_isstub(dns_db_t *db) {
+
+ /*
+ * Does 'db' have stub semantics?
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+
+ if ((db->attributes & DNS_DBATTR_STUB) != 0)
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_db_issecure(dns_db_t *db) {
+
+ /*
+ * Is 'db' secure?
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
+
+ return ((db->methods->issecure)(db));
+}
+
+isc_boolean_t
+dns_db_ispersistent(dns_db_t *db) {
+
+ /*
+ * Is 'db' persistent?
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+
+ return ((db->methods->ispersistent)(db));
+}
+
+dns_name_t *
+dns_db_origin(dns_db_t *db) {
+ /*
+ * The origin of the database.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+
+ return (&db->origin);
+}
+
+dns_rdataclass_t
+dns_db_class(dns_db_t *db) {
+ /*
+ * The class of the database.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+
+ return (db->rdclass);
+}
+
+isc_result_t
+dns_db_beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp,
+ dns_dbload_t **dbloadp) {
+ /*
+ * Begin loading 'db'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(addp != NULL && *addp == NULL);
+ REQUIRE(dbloadp != NULL && *dbloadp == NULL);
+
+ return ((db->methods->beginload)(db, addp, dbloadp));
+}
+
+isc_result_t
+dns_db_endload(dns_db_t *db, dns_dbload_t **dbloadp) {
+ /*
+ * Finish loading 'db'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(dbloadp != NULL && *dbloadp != NULL);
+
+ return ((db->methods->endload)(db, dbloadp));
+}
+
+isc_result_t
+dns_db_load(dns_db_t *db, const char *filename) {
+ return (dns_db_load2(db, filename, dns_masterformat_text));
+}
+
+isc_result_t
+dns_db_load2(dns_db_t *db, const char *filename, dns_masterformat_t format) {
+ isc_result_t result, eresult;
+ dns_rdatacallbacks_t callbacks;
+ unsigned int options = 0;
+
+ /*
+ * Load master file 'filename' into 'db'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+
+ if ((db->attributes & DNS_DBATTR_CACHE) != 0)
+ options |= DNS_MASTER_AGETTL;
+
+ dns_rdatacallbacks_init(&callbacks);
+
+ result = dns_db_beginload(db, &callbacks.add, &callbacks.add_private);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dns_master_loadfile2(filename, &db->origin, &db->origin,
+ db->rdclass, options,
+ &callbacks, db->mctx, format);
+ eresult = dns_db_endload(db, &callbacks.add_private);
+ /*
+ * We always call dns_db_endload(), but we only want to return its
+ * result if dns_master_loadfile() succeeded. If dns_master_loadfile()
+ * failed, we want to return the result code it gave us.
+ */
+ if (eresult != ISC_R_SUCCESS &&
+ (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE))
+ result = eresult;
+
+ return (result);
+}
+
+isc_result_t
+dns_db_dump(dns_db_t *db, dns_dbversion_t *version, const char *filename) {
+ return ((db->methods->dump)(db, version, filename,
+ dns_masterformat_text));
+}
+
+isc_result_t
+dns_db_dump2(dns_db_t *db, dns_dbversion_t *version, const char *filename,
+ dns_masterformat_t masterformat) {
+ /*
+ * Dump 'db' into master file 'filename' in the 'masterformat' format.
+ * XXXJT: is it okay to modify the interface to the existing "dump"
+ * method?
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+
+ return ((db->methods->dump)(db, version, filename, masterformat));
+}
+
+/***
+ *** Version Methods
+ ***/
+
+void
+dns_db_currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
+
+ /*
+ * Open the current version for reading.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
+ REQUIRE(versionp != NULL && *versionp == NULL);
+
+ (db->methods->currentversion)(db, versionp);
+}
+
+isc_result_t
+dns_db_newversion(dns_db_t *db, dns_dbversion_t **versionp) {
+
+ /*
+ * Open a new version for reading and writing.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
+ REQUIRE(versionp != NULL && *versionp == NULL);
+
+ return ((db->methods->newversion)(db, versionp));
+}
+
+void
+dns_db_attachversion(dns_db_t *db, dns_dbversion_t *source,
+ dns_dbversion_t **targetp)
+{
+ /*
+ * Attach '*targetp' to 'source'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
+ REQUIRE(source != NULL);
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ (db->methods->attachversion)(db, source, targetp);
+
+ ENSURE(*targetp != NULL);
+}
+
+void
+dns_db_closeversion(dns_db_t *db, dns_dbversion_t **versionp,
+ isc_boolean_t commit)
+{
+
+ /*
+ * Close version '*versionp'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
+ REQUIRE(versionp != NULL && *versionp != NULL);
+
+ (db->methods->closeversion)(db, versionp, commit);
+
+ ENSURE(*versionp == NULL);
+}
+
+/***
+ *** Node Methods
+ ***/
+
+isc_result_t
+dns_db_findnode(dns_db_t *db, dns_name_t *name,
+ isc_boolean_t create, dns_dbnode_t **nodep)
+{
+
+ /*
+ * Find the node with name 'name'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(nodep != NULL && *nodep == NULL);
+
+ return ((db->methods->findnode)(db, name, create, nodep));
+}
+
+isc_result_t
+dns_db_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
+ dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
+ dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+
+ /*
+ * Find the best match for 'name' and 'type' in version 'version'
+ * of 'db'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(type != dns_rdatatype_rrsig);
+ REQUIRE(nodep == NULL || (nodep != NULL && *nodep == NULL));
+ REQUIRE(dns_name_hasbuffer(foundname));
+ REQUIRE(rdataset == NULL ||
+ (DNS_RDATASET_VALID(rdataset) &&
+ ! dns_rdataset_isassociated(rdataset)));
+ REQUIRE(sigrdataset == NULL ||
+ (DNS_RDATASET_VALID(sigrdataset) &&
+ ! dns_rdataset_isassociated(sigrdataset)));
+
+ return ((db->methods->find)(db, name, version, type, options, now,
+ nodep, foundname, rdataset, sigrdataset));
+}
+
+isc_result_t
+dns_db_findzonecut(dns_db_t *db, dns_name_t *name,
+ unsigned int options, isc_stdtime_t now,
+ dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ /*
+ * Find the deepest known zonecut which encloses 'name' in 'db'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
+ REQUIRE(nodep == NULL || (nodep != NULL && *nodep == NULL));
+ REQUIRE(dns_name_hasbuffer(foundname));
+ REQUIRE(sigrdataset == NULL ||
+ (DNS_RDATASET_VALID(sigrdataset) &&
+ ! dns_rdataset_isassociated(sigrdataset)));
+
+ return ((db->methods->findzonecut)(db, name, options, now, nodep,
+ foundname, rdataset, sigrdataset));
+}
+
+void
+dns_db_attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
+
+ /*
+ * Attach *targetp to source.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(source != NULL);
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ (db->methods->attachnode)(db, source, targetp);
+}
+
+void
+dns_db_detachnode(dns_db_t *db, dns_dbnode_t **nodep) {
+
+ /*
+ * Detach *nodep from its node.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(nodep != NULL && *nodep != NULL);
+
+ (db->methods->detachnode)(db, nodep);
+
+ ENSURE(*nodep == NULL);
+}
+
+isc_result_t
+dns_db_expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
+
+ /*
+ * Mark as stale all records at 'node' which expire at or before 'now'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
+ REQUIRE(node != NULL);
+
+ return ((db->methods->expirenode)(db, node, now));
+}
+
+void
+dns_db_printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
+ /*
+ * Print a textual representation of the contents of the node to
+ * 'out'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(node != NULL);
+
+ (db->methods->printnode)(db, node, out);
+}
+
+/***
+ *** DB Iterator Creation
+ ***/
+
+isc_result_t
+dns_db_createiterator(dns_db_t *db, isc_boolean_t relative_names,
+ dns_dbiterator_t **iteratorp)
+{
+ /*
+ * Create an iterator for version 'version' of 'db'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(iteratorp != NULL && *iteratorp == NULL);
+
+ return (db->methods->createiterator(db, relative_names, iteratorp));
+}
+
+/***
+ *** Rdataset Methods
+ ***/
+
+isc_result_t
+dns_db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers,
+ isc_stdtime_t now, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset)
+{
+ /*
+ * Search for an rdataset of type 'type' at 'node' that are in version
+ * 'version' of 'db'. If found, make 'rdataset' refer to it.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(node != NULL);
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(! dns_rdataset_isassociated(rdataset));
+ REQUIRE(covers == 0 || type == dns_rdatatype_rrsig);
+ REQUIRE(type != dns_rdatatype_any);
+ REQUIRE(sigrdataset == NULL ||
+ (DNS_RDATASET_VALID(sigrdataset) &&
+ ! dns_rdataset_isassociated(sigrdataset)));
+
+ return ((db->methods->findrdataset)(db, node, version, type, covers,
+ now, rdataset, sigrdataset));
+}
+
+isc_result_t
+dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
+{
+ /*
+ * Make '*iteratorp' an rdataset iteratator for all rdatasets at
+ * 'node' in version 'version' of 'db'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(iteratorp != NULL && *iteratorp == NULL);
+
+ return ((db->methods->allrdatasets)(db, node, version, now,
+ iteratorp));
+}
+
+isc_result_t
+dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdataset_t *rdataset,
+ unsigned int options, dns_rdataset_t *addedrdataset)
+{
+ /*
+ * Add 'rdataset' to 'node' in version 'version' of 'db'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(node != NULL);
+ REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)||
+ ((db->attributes & DNS_DBATTR_CACHE) != 0 &&
+ version == NULL && (options & DNS_DBADD_MERGE) == 0));
+ REQUIRE((options & DNS_DBADD_EXACT) == 0 ||
+ (options & DNS_DBADD_MERGE) != 0);
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(dns_rdataset_isassociated(rdataset));
+ REQUIRE(rdataset->rdclass == db->rdclass);
+ REQUIRE(addedrdataset == NULL ||
+ (DNS_RDATASET_VALID(addedrdataset) &&
+ ! dns_rdataset_isassociated(addedrdataset)));
+
+ return ((db->methods->addrdataset)(db, node, version, now, rdataset,
+ options, addedrdataset));
+}
+
+isc_result_t
+dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version, dns_rdataset_t *rdataset,
+ unsigned int options, dns_rdataset_t *newrdataset)
+{
+ /*
+ * Remove any rdata in 'rdataset' from 'node' in version 'version' of
+ * 'db'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(node != NULL);
+ REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL);
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(dns_rdataset_isassociated(rdataset));
+ REQUIRE(rdataset->rdclass == db->rdclass);
+ REQUIRE(newrdataset == NULL ||
+ (DNS_RDATASET_VALID(newrdataset) &&
+ ! dns_rdataset_isassociated(newrdataset)));
+
+ return ((db->methods->subtractrdataset)(db, node, version, rdataset,
+ options, newrdataset));
+}
+
+isc_result_t
+dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version, dns_rdatatype_t type,
+ dns_rdatatype_t covers)
+{
+ /*
+ * Make it so that no rdataset of type 'type' exists at 'node' in
+ * version version 'version' of 'db'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(node != NULL);
+ REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)||
+ ((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL));
+
+ return ((db->methods->deleterdataset)(db, node, version,
+ type, covers));
+}
+
+void
+dns_db_overmem(dns_db_t *db, isc_boolean_t overmem) {
+
+ REQUIRE(DNS_DB_VALID(db));
+
+ (db->methods->overmem)(db, overmem);
+}
+
+isc_result_t
+dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, isc_uint32_t *serialp)
+{
+ isc_result_t result;
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_buffer_t buffer;
+
+ REQUIRE(dns_db_iszone(db) || dns_db_isstub(db));
+
+ result = dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0,
+ (isc_stdtime_t)0, &rdataset, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto freenode;
+
+ result = dns_rdataset_first(&rdataset);
+ if (result != ISC_R_SUCCESS)
+ goto freerdataset;
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdataset_next(&rdataset);
+ INSIST(result == ISC_R_NOMORE);
+
+ INSIST(rdata.length > 20);
+ isc_buffer_init(&buffer, rdata.data, rdata.length);
+ isc_buffer_add(&buffer, rdata.length);
+ isc_buffer_forward(&buffer, rdata.length - 20);
+ *serialp = isc_buffer_getuint32(&buffer);
+
+ result = ISC_R_SUCCESS;
+
+ freerdataset:
+ dns_rdataset_disassociate(&rdataset);
+
+ freenode:
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+unsigned int
+dns_db_nodecount(dns_db_t *db) {
+ REQUIRE(DNS_DB_VALID(db));
+
+ return ((db->methods->nodecount)(db));
+}
+
+void
+dns_db_settask(dns_db_t *db, isc_task_t *task) {
+ REQUIRE(DNS_DB_VALID(db));
+
+ (db->methods->settask)(db, task);
+}
+
+isc_result_t
+dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg,
+ isc_mem_t *mctx, dns_dbimplementation_t **dbimp)
+{
+ dns_dbimplementation_t *imp;
+
+ REQUIRE(name != NULL);
+ REQUIRE(dbimp != NULL && *dbimp == NULL);
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
+
+ RWLOCK(&implock, isc_rwlocktype_write);
+ imp = impfind(name);
+ if (imp != NULL) {
+ RWUNLOCK(&implock, isc_rwlocktype_write);
+ return (ISC_R_EXISTS);
+ }
+
+ imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t));
+ if (imp == NULL) {
+ RWUNLOCK(&implock, isc_rwlocktype_write);
+ return (ISC_R_NOMEMORY);
+ }
+ imp->name = name;
+ imp->create = create;
+ imp->mctx = NULL;
+ imp->driverarg = driverarg;
+ isc_mem_attach(mctx, &imp->mctx);
+ ISC_LINK_INIT(imp, link);
+ ISC_LIST_APPEND(implementations, imp, link);
+ RWUNLOCK(&implock, isc_rwlocktype_write);
+
+ *dbimp = imp;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_db_unregister(dns_dbimplementation_t **dbimp) {
+ dns_dbimplementation_t *imp;
+ isc_mem_t *mctx;
+
+ REQUIRE(dbimp != NULL && *dbimp != NULL);
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
+
+ imp = *dbimp;
+ RWLOCK(&implock, isc_rwlocktype_write);
+ ISC_LIST_UNLINK(implementations, imp, link);
+ mctx = imp->mctx;
+ isc_mem_put(mctx, imp, sizeof(dns_dbimplementation_t));
+ isc_mem_detach(&mctx);
+ RWUNLOCK(&implock, isc_rwlocktype_write);
+}
+
+isc_result_t
+dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(dns_db_iszone(db) == ISC_TRUE);
+ REQUIRE(nodep != NULL && *nodep == NULL);
+
+ if (db->methods->getoriginnode != NULL)
+ return ((db->methods->getoriginnode)(db, nodep));
+
+ return (ISC_R_NOTFOUND);
+}
diff --git a/lib/dns/dbiterator.c b/lib/dns/dbiterator.c
new file mode 100644
index 0000000..d462ad5
--- /dev/null
+++ b/lib/dns/dbiterator.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2004, 2005 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: dbiterator.c,v 1.14.18.2 2005/04/29 00:15:50 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/util.h>
+
+#include <dns/dbiterator.h>
+#include <dns/name.h>
+
+void
+dns_dbiterator_destroy(dns_dbiterator_t **iteratorp) {
+ /*
+ * Destroy '*iteratorp'.
+ */
+
+ REQUIRE(iteratorp != NULL);
+ REQUIRE(DNS_DBITERATOR_VALID(*iteratorp));
+
+ (*iteratorp)->methods->destroy(iteratorp);
+
+ ENSURE(*iteratorp == NULL);
+}
+
+isc_result_t
+dns_dbiterator_first(dns_dbiterator_t *iterator) {
+ /*
+ * Move the node cursor to the first node in the database (if any).
+ */
+
+ REQUIRE(DNS_DBITERATOR_VALID(iterator));
+
+ return (iterator->methods->first(iterator));
+}
+
+isc_result_t
+dns_dbiterator_last(dns_dbiterator_t *iterator) {
+ /*
+ * Move the node cursor to the first node in the database (if any).
+ */
+
+ REQUIRE(DNS_DBITERATOR_VALID(iterator));
+
+ return (iterator->methods->last(iterator));
+}
+
+isc_result_t
+dns_dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
+ /*
+ * Move the node cursor to the node with name 'name'.
+ */
+
+ REQUIRE(DNS_DBITERATOR_VALID(iterator));
+
+ return (iterator->methods->seek(iterator, name));
+}
+
+isc_result_t
+dns_dbiterator_prev(dns_dbiterator_t *iterator) {
+ /*
+ * Move the node cursor to the previous node in the database (if any).
+ */
+
+ REQUIRE(DNS_DBITERATOR_VALID(iterator));
+
+ return (iterator->methods->prev(iterator));
+}
+
+isc_result_t
+dns_dbiterator_next(dns_dbiterator_t *iterator) {
+ /*
+ * Move the node cursor to the next node in the database (if any).
+ */
+
+ REQUIRE(DNS_DBITERATOR_VALID(iterator));
+
+ return (iterator->methods->next(iterator));
+}
+
+isc_result_t
+dns_dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
+ dns_name_t *name)
+{
+ /*
+ * Return the current node.
+ */
+
+ REQUIRE(DNS_DBITERATOR_VALID(iterator));
+ REQUIRE(nodep != NULL && *nodep == NULL);
+ REQUIRE(name == NULL || dns_name_hasbuffer(name));
+
+ return (iterator->methods->current(iterator, nodep, name));
+}
+
+isc_result_t
+dns_dbiterator_pause(dns_dbiterator_t *iterator) {
+ /*
+ * Pause iteration.
+ */
+
+ REQUIRE(DNS_DBITERATOR_VALID(iterator));
+
+ return (iterator->methods->pause(iterator));
+}
+
+isc_result_t
+dns_dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
+
+ /*
+ * Return the origin to which returned node names are relative.
+ */
+
+ REQUIRE(DNS_DBITERATOR_VALID(iterator));
+ REQUIRE(iterator->relative_names);
+ REQUIRE(dns_name_hasbuffer(name));
+
+ return (iterator->methods->origin(iterator, name));
+}
+
+void
+dns_dbiterator_setcleanmode(dns_dbiterator_t *iterator, isc_boolean_t mode) {
+ REQUIRE(DNS_DBITERATOR_VALID(iterator));
+
+ iterator->cleaning = mode;
+}
diff --git a/lib/dns/dbtable.c b/lib/dns/dbtable.c
new file mode 100644
index 0000000..b091e42
--- /dev/null
+++ b/lib/dns/dbtable.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2004, 2005 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: dbtable.c,v 1.28.18.3 2005/07/12 01:22:19 marka Exp $
+ */
+
+/*! \file
+ * \author
+ * Principal Author: DCL
+ */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/rwlock.h>
+#include <isc/util.h>
+
+#include <dns/dbtable.h>
+#include <dns/db.h>
+#include <dns/rbt.h>
+#include <dns/result.h>
+
+struct dns_dbtable {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ dns_rdataclass_t rdclass;
+ isc_mutex_t lock;
+ isc_rwlock_t tree_lock;
+ /* Locked by lock. */
+ unsigned int references;
+ /* Locked by tree_lock. */
+ dns_rbt_t * rbt;
+ dns_db_t * default_db;
+};
+
+#define DBTABLE_MAGIC ISC_MAGIC('D', 'B', '-', '-')
+#define VALID_DBTABLE(dbtable) ISC_MAGIC_VALID(dbtable, DBTABLE_MAGIC)
+
+static void
+dbdetach(void *data, void *arg) {
+ dns_db_t *db = data;
+
+ UNUSED(arg);
+
+ dns_db_detach(&db);
+}
+
+isc_result_t
+dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
+ dns_dbtable_t **dbtablep)
+{
+ dns_dbtable_t *dbtable;
+ isc_result_t result;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(dbtablep != NULL && *dbtablep == NULL);
+
+ dbtable = (dns_dbtable_t *)isc_mem_get(mctx, sizeof(*dbtable));
+ if (dbtable == NULL)
+ return (ISC_R_NOMEMORY);
+
+ dbtable->rbt = NULL;
+ result = dns_rbt_create(mctx, dbdetach, NULL, &dbtable->rbt);
+ if (result != ISC_R_SUCCESS)
+ goto clean1;
+
+ result = isc_mutex_init(&dbtable->lock);
+ if (result != ISC_R_SUCCESS)
+ goto clean2;
+
+ result = isc_rwlock_init(&dbtable->tree_lock, 0, 0);
+ if (result != ISC_R_SUCCESS)
+ goto clean3;
+
+ dbtable->default_db = NULL;
+ dbtable->mctx = mctx;
+ dbtable->rdclass = rdclass;
+ dbtable->magic = DBTABLE_MAGIC;
+ dbtable->references = 1;
+
+ *dbtablep = dbtable;
+
+ return (ISC_R_SUCCESS);
+
+ clean3:
+ DESTROYLOCK(&dbtable->lock);
+
+ clean2:
+ dns_rbt_destroy(&dbtable->rbt);
+
+ clean1:
+ isc_mem_put(mctx, dbtable, sizeof(*dbtable));
+
+ return (result);
+}
+
+static inline void
+dbtable_free(dns_dbtable_t *dbtable) {
+ /*
+ * Caller must ensure that it is safe to call.
+ */
+
+ RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
+
+ if (dbtable->default_db != NULL)
+ dns_db_detach(&dbtable->default_db);
+
+ dns_rbt_destroy(&dbtable->rbt);
+
+ RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
+
+ isc_rwlock_destroy(&dbtable->tree_lock);
+
+ dbtable->magic = 0;
+
+ isc_mem_put(dbtable->mctx, dbtable, sizeof(*dbtable));
+}
+
+void
+dns_dbtable_attach(dns_dbtable_t *source, dns_dbtable_t **targetp) {
+ REQUIRE(VALID_DBTABLE(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ LOCK(&source->lock);
+
+ INSIST(source->references > 0);
+ source->references++;
+ INSIST(source->references != 0);
+
+ UNLOCK(&source->lock);
+
+ *targetp = source;
+}
+
+void
+dns_dbtable_detach(dns_dbtable_t **dbtablep) {
+ dns_dbtable_t *dbtable;
+ isc_boolean_t free_dbtable = ISC_FALSE;
+
+ REQUIRE(dbtablep != NULL);
+ dbtable = *dbtablep;
+ REQUIRE(VALID_DBTABLE(dbtable));
+
+ LOCK(&dbtable->lock);
+
+ INSIST(dbtable->references > 0);
+ dbtable->references--;
+ if (dbtable->references == 0)
+ free_dbtable = ISC_TRUE;
+
+ UNLOCK(&dbtable->lock);
+
+ if (free_dbtable)
+ dbtable_free(dbtable);
+
+ *dbtablep = NULL;
+}
+
+isc_result_t
+dns_dbtable_add(dns_dbtable_t *dbtable, dns_db_t *db) {
+ isc_result_t result;
+ dns_db_t *clone;
+
+ REQUIRE(VALID_DBTABLE(dbtable));
+ REQUIRE(dns_db_class(db) == dbtable->rdclass);
+
+ clone = NULL;
+ dns_db_attach(db, &clone);
+
+ RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
+ result = dns_rbt_addname(dbtable->rbt, dns_db_origin(clone), clone);
+ RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
+
+ return (result);
+}
+
+void
+dns_dbtable_remove(dns_dbtable_t *dbtable, dns_db_t *db) {
+ dns_db_t *stored_data = NULL;
+ isc_result_t result;
+ dns_name_t *name;
+
+ REQUIRE(VALID_DBTABLE(dbtable));
+
+ name = dns_db_origin(db);
+
+ /*
+ * There is a requirement that the association of name with db
+ * be verified. With the current rbt.c this is expensive to do,
+ * because effectively two find operations are being done, but
+ * deletion is relatively infrequent.
+ * XXXDCL ... this could be cheaper now with dns_rbt_deletenode.
+ */
+
+ RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
+
+ result = dns_rbt_findname(dbtable->rbt, name, 0, NULL,
+ (void **) (void *)&stored_data);
+
+ if (result == ISC_R_SUCCESS) {
+ INSIST(stored_data == db);
+
+ (void)dns_rbt_deletename(dbtable->rbt, name, ISC_FALSE);
+ }
+
+ RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
+}
+
+void
+dns_dbtable_adddefault(dns_dbtable_t *dbtable, dns_db_t *db) {
+ REQUIRE(VALID_DBTABLE(dbtable));
+ REQUIRE(dbtable->default_db == NULL);
+ REQUIRE(dns_name_compare(dns_db_origin(db), dns_rootname) == 0);
+
+ RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
+
+ dbtable->default_db = NULL;
+ dns_db_attach(db, &dbtable->default_db);
+
+ RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
+}
+
+void
+dns_dbtable_getdefault(dns_dbtable_t *dbtable, dns_db_t **dbp) {
+ REQUIRE(VALID_DBTABLE(dbtable));
+ REQUIRE(dbp != NULL && *dbp == NULL);
+
+ RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
+
+ dns_db_attach(dbtable->default_db, dbp);
+
+ RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
+}
+
+void
+dns_dbtable_removedefault(dns_dbtable_t *dbtable) {
+ REQUIRE(VALID_DBTABLE(dbtable));
+
+ RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
+
+ dns_db_detach(&dbtable->default_db);
+
+ RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
+}
+
+isc_result_t
+dns_dbtable_find(dns_dbtable_t *dbtable, dns_name_t *name,
+ unsigned int options, dns_db_t **dbp)
+{
+ dns_db_t *stored_data = NULL;
+ isc_result_t result;
+ unsigned int rbtoptions = 0;
+
+ REQUIRE(dbp != NULL && *dbp == NULL);
+
+ if ((options & DNS_DBTABLEFIND_NOEXACT) != 0)
+ rbtoptions |= DNS_RBTFIND_NOEXACT;
+
+ RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
+
+ result = dns_rbt_findname(dbtable->rbt, name, rbtoptions, NULL,
+ (void **) (void *)&stored_data);
+
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
+ dns_db_attach(stored_data, dbp);
+ else if (dbtable->default_db != NULL) {
+ dns_db_attach(dbtable->default_db, dbp);
+ result = DNS_R_PARTIALMATCH;
+ } else
+ result = ISC_R_NOTFOUND;
+
+ RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
+
+ return (result);
+}
diff --git a/lib/dns/diff.c b/lib/dns/diff.c
new file mode 100644
index 0000000..22a3938
--- /dev/null
+++ b/lib/dns/diff.c
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2004, 2005 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: diff.c,v 1.9.18.3 2005/04/27 05:01:15 sra Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/file.h>
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/diff.h>
+#include <dns/log.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatatype.h>
+#include <dns/result.h>
+
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto failure; \
+ } while (0)
+
+#define DIFF_COMMON_LOGARGS \
+ dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DIFF
+
+static dns_rdatatype_t
+rdata_covers(dns_rdata_t *rdata) {
+ return (rdata->type == dns_rdatatype_rrsig ?
+ dns_rdata_covers(rdata) : 0);
+}
+
+isc_result_t
+dns_difftuple_create(isc_mem_t *mctx,
+ dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
+ dns_rdata_t *rdata, dns_difftuple_t **tp)
+{
+ dns_difftuple_t *t;
+ unsigned int size;
+ unsigned char *datap;
+
+ REQUIRE(tp != NULL && *tp == NULL);
+
+ /*
+ * Create a new tuple. The variable-size wire-format name data and
+ * rdata immediately follow the dns_difftuple_t structure
+ * in memory.
+ */
+ size = sizeof(*t) + name->length + rdata->length;
+ t = isc_mem_allocate(mctx, size);
+ if (t == NULL)
+ return (ISC_R_NOMEMORY);
+ t->mctx = mctx;
+ t->op = op;
+
+ datap = (unsigned char *)(t + 1);
+
+ memcpy(datap, name->ndata, name->length);
+ dns_name_init(&t->name, NULL);
+ dns_name_clone(name, &t->name);
+ t->name.ndata = datap;
+ datap += name->length;
+
+ t->ttl = ttl;
+
+ memcpy(datap, rdata->data, rdata->length);
+ dns_rdata_init(&t->rdata);
+ dns_rdata_clone(rdata, &t->rdata);
+ t->rdata.data = datap;
+ datap += rdata->length;
+
+ ISC_LINK_INIT(&t->rdata, link);
+ ISC_LINK_INIT(t, link);
+ t->magic = DNS_DIFFTUPLE_MAGIC;
+
+ INSIST(datap == (unsigned char *)t + size);
+
+ *tp = t;
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_difftuple_free(dns_difftuple_t **tp) {
+ dns_difftuple_t *t = *tp;
+ REQUIRE(DNS_DIFFTUPLE_VALID(t));
+ dns_name_invalidate(&t->name);
+ t->magic = 0;
+ isc_mem_free(t->mctx, t);
+ *tp = NULL;
+}
+
+isc_result_t
+dns_difftuple_copy(dns_difftuple_t *orig, dns_difftuple_t **copyp) {
+ return (dns_difftuple_create(orig->mctx, orig->op, &orig->name,
+ orig->ttl, &orig->rdata, copyp));
+}
+
+void
+dns_diff_init(isc_mem_t *mctx, dns_diff_t *diff) {
+ diff->mctx = mctx;
+ ISC_LIST_INIT(diff->tuples);
+ diff->magic = DNS_DIFF_MAGIC;
+}
+
+void
+dns_diff_clear(dns_diff_t *diff) {
+ dns_difftuple_t *t;
+ REQUIRE(DNS_DIFF_VALID(diff));
+ while ((t = ISC_LIST_HEAD(diff->tuples)) != NULL) {
+ ISC_LIST_UNLINK(diff->tuples, t, link);
+ dns_difftuple_free(&t);
+ }
+ ENSURE(ISC_LIST_EMPTY(diff->tuples));
+}
+
+void
+dns_diff_append(dns_diff_t *diff, dns_difftuple_t **tuplep)
+{
+ ISC_LIST_APPEND(diff->tuples, *tuplep, link);
+ *tuplep = NULL;
+}
+
+/* XXX this is O(N) */
+
+void
+dns_diff_appendminimal(dns_diff_t *diff, dns_difftuple_t **tuplep)
+{
+ dns_difftuple_t *ot, *next_ot;
+
+ REQUIRE(DNS_DIFF_VALID(diff));
+ REQUIRE(DNS_DIFFTUPLE_VALID(*tuplep));
+
+ /*
+ * Look for an existing tuple with the same owner name,
+ * rdata, and TTL. If we are doing an addition and find a
+ * deletion or vice versa, remove both the old and the
+ * new tuple since they cancel each other out (assuming
+ * that we never delete nonexistent data or add existing
+ * data).
+ *
+ * If we find an old update of the same kind as
+ * the one we are doing, there must be a programming
+ * error. We report it but try to continue anyway.
+ */
+ for (ot = ISC_LIST_HEAD(diff->tuples); ot != NULL;
+ ot = next_ot)
+ {
+ next_ot = ISC_LIST_NEXT(ot, link);
+ if (dns_name_equal(&ot->name, &(*tuplep)->name) &&
+ dns_rdata_compare(&ot->rdata, &(*tuplep)->rdata) == 0 &&
+ ot->ttl == (*tuplep)->ttl)
+ {
+ ISC_LIST_UNLINK(diff->tuples, ot, link);
+ if ((*tuplep)->op == ot->op) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "unexpected non-minimal diff");
+ } else {
+ dns_difftuple_free(tuplep);
+ }
+ dns_difftuple_free(&ot);
+ break;
+ }
+ }
+
+ if (*tuplep != NULL) {
+ ISC_LIST_APPEND(diff->tuples, *tuplep, link);
+ *tuplep = NULL;
+ }
+
+ ENSURE(*tuplep == NULL);
+}
+
+static isc_result_t
+diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
+ isc_boolean_t warn)
+{
+ dns_difftuple_t *t;
+ dns_dbnode_t *node = NULL;
+ isc_result_t result;
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char typebuf[DNS_RDATATYPE_FORMATSIZE];
+ char classbuf[DNS_RDATACLASS_FORMATSIZE];
+
+ REQUIRE(DNS_DIFF_VALID(diff));
+ REQUIRE(DNS_DB_VALID(db));
+
+ t = ISC_LIST_HEAD(diff->tuples);
+ while (t != NULL) {
+ dns_name_t *name;
+
+ INSIST(node == NULL);
+ name = &t->name;
+ /*
+ * Find the node.
+ * We create the node if it does not exist.
+ * This will cause an empty node to be created if the diff
+ * contains a deletion of an RR at a nonexistent name,
+ * but such diffs should never be created in the first
+ * place.
+ */
+ node = NULL;
+ CHECK(dns_db_findnode(db, name, ISC_TRUE, &node));
+
+ while (t != NULL && dns_name_equal(&t->name, name)) {
+ dns_rdatatype_t type, covers;
+ dns_diffop_t op;
+ dns_rdatalist_t rdl;
+ dns_rdataset_t rds;
+
+ op = t->op;
+ type = t->rdata.type;
+ covers = rdata_covers(&t->rdata);
+
+ /*
+ * Collect a contiguous set of updates with
+ * the same operation (add/delete) and RR type
+ * into a single rdatalist so that the
+ * database rrset merging/subtraction code
+ * can work more efficiently than if each
+ * RR were merged into / subtracted from
+ * the database separately.
+ *
+ * This is done by linking rdata structures from the
+ * diff into "rdatalist". This uses the rdata link
+ * field, not the diff link field, so the structure
+ * of the diff itself is not affected.
+ */
+
+ rdl.type = type;
+ rdl.covers = covers;
+ rdl.rdclass = t->rdata.rdclass;
+ rdl.ttl = t->ttl;
+ ISC_LIST_INIT(rdl.rdata);
+ ISC_LINK_INIT(&rdl, link);
+
+ while (t != NULL &&
+ dns_name_equal(&t->name, name) &&
+ t->op == op &&
+ t->rdata.type == type &&
+ rdata_covers(&t->rdata) == covers)
+ {
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ dns_rdatatype_format(t->rdata.type, typebuf,
+ sizeof(typebuf));
+ dns_rdataclass_format(t->rdata.rdclass,
+ classbuf,
+ sizeof(classbuf));
+ if (t->ttl != rdl.ttl && warn)
+ isc_log_write(DIFF_COMMON_LOGARGS,
+ ISC_LOG_WARNING,
+ "'%s/%s/%s': TTL differs in "
+ "rdataset, adjusting "
+ "%lu -> %lu",
+ namebuf, typebuf, classbuf,
+ (unsigned long) t->ttl,
+ (unsigned long) rdl.ttl);
+ ISC_LIST_APPEND(rdl.rdata, &t->rdata, link);
+ t = ISC_LIST_NEXT(t, link);
+ }
+
+ /*
+ * Convert the rdatalist into a rdataset.
+ */
+ dns_rdataset_init(&rds);
+ CHECK(dns_rdatalist_tordataset(&rdl, &rds));
+ rds.trust = dns_trust_ultimate;
+
+ /*
+ * Merge the rdataset into the database.
+ */
+ if (op == DNS_DIFFOP_ADD) {
+ result = dns_db_addrdataset(db, node, ver,
+ 0, &rds,
+ DNS_DBADD_MERGE|
+ DNS_DBADD_EXACT|
+ DNS_DBADD_EXACTTTL,
+ NULL);
+ } else if (op == DNS_DIFFOP_DEL) {
+ result = dns_db_subtractrdataset(db, node, ver,
+ &rds,
+ DNS_DBSUB_EXACT,
+ NULL);
+ } else {
+ INSIST(0);
+ }
+ if (result == DNS_R_UNCHANGED) {
+ /*
+ * This will not happen when executing a
+ * dynamic update, because that code will
+ * generate strictly minimal diffs.
+ * It may happen when receiving an IXFR
+ * from a server that is not as careful.
+ * Issue a warning and continue.
+ */
+ if (warn)
+ isc_log_write(DIFF_COMMON_LOGARGS,
+ ISC_LOG_WARNING,
+ "update with no effect");
+ } else if (result == ISC_R_SUCCESS ||
+ result == DNS_R_NXRRSET) {
+ /*
+ * OK.
+ */
+ } else {
+ CHECK(result);
+ }
+ }
+ dns_db_detachnode(db, &node);
+ }
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+isc_result_t
+dns_diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver) {
+ return (diff_apply(diff, db, ver, ISC_TRUE));
+}
+
+isc_result_t
+dns_diff_applysilently(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver) {
+ return (diff_apply(diff, db, ver, ISC_FALSE));
+}
+
+/* XXX this duplicates lots of code in diff_apply(). */
+
+isc_result_t
+dns_diff_load(dns_diff_t *diff, dns_addrdatasetfunc_t addfunc,
+ void *add_private)
+{
+ dns_difftuple_t *t;
+ isc_result_t result;
+
+ REQUIRE(DNS_DIFF_VALID(diff));
+
+ t = ISC_LIST_HEAD(diff->tuples);
+ while (t != NULL) {
+ dns_name_t *name;
+
+ name = &t->name;
+ while (t != NULL && dns_name_equal(&t->name, name)) {
+ dns_rdatatype_t type, covers;
+ dns_diffop_t op;
+ dns_rdatalist_t rdl;
+ dns_rdataset_t rds;
+
+ op = t->op;
+ type = t->rdata.type;
+ covers = rdata_covers(&t->rdata);
+
+ rdl.type = type;
+ rdl.covers = covers;
+ rdl.rdclass = t->rdata.rdclass;
+ rdl.ttl = t->ttl;
+ ISC_LIST_INIT(rdl.rdata);
+ ISC_LINK_INIT(&rdl, link);
+
+ while (t != NULL && dns_name_equal(&t->name, name) &&
+ t->op == op && t->rdata.type == type &&
+ rdata_covers(&t->rdata) == covers)
+ {
+ ISC_LIST_APPEND(rdl.rdata, &t->rdata, link);
+ t = ISC_LIST_NEXT(t, link);
+ }
+
+ /*
+ * Convert the rdatalist into a rdataset.
+ */
+ dns_rdataset_init(&rds);
+ CHECK(dns_rdatalist_tordataset(&rdl, &rds));
+ rds.trust = dns_trust_ultimate;
+
+ INSIST(op == DNS_DIFFOP_ADD);
+ result = (*addfunc)(add_private, name, &rds);
+ if (result == DNS_R_UNCHANGED) {
+ isc_log_write(DIFF_COMMON_LOGARGS,
+ ISC_LOG_WARNING,
+ "update with no effect");
+ } else if (result == ISC_R_SUCCESS ||
+ result == DNS_R_NXRRSET) {
+ /*
+ * OK.
+ */
+ } else {
+ CHECK(result);
+ }
+ }
+ }
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+/*
+ * XXX uses qsort(); a merge sort would be more natural for lists,
+ * and perhaps safer wrt thread stack overflow.
+ */
+isc_result_t
+dns_diff_sort(dns_diff_t *diff, dns_diff_compare_func *compare) {
+ unsigned int length = 0;
+ unsigned int i;
+ dns_difftuple_t **v;
+ dns_difftuple_t *p;
+ REQUIRE(DNS_DIFF_VALID(diff));
+
+ for (p = ISC_LIST_HEAD(diff->tuples);
+ p != NULL;
+ p = ISC_LIST_NEXT(p, link))
+ length++;
+ if (length == 0)
+ return (ISC_R_SUCCESS);
+ v = isc_mem_get(diff->mctx, length * sizeof(dns_difftuple_t *));
+ if (v == NULL)
+ return (ISC_R_NOMEMORY);
+ i = 0;
+ for (i = 0; i < length; i++) {
+ p = ISC_LIST_HEAD(diff->tuples);
+ v[i] = p;
+ ISC_LIST_UNLINK(diff->tuples, p, link);
+ }
+ INSIST(ISC_LIST_HEAD(diff->tuples) == NULL);
+ qsort(v, length, sizeof(v[0]), compare);
+ for (i = 0; i < length; i++) {
+ ISC_LIST_APPEND(diff->tuples, v[i], link);
+ }
+ isc_mem_put(diff->mctx, v, length * sizeof(dns_difftuple_t *));
+ return (ISC_R_SUCCESS);
+}
+
+
+/*
+ * Create an rdataset containing the single RR of the given
+ * tuple. The caller must allocate the the rdata, rdataset and
+ * an rdatalist structure for it to refer to.
+ */
+
+static isc_result_t
+diff_tuple_tordataset(dns_difftuple_t *t, dns_rdata_t *rdata,
+ dns_rdatalist_t *rdl, dns_rdataset_t *rds)
+{
+ REQUIRE(DNS_DIFFTUPLE_VALID(t));
+ REQUIRE(rdl != NULL);
+ REQUIRE(rds != NULL);
+
+ rdl->type = t->rdata.type;
+ rdl->rdclass = t->rdata.rdclass;
+ rdl->ttl = t->ttl;
+ ISC_LIST_INIT(rdl->rdata);
+ ISC_LINK_INIT(rdl, link);
+ dns_rdataset_init(rds);
+ ISC_LINK_INIT(rdata, link);
+ dns_rdata_clone(&t->rdata, rdata);
+ ISC_LIST_APPEND(rdl->rdata, rdata, link);
+ return (dns_rdatalist_tordataset(rdl, rds));
+}
+
+isc_result_t
+dns_diff_print(dns_diff_t *diff, FILE *file) {
+ isc_result_t result;
+ dns_difftuple_t *t;
+ char *mem = NULL;
+ unsigned int size = 2048;
+
+ REQUIRE(DNS_DIFF_VALID(diff));
+
+ mem = isc_mem_get(diff->mctx, size);
+ if (mem == NULL)
+ return (ISC_R_NOMEMORY);
+
+ for (t = ISC_LIST_HEAD(diff->tuples); t != NULL;
+ t = ISC_LIST_NEXT(t, link))
+ {
+ isc_buffer_t buf;
+ isc_region_t r;
+
+ dns_rdatalist_t rdl;
+ dns_rdataset_t rds;
+ dns_rdata_t rd = DNS_RDATA_INIT;
+
+ result = diff_tuple_tordataset(t, &rd, &rdl, &rds);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "diff_tuple_tordataset failed: %s",
+ dns_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+ again:
+ isc_buffer_init(&buf, mem, size);
+ result = dns_rdataset_totext(&rds, &t->name,
+ ISC_FALSE, ISC_FALSE, &buf);
+
+ if (result == ISC_R_NOSPACE) {
+ isc_mem_put(diff->mctx, mem, size);
+ size += 1024;
+ mem = isc_mem_get(diff->mctx, size);
+ if (mem == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ goto again;
+ }
+
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ /*
+ * Get rid of final newline.
+ */
+ INSIST(buf.used >= 1 &&
+ ((char *) buf.base)[buf.used-1] == '\n');
+ buf.used--;
+
+ isc_buffer_usedregion(&buf, &r);
+ if (file != NULL)
+ fprintf(file, "%s %.*s\n",
+ t->op == DNS_DIFFOP_ADD ? "add" : "del",
+ (int) r.length, (char *) r.base);
+ else
+ isc_log_write(DIFF_COMMON_LOGARGS, ISC_LOG_DEBUG(7),
+ "%s %.*s",
+ t->op == DNS_DIFFOP_ADD ? "add" : "del",
+ (int) r.length, (char *) r.base);
+ }
+ result = ISC_R_SUCCESS;
+ cleanup:
+ if (mem != NULL)
+ isc_mem_put(diff->mctx, mem, size);
+ return (result);
+}
diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c
new file mode 100644
index 0000000..f3ef091
--- /dev/null
+++ b/lib/dns/dispatch.c
@@ -0,0 +1,2674 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: dispatch.c,v 1.116.18.19 2007/08/28 07:20:04 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <isc/entropy.h>
+#include <isc/mem.h>
+#include <isc/mutex.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include <dns/acl.h>
+#include <dns/dispatch.h>
+#include <dns/events.h>
+#include <dns/log.h>
+#include <dns/message.h>
+#include <dns/portlist.h>
+#include <dns/tcpmsg.h>
+#include <dns/types.h>
+
+typedef ISC_LIST(dns_dispentry_t) dns_displist_t;
+
+typedef struct dns_nsid {
+ isc_uint16_t nsid_state;
+ isc_uint16_t *nsid_vtable;
+ isc_uint16_t *nsid_pool;
+ isc_uint16_t nsid_a1, nsid_a2, nsid_a3;
+ isc_uint16_t nsid_c1, nsid_c2, nsid_c3;
+ isc_uint16_t nsid_state2;
+ isc_boolean_t nsid_usepool;
+} dns_nsid_t;
+
+typedef struct dns_qid {
+ unsigned int magic;
+ unsigned int qid_nbuckets; /*%< hash table size */
+ unsigned int qid_increment; /*%< id increment on collision */
+ isc_mutex_t lock;
+ dns_nsid_t nsid;
+ dns_displist_t *qid_table; /*%< the table itself */
+} dns_qid_t;
+
+struct dns_dispatchmgr {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t *mctx;
+ dns_acl_t *blackhole;
+ dns_portlist_t *portlist;
+
+ /* Locked by "lock". */
+ isc_mutex_t lock;
+ unsigned int state;
+ ISC_LIST(dns_dispatch_t) list;
+
+ /* locked by buffer lock */
+ dns_qid_t *qid;
+ isc_mutex_t buffer_lock;
+ unsigned int buffers; /*%< allocated buffers */
+ unsigned int buffersize; /*%< size of each buffer */
+ unsigned int maxbuffers; /*%< max buffers */
+
+ /* Locked internally. */
+ isc_mutex_t pool_lock;
+ isc_mempool_t *epool; /*%< memory pool for events */
+ isc_mempool_t *rpool; /*%< memory pool for replies */
+ isc_mempool_t *dpool; /*%< dispatch allocations */
+ isc_mempool_t *bpool; /*%< memory pool for buffers */
+
+ isc_entropy_t *entropy; /*%< entropy source */
+};
+
+#define MGR_SHUTTINGDOWN 0x00000001U
+#define MGR_IS_SHUTTINGDOWN(l) (((l)->state & MGR_SHUTTINGDOWN) != 0)
+
+#define IS_PRIVATE(d) (((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0)
+
+struct dns_dispentry {
+ unsigned int magic;
+ dns_dispatch_t *disp;
+ dns_messageid_t id;
+ unsigned int bucket;
+ isc_sockaddr_t host;
+ isc_task_t *task;
+ isc_taskaction_t action;
+ void *arg;
+ isc_boolean_t item_out;
+ ISC_LIST(dns_dispatchevent_t) items;
+ ISC_LINK(dns_dispentry_t) link;
+};
+
+#define INVALID_BUCKET (0xffffdead)
+
+struct dns_dispatch {
+ /* Unlocked. */
+ unsigned int magic; /*%< magic */
+ dns_dispatchmgr_t *mgr; /*%< dispatch manager */
+ isc_task_t *task; /*%< internal task */
+ isc_socket_t *socket; /*%< isc socket attached to */
+ isc_sockaddr_t local; /*%< local address */
+ unsigned int maxrequests; /*%< max requests */
+ isc_event_t *ctlevent;
+
+ /*% Locked by mgr->lock. */
+ ISC_LINK(dns_dispatch_t) link;
+
+ /* Locked by "lock". */
+ isc_mutex_t lock; /*%< locks all below */
+ isc_sockettype_t socktype;
+ unsigned int attributes;
+ unsigned int refcount; /*%< number of users */
+ dns_dispatchevent_t *failsafe_ev; /*%< failsafe cancel event */
+ unsigned int shutting_down : 1,
+ shutdown_out : 1,
+ connected : 1,
+ tcpmsg_valid : 1,
+ recv_pending : 1; /*%< is a recv() pending? */
+ isc_result_t shutdown_why;
+ unsigned int requests; /*%< how many requests we have */
+ unsigned int tcpbuffers; /*%< allocated buffers */
+ dns_tcpmsg_t tcpmsg; /*%< for tcp streams */
+ dns_qid_t *qid;
+};
+
+#define QID_MAGIC ISC_MAGIC('Q', 'i', 'd', ' ')
+#define VALID_QID(e) ISC_MAGIC_VALID((e), QID_MAGIC)
+
+#define RESPONSE_MAGIC ISC_MAGIC('D', 'r', 's', 'p')
+#define VALID_RESPONSE(e) ISC_MAGIC_VALID((e), RESPONSE_MAGIC)
+
+#define DISPATCH_MAGIC ISC_MAGIC('D', 'i', 's', 'p')
+#define VALID_DISPATCH(e) ISC_MAGIC_VALID((e), DISPATCH_MAGIC)
+
+#define DNS_DISPATCHMGR_MAGIC ISC_MAGIC('D', 'M', 'g', 'r')
+#define VALID_DISPATCHMGR(e) ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC)
+
+#define DNS_QID(disp) ((disp)->socktype == isc_sockettype_tcp) ? \
+ (disp)->qid : (disp)->mgr->qid
+/*
+ * Statics.
+ */
+static dns_dispentry_t *bucket_search(dns_qid_t *, isc_sockaddr_t *,
+ dns_messageid_t, unsigned int);
+static isc_boolean_t destroy_disp_ok(dns_dispatch_t *);
+static void destroy_disp(isc_task_t *task, isc_event_t *event);
+static void udp_recv(isc_task_t *, isc_event_t *);
+static void tcp_recv(isc_task_t *, isc_event_t *);
+static void startrecv(dns_dispatch_t *);
+static dns_messageid_t dns_randomid(dns_nsid_t *);
+static isc_uint32_t dns_hash(dns_qid_t *, isc_sockaddr_t *, dns_messageid_t);
+static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
+static void *allocate_udp_buffer(dns_dispatch_t *disp);
+static inline void free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
+static inline dns_dispatchevent_t *allocate_event(dns_dispatch_t *disp);
+static void do_cancel(dns_dispatch_t *disp);
+static dns_dispentry_t *linear_first(dns_qid_t *disp);
+static dns_dispentry_t *linear_next(dns_qid_t *disp,
+ dns_dispentry_t *resp);
+static void dispatch_free(dns_dispatch_t **dispp);
+static isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr,
+ isc_socketmgr_t *sockmgr,
+ isc_taskmgr_t *taskmgr,
+ isc_sockaddr_t *localaddr,
+ unsigned int maxrequests,
+ unsigned int attributes,
+ dns_dispatch_t **dispp);
+static isc_boolean_t destroy_mgr_ok(dns_dispatchmgr_t *mgr);
+static void destroy_mgr(dns_dispatchmgr_t **mgrp);
+static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
+ unsigned int increment, isc_boolean_t usepool,
+ dns_qid_t **qidp);
+static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
+static isc_uint16_t nsid_next(dns_nsid_t *nsid);
+static isc_result_t nsid_init(isc_mem_t *mctx, dns_nsid_t *nsid, isc_boolean_t usepool);
+static void nsid_destroy(isc_mem_t *mctx, dns_nsid_t *nsid);
+
+#define LVL(x) ISC_LOG_DEBUG(x)
+
+static void
+mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+
+static void
+mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) {
+ char msgbuf[2048];
+ va_list ap;
+
+ if (! isc_log_wouldlog(dns_lctx, level))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
+ level, "dispatchmgr %p: %s", mgr, msgbuf);
+}
+
+static void
+dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+
+static void
+dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) {
+ char msgbuf[2048];
+ va_list ap;
+
+ if (! isc_log_wouldlog(dns_lctx, level))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
+ level, "dispatch %p: %s", disp, msgbuf);
+}
+
+static void
+request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
+ int level, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(4, 5);
+
+static void
+request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
+ int level, const char *fmt, ...)
+{
+ char msgbuf[2048];
+ char peerbuf[256];
+ va_list ap;
+
+ if (! isc_log_wouldlog(dns_lctx, level))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ if (VALID_RESPONSE(resp)) {
+ isc_sockaddr_format(&resp->host, peerbuf, sizeof(peerbuf));
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
+ DNS_LOGMODULE_DISPATCH, level,
+ "dispatch %p response %p %s: %s", disp, resp,
+ peerbuf, msgbuf);
+ } else {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
+ DNS_LOGMODULE_DISPATCH, level,
+ "dispatch %p req/resp %p: %s", disp, resp,
+ msgbuf);
+ }
+}
+
+/*
+ * Return an unpredictable message ID.
+ */
+static dns_messageid_t
+dns_randomid(dns_nsid_t *nsid) {
+ isc_uint32_t id;
+
+ id = nsid_next(nsid);
+
+ return ((dns_messageid_t)id);
+}
+
+/*
+ * Return a hash of the destination and message id.
+ */
+static isc_uint32_t
+dns_hash(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id) {
+ unsigned int ret;
+
+ ret = isc_sockaddr_hash(dest, ISC_TRUE);
+ ret ^= id;
+ ret %= qid->qid_nbuckets;
+
+ INSIST(ret < qid->qid_nbuckets);
+
+ return (ret);
+}
+
+/*
+ * Find the first entry in 'qid'. Returns NULL if there are no entries.
+ */
+static dns_dispentry_t *
+linear_first(dns_qid_t *qid) {
+ dns_dispentry_t *ret;
+ unsigned int bucket;
+
+ bucket = 0;
+
+ while (bucket < qid->qid_nbuckets) {
+ ret = ISC_LIST_HEAD(qid->qid_table[bucket]);
+ if (ret != NULL)
+ return (ret);
+ bucket++;
+ }
+
+ return (NULL);
+}
+
+/*
+ * Find the next entry after 'resp' in 'qid'. Return NULL if there are
+ * no more entries.
+ */
+static dns_dispentry_t *
+linear_next(dns_qid_t *qid, dns_dispentry_t *resp) {
+ dns_dispentry_t *ret;
+ unsigned int bucket;
+
+ ret = ISC_LIST_NEXT(resp, link);
+ if (ret != NULL)
+ return (ret);
+
+ bucket = resp->bucket;
+ bucket++;
+ while (bucket < qid->qid_nbuckets) {
+ ret = ISC_LIST_HEAD(qid->qid_table[bucket]);
+ if (ret != NULL)
+ return (ret);
+ bucket++;
+ }
+
+ return (NULL);
+}
+
+/*
+ * The dispatch must be locked.
+ */
+static isc_boolean_t
+destroy_disp_ok(dns_dispatch_t *disp)
+{
+ if (disp->refcount != 0)
+ return (ISC_FALSE);
+
+ if (disp->recv_pending != 0)
+ return (ISC_FALSE);
+
+ if (disp->shutting_down == 0)
+ return (ISC_FALSE);
+
+ return (ISC_TRUE);
+}
+
+
+/*
+ * Called when refcount reaches 0 (and safe to destroy).
+ *
+ * The dispatcher must not be locked.
+ * The manager must be locked.
+ */
+static void
+destroy_disp(isc_task_t *task, isc_event_t *event) {
+ dns_dispatch_t *disp;
+ dns_dispatchmgr_t *mgr;
+ isc_boolean_t killmgr;
+
+ INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL);
+
+ UNUSED(task);
+
+ disp = event->ev_arg;
+ mgr = disp->mgr;
+
+ LOCK(&mgr->lock);
+ ISC_LIST_UNLINK(mgr->list, disp, link);
+
+ dispatch_log(disp, LVL(90),
+ "shutting down; detaching from sock %p, task %p",
+ disp->socket, disp->task);
+
+ isc_socket_detach(&disp->socket);
+ isc_task_detach(&disp->task);
+ isc_event_free(&event);
+
+ dispatch_free(&disp);
+
+ killmgr = destroy_mgr_ok(mgr);
+ UNLOCK(&mgr->lock);
+ if (killmgr)
+ destroy_mgr(&mgr);
+}
+
+
+/*
+ * Find an entry for query ID 'id' and socket address 'dest' in 'qid'.
+ * Return NULL if no such entry exists.
+ */
+static dns_dispentry_t *
+bucket_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
+ unsigned int bucket)
+{
+ dns_dispentry_t *res;
+
+ REQUIRE(bucket < qid->qid_nbuckets);
+
+ res = ISC_LIST_HEAD(qid->qid_table[bucket]);
+
+ while (res != NULL) {
+ if ((res->id == id) && isc_sockaddr_equal(dest, &res->host))
+ return (res);
+ res = ISC_LIST_NEXT(res, link);
+ }
+
+ return (NULL);
+}
+
+static void
+free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
+ INSIST(buf != NULL && len != 0);
+
+
+ switch (disp->socktype) {
+ case isc_sockettype_tcp:
+ INSIST(disp->tcpbuffers > 0);
+ disp->tcpbuffers--;
+ isc_mem_put(disp->mgr->mctx, buf, len);
+ break;
+ case isc_sockettype_udp:
+ LOCK(&disp->mgr->buffer_lock);
+ INSIST(disp->mgr->buffers > 0);
+ INSIST(len == disp->mgr->buffersize);
+ disp->mgr->buffers--;
+ isc_mempool_put(disp->mgr->bpool, buf);
+ UNLOCK(&disp->mgr->buffer_lock);
+ break;
+ default:
+ INSIST(0);
+ break;
+ }
+}
+
+static void *
+allocate_udp_buffer(dns_dispatch_t *disp) {
+ void *temp;
+
+ LOCK(&disp->mgr->buffer_lock);
+ temp = isc_mempool_get(disp->mgr->bpool);
+
+ if (temp != NULL)
+ disp->mgr->buffers++;
+ UNLOCK(&disp->mgr->buffer_lock);
+
+ return (temp);
+}
+
+static inline void
+free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
+ if (disp->failsafe_ev == ev) {
+ INSIST(disp->shutdown_out == 1);
+ disp->shutdown_out = 0;
+
+ return;
+ }
+
+ isc_mempool_put(disp->mgr->epool, ev);
+}
+
+static inline dns_dispatchevent_t *
+allocate_event(dns_dispatch_t *disp) {
+ dns_dispatchevent_t *ev;
+
+ ev = isc_mempool_get(disp->mgr->epool);
+ if (ev == NULL)
+ return (NULL);
+ ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0,
+ NULL, NULL, NULL, NULL, NULL);
+
+ return (ev);
+}
+
+/*
+ * General flow:
+ *
+ * If I/O result == CANCELED or error, free the buffer.
+ *
+ * If query, free the buffer, restart.
+ *
+ * If response:
+ * Allocate event, fill in details.
+ * If cannot allocate, free buffer, restart.
+ * find target. If not found, free buffer, restart.
+ * if event queue is not empty, queue. else, send.
+ * restart.
+ */
+static void
+udp_recv(isc_task_t *task, isc_event_t *ev_in) {
+ isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
+ dns_dispatch_t *disp = ev_in->ev_arg;
+ dns_messageid_t id;
+ isc_result_t dres;
+ isc_buffer_t source;
+ unsigned int flags;
+ dns_dispentry_t *resp;
+ dns_dispatchevent_t *rev;
+ unsigned int bucket;
+ isc_boolean_t killit;
+ isc_boolean_t queue_response;
+ dns_dispatchmgr_t *mgr;
+ dns_qid_t *qid;
+ isc_netaddr_t netaddr;
+ int match;
+
+ UNUSED(task);
+
+ LOCK(&disp->lock);
+
+ mgr = disp->mgr;
+ qid = mgr->qid;
+
+ dispatch_log(disp, LVL(90),
+ "got packet: requests %d, buffers %d, recvs %d",
+ disp->requests, disp->mgr->buffers, disp->recv_pending);
+
+ if (ev->ev_type == ISC_SOCKEVENT_RECVDONE) {
+ /*
+ * Unless the receive event was imported from a listening
+ * interface, in which case the event type is
+ * DNS_EVENT_IMPORTRECVDONE, receive operation must be pending.
+ */
+ INSIST(disp->recv_pending != 0);
+ disp->recv_pending = 0;
+ }
+
+ if (disp->shutting_down) {
+ /*
+ * This dispatcher is shutting down.
+ */
+ free_buffer(disp, ev->region.base, ev->region.length);
+
+ isc_event_free(&ev_in);
+ ev = NULL;
+
+ killit = destroy_disp_ok(disp);
+ UNLOCK(&disp->lock);
+ if (killit)
+ isc_task_send(disp->task, &disp->ctlevent);
+
+ return;
+ }
+
+ if (ev->result != ISC_R_SUCCESS) {
+ free_buffer(disp, ev->region.base, ev->region.length);
+
+ if (ev->result != ISC_R_CANCELED)
+ dispatch_log(disp, ISC_LOG_ERROR,
+ "odd socket result in udp_recv(): %s",
+ isc_result_totext(ev->result));
+
+ UNLOCK(&disp->lock);
+ isc_event_free(&ev_in);
+ return;
+ }
+
+ /*
+ * If this is from a blackholed address, drop it.
+ */
+ isc_netaddr_fromsockaddr(&netaddr, &ev->address);
+ if (disp->mgr->blackhole != NULL &&
+ dns_acl_match(&netaddr, NULL, disp->mgr->blackhole,
+ NULL, &match, NULL) == ISC_R_SUCCESS &&
+ match > 0)
+ {
+ if (isc_log_wouldlog(dns_lctx, LVL(10))) {
+ char netaddrstr[ISC_NETADDR_FORMATSIZE];
+ isc_netaddr_format(&netaddr, netaddrstr,
+ sizeof(netaddrstr));
+ dispatch_log(disp, LVL(10),
+ "blackholed packet from %s",
+ netaddrstr);
+ }
+ free_buffer(disp, ev->region.base, ev->region.length);
+ goto restart;
+ }
+
+ /*
+ * Peek into the buffer to see what we can see.
+ */
+ isc_buffer_init(&source, ev->region.base, ev->region.length);
+ isc_buffer_add(&source, ev->n);
+ dres = dns_message_peekheader(&source, &id, &flags);
+ if (dres != ISC_R_SUCCESS) {
+ free_buffer(disp, ev->region.base, ev->region.length);
+ dispatch_log(disp, LVL(10), "got garbage packet");
+ goto restart;
+ }
+
+ dispatch_log(disp, LVL(92),
+ "got valid DNS message header, /QR %c, id %u",
+ ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id);
+
+ /*
+ * Look at flags. If query, drop it. If response,
+ * look to see where it goes.
+ */
+ queue_response = ISC_FALSE;
+ if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
+ /* query */
+ free_buffer(disp, ev->region.base, ev->region.length);
+ goto restart;
+ }
+
+ dns_dispatch_hash(&ev->timestamp, sizeof(&ev->timestamp));
+ dns_dispatch_hash(ev->region.base, ev->region.length);
+
+ /* response */
+ bucket = dns_hash(qid, &ev->address, id);
+ LOCK(&qid->lock);
+ resp = bucket_search(qid, &ev->address, id, bucket);
+ dispatch_log(disp, LVL(90),
+ "search for response in bucket %d: %s",
+ bucket, (resp == NULL ? "not found" : "found"));
+
+ if (resp == NULL) {
+ free_buffer(disp, ev->region.base, ev->region.length);
+ goto unlock;
+ }
+
+ /*
+ * Now that we have the original dispatch the query was sent
+ * from check that the address and port the response was
+ * sent to make sense.
+ */
+ if (disp != resp->disp) {
+ isc_sockaddr_t a1;
+ isc_sockaddr_t a2;
+
+ /*
+ * Check that the socket types and ports match.
+ */
+ if (disp->socktype != resp->disp->socktype ||
+ isc_sockaddr_getport(&disp->local) !=
+ isc_sockaddr_getport(&resp->disp->local)) {
+ free_buffer(disp, ev->region.base, ev->region.length);
+ goto unlock;
+ }
+
+ /*
+ * If both dispatches are bound to an address then fail as
+ * the addresses can't be equal (enforced by the IP stack).
+ *
+ * Note under Linux a packet can be sent out via IPv4 socket
+ * and the response be received via a IPv6 socket.
+ *
+ * Requests sent out via IPv6 should always come back in
+ * via IPv6.
+ */
+ if (isc_sockaddr_pf(&resp->disp->local) == PF_INET6 &&
+ isc_sockaddr_pf(&disp->local) != PF_INET6) {
+ free_buffer(disp, ev->region.base, ev->region.length);
+ goto unlock;
+ }
+ isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local));
+ isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local));
+ if (!isc_sockaddr_eqaddr(&a1, &resp->disp->local) &&
+ !isc_sockaddr_eqaddr(&a2, &disp->local)) {
+ free_buffer(disp, ev->region.base, ev->region.length);
+ goto unlock;
+ }
+ }
+
+ queue_response = resp->item_out;
+ rev = allocate_event(resp->disp);
+ if (rev == NULL) {
+ free_buffer(disp, ev->region.base, ev->region.length);
+ goto unlock;
+ }
+
+ /*
+ * At this point, rev contains the event we want to fill in, and
+ * resp contains the information on the place to send it to.
+ * Send the event off.
+ */
+ isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length);
+ isc_buffer_add(&rev->buffer, ev->n);
+ rev->result = ISC_R_SUCCESS;
+ rev->id = id;
+ rev->addr = ev->address;
+ rev->pktinfo = ev->pktinfo;
+ rev->attributes = ev->attributes;
+ if (queue_response) {
+ ISC_LIST_APPEND(resp->items, rev, ev_link);
+ } else {
+ ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL,
+ DNS_EVENT_DISPATCH,
+ resp->action, resp->arg, resp, NULL, NULL);
+ request_log(disp, resp, LVL(90),
+ "[a] Sent event %p buffer %p len %d to task %p",
+ rev, rev->buffer.base, rev->buffer.length,
+ resp->task);
+ resp->item_out = ISC_TRUE;
+ isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
+ }
+ unlock:
+ UNLOCK(&qid->lock);
+
+ /*
+ * Restart recv() to get the next packet.
+ */
+ restart:
+ startrecv(disp);
+
+ UNLOCK(&disp->lock);
+
+ isc_event_free(&ev_in);
+}
+
+/*
+ * General flow:
+ *
+ * If I/O result == CANCELED, EOF, or error, notify everyone as the
+ * various queues drain.
+ *
+ * If query, restart.
+ *
+ * If response:
+ * Allocate event, fill in details.
+ * If cannot allocate, restart.
+ * find target. If not found, restart.
+ * if event queue is not empty, queue. else, send.
+ * restart.
+ */
+static void
+tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
+ dns_dispatch_t *disp = ev_in->ev_arg;
+ dns_tcpmsg_t *tcpmsg = &disp->tcpmsg;
+ dns_messageid_t id;
+ isc_result_t dres;
+ unsigned int flags;
+ dns_dispentry_t *resp;
+ dns_dispatchevent_t *rev;
+ unsigned int bucket;
+ isc_boolean_t killit;
+ isc_boolean_t queue_response;
+ dns_qid_t *qid;
+ int level;
+ char buf[ISC_SOCKADDR_FORMATSIZE];
+
+ UNUSED(task);
+
+ REQUIRE(VALID_DISPATCH(disp));
+
+ qid = disp->qid;
+
+ dispatch_log(disp, LVL(90),
+ "got TCP packet: requests %d, buffers %d, recvs %d",
+ disp->requests, disp->tcpbuffers, disp->recv_pending);
+
+ LOCK(&disp->lock);
+
+ INSIST(disp->recv_pending != 0);
+ disp->recv_pending = 0;
+
+ if (disp->refcount == 0) {
+ /*
+ * This dispatcher is shutting down. Force cancelation.
+ */
+ tcpmsg->result = ISC_R_CANCELED;
+ }
+
+ if (tcpmsg->result != ISC_R_SUCCESS) {
+ switch (tcpmsg->result) {
+ case ISC_R_CANCELED:
+ break;
+
+ case ISC_R_EOF:
+ dispatch_log(disp, LVL(90), "shutting down on EOF");
+ do_cancel(disp);
+ break;
+
+ case ISC_R_CONNECTIONRESET:
+ level = ISC_LOG_INFO;
+ goto logit;
+
+ default:
+ level = ISC_LOG_ERROR;
+ logit:
+ isc_sockaddr_format(&tcpmsg->address, buf, sizeof(buf));
+ dispatch_log(disp, level, "shutting down due to TCP "
+ "receive error: %s: %s", buf,
+ isc_result_totext(tcpmsg->result));
+ do_cancel(disp);
+ break;
+ }
+
+ /*
+ * The event is statically allocated in the tcpmsg
+ * structure, and destroy_disp() frees the tcpmsg, so we must
+ * free the event *before* calling destroy_disp().
+ */
+ isc_event_free(&ev_in);
+
+ disp->shutting_down = 1;
+ disp->shutdown_why = tcpmsg->result;
+
+ /*
+ * If the recv() was canceled pass the word on.
+ */
+ killit = destroy_disp_ok(disp);
+ UNLOCK(&disp->lock);
+ if (killit)
+ isc_task_send(disp->task, &disp->ctlevent);
+ return;
+ }
+
+ dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p",
+ tcpmsg->result,
+ tcpmsg->buffer.length, tcpmsg->buffer.base);
+
+ /*
+ * Peek into the buffer to see what we can see.
+ */
+ dres = dns_message_peekheader(&tcpmsg->buffer, &id, &flags);
+ if (dres != ISC_R_SUCCESS) {
+ dispatch_log(disp, LVL(10), "got garbage packet");
+ goto restart;
+ }
+
+ dispatch_log(disp, LVL(92),
+ "got valid DNS message header, /QR %c, id %u",
+ ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id);
+
+ /*
+ * Allocate an event to send to the query or response client, and
+ * allocate a new buffer for our use.
+ */
+
+ /*
+ * Look at flags. If query, drop it. If response,
+ * look to see where it goes.
+ */
+ queue_response = ISC_FALSE;
+ if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
+ /*
+ * Query.
+ */
+ goto restart;
+ }
+
+ dns_dispatch_hash(tcpmsg->buffer.base, tcpmsg->buffer.length);
+
+ /*
+ * Response.
+ */
+ bucket = dns_hash(qid, &tcpmsg->address, id);
+ LOCK(&qid->lock);
+ resp = bucket_search(qid, &tcpmsg->address, id, bucket);
+ dispatch_log(disp, LVL(90),
+ "search for response in bucket %d: %s",
+ bucket, (resp == NULL ? "not found" : "found"));
+
+ if (resp == NULL)
+ goto unlock;
+ queue_response = resp->item_out;
+ rev = allocate_event(disp);
+ if (rev == NULL)
+ goto unlock;
+
+ /*
+ * At this point, rev contains the event we want to fill in, and
+ * resp contains the information on the place to send it to.
+ * Send the event off.
+ */
+ dns_tcpmsg_keepbuffer(tcpmsg, &rev->buffer);
+ disp->tcpbuffers++;
+ rev->result = ISC_R_SUCCESS;
+ rev->id = id;
+ rev->addr = tcpmsg->address;
+ if (queue_response) {
+ ISC_LIST_APPEND(resp->items, rev, ev_link);
+ } else {
+ ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH,
+ resp->action, resp->arg, resp, NULL, NULL);
+ request_log(disp, resp, LVL(90),
+ "[b] Sent event %p buffer %p len %d to task %p",
+ rev, rev->buffer.base, rev->buffer.length,
+ resp->task);
+ resp->item_out = ISC_TRUE;
+ isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
+ }
+ unlock:
+ UNLOCK(&qid->lock);
+
+ /*
+ * Restart recv() to get the next packet.
+ */
+ restart:
+ startrecv(disp);
+
+ UNLOCK(&disp->lock);
+
+ isc_event_free(&ev_in);
+}
+
+/*
+ * disp must be locked.
+ */
+static void
+startrecv(dns_dispatch_t *disp) {
+ isc_result_t res;
+ isc_region_t region;
+
+ if (disp->shutting_down == 1)
+ return;
+
+ if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
+ return;
+
+ if (disp->recv_pending != 0)
+ return;
+
+ if (disp->mgr->buffers >= disp->mgr->maxbuffers)
+ return;
+
+ switch (disp->socktype) {
+ /*
+ * UDP reads are always maximal.
+ */
+ case isc_sockettype_udp:
+ region.length = disp->mgr->buffersize;
+ region.base = allocate_udp_buffer(disp);
+ if (region.base == NULL)
+ return;
+ res = isc_socket_recv(disp->socket, &region, 1,
+ disp->task, udp_recv, disp);
+ if (res != ISC_R_SUCCESS) {
+ free_buffer(disp, region.base, region.length);
+ disp->shutdown_why = res;
+ disp->shutting_down = 1;
+ do_cancel(disp);
+ return;
+ }
+ INSIST(disp->recv_pending == 0);
+ disp->recv_pending = 1;
+ break;
+
+ case isc_sockettype_tcp:
+ res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task,
+ tcp_recv, disp);
+ if (res != ISC_R_SUCCESS) {
+ disp->shutdown_why = res;
+ disp->shutting_down = 1;
+ do_cancel(disp);
+ return;
+ }
+ INSIST(disp->recv_pending == 0);
+ disp->recv_pending = 1;
+ break;
+ default:
+ INSIST(0);
+ break;
+ }
+}
+
+/*
+ * Mgr must be locked when calling this function.
+ */
+static isc_boolean_t
+destroy_mgr_ok(dns_dispatchmgr_t *mgr) {
+ mgr_log(mgr, LVL(90),
+ "destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, "
+ "epool=%d, rpool=%d, dpool=%d",
+ MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list),
+ isc_mempool_getallocated(mgr->epool),
+ isc_mempool_getallocated(mgr->rpool),
+ isc_mempool_getallocated(mgr->dpool));
+ if (!MGR_IS_SHUTTINGDOWN(mgr))
+ return (ISC_FALSE);
+ if (!ISC_LIST_EMPTY(mgr->list))
+ return (ISC_FALSE);
+ if (isc_mempool_getallocated(mgr->epool) != 0)
+ return (ISC_FALSE);
+ if (isc_mempool_getallocated(mgr->rpool) != 0)
+ return (ISC_FALSE);
+ if (isc_mempool_getallocated(mgr->dpool) != 0)
+ return (ISC_FALSE);
+
+ return (ISC_TRUE);
+}
+
+/*
+ * Mgr must be unlocked when calling this function.
+ */
+static void
+destroy_mgr(dns_dispatchmgr_t **mgrp) {
+ isc_mem_t *mctx;
+ dns_dispatchmgr_t *mgr;
+
+ mgr = *mgrp;
+ *mgrp = NULL;
+
+ mctx = mgr->mctx;
+
+ mgr->magic = 0;
+ mgr->mctx = NULL;
+ DESTROYLOCK(&mgr->lock);
+ mgr->state = 0;
+
+ isc_mempool_destroy(&mgr->epool);
+ isc_mempool_destroy(&mgr->rpool);
+ isc_mempool_destroy(&mgr->dpool);
+ isc_mempool_destroy(&mgr->bpool);
+
+ DESTROYLOCK(&mgr->pool_lock);
+
+ if (mgr->entropy != NULL)
+ isc_entropy_detach(&mgr->entropy);
+ if (mgr->qid != NULL)
+ qid_destroy(mctx, &mgr->qid);
+
+ DESTROYLOCK(&mgr->buffer_lock);
+
+ if (mgr->blackhole != NULL)
+ dns_acl_detach(&mgr->blackhole);
+
+ if (mgr->portlist != NULL)
+ dns_portlist_detach(&mgr->portlist);
+
+ isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
+ isc_mem_detach(&mctx);
+}
+
+static isc_result_t
+create_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
+ isc_socket_t **sockp)
+{
+ isc_socket_t *sock;
+ isc_result_t result;
+
+ sock = NULL;
+ result = isc_socket_create(mgr, isc_sockaddr_pf(local),
+ isc_sockettype_udp, &sock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+#ifndef ISC_ALLOW_MAPPED
+ isc_socket_ipv6only(sock, ISC_TRUE);
+#endif
+ result = isc_socket_bind(sock, local);
+ if (result != ISC_R_SUCCESS) {
+ isc_socket_detach(&sock);
+ return (result);
+ }
+
+ *sockp = sock;
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Publics.
+ */
+
+isc_result_t
+dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
+ dns_dispatchmgr_t **mgrp)
+{
+ dns_dispatchmgr_t *mgr;
+ isc_result_t result;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(mgrp != NULL && *mgrp == NULL);
+
+ mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t));
+ if (mgr == NULL)
+ return (ISC_R_NOMEMORY);
+
+ mgr->mctx = NULL;
+ isc_mem_attach(mctx, &mgr->mctx);
+
+ mgr->blackhole = NULL;
+ mgr->portlist = NULL;
+
+ result = isc_mutex_init(&mgr->lock);
+ if (result != ISC_R_SUCCESS)
+ goto deallocate;
+
+ result = isc_mutex_init(&mgr->buffer_lock);
+ if (result != ISC_R_SUCCESS)
+ goto kill_lock;
+
+ result = isc_mutex_init(&mgr->pool_lock);
+ if (result != ISC_R_SUCCESS)
+ goto kill_buffer_lock;
+
+ mgr->epool = NULL;
+ if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatchevent_t),
+ &mgr->epool) != ISC_R_SUCCESS) {
+ result = ISC_R_NOMEMORY;
+ goto kill_pool_lock;
+ }
+
+ mgr->rpool = NULL;
+ if (isc_mempool_create(mgr->mctx, sizeof(dns_dispentry_t),
+ &mgr->rpool) != ISC_R_SUCCESS) {
+ result = ISC_R_NOMEMORY;
+ goto kill_epool;
+ }
+
+ mgr->dpool = NULL;
+ if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatch_t),
+ &mgr->dpool) != ISC_R_SUCCESS) {
+ result = ISC_R_NOMEMORY;
+ goto kill_rpool;
+ }
+
+ isc_mempool_setname(mgr->epool, "dispmgr_epool");
+ isc_mempool_setfreemax(mgr->epool, 1024);
+ isc_mempool_associatelock(mgr->epool, &mgr->pool_lock);
+
+ isc_mempool_setname(mgr->rpool, "dispmgr_rpool");
+ isc_mempool_setfreemax(mgr->rpool, 1024);
+ isc_mempool_associatelock(mgr->rpool, &mgr->pool_lock);
+
+ isc_mempool_setname(mgr->dpool, "dispmgr_dpool");
+ isc_mempool_setfreemax(mgr->dpool, 1024);
+ isc_mempool_associatelock(mgr->dpool, &mgr->pool_lock);
+
+ mgr->buffers = 0;
+ mgr->buffersize = 0;
+ mgr->maxbuffers = 0;
+ mgr->bpool = NULL;
+ mgr->entropy = NULL;
+ mgr->qid = NULL;
+ mgr->state = 0;
+ ISC_LIST_INIT(mgr->list);
+ mgr->magic = DNS_DISPATCHMGR_MAGIC;
+
+ if (entropy != NULL)
+ isc_entropy_attach(entropy, &mgr->entropy);
+
+ *mgrp = mgr;
+ return (ISC_R_SUCCESS);
+
+ kill_rpool:
+ isc_mempool_destroy(&mgr->rpool);
+ kill_epool:
+ isc_mempool_destroy(&mgr->epool);
+ kill_pool_lock:
+ DESTROYLOCK(&mgr->pool_lock);
+ kill_buffer_lock:
+ DESTROYLOCK(&mgr->buffer_lock);
+ kill_lock:
+ DESTROYLOCK(&mgr->lock);
+ deallocate:
+ isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
+ isc_mem_detach(&mctx);
+
+ return (result);
+}
+
+void
+dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) {
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+ if (mgr->blackhole != NULL)
+ dns_acl_detach(&mgr->blackhole);
+ dns_acl_attach(blackhole, &mgr->blackhole);
+}
+
+dns_acl_t *
+dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) {
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+ return (mgr->blackhole);
+}
+
+void
+dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr,
+ dns_portlist_t *portlist)
+{
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+ if (mgr->portlist != NULL)
+ dns_portlist_detach(&mgr->portlist);
+ if (portlist != NULL)
+ dns_portlist_attach(portlist, &mgr->portlist);
+}
+
+dns_portlist_t *
+dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr) {
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+ return (mgr->portlist);
+}
+
+static isc_result_t
+dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
+ unsigned int buffersize, unsigned int maxbuffers,
+ unsigned int buckets, unsigned int increment)
+{
+ isc_result_t result;
+
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+ REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
+ REQUIRE(maxbuffers > 0);
+ REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */
+ REQUIRE(increment > buckets);
+
+ /*
+ * Keep some number of items around. This should be a config
+ * option. For now, keep 8, but later keep at least two even
+ * if the caller wants less. This allows us to ensure certain
+ * things, like an event can be "freed" and the next allocation
+ * will always succeed.
+ *
+ * Note that if limits are placed on anything here, we use one
+ * event internally, so the actual limit should be "wanted + 1."
+ *
+ * XXXMLG
+ */
+
+ if (maxbuffers < 8)
+ maxbuffers = 8;
+
+ LOCK(&mgr->buffer_lock);
+ if (mgr->bpool != NULL) {
+ isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
+ mgr->maxbuffers = maxbuffers;
+ UNLOCK(&mgr->buffer_lock);
+ return (ISC_R_SUCCESS);
+ }
+
+ if (isc_mempool_create(mgr->mctx, buffersize,
+ &mgr->bpool) != ISC_R_SUCCESS) {
+ UNLOCK(&mgr->buffer_lock);
+ return (ISC_R_NOMEMORY);
+ }
+
+ isc_mempool_setname(mgr->bpool, "dispmgr_bpool");
+ isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
+ isc_mempool_associatelock(mgr->bpool, &mgr->pool_lock);
+
+ result = qid_allocate(mgr, buckets, increment, ISC_TRUE, &mgr->qid);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ mgr->buffersize = buffersize;
+ mgr->maxbuffers = maxbuffers;
+ UNLOCK(&mgr->buffer_lock);
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ isc_mempool_destroy(&mgr->bpool);
+ UNLOCK(&mgr->buffer_lock);
+ return (ISC_R_NOMEMORY);
+}
+
+void
+dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) {
+ dns_dispatchmgr_t *mgr;
+ isc_boolean_t killit;
+
+ REQUIRE(mgrp != NULL);
+ REQUIRE(VALID_DISPATCHMGR(*mgrp));
+
+ mgr = *mgrp;
+ *mgrp = NULL;
+
+ LOCK(&mgr->lock);
+ mgr->state |= MGR_SHUTTINGDOWN;
+
+ killit = destroy_mgr_ok(mgr);
+ UNLOCK(&mgr->lock);
+
+ mgr_log(mgr, LVL(90), "destroy: killit=%d", killit);
+
+ if (killit)
+ destroy_mgr(&mgr);
+}
+
+static isc_boolean_t
+blacklisted(dns_dispatchmgr_t *mgr, isc_socket_t *sock) {
+ isc_sockaddr_t sockaddr;
+ isc_result_t result;
+
+ if (mgr->portlist == NULL)
+ return (ISC_FALSE);
+
+ result = isc_socket_getsockname(sock, &sockaddr);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_FALSE);
+
+ if (mgr->portlist != NULL &&
+ dns_portlist_match(mgr->portlist, isc_sockaddr_pf(&sockaddr),
+ isc_sockaddr_getport(&sockaddr)))
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+#define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))
+
+static isc_boolean_t
+local_addr_match(dns_dispatch_t *disp, isc_sockaddr_t *addr) {
+ isc_sockaddr_t sockaddr;
+ isc_result_t result;
+
+ if (addr == NULL)
+ return (ISC_TRUE);
+
+ /*
+ * Don't match wildcard ports against newly blacklisted ports.
+ */
+ if (disp->mgr->portlist != NULL &&
+ isc_sockaddr_getport(addr) == 0 &&
+ isc_sockaddr_getport(&disp->local) == 0 &&
+ blacklisted(disp->mgr, disp->socket))
+ return (ISC_FALSE);
+
+ /*
+ * Check if we match the binding <address,port>.
+ * Wildcard ports match/fail here.
+ */
+ if (isc_sockaddr_equal(&disp->local, addr))
+ return (ISC_TRUE);
+ if (isc_sockaddr_getport(addr) == 0)
+ return (ISC_FALSE);
+
+ /*
+ * Check if we match a bound wildcard port <address,port>.
+ */
+ if (!isc_sockaddr_eqaddr(&disp->local, addr))
+ return (ISC_FALSE);
+ result = isc_socket_getsockname(disp->socket, &sockaddr);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_FALSE);
+
+ return (isc_sockaddr_equal(&sockaddr, addr));
+}
+
+/*
+ * Requires mgr be locked.
+ *
+ * No dispatcher can be locked by this thread when calling this function.
+ *
+ *
+ * NOTE:
+ * If a matching dispatcher is found, it is locked after this function
+ * returns, and must be unlocked by the caller.
+ */
+static isc_result_t
+dispatch_find(dns_dispatchmgr_t *mgr, isc_sockaddr_t *local,
+ unsigned int attributes, unsigned int mask,
+ dns_dispatch_t **dispp)
+{
+ dns_dispatch_t *disp;
+ isc_result_t result;
+
+ /*
+ * Make certain that we will not match a private dispatch.
+ */
+ attributes &= ~DNS_DISPATCHATTR_PRIVATE;
+ mask |= DNS_DISPATCHATTR_PRIVATE;
+
+ disp = ISC_LIST_HEAD(mgr->list);
+ while (disp != NULL) {
+ LOCK(&disp->lock);
+ if ((disp->shutting_down == 0)
+ && ATTRMATCH(disp->attributes, attributes, mask)
+ && local_addr_match(disp, local))
+ break;
+ UNLOCK(&disp->lock);
+ disp = ISC_LIST_NEXT(disp, link);
+ }
+
+ if (disp == NULL) {
+ result = ISC_R_NOTFOUND;
+ goto out;
+ }
+
+ *dispp = disp;
+ result = ISC_R_SUCCESS;
+ out:
+
+ return (result);
+}
+
+static isc_result_t
+qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
+ unsigned int increment, isc_boolean_t usepool, dns_qid_t **qidp)
+{
+ dns_qid_t *qid;
+ unsigned int i;
+ isc_result_t result;
+
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+ REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */
+ REQUIRE(increment > buckets);
+ REQUIRE(qidp != NULL && *qidp == NULL);
+
+ qid = isc_mem_get(mgr->mctx, sizeof(*qid));
+ if (qid == NULL)
+ return (ISC_R_NOMEMORY);
+
+ qid->qid_table = isc_mem_get(mgr->mctx,
+ buckets * sizeof(dns_displist_t));
+ if (qid->qid_table == NULL) {
+ isc_mem_put(mgr->mctx, qid, sizeof(*qid));
+ return (ISC_R_NOMEMORY);
+ }
+
+ result = nsid_init(mgr->mctx, &qid->nsid, usepool);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mgr->mctx, qid->qid_table,
+ buckets * sizeof(dns_displist_t));
+ isc_mem_put(mgr->mctx, qid, sizeof(*qid));
+ return (ISC_R_NOMEMORY);
+ }
+
+ result = isc_mutex_init(&qid->lock);
+ if (result != ISC_R_SUCCESS) {
+ nsid_destroy(mgr->mctx, &qid->nsid);
+ isc_mem_put(mgr->mctx, qid->qid_table,
+ buckets * sizeof(dns_displist_t));
+ isc_mem_put(mgr->mctx, qid, sizeof(*qid));
+ return (result);
+ }
+
+ for (i = 0; i < buckets; i++)
+ ISC_LIST_INIT(qid->qid_table[i]);
+
+ qid->qid_nbuckets = buckets;
+ qid->qid_increment = increment;
+ qid->magic = QID_MAGIC;
+ *qidp = qid;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) {
+ dns_qid_t *qid;
+
+ REQUIRE(qidp != NULL);
+ qid = *qidp;
+
+ REQUIRE(VALID_QID(qid));
+
+ *qidp = NULL;
+ qid->magic = 0;
+ nsid_destroy(mctx, &qid->nsid);
+ isc_mem_put(mctx, qid->qid_table,
+ qid->qid_nbuckets * sizeof(dns_displist_t));
+ DESTROYLOCK(&qid->lock);
+ isc_mem_put(mctx, qid, sizeof(*qid));
+}
+
+/*
+ * Allocate and set important limits.
+ */
+static isc_result_t
+dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests,
+ dns_dispatch_t **dispp)
+{
+ dns_dispatch_t *disp;
+ isc_result_t result;
+
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+ REQUIRE(dispp != NULL && *dispp == NULL);
+
+ /*
+ * Set up the dispatcher, mostly. Don't bother setting some of
+ * the options that are controlled by tcp vs. udp, etc.
+ */
+
+ disp = isc_mempool_get(mgr->dpool);
+ if (disp == NULL)
+ return (ISC_R_NOMEMORY);
+
+ disp->magic = 0;
+ disp->mgr = mgr;
+ disp->maxrequests = maxrequests;
+ disp->attributes = 0;
+ ISC_LINK_INIT(disp, link);
+ disp->refcount = 1;
+ disp->recv_pending = 0;
+ memset(&disp->local, 0, sizeof(disp->local));
+ disp->shutting_down = 0;
+ disp->shutdown_out = 0;
+ disp->connected = 0;
+ disp->tcpmsg_valid = 0;
+ disp->shutdown_why = ISC_R_UNEXPECTED;
+ disp->requests = 0;
+ disp->tcpbuffers = 0;
+ disp->qid = NULL;
+
+ result = isc_mutex_init(&disp->lock);
+ if (result != ISC_R_SUCCESS)
+ goto deallocate;
+
+ disp->failsafe_ev = allocate_event(disp);
+ if (disp->failsafe_ev == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto kill_lock;
+ }
+
+ disp->magic = DISPATCH_MAGIC;
+
+ *dispp = disp;
+ return (ISC_R_SUCCESS);
+
+ /*
+ * error returns
+ */
+ kill_lock:
+ DESTROYLOCK(&disp->lock);
+ deallocate:
+ isc_mempool_put(mgr->dpool, disp);
+
+ return (result);
+}
+
+
+/*
+ * MUST be unlocked, and not used by anthing.
+ */
+static void
+dispatch_free(dns_dispatch_t **dispp)
+{
+ dns_dispatch_t *disp;
+ dns_dispatchmgr_t *mgr;
+
+ REQUIRE(VALID_DISPATCH(*dispp));
+ disp = *dispp;
+ *dispp = NULL;
+
+ mgr = disp->mgr;
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+
+ if (disp->tcpmsg_valid) {
+ dns_tcpmsg_invalidate(&disp->tcpmsg);
+ disp->tcpmsg_valid = 0;
+ }
+
+ INSIST(disp->tcpbuffers == 0);
+ INSIST(disp->requests == 0);
+ INSIST(disp->recv_pending == 0);
+
+ isc_mempool_put(mgr->epool, disp->failsafe_ev);
+ disp->failsafe_ev = NULL;
+
+ if (disp->qid != NULL)
+ qid_destroy(mgr->mctx, &disp->qid);
+ disp->mgr = NULL;
+ DESTROYLOCK(&disp->lock);
+ disp->magic = 0;
+ isc_mempool_put(mgr->dpool, disp);
+}
+
+isc_result_t
+dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
+ isc_taskmgr_t *taskmgr, unsigned int buffersize,
+ unsigned int maxbuffers, unsigned int maxrequests,
+ unsigned int buckets, unsigned int increment,
+ unsigned int attributes, dns_dispatch_t **dispp)
+{
+ isc_result_t result;
+ dns_dispatch_t *disp;
+
+ UNUSED(maxbuffers);
+ UNUSED(buffersize);
+
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+ REQUIRE(isc_socket_gettype(sock) == isc_sockettype_tcp);
+ REQUIRE((attributes & DNS_DISPATCHATTR_TCP) != 0);
+ REQUIRE((attributes & DNS_DISPATCHATTR_UDP) == 0);
+
+ attributes |= DNS_DISPATCHATTR_PRIVATE; /* XXXMLG */
+
+ LOCK(&mgr->lock);
+
+ /*
+ * dispatch_allocate() checks mgr for us.
+ * qid_allocate() checks buckets and increment for us.
+ */
+ disp = NULL;
+ result = dispatch_allocate(mgr, maxrequests, &disp);
+ if (result != ISC_R_SUCCESS) {
+ UNLOCK(&mgr->lock);
+ return (result);
+ }
+
+ result = qid_allocate(mgr, buckets, increment, ISC_FALSE, &disp->qid);
+ if (result != ISC_R_SUCCESS)
+ goto deallocate_dispatch;
+
+ disp->socktype = isc_sockettype_tcp;
+ disp->socket = NULL;
+ isc_socket_attach(sock, &disp->socket);
+
+ disp->task = NULL;
+ result = isc_task_create(taskmgr, 0, &disp->task);
+ if (result != ISC_R_SUCCESS)
+ goto kill_socket;
+
+ disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
+ DNS_EVENT_DISPATCHCONTROL,
+ destroy_disp, disp,
+ sizeof(isc_event_t));
+ if (disp->ctlevent == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto kill_task;
+ }
+
+ isc_task_setname(disp->task, "tcpdispatch", disp);
+
+ dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg);
+ disp->tcpmsg_valid = 1;
+
+ disp->attributes = attributes;
+
+ /*
+ * Append it to the dispatcher list.
+ */
+ ISC_LIST_APPEND(mgr->list, disp, link);
+ UNLOCK(&mgr->lock);
+
+ mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp);
+ dispatch_log(disp, LVL(90), "created task %p", disp->task);
+
+ *dispp = disp;
+
+ return (ISC_R_SUCCESS);
+
+ /*
+ * Error returns.
+ */
+ kill_task:
+ isc_task_detach(&disp->task);
+ kill_socket:
+ isc_socket_detach(&disp->socket);
+ deallocate_dispatch:
+ dispatch_free(&disp);
+
+ UNLOCK(&mgr->lock);
+
+ return (result);
+}
+
+isc_result_t
+dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
+ isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
+ unsigned int buffersize,
+ unsigned int maxbuffers, unsigned int maxrequests,
+ unsigned int buckets, unsigned int increment,
+ unsigned int attributes, unsigned int mask,
+ dns_dispatch_t **dispp)
+{
+ isc_result_t result;
+ dns_dispatch_t *disp;
+
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+ REQUIRE(sockmgr != NULL);
+ REQUIRE(localaddr != NULL);
+ REQUIRE(taskmgr != NULL);
+ REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
+ REQUIRE(maxbuffers > 0);
+ REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */
+ REQUIRE(increment > buckets);
+ REQUIRE(dispp != NULL && *dispp == NULL);
+ REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0);
+
+ result = dns_dispatchmgr_setudp(mgr, buffersize, maxbuffers,
+ buckets, increment);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ LOCK(&mgr->lock);
+
+ /*
+ * First, see if we have a dispatcher that matches.
+ */
+ disp = NULL;
+ result = dispatch_find(mgr, localaddr, attributes, mask, &disp);
+ if (result == ISC_R_SUCCESS) {
+ disp->refcount++;
+
+ if (disp->maxrequests < maxrequests)
+ disp->maxrequests = maxrequests;
+
+ if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0 &&
+ (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
+ {
+ disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
+ if (disp->recv_pending != 0)
+ isc_socket_cancel(disp->socket, disp->task,
+ ISC_SOCKCANCEL_RECV);
+ }
+
+ UNLOCK(&disp->lock);
+ UNLOCK(&mgr->lock);
+
+ *dispp = disp;
+
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * Nope, create one.
+ */
+ result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr,
+ maxrequests, attributes, &disp);
+ if (result != ISC_R_SUCCESS) {
+ UNLOCK(&mgr->lock);
+ return (result);
+ }
+
+ UNLOCK(&mgr->lock);
+ *dispp = disp;
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * mgr should be locked.
+ */
+
+#ifndef DNS_DISPATCH_HELD
+#define DNS_DISPATCH_HELD 20U
+#endif
+
+static isc_result_t
+dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
+ isc_taskmgr_t *taskmgr,
+ isc_sockaddr_t *localaddr,
+ unsigned int maxrequests,
+ unsigned int attributes,
+ dns_dispatch_t **dispp)
+{
+ isc_result_t result;
+ dns_dispatch_t *disp;
+ isc_socket_t *sock = NULL;
+ isc_socket_t *held[DNS_DISPATCH_HELD];
+ unsigned int i = 0, j = 0;
+
+ /*
+ * dispatch_allocate() checks mgr for us.
+ */
+ disp = NULL;
+ result = dispatch_allocate(mgr, maxrequests, &disp);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Try to allocate a socket that is not on the blacklist.
+ * Hold up to DNS_DISPATCH_HELD sockets to prevent the OS
+ * from returning the same port to us too quickly.
+ */
+ memset(held, 0, sizeof(held));
+ getsocket:
+ result = create_socket(sockmgr, localaddr, &sock);
+ if (result != ISC_R_SUCCESS)
+ goto deallocate_dispatch;
+ if (isc_sockaddr_getport(localaddr) == 0 && blacklisted(mgr, sock)) {
+ if (held[i] != NULL)
+ isc_socket_detach(&held[i]);
+ held[i++] = sock;
+ sock = NULL;
+ if (i == DNS_DISPATCH_HELD)
+ i = 0;
+ if (j++ == 0xffffU) {
+ mgr_log(mgr, ISC_LOG_ERROR, "avoid-v%s-udp-ports: "
+ "unable to allocate a non-blacklisted port",
+ isc_sockaddr_pf(localaddr) == AF_INET ?
+ "4" : "6");
+ result = ISC_R_FAILURE;
+ goto deallocate_dispatch;
+ }
+ goto getsocket;
+ }
+
+ disp->socktype = isc_sockettype_udp;
+ disp->socket = sock;
+ disp->local = *localaddr;
+
+ disp->task = NULL;
+ result = isc_task_create(taskmgr, 0, &disp->task);
+ if (result != ISC_R_SUCCESS)
+ goto kill_socket;
+
+ disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
+ DNS_EVENT_DISPATCHCONTROL,
+ destroy_disp, disp,
+ sizeof(isc_event_t));
+ if (disp->ctlevent == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto kill_task;
+ }
+
+ isc_task_setname(disp->task, "udpdispatch", disp);
+
+ attributes &= ~DNS_DISPATCHATTR_TCP;
+ attributes |= DNS_DISPATCHATTR_UDP;
+ disp->attributes = attributes;
+
+ /*
+ * Append it to the dispatcher list.
+ */
+ ISC_LIST_APPEND(mgr->list, disp, link);
+
+ mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp);
+ dispatch_log(disp, LVL(90), "created task %p", disp->task);
+ dispatch_log(disp, LVL(90), "created socket %p", disp->socket);
+
+ *dispp = disp;
+
+ goto cleanheld;
+
+ /*
+ * Error returns.
+ */
+ kill_task:
+ isc_task_detach(&disp->task);
+ kill_socket:
+ isc_socket_detach(&disp->socket);
+ deallocate_dispatch:
+ dispatch_free(&disp);
+ cleanheld:
+ for (i = 0; i < DNS_DISPATCH_HELD; i++)
+ if (held[i] != NULL)
+ isc_socket_detach(&held[i]);
+ return (result);
+}
+
+void
+dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) {
+ REQUIRE(VALID_DISPATCH(disp));
+ REQUIRE(dispp != NULL && *dispp == NULL);
+
+ LOCK(&disp->lock);
+ disp->refcount++;
+ UNLOCK(&disp->lock);
+
+ *dispp = disp;
+}
+
+/*
+ * It is important to lock the manager while we are deleting the dispatch,
+ * since dns_dispatch_getudp will call dispatch_find, which returns to
+ * the caller a dispatch but does not attach to it until later. _getudp
+ * locks the manager, however, so locking it here will keep us from attaching
+ * to a dispatcher that is in the process of going away.
+ */
+void
+dns_dispatch_detach(dns_dispatch_t **dispp) {
+ dns_dispatch_t *disp;
+ isc_boolean_t killit;
+
+ REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp));
+
+ disp = *dispp;
+ *dispp = NULL;
+
+ LOCK(&disp->lock);
+
+ INSIST(disp->refcount > 0);
+ disp->refcount--;
+ killit = ISC_FALSE;
+ if (disp->refcount == 0) {
+ if (disp->recv_pending > 0)
+ isc_socket_cancel(disp->socket, disp->task,
+ ISC_SOCKCANCEL_RECV);
+ disp->shutting_down = 1;
+ }
+
+ dispatch_log(disp, LVL(90), "detach: refcount %d", disp->refcount);
+
+ killit = destroy_disp_ok(disp);
+ UNLOCK(&disp->lock);
+ if (killit)
+ isc_task_send(disp->task, &disp->ctlevent);
+}
+
+isc_result_t
+dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_messageid_t *idp, dns_dispentry_t **resp)
+{
+ dns_dispentry_t *res;
+ unsigned int bucket;
+ dns_messageid_t id;
+ int i;
+ isc_boolean_t ok;
+ dns_qid_t *qid;
+
+ REQUIRE(VALID_DISPATCH(disp));
+ REQUIRE(task != NULL);
+ REQUIRE(dest != NULL);
+ REQUIRE(resp != NULL && *resp == NULL);
+ REQUIRE(idp != NULL);
+
+ LOCK(&disp->lock);
+
+ if (disp->shutting_down == 1) {
+ UNLOCK(&disp->lock);
+ return (ISC_R_SHUTTINGDOWN);
+ }
+
+ if (disp->requests >= disp->maxrequests) {
+ UNLOCK(&disp->lock);
+ return (ISC_R_QUOTA);
+ }
+
+ /*
+ * Try somewhat hard to find an unique ID.
+ */
+ qid = DNS_QID(disp);
+ LOCK(&qid->lock);
+ id = dns_randomid(&qid->nsid);
+ bucket = dns_hash(qid, dest, id);
+ ok = ISC_FALSE;
+ for (i = 0; i < 64; i++) {
+ if (bucket_search(qid, dest, id, bucket) == NULL) {
+ ok = ISC_TRUE;
+ break;
+ }
+ id += qid->qid_increment;
+ id &= 0x0000ffff;
+ bucket = dns_hash(qid, dest, id);
+ }
+
+ if (!ok) {
+ UNLOCK(&qid->lock);
+ UNLOCK(&disp->lock);
+ return (ISC_R_NOMORE);
+ }
+
+ res = isc_mempool_get(disp->mgr->rpool);
+ if (res == NULL) {
+ UNLOCK(&qid->lock);
+ UNLOCK(&disp->lock);
+ return (ISC_R_NOMEMORY);
+ }
+
+ disp->refcount++;
+ disp->requests++;
+ res->task = NULL;
+ isc_task_attach(task, &res->task);
+ res->disp = disp;
+ res->id = id;
+ res->bucket = bucket;
+ res->host = *dest;
+ res->action = action;
+ res->arg = arg;
+ res->item_out = ISC_FALSE;
+ ISC_LIST_INIT(res->items);
+ ISC_LINK_INIT(res, link);
+ res->magic = RESPONSE_MAGIC;
+ ISC_LIST_APPEND(qid->qid_table[bucket], res, link);
+ UNLOCK(&qid->lock);
+
+ request_log(disp, res, LVL(90),
+ "attached to task %p", res->task);
+
+ if (((disp->attributes & DNS_DISPATCHATTR_UDP) != 0) ||
+ ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0))
+ startrecv(disp);
+
+ UNLOCK(&disp->lock);
+
+ *idp = id;
+ *resp = res;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_dispatch_starttcp(dns_dispatch_t *disp) {
+
+ REQUIRE(VALID_DISPATCH(disp));
+
+ dispatch_log(disp, LVL(90), "starttcp %p", disp->task);
+
+ LOCK(&disp->lock);
+ disp->attributes |= DNS_DISPATCHATTR_CONNECTED;
+ startrecv(disp);
+ UNLOCK(&disp->lock);
+}
+
+void
+dns_dispatch_removeresponse(dns_dispentry_t **resp,
+ dns_dispatchevent_t **sockevent)
+{
+ dns_dispatchmgr_t *mgr;
+ dns_dispatch_t *disp;
+ dns_dispentry_t *res;
+ dns_dispatchevent_t *ev;
+ unsigned int bucket;
+ isc_boolean_t killit;
+ unsigned int n;
+ isc_eventlist_t events;
+ dns_qid_t *qid;
+
+ REQUIRE(resp != NULL);
+ REQUIRE(VALID_RESPONSE(*resp));
+
+ res = *resp;
+ *resp = NULL;
+
+ disp = res->disp;
+ REQUIRE(VALID_DISPATCH(disp));
+ mgr = disp->mgr;
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+
+ qid = DNS_QID(disp);
+
+ if (sockevent != NULL) {
+ REQUIRE(*sockevent != NULL);
+ ev = *sockevent;
+ *sockevent = NULL;
+ } else {
+ ev = NULL;
+ }
+
+ LOCK(&disp->lock);
+
+ INSIST(disp->requests > 0);
+ disp->requests--;
+ INSIST(disp->refcount > 0);
+ disp->refcount--;
+ killit = ISC_FALSE;
+ if (disp->refcount == 0) {
+ if (disp->recv_pending > 0)
+ isc_socket_cancel(disp->socket, disp->task,
+ ISC_SOCKCANCEL_RECV);
+ disp->shutting_down = 1;
+ }
+
+ bucket = res->bucket;
+
+ LOCK(&qid->lock);
+ ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
+ UNLOCK(&qid->lock);
+
+ if (ev == NULL && res->item_out) {
+ /*
+ * We've posted our event, but the caller hasn't gotten it
+ * yet. Take it back.
+ */
+ ISC_LIST_INIT(events);
+ n = isc_task_unsend(res->task, res, DNS_EVENT_DISPATCH,
+ NULL, &events);
+ /*
+ * We had better have gotten it back.
+ */
+ INSIST(n == 1);
+ ev = (dns_dispatchevent_t *)ISC_LIST_HEAD(events);
+ }
+
+ if (ev != NULL) {
+ REQUIRE(res->item_out == ISC_TRUE);
+ res->item_out = ISC_FALSE;
+ if (ev->buffer.base != NULL)
+ free_buffer(disp, ev->buffer.base, ev->buffer.length);
+ free_event(disp, ev);
+ }
+
+ request_log(disp, res, LVL(90), "detaching from task %p", res->task);
+ isc_task_detach(&res->task);
+
+ /*
+ * Free any buffered requests as well
+ */
+ ev = ISC_LIST_HEAD(res->items);
+ while (ev != NULL) {
+ ISC_LIST_UNLINK(res->items, ev, ev_link);
+ if (ev->buffer.base != NULL)
+ free_buffer(disp, ev->buffer.base, ev->buffer.length);
+ free_event(disp, ev);
+ ev = ISC_LIST_HEAD(res->items);
+ }
+ res->magic = 0;
+ isc_mempool_put(disp->mgr->rpool, res);
+ if (disp->shutting_down == 1)
+ do_cancel(disp);
+ else
+ startrecv(disp);
+
+ killit = destroy_disp_ok(disp);
+ UNLOCK(&disp->lock);
+ if (killit)
+ isc_task_send(disp->task, &disp->ctlevent);
+}
+
+static void
+do_cancel(dns_dispatch_t *disp) {
+ dns_dispatchevent_t *ev;
+ dns_dispentry_t *resp;
+ dns_qid_t *qid;
+
+ if (disp->shutdown_out == 1)
+ return;
+
+ qid = DNS_QID(disp);
+
+ /*
+ * Search for the first response handler without packets outstanding.
+ */
+ LOCK(&qid->lock);
+ for (resp = linear_first(qid);
+ resp != NULL && resp->item_out != ISC_FALSE;
+ /* Empty. */)
+ resp = linear_next(qid, resp);
+ /*
+ * No one to send the cancel event to, so nothing to do.
+ */
+ if (resp == NULL)
+ goto unlock;
+
+ /*
+ * Send the shutdown failsafe event to this resp.
+ */
+ ev = disp->failsafe_ev;
+ ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH,
+ resp->action, resp->arg, resp, NULL, NULL);
+ ev->result = disp->shutdown_why;
+ ev->buffer.base = NULL;
+ ev->buffer.length = 0;
+ disp->shutdown_out = 1;
+ request_log(disp, resp, LVL(10),
+ "cancel: failsafe event %p -> task %p",
+ ev, resp->task);
+ resp->item_out = ISC_TRUE;
+ isc_task_send(resp->task, ISC_EVENT_PTR(&ev));
+ unlock:
+ UNLOCK(&qid->lock);
+}
+
+isc_socket_t *
+dns_dispatch_getsocket(dns_dispatch_t *disp) {
+ REQUIRE(VALID_DISPATCH(disp));
+
+ return (disp->socket);
+}
+
+isc_result_t
+dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) {
+
+ REQUIRE(VALID_DISPATCH(disp));
+ REQUIRE(addrp != NULL);
+
+ if (disp->socktype == isc_sockettype_udp) {
+ *addrp = disp->local;
+ return (ISC_R_SUCCESS);
+ }
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+void
+dns_dispatch_cancel(dns_dispatch_t *disp) {
+ REQUIRE(VALID_DISPATCH(disp));
+
+ LOCK(&disp->lock);
+
+ if (disp->shutting_down == 1) {
+ UNLOCK(&disp->lock);
+ return;
+ }
+
+ disp->shutdown_why = ISC_R_CANCELED;
+ disp->shutting_down = 1;
+ do_cancel(disp);
+
+ UNLOCK(&disp->lock);
+
+ return;
+}
+
+void
+dns_dispatch_changeattributes(dns_dispatch_t *disp,
+ unsigned int attributes, unsigned int mask)
+{
+ REQUIRE(VALID_DISPATCH(disp));
+
+ /* XXXMLG
+ * Should check for valid attributes here!
+ */
+
+ LOCK(&disp->lock);
+
+ if ((mask & DNS_DISPATCHATTR_NOLISTEN) != 0) {
+ if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0 &&
+ (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) {
+ disp->attributes &= ~DNS_DISPATCHATTR_NOLISTEN;
+ startrecv(disp);
+ } else if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN)
+ == 0 &&
+ (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) {
+ disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
+ if (disp->recv_pending != 0)
+ isc_socket_cancel(disp->socket, disp->task,
+ ISC_SOCKCANCEL_RECV);
+ }
+ }
+
+ disp->attributes &= ~mask;
+ disp->attributes |= (attributes & mask);
+ UNLOCK(&disp->lock);
+}
+
+void
+dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) {
+ void *buf;
+ isc_socketevent_t *sevent, *newsevent;
+
+ REQUIRE(VALID_DISPATCH(disp));
+ REQUIRE((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0);
+ REQUIRE(event != NULL);
+
+ sevent = (isc_socketevent_t *)event;
+
+ INSIST(sevent->n <= disp->mgr->buffersize);
+ newsevent = (isc_socketevent_t *)
+ isc_event_allocate(disp->mgr->mctx, NULL,
+ DNS_EVENT_IMPORTRECVDONE, udp_recv,
+ disp, sizeof(isc_socketevent_t));
+ if (newsevent == NULL)
+ return;
+
+ buf = allocate_udp_buffer(disp);
+ if (buf == NULL) {
+ isc_event_free(ISC_EVENT_PTR(&newsevent));
+ return;
+ }
+ memcpy(buf, sevent->region.base, sevent->n);
+ newsevent->region.base = buf;
+ newsevent->region.length = disp->mgr->buffersize;
+ newsevent->n = sevent->n;
+ newsevent->result = sevent->result;
+ newsevent->address = sevent->address;
+ newsevent->timestamp = sevent->timestamp;
+ newsevent->pktinfo = sevent->pktinfo;
+ newsevent->attributes = sevent->attributes;
+
+ isc_task_send(disp->task, ISC_EVENT_PTR(&newsevent));
+}
+
+#if 0
+void
+dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) {
+ dns_dispatch_t *disp;
+ char foo[1024];
+
+ disp = ISC_LIST_HEAD(mgr->list);
+ while (disp != NULL) {
+ isc_sockaddr_format(&disp->local, foo, sizeof(foo));
+ printf("\tdispatch %p, addr %s\n", disp, foo);
+ disp = ISC_LIST_NEXT(disp, link);
+ }
+}
+#endif
+
+/*
+ * Allow the user to pick one of two ID randomization algorithms.
+ *
+ * The first algorithm is an adaptation of the sequence shuffling
+ * algorithm discovered by Carter Bays and S. D. Durham [ACM Trans. Math.
+ * Software 2 (1976), 59-64], as documented as Algorithm B in Chapter
+ * 3.2.2 in Volume 2 of Knuth's "The Art of Computer Programming". We use
+ * a randomly selected linear congruential random number generator with a
+ * modulus of 2^16, whose increment is a randomly picked odd number, and
+ * whose multiplier is picked from a set which meets the following
+ * criteria:
+ * Is of the form 8*n+5, which ensures "high potency" according to
+ * principle iii in the summary chapter 3.6. This form also has a
+ * gcd(a-1,m) of 4 which is good according to principle iv.
+ *
+ * Is between 0.01 and 0.99 times the modulus as specified by
+ * principle iv.
+ *
+ * Passes the spectral test "with flying colors" (ut >= 1) in
+ * dimensions 2 through 6 as calculated by Algorithm S in Chapter
+ * 3.3.4 and the ratings calculated by formula 35 in section E.
+ *
+ * Of the multipliers that pass this test, pick the set that is
+ * best according to the theoretical bounds of the serial
+ * correlation test. This was calculated using a simplified
+ * version of Knuth's Theorem K in Chapter 3.3.3.
+ *
+ * These criteria may not be important for this use, but we might as well
+ * pick from the best generators since there are so many possible ones and
+ * we don't have that many random bits to do the picking.
+ *
+ * We use a modulus of 2^16 instead of something bigger so that we will
+ * tend to cycle through all the possible IDs before repeating any,
+ * however the shuffling will perturb this somewhat. Theoretically there
+ * is no minimimum interval between two uses of the same ID, but in
+ * practice it seems to be >64000.
+ *
+ * Our adaptatation of Algorithm B mixes the hash state which has
+ * captured various random events into the shuffler to perturb the
+ * sequence.
+ *
+ * One disadvantage of this algorithm is that if the generator parameters
+ * were to be guessed, it would be possible to mount a limited brute force
+ * attack on the ID space since the IDs are only shuffled within a limited
+ * range.
+ *
+ * The second algorithm uses the same random number generator to populate
+ * a pool of 65536 IDs. The hash state is used to pick an ID from a window
+ * of 4096 IDs in this pool, then the chosen ID is swapped with the ID
+ * at the beginning of the window and the window position is advanced.
+ * This means that the interval between uses of the ID will be no less
+ * than 65536-4096. The ID sequence in the pool will become more random
+ * over time.
+ *
+ * For both algorithms, two more linear congruential random number generators
+ * are selected. The ID from the first part of algorithm is used to seed
+ * the first of these generators, and its output is used to seed the second.
+ * The strategy is use these generators as 1 to 1 hashes to obfuscate the
+ * properties of the generator used in the first part of either algorithm.
+ *
+ * The first algorithm may be suitable for use in a client resolver since
+ * its memory requirements are fairly low and it's pretty random out of
+ * the box. It is somewhat succeptible to a limited brute force attack,
+ * so the second algorithm is probably preferable for a longer running
+ * program that issues a large number of queries and has time to randomize
+ * the pool.
+ */
+
+#define NSID_SHUFFLE_TABLE_SIZE 100 /* Suggested by Knuth */
+/*
+ * Pick one of the next 4096 IDs in the pool.
+ * There is a tradeoff here between randomness and how often and ID is reused.
+ */
+#define NSID_LOOKAHEAD 4096 /* Must be a power of 2 */
+#define NSID_SHUFFLE_ONLY 1 /* algorithm 1 */
+#define NSID_USE_POOL 2 /* algorithm 2 */
+#define NSID_HASHSHIFT 3
+#define NSID_HASHROTATE(v) \
+ (((v) << NSID_HASHSHIFT) | ((v) >> ((sizeof(v) * 8) - NSID_HASHSHIFT)))
+
+static isc_uint32_t nsid_hash_state;
+
+/*
+ * Keep a running hash of various bits of data that we'll use to
+ * stir the ID pool or perturb the ID generator
+ */
+static void
+nsid_hash(void *data, size_t len) {
+ unsigned char *p = data;
+ /*
+ * Hash function similar to the one we use for hashing names.
+ * We don't fold case or toss the upper bit here, though.
+ * This hash doesn't do much interesting when fed binary zeros,
+ * so there may be a better hash function.
+ * This function doesn't need to be very strong since we're
+ * only using it to stir the pool, but it should be reasonably
+ * fast.
+ */
+ /*
+ * We don't care about locking access to nsid_hash_state.
+ * In fact races make the result even more non deteministic.
+ */
+ while (len-- > 0U) {
+ nsid_hash_state = NSID_HASHROTATE(nsid_hash_state);
+ nsid_hash_state += *p++;
+ }
+}
+
+/*
+ * Table of good linear congruential multipliers for modulus 2^16
+ * in order of increasing serial correlation bounds (so trim from
+ * the end).
+ */
+static const isc_uint16_t nsid_multiplier_table[] = {
+ 17565, 25013, 11733, 19877, 23989, 23997, 24997, 25421,
+ 26781, 27413, 35901, 35917, 35973, 36229, 38317, 38437,
+ 39941, 40493, 41853, 46317, 50581, 51429, 53453, 53805,
+ 11317, 11789, 12045, 12413, 14277, 14821, 14917, 18989,
+ 19821, 23005, 23533, 23573, 23693, 27549, 27709, 28461,
+ 29365, 35605, 37693, 37757, 38309, 41285, 45261, 47061,
+ 47269, 48133, 48597, 50277, 50717, 50757, 50805, 51341,
+ 51413, 51581, 51597, 53445, 11493, 14229, 20365, 20653,
+ 23485, 25541, 27429, 29421, 30173, 35445, 35653, 36789,
+ 36797, 37109, 37157, 37669, 38661, 39773, 40397, 41837,
+ 41877, 45293, 47277, 47845, 49853, 51085, 51349, 54085,
+ 56933, 8877, 8973, 9885, 11365, 11813, 13581, 13589,
+ 13613, 14109, 14317, 15765, 15789, 16925, 17069, 17205,
+ 17621, 17941, 19077, 19381, 20245, 22845, 23733, 24869,
+ 25453, 27213, 28381, 28965, 29245, 29997, 30733, 30901,
+ 34877, 35485, 35613, 36133, 36661, 36917, 38597, 40285,
+ 40693, 41413, 41541, 41637, 42053, 42349, 45245, 45469,
+ 46493, 48205, 48613, 50861, 51861, 52877, 53933, 54397,
+ 55669, 56453, 56965, 58021, 7757, 7781, 8333, 9661,
+ 12229, 14373, 14453, 17549, 18141, 19085, 20773, 23701,
+ 24205, 24333, 25261, 25317, 27181, 30117, 30477, 34757,
+ 34885, 35565, 35885, 36541, 37957, 39733, 39813, 41157,
+ 41893, 42317, 46621, 48117, 48181, 49525, 55261, 55389,
+ 56845, 7045, 7749, 7965, 8469, 9133, 9549, 9789,
+ 10173, 11181, 11285, 12253, 13453, 13533, 13757, 14477,
+ 15053, 16901, 17213, 17269, 17525, 17629, 18605, 19013,
+ 19829, 19933, 20069, 20093, 23261, 23333, 24949, 25309,
+ 27613, 28453, 28709, 29301, 29541, 34165, 34413, 37301,
+ 37773, 38045, 38405, 41077, 41781, 41925, 42717, 44437,
+ 44525, 44613, 45933, 45941, 47077, 50077, 50893, 52117,
+ 5293, 55069, 55989, 58125, 59205, 6869, 14685, 15453,
+ 16821, 17045, 17613, 18437, 21029, 22773, 22909, 25445,
+ 25757, 26541, 30709, 30909, 31093, 31149, 37069, 37725,
+ 37925, 38949, 39637, 39701, 40765, 40861, 42965, 44813,
+ 45077, 45733, 47045, 50093, 52861, 52957, 54181, 56325,
+ 56365, 56381, 56877, 57013, 5741, 58101, 58669, 8613,
+ 10045, 10261, 10653, 10733, 11461, 12261, 14069, 15877,
+ 17757, 21165, 23885, 24701, 26429, 26645, 27925, 28765,
+ 29197, 30189, 31293, 39781, 39909, 40365, 41229, 41453,
+ 41653, 42165, 42365, 47421, 48029, 48085, 52773, 5573,
+ 57037, 57637, 58341, 58357, 58901, 6357, 7789, 9093,
+ 10125, 10709, 10765, 11957, 12469, 13437, 13509, 14773,
+ 15437, 15773, 17813, 18829, 19565, 20237, 23461, 23685,
+ 23725, 23941, 24877, 25461, 26405, 29509, 30285, 35181,
+ 37229, 37893, 38565, 40293, 44189, 44581, 45701, 47381,
+ 47589, 48557, 4941, 51069, 5165, 52797, 53149, 5341,
+ 56301, 56765, 58581, 59493, 59677, 6085, 6349, 8293,
+ 8501, 8517, 11597, 11709, 12589, 12693, 13517, 14909,
+ 17397, 18085, 21101, 21269, 22717, 25237, 25661, 29189,
+ 30101, 31397, 33933, 34213, 34661, 35533, 36493, 37309,
+ 40037, 4189, 42909, 44309, 44357, 44389, 4541, 45461,
+ 46445, 48237, 54149, 55301, 55853, 56621, 56717, 56901,
+ 5813, 58437, 12493, 15365, 15989, 17829, 18229, 19341,
+ 21013, 21357, 22925, 24885, 26053, 27581, 28221, 28485,
+ 30605, 30613, 30789, 35437, 36285, 37189, 3941, 41797,
+ 4269, 42901, 43293, 44645, 45221, 46893, 4893, 50301,
+ 50325, 5189, 52109, 53517, 54053, 54485, 5525, 55949,
+ 56973, 59069, 59421, 60733, 61253, 6421, 6701, 6709,
+ 7101, 8669, 15797, 19221, 19837, 20133, 20957, 21293,
+ 21461, 22461, 29085, 29861, 30869, 34973, 36469, 37565,
+ 38125, 38829, 39469, 40061, 40117, 44093, 47429, 48341,
+ 50597, 51757, 5541, 57629, 58405, 59621, 59693, 59701,
+ 61837, 7061, 10421, 11949, 15405, 20861, 25397, 25509,
+ 25893, 26037, 28629, 28869, 29605, 30213, 34205, 35637,
+ 36365, 37285, 3773, 39117, 4021, 41061, 42653, 44509,
+ 4461, 44829, 4725, 5125, 52269, 56469, 59085, 5917,
+ 60973, 8349, 17725, 18637, 19773, 20293, 21453, 22533,
+ 24285, 26333, 26997, 31501, 34541, 34805, 37509, 38477,
+ 41333, 44125, 46285, 46997, 47637, 48173, 4925, 50253,
+ 50381, 50917, 51205, 51325, 52165, 52229, 5253, 5269,
+ 53509, 56253, 56341, 5821, 58373, 60301, 61653, 61973,
+ 62373, 8397, 11981, 14341, 14509, 15077, 22261, 22429,
+ 24261, 28165, 28685, 30661, 34021, 34445, 39149, 3917,
+ 43013, 43317, 44053, 44101, 4533, 49541, 49981, 5277,
+ 54477, 56357, 57261, 57765, 58573, 59061, 60197, 61197,
+ 62189, 7725, 8477, 9565, 10229, 11437, 14613, 14709,
+ 16813, 20029, 20677, 31445, 3165, 31957, 3229, 33541,
+ 36645, 3805, 38973, 3965, 4029, 44293, 44557, 46245,
+ 48917, 4909, 51749, 53709, 55733, 56445, 5925, 6093,
+ 61053, 62637, 8661, 9109, 10821, 11389, 13813, 14325,
+ 15501, 16149, 18845, 22669, 26437, 29869, 31837, 33709,
+ 33973, 34173, 3677, 3877, 3981, 39885, 42117, 4421,
+ 44221, 44245, 44693, 46157, 47309, 5005, 51461, 52037,
+ 55333, 55693, 56277, 58949, 6205, 62141, 62469, 6293,
+ 10101, 12509, 14029, 17997, 20469, 21149, 25221, 27109,
+ 2773, 2877, 29405, 31493, 31645, 4077, 42005, 42077,
+ 42469, 42501, 44013, 48653, 49349, 4997, 50101, 55405,
+ 56957, 58037, 59429, 60749, 61797, 62381, 62837, 6605,
+ 10541, 23981, 24533, 2701, 27333, 27341, 31197, 33805,
+ 3621, 37381, 3749, 3829, 38533, 42613, 44381, 45901,
+ 48517, 51269, 57725, 59461, 60045, 62029, 13805, 14013,
+ 15461, 16069, 16157, 18573, 2309, 23501, 28645, 3077,
+ 31541, 36357, 36877, 3789, 39429, 39805, 47685, 47949,
+ 49413, 5485, 56757, 57549, 57805, 58317, 59549, 62213,
+ 62613, 62853, 62933, 8909, 12941, 16677, 20333, 21541,
+ 24429, 26077, 26421, 2885, 31269, 33381, 3661, 40925,
+ 42925, 45173, 4525, 4709, 53133, 55941, 57413, 57797,
+ 62125, 62237, 62733, 6773, 12317, 13197, 16533, 16933,
+ 18245, 2213, 2477, 29757, 33293, 35517, 40133, 40749,
+ 4661, 49941, 62757, 7853, 8149, 8573, 11029, 13421,
+ 21549, 22709, 22725, 24629, 2469, 26125, 2669, 34253,
+ 36709, 41013, 45597, 46637, 52285, 52333, 54685, 59013,
+ 60997, 61189, 61981, 62605, 62821, 7077, 7525, 8781,
+ 10861, 15277, 2205, 22077, 28517, 28949, 32109, 33493,
+ 4661, 49941, 62757, 7853, 8149, 8573, 11029, 13421,
+ 21549, 22709, 22725, 24629, 2469, 26125, 2669, 34253,
+ 36709, 41013, 45597, 46637, 52285, 52333, 54685, 59013,
+ 60997, 61189, 61981, 62605, 62821, 7077, 7525, 8781,
+ 10861, 15277, 2205, 22077, 28517, 28949, 32109, 33493,
+ 3685, 39197, 39869, 42621, 44997, 48565, 5221, 57381,
+ 61749, 62317, 63245, 63381, 23149, 2549, 28661, 31653,
+ 33885, 36341, 37053, 39517, 42805, 45853, 48997, 59349,
+ 60053, 62509, 63069, 6525, 1893, 20181, 2365, 24893,
+ 27397, 31357, 32277, 33357, 34437, 36677, 37661, 43469,
+ 43917, 50997, 53869, 5653, 13221, 16741, 17893, 2157,
+ 28653, 31789, 35301, 35821, 61613, 62245, 12405, 14517,
+ 17453, 18421, 3149, 3205, 40341, 4109, 43941, 46869,
+ 48837, 50621, 57405, 60509, 62877, 8157, 12933, 12957,
+ 16501, 19533, 3461, 36829, 52357, 58189, 58293, 63053,
+ 17109, 1933, 32157, 37701, 59005, 61621, 13029, 15085,
+ 16493, 32317, 35093, 5061, 51557, 62221, 20765, 24613,
+ 2629, 30861, 33197, 33749, 35365, 37933, 40317, 48045,
+ 56229, 61157, 63797, 7917, 17965, 1917, 1973, 20301,
+ 2253, 33157, 58629, 59861, 61085, 63909, 8141, 9221,
+ 14757, 1581, 21637, 26557, 33869, 34285, 35733, 40933,
+ 42517, 43501, 53653, 61885, 63805, 7141, 21653, 54973,
+ 31189, 60061, 60341, 63357, 16045, 2053, 26069, 33997,
+ 43901, 54565, 63837, 8949, 17909, 18693, 32349, 33125,
+ 37293, 48821, 49053, 51309, 64037, 7117, 1445, 20405,
+ 23085, 26269, 26293, 27349, 32381, 33141, 34525, 36461,
+ 37581, 43525, 4357, 43877, 5069, 55197, 63965, 9845,
+ 12093, 2197, 2229, 32165, 33469, 40981, 42397, 8749,
+ 10853, 1453, 18069, 21693, 30573, 36261, 37421, 42533
+};
+
+#define NSID_MULT_TABLE_SIZE \
+ ((sizeof nsid_multiplier_table)/(sizeof nsid_multiplier_table[0]))
+#define NSID_RANGE_MASK (NSID_LOOKAHEAD - 1)
+#define NSID_POOL_MASK 0xFFFF /* used to wrap the pool index */
+#define NSID_SHUFFLE_ONLY 1
+#define NSID_USE_POOL 2
+
+static isc_uint16_t
+nsid_next(dns_nsid_t *nsid) {
+ isc_uint16_t id, compressed_hash;
+ isc_uint16_t j;
+
+ compressed_hash = ((nsid_hash_state >> 16) ^
+ (nsid_hash_state)) & 0xFFFF;
+
+ if (nsid->nsid_usepool) {
+ isc_uint16_t pick;
+
+ pick = compressed_hash & NSID_RANGE_MASK;
+ pick = (nsid->nsid_state + pick) & NSID_POOL_MASK;
+ id = nsid->nsid_pool[pick];
+ if (pick != 0) {
+ /* Swap two IDs to stir the pool */
+ nsid->nsid_pool[pick] =
+ nsid->nsid_pool[nsid->nsid_state];
+ nsid->nsid_pool[nsid->nsid_state] = id;
+ }
+
+ /* increment the base pointer into the pool */
+ if (nsid->nsid_state == 65535)
+ nsid->nsid_state = 0;
+ else
+ nsid->nsid_state++;
+ } else {
+ /*
+ * This is the original Algorithm B
+ * j = ((u_long) NSID_SHUFFLE_TABLE_SIZE * nsid_state2) >> 16;
+ *
+ * We'll perturb it with some random stuff ...
+ */
+ j = ((isc_uint32_t) NSID_SHUFFLE_TABLE_SIZE *
+ (nsid->nsid_state2 ^ compressed_hash)) >> 16;
+ nsid->nsid_state2 = id = nsid->nsid_vtable[j];
+ nsid->nsid_state = (((isc_uint32_t) nsid->nsid_a1 * nsid->nsid_state) +
+ nsid->nsid_c1) & 0xFFFF;
+ nsid->nsid_vtable[j] = nsid->nsid_state;
+ }
+
+ /* Now lets obfuscate ... */
+ id = (((isc_uint32_t) nsid->nsid_a2 * id) + nsid->nsid_c2) & 0xFFFF;
+ id = (((isc_uint32_t) nsid->nsid_a3 * id) + nsid->nsid_c3) & 0xFFFF;
+
+ return (id);
+}
+
+static isc_result_t
+nsid_init(isc_mem_t *mctx, dns_nsid_t *nsid, isc_boolean_t usepool) {
+ isc_time_t now;
+ pid_t mypid;
+ isc_uint16_t a1ndx, a2ndx, a3ndx, c1ndx, c2ndx, c3ndx;
+ int i;
+
+ isc_time_now(&now);
+ mypid = getpid();
+
+ /* Initialize the state */
+ memset(nsid, 0, sizeof(*nsid));
+ nsid_hash(&now, sizeof now);
+ nsid_hash(&mypid, sizeof mypid);
+
+ /*
+ * Select our random number generators and initial seed.
+ * We could really use more random bits at this point,
+ * but we'll try to make a silk purse out of a sows ear ...
+ */
+ /* generator 1 */
+ a1ndx = ((isc_uint32_t) NSID_MULT_TABLE_SIZE *
+ (nsid_hash_state & 0xFFFF)) >> 16;
+ nsid->nsid_a1 = nsid_multiplier_table[a1ndx];
+ c1ndx = (nsid_hash_state >> 9) & 0x7FFF;
+ nsid->nsid_c1 = 2 * c1ndx + 1;
+
+ /* generator 2, distinct from 1 */
+ a2ndx = ((isc_uint32_t) (NSID_MULT_TABLE_SIZE - 1) *
+ ((nsid_hash_state >> 10) & 0xFFFF)) >> 16;
+ if (a2ndx >= a1ndx)
+ a2ndx++;
+ nsid->nsid_a2 = nsid_multiplier_table[a2ndx];
+ c2ndx = nsid_hash_state % 32767;
+ if (c2ndx >= c1ndx)
+ c2ndx++;
+ nsid->nsid_c2 = 2*c2ndx + 1;
+
+ /* generator 3, distinct from 1 and 2 */
+ a3ndx = ((isc_uint32_t) (NSID_MULT_TABLE_SIZE - 2) *
+ ((nsid_hash_state >> 20) & 0xFFFF)) >> 16;
+ if (a3ndx >= a1ndx || a3ndx >= a2ndx)
+ a3ndx++;
+ if (a3ndx >= a1ndx && a3ndx >= a2ndx)
+ a3ndx++;
+ nsid->nsid_a3 = nsid_multiplier_table[a3ndx];
+ c3ndx = nsid_hash_state % 32766;
+ if (c3ndx >= c1ndx || c3ndx >= c2ndx)
+ c3ndx++;
+ if (c3ndx >= c1ndx && c3ndx >= c2ndx)
+ c3ndx++;
+ nsid->nsid_c3 = 2*c3ndx + 1;
+
+ nsid->nsid_state =
+ ((nsid_hash_state >> 16) ^ (nsid_hash_state)) & 0xFFFF;
+
+ nsid->nsid_usepool = usepool;
+ if (nsid->nsid_usepool) {
+ nsid->nsid_pool = isc_mem_get(mctx, 0x10000 * sizeof(isc_uint16_t));
+ if (nsid->nsid_pool == NULL)
+ return (ISC_R_NOMEMORY);
+ for (i = 0; ; i++) {
+ nsid->nsid_pool[i] = nsid->nsid_state;
+ nsid->nsid_state =
+ (((u_long) nsid->nsid_a1 * nsid->nsid_state) +
+ nsid->nsid_c1) & 0xFFFF;
+ if (i == 0xFFFF)
+ break;
+ }
+ } else {
+ nsid->nsid_vtable = isc_mem_get(mctx, NSID_SHUFFLE_TABLE_SIZE *
+ (sizeof(isc_uint16_t)) );
+ if (nsid->nsid_vtable == NULL)
+ return (ISC_R_NOMEMORY);
+
+ for (i = 0; i < NSID_SHUFFLE_TABLE_SIZE; i++) {
+ nsid->nsid_vtable[i] = nsid->nsid_state;
+ nsid->nsid_state =
+ (((isc_uint32_t) nsid->nsid_a1 * nsid->nsid_state) +
+ nsid->nsid_c1) & 0xFFFF;
+ }
+ nsid->nsid_state2 = nsid->nsid_state;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static void
+nsid_destroy(isc_mem_t *mctx, dns_nsid_t *nsid) {
+ if (nsid->nsid_usepool)
+ isc_mem_put(mctx, nsid->nsid_pool,
+ 0x10000 * sizeof(isc_uint16_t));
+ else
+ isc_mem_put(mctx, nsid->nsid_vtable,
+ NSID_SHUFFLE_TABLE_SIZE * (sizeof(isc_uint16_t)) );
+ memset(nsid, 0, sizeof(*nsid));
+}
+
+void
+dns_dispatch_hash(void *data, size_t len) {
+ nsid_hash(data, len);
+}
diff --git a/lib/dns/dlz.c b/lib/dns/dlz.c
new file mode 100644
index 0000000..ee6c03b
--- /dev/null
+++ b/lib/dns/dlz.c
@@ -0,0 +1,510 @@
+/*
+ * Portions Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions 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.
+ */
+
+/*
+ * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER 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 development of Dynamically Loadable Zones (DLZ) for Bind 9 was
+ * conceived and contributed by Rob Butler.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: dlz.c,v 1.2.2.2 2005/09/06 03:47:17 marka Exp $ */
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <config.h>
+
+#include <dns/fixedname.h>
+#include <dns/log.h>
+#include <dns/master.h>
+#include <dns/dlz.h>
+
+
+#include <isc/buffer.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/rwlock.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/***
+ *** Supported DLZ DB Implementations Registry
+ ***/
+
+static ISC_LIST(dns_dlzimplementation_t) dlz_implementations;
+static isc_rwlock_t dlz_implock;
+static isc_once_t once = ISC_ONCE_INIT;
+
+static void
+dlz_initialize(void) {
+ RUNTIME_CHECK(isc_rwlock_init(&dlz_implock, 0, 0) == ISC_R_SUCCESS);
+ ISC_LIST_INIT(dlz_implementations);
+}
+
+/*%
+ * Searches the dlz_implementations list for a driver matching name.
+ */
+static inline dns_dlzimplementation_t *
+dlz_impfind(const char *name) {
+ dns_dlzimplementation_t *imp;
+
+ for (imp = ISC_LIST_HEAD(dlz_implementations);
+ imp != NULL;
+ imp = ISC_LIST_NEXT(imp, link))
+ if (strcasecmp(name, imp->name) == 0)
+ return (imp);
+ return (NULL);
+}
+
+/***
+ *** Basic DLZ Methods
+ ***/
+
+isc_result_t
+dns_dlzallowzonexfr(dns_view_t *view, dns_name_t *name,
+ isc_sockaddr_t *clientaddr, dns_db_t **dbp)
+{
+ isc_result_t result;
+ dns_dlzallowzonexfr_t allowzonexfr;
+ dns_dlzdb_t *dlzdatabase;
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(DNS_DLZ_VALID(view->dlzdatabase));
+ REQUIRE(name != NULL);
+ REQUIRE(dbp != NULL && *dbp == NULL);
+
+ /* ask driver if the zone is supported */
+ dlzdatabase = view->dlzdatabase;
+ allowzonexfr = dlzdatabase->implementation->methods->allowzonexfr;
+ result = (*allowzonexfr)(dlzdatabase->implementation->driverarg,
+ dlzdatabase->dbdata, dlzdatabase->mctx,
+ view->rdclass, name, clientaddr, dbp);
+
+ if (result == ISC_R_NOTIMPLEMENTED)
+ return (ISC_R_NOTFOUND);
+ return (result);
+}
+
+isc_result_t
+dns_dlzcreate(isc_mem_t *mctx, const char *dlzname, const char *drivername,
+ unsigned int argc, char *argv[], dns_dlzdb_t **dbp)
+{
+ dns_dlzimplementation_t *impinfo;
+ isc_result_t result;
+
+ /*
+ * initialize the dlz_implementations list, this is guaranteed
+ * to only really happen once.
+ */
+ RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(dbp != NULL && *dbp == NULL);
+ REQUIRE(dlzname != NULL);
+ REQUIRE(drivername != NULL);
+ REQUIRE(mctx != NULL);
+
+ /* write log message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
+ "Loading '%s' using driver %s", dlzname, drivername);
+
+ /* lock the dlz_implementations list so we can search it. */
+ RWLOCK(&dlz_implock, isc_rwlocktype_read);
+
+ /* search for the driver implementation */
+ impinfo = dlz_impfind(drivername);
+ if (impinfo == NULL) {
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "unsupported DLZ database driver '%s'."
+ " %s not loaded.",
+ drivername, dlzname);
+
+ return (ISC_R_NOTFOUND);
+ }
+
+ /* Allocate memory to hold the DLZ database driver */
+ (*dbp) = isc_mem_get(mctx, sizeof(dns_dlzdb_t));
+ if ((*dbp) == NULL) {
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
+ return (ISC_R_NOMEMORY);
+ }
+
+ /* Make sure memory region is set to all 0's */
+ memset((*dbp), 0, sizeof(dns_dlzdb_t));
+
+ (*dbp)->implementation = impinfo;
+
+ /* Create a new database using implementation 'drivername'. */
+ result = ((impinfo->methods->create)(mctx, dlzname, argc, argv,
+ impinfo->driverarg,
+ &(*dbp)->dbdata));
+
+ /* mark the DLZ driver as valid */
+ if (result == ISC_R_SUCCESS) {
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
+ (*dbp)->magic = DNS_DLZ_MAGIC;
+ isc_mem_attach(mctx, &(*dbp)->mctx);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "DLZ driver loaded successfully.");
+ return (ISC_R_SUCCESS);
+ } else {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "DLZ driver failed to load.");
+ }
+
+ /* impinfo->methods->create failed. */
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
+ isc_mem_put(mctx, (*dbp), sizeof(dns_dlzdb_t));
+ return (result);
+}
+
+void
+dns_dlzdestroy(dns_dlzdb_t **dbp) {
+ isc_mem_t *mctx;
+ dns_dlzdestroy_t destroy;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unloading DLZ driver.");
+
+ /*
+ * Perform checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(dbp != NULL && DNS_DLZ_VALID(*dbp));
+
+ /* call the drivers destroy method */
+ if ((*dbp) != NULL) {
+ mctx = (*dbp)->mctx;
+ destroy = (*dbp)->implementation->methods->destroy;
+ (*destroy)((*dbp)->implementation->driverarg,(*dbp)->dbdata);
+ /* return memory */
+ isc_mem_put(mctx, (*dbp), sizeof(dns_dlzdb_t));
+ isc_mem_detach(&mctx);
+ }
+
+ *dbp = NULL;
+}
+
+
+isc_result_t
+dns_dlzfindzone(dns_view_t *view, dns_name_t *name, unsigned int minlabels,
+ dns_db_t **dbp)
+{
+ dns_fixedname_t fname;
+ dns_name_t *zonename;
+ unsigned int namelabels;
+ unsigned int i;
+ isc_result_t result;
+ dns_dlzfindzone_t findzone;
+ dns_dlzdb_t *dlzdatabase;
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(DNS_DLZ_VALID(view->dlzdatabase));
+ REQUIRE(name != NULL);
+ REQUIRE(dbp != NULL && *dbp == NULL);
+
+ /* setup a "fixed" dns name */
+ dns_fixedname_init(&fname);
+ zonename = dns_fixedname_name(&fname);
+
+ /* count the number of labels in the name */
+ namelabels = dns_name_countlabels(name);
+
+ /*
+ * loop through starting with the longest domain name and
+ * trying shorter names portions of the name until we find a
+ * match, have an error, or are below the 'minlabels'
+ * threshold. minlabels is 0, if the standard database didn't
+ * have a zone name match. Otherwise minlables is the number
+ * of labels in that name. We need to beat that for a
+ * "better" match for the DLZ database to be authoritative
+ * instead of the standard database.
+ */
+ for (i = namelabels; i > minlabels && i > 1; i--) {
+ if (i == namelabels) {
+ result = dns_name_copy(name, zonename, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else
+ dns_name_split(name, i, NULL, zonename);
+
+ /* ask SDLZ driver if the zone is supported */
+ dlzdatabase = view->dlzdatabase;
+ findzone = dlzdatabase->implementation->methods->findzone;
+ result = (*findzone)(dlzdatabase->implementation->driverarg,
+ dlzdatabase->dbdata, dlzdatabase->mctx,
+ view->rdclass, zonename, dbp);
+ if (result != ISC_R_NOTFOUND)
+ return (result);
+ }
+ return (ISC_R_NOTFOUND);
+}
+
+/*%
+ * Registers a DLZ driver. This basically just adds the dlz
+ * driver to the list of available drivers in the dlz_implementations list.
+ */
+isc_result_t
+dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods,
+ void *driverarg, isc_mem_t *mctx,
+ dns_dlzimplementation_t **dlzimp)
+{
+
+ dns_dlzimplementation_t *dlz_imp;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering DLZ driver '%s'", drivername);
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(drivername != NULL);
+ REQUIRE(methods != NULL);
+ REQUIRE(methods->create != NULL);
+ REQUIRE(methods->destroy != NULL);
+ REQUIRE(methods->findzone != NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(dlzimp != NULL && *dlzimp == NULL);
+
+ /*
+ * initialize the dlz_implementations list, this is guaranteed
+ * to only really happen once.
+ */
+ RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
+
+ /* lock the dlz_implementations list so we can modify it. */
+ RWLOCK(&dlz_implock, isc_rwlocktype_write);
+
+ /*
+ * check that another already registered driver isn't using
+ * the same name
+ */
+ dlz_imp = dlz_impfind(drivername);
+ if (dlz_imp != NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "DLZ Driver '%s' already registered",
+ drivername);
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
+ return (ISC_R_EXISTS);
+ }
+
+ /*
+ * Allocate memory for a dlz_implementation object. Error if
+ * we cannot.
+ */
+ dlz_imp = isc_mem_get(mctx, sizeof(dns_dlzimplementation_t));
+ if (dlz_imp == NULL) {
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
+ return (ISC_R_NOMEMORY);
+ }
+
+ /* Make sure memory region is set to all 0's */
+ memset(dlz_imp, 0, sizeof(dns_dlzimplementation_t));
+
+ /* Store the data passed into this method */
+ dlz_imp->name = drivername;
+ dlz_imp->methods = methods;
+ dlz_imp->mctx = NULL;
+ dlz_imp->driverarg = driverarg;
+
+ /* attach the new dlz_implementation object to a memory context */
+ isc_mem_attach(mctx, &dlz_imp->mctx);
+
+ /*
+ * prepare the dlz_implementation object to be put in a list,
+ * and append it to the list
+ */
+ ISC_LINK_INIT(dlz_imp, link);
+ ISC_LIST_APPEND(dlz_implementations, dlz_imp, link);
+
+ /* Unlock the dlz_implementations list. */
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
+
+ /* Pass back the dlz_implementation that we created. */
+ *dlzimp = dlz_imp;
+
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Helper function for dns_dlzstrtoargv().
+ * Pardon the gratuitous recursion.
+ */
+static isc_result_t
+dns_dlzstrtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp,
+ char ***argvp, unsigned int n)
+{
+ isc_result_t result;
+
+ restart:
+ /* 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 == '\n') {
+ *p = ' ';
+ goto restart;
+ }
+ p++;
+ }
+
+ /* do "grouping", items between { and } are one arg */
+ if (*p == '{') {
+ char *t = p;
+ /*
+ * shift all characters to left by 1 to get rid of '{'
+ */
+ while (*t != '\0') {
+ t++;
+ *(t-1) = *t;
+ }
+ while (*p != '\0' && *p != '}') {
+ p++;
+ }
+ /* get rid of '}' character */
+ if (*p == '}') {
+ *p = '\0';
+ p++;
+ }
+ /* normal case, no "grouping" */
+ } else if (*p != '\0')
+ *p++ = '\0';
+
+ result = dns_dlzstrtoargvsub(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.
+ */
+isc_result_t
+dns_dlzstrtoargv(isc_mem_t *mctx, char *s,
+ unsigned int *argcp, char ***argvp)
+{
+ return(dns_dlzstrtoargvsub(mctx, s, argcp, argvp, 0));
+}
+
+/*%
+ * Unregisters a DLZ driver. This basically just removes the dlz
+ * driver from the list of available drivers in the dlz_implementations list.
+ */
+void
+dns_dlzunregister(dns_dlzimplementation_t **dlzimp) {
+ dns_dlzimplementation_t *dlz_imp;
+ isc_mem_t *mctx;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering DLZ driver.");
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(dlzimp != NULL && *dlzimp != NULL);
+
+ /*
+ * initialize the dlz_implementations list, this is guaranteed
+ * to only really happen once.
+ */
+ RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
+
+ dlz_imp = *dlzimp;
+
+ /* lock the dlz_implementations list so we can modify it. */
+ RWLOCK(&dlz_implock, isc_rwlocktype_write);
+
+ /* remove the dlz_implementation object from the list */
+ ISC_LIST_UNLINK(dlz_implementations, dlz_imp, link);
+ mctx = dlz_imp->mctx;
+
+ /*
+ * return the memory back to the available memory pool and
+ * remove it from the memory context.
+ */
+ isc_mem_put(mctx, dlz_imp, sizeof(dns_dlzimplementation_t));
+ isc_mem_detach(&mctx);
+
+ /* Unlock the dlz_implementations list. */
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
+}
diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c
new file mode 100644
index 0000000..75ca440
--- /dev/null
+++ b/lib/dns/dnssec.c
@@ -0,0 +1,865 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: dnssec.c,v 1.81.18.10 2007/09/14 04:35:42 marka Exp $
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/mem.h>
+#include <isc/serial.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/dnssec.h>
+#include <dns/fixedname.h>
+#include <dns/keyvalues.h>
+#include <dns/message.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/result.h>
+#include <dns/tsig.h> /* for DNS_TSIG_FUDGE */
+
+#include <dst/result.h>
+
+#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
+
+#define RETERR(x) do { \
+ result = (x); \
+ if (result != ISC_R_SUCCESS) \
+ goto failure; \
+ } while (0)
+
+
+#define TYPE_SIGN 0
+#define TYPE_VERIFY 1
+
+static isc_result_t
+digest_callback(void *arg, isc_region_t *data);
+
+static int
+rdata_compare_wrapper(const void *rdata1, const void *rdata2);
+
+static isc_result_t
+rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
+ dns_rdata_t **rdata, int *nrdata);
+
+static isc_result_t
+digest_callback(void *arg, isc_region_t *data) {
+ dst_context_t *ctx = arg;
+
+ return (dst_context_adddata(ctx, data));
+}
+
+/*
+ * Make qsort happy.
+ */
+static int
+rdata_compare_wrapper(const void *rdata1, const void *rdata2) {
+ return (dns_rdata_compare((const dns_rdata_t *)rdata1,
+ (const dns_rdata_t *)rdata2));
+}
+
+/*
+ * Sort the rdataset into an array.
+ */
+static isc_result_t
+rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
+ dns_rdata_t **rdata, int *nrdata)
+{
+ isc_result_t ret;
+ int i = 0, n;
+ dns_rdata_t *data;
+
+ n = dns_rdataset_count(set);
+
+ data = isc_mem_get(mctx, n * sizeof(dns_rdata_t));
+ if (data == NULL)
+ return (ISC_R_NOMEMORY);
+
+ ret = dns_rdataset_first(set);
+ if (ret != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, data, n * sizeof(dns_rdata_t));
+ return (ret);
+ }
+
+ /*
+ * Put them in the array.
+ */
+ do {
+ dns_rdata_init(&data[i]);
+ dns_rdataset_current(set, &data[i++]);
+ } while (dns_rdataset_next(set) == ISC_R_SUCCESS);
+
+ /*
+ * Sort the array.
+ */
+ qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
+ *rdata = data;
+ *nrdata = n;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx,
+ dst_key_t **key)
+{
+ isc_buffer_t b;
+ isc_region_t r;
+
+ INSIST(name != NULL);
+ INSIST(rdata != NULL);
+ INSIST(mctx != NULL);
+ INSIST(key != NULL);
+ INSIST(*key == NULL);
+ REQUIRE(rdata->type == dns_rdatatype_key ||
+ rdata->type == dns_rdatatype_dnskey);
+
+ dns_rdata_toregion(rdata, &r);
+ isc_buffer_init(&b, r.base, r.length);
+ isc_buffer_add(&b, r.length);
+ return (dst_key_fromdns(name, rdata->rdclass, &b, mctx, key));
+}
+
+static isc_result_t
+digest_sig(dst_context_t *ctx, dns_rdata_t *sigrdata, dns_rdata_rrsig_t *sig) {
+ isc_region_t r;
+ isc_result_t ret;
+ dns_fixedname_t fname;
+
+ dns_rdata_toregion(sigrdata, &r);
+ INSIST(r.length >= 19);
+
+ r.length = 18;
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ dns_fixedname_init(&fname);
+ RUNTIME_CHECK(dns_name_downcase(&sig->signer,
+ dns_fixedname_name(&fname), NULL)
+ == ISC_R_SUCCESS);
+ dns_name_toregion(dns_fixedname_name(&fname), &r);
+ return (dst_context_adddata(ctx, &r));
+}
+
+isc_result_t
+dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
+ isc_stdtime_t *inception, isc_stdtime_t *expire,
+ isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
+{
+ dns_rdata_rrsig_t sig;
+ dns_rdata_t tmpsigrdata;
+ dns_rdata_t *rdatas;
+ int nrdatas, i;
+ isc_buffer_t sigbuf, envbuf;
+ isc_region_t r;
+ dst_context_t *ctx = NULL;
+ isc_result_t ret;
+ isc_buffer_t *databuf = NULL;
+ char data[256 + 8];
+ isc_uint32_t flags;
+ unsigned int sigsize;
+ dns_fixedname_t fnewname;
+
+ REQUIRE(name != NULL);
+ REQUIRE(dns_name_countlabels(name) <= 255);
+ REQUIRE(set != NULL);
+ REQUIRE(key != NULL);
+ REQUIRE(inception != NULL);
+ REQUIRE(expire != NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(sigrdata != NULL);
+
+ if (*inception >= *expire)
+ return (DNS_R_INVALIDTIME);
+
+ /*
+ * Is the key allowed to sign data?
+ */
+ flags = dst_key_flags(key);
+ if (flags & DNS_KEYTYPE_NOAUTH)
+ return (DNS_R_KEYUNAUTHORIZED);
+ if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
+ return (DNS_R_KEYUNAUTHORIZED);
+
+ sig.mctx = mctx;
+ sig.common.rdclass = set->rdclass;
+ sig.common.rdtype = dns_rdatatype_rrsig;
+ ISC_LINK_INIT(&sig.common, link);
+
+ dns_name_init(&sig.signer, NULL);
+ dns_name_clone(dst_key_name(key), &sig.signer);
+
+ sig.covered = set->type;
+ sig.algorithm = dst_key_alg(key);
+ sig.labels = dns_name_countlabels(name) - 1;
+ if (dns_name_iswildcard(name))
+ sig.labels--;
+ sig.originalttl = set->ttl;
+ sig.timesigned = *inception;
+ sig.timeexpire = *expire;
+ sig.keyid = dst_key_id(key);
+ ret = dst_key_sigsize(key, &sigsize);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ sig.siglen = sigsize;
+ /*
+ * The actual contents of sig.signature are not important yet, since
+ * they're not used in digest_sig().
+ */
+ sig.signature = isc_mem_get(mctx, sig.siglen);
+ if (sig.signature == NULL)
+ return (ISC_R_NOMEMORY);
+
+ ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_signature;
+
+ dns_rdata_init(&tmpsigrdata);
+ ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
+ sig.common.rdtype, &sig, databuf);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_databuf;
+
+ ret = dst_context_create(key, mctx, &ctx);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_databuf;
+
+ /*
+ * Digest the SIG rdata.
+ */
+ ret = digest_sig(ctx, &tmpsigrdata, &sig);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ dns_fixedname_init(&fnewname);
+ RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
+ NULL) == ISC_R_SUCCESS);
+ dns_name_toregion(dns_fixedname_name(&fnewname), &r);
+
+ /*
+ * Create an envelope for each rdata: <name|type|class|ttl>.
+ */
+ isc_buffer_init(&envbuf, data, sizeof(data));
+ memcpy(data, r.base, r.length);
+ isc_buffer_add(&envbuf, r.length);
+ isc_buffer_putuint16(&envbuf, set->type);
+ isc_buffer_putuint16(&envbuf, set->rdclass);
+ isc_buffer_putuint32(&envbuf, set->ttl);
+
+ ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+ isc_buffer_usedregion(&envbuf, &r);
+
+ for (i = 0; i < nrdatas; i++) {
+ isc_uint16_t len;
+ isc_buffer_t lenbuf;
+ isc_region_t lenr;
+
+ /*
+ * Skip duplicates.
+ */
+ if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
+ continue;
+
+ /*
+ * Digest the envelope.
+ */
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_array;
+
+ /*
+ * Digest the length of the rdata.
+ */
+ isc_buffer_init(&lenbuf, &len, sizeof(len));
+ INSIST(rdatas[i].length < 65536);
+ isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
+ isc_buffer_usedregion(&lenbuf, &lenr);
+ ret = dst_context_adddata(ctx, &lenr);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_array;
+
+ /*
+ * Digest the rdata.
+ */
+ ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_array;
+ }
+
+ isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
+ ret = dst_context_sign(ctx, &sigbuf);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_array;
+ isc_buffer_usedregion(&sigbuf, &r);
+ if (r.length != sig.siglen) {
+ ret = ISC_R_NOSPACE;
+ goto cleanup_array;
+ }
+ memcpy(sig.signature, r.base, sig.siglen);
+
+ ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
+ sig.common.rdtype, &sig, buffer);
+
+cleanup_array:
+ isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
+cleanup_context:
+ dst_context_destroy(&ctx);
+cleanup_databuf:
+ isc_buffer_free(&databuf);
+cleanup_signature:
+ isc_mem_put(mctx, sig.signature, sig.siglen);
+
+ return (ret);
+}
+
+isc_result_t
+dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
+ isc_boolean_t ignoretime, isc_mem_t *mctx,
+ dns_rdata_t *sigrdata, dns_name_t *wild)
+{
+ dns_rdata_rrsig_t sig;
+ dns_fixedname_t fnewname;
+ isc_region_t r;
+ isc_buffer_t envbuf;
+ dns_rdata_t *rdatas;
+ int nrdatas, i;
+ isc_stdtime_t now;
+ isc_result_t ret;
+ unsigned char data[300];
+ dst_context_t *ctx = NULL;
+ int labels = 0;
+ isc_uint32_t flags;
+
+ REQUIRE(name != NULL);
+ REQUIRE(set != NULL);
+ REQUIRE(key != NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
+
+ ret = dns_rdata_tostruct(sigrdata, &sig, NULL);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ if (isc_serial_lt(sig.timeexpire, sig.timesigned))
+ return (DNS_R_SIGINVALID);
+
+ if (!ignoretime) {
+ isc_stdtime_get(&now);
+
+ /*
+ * Is SIG temporally valid?
+ */
+ if (isc_serial_lt((isc_uint32_t)now, sig.timesigned))
+ return (DNS_R_SIGFUTURE);
+ else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now))
+ return (DNS_R_SIGEXPIRED);
+ }
+
+ /*
+ * Is the key allowed to sign data?
+ */
+ flags = dst_key_flags(key);
+ if (flags & DNS_KEYTYPE_NOAUTH)
+ return (DNS_R_KEYUNAUTHORIZED);
+ if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
+ return (DNS_R_KEYUNAUTHORIZED);
+
+ ret = dst_context_create(key, mctx, &ctx);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_struct;
+
+ /*
+ * Digest the SIG rdata (not including the signature).
+ */
+ ret = digest_sig(ctx, sigrdata, &sig);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ /*
+ * If the name is an expanded wildcard, use the wildcard name.
+ */
+ dns_fixedname_init(&fnewname);
+ labels = dns_name_countlabels(name) - 1;
+ RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
+ NULL) == ISC_R_SUCCESS);
+ if (labels - sig.labels > 0)
+ dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
+ NULL, dns_fixedname_name(&fnewname));
+
+ dns_name_toregion(dns_fixedname_name(&fnewname), &r);
+
+ /*
+ * Create an envelope for each rdata: <name|type|class|ttl>.
+ */
+ isc_buffer_init(&envbuf, data, sizeof(data));
+ if (labels - sig.labels > 0) {
+ isc_buffer_putuint8(&envbuf, 1);
+ isc_buffer_putuint8(&envbuf, '*');
+ memcpy(data + 2, r.base, r.length);
+ }
+ else
+ memcpy(data, r.base, r.length);
+ isc_buffer_add(&envbuf, r.length);
+ isc_buffer_putuint16(&envbuf, set->type);
+ isc_buffer_putuint16(&envbuf, set->rdclass);
+ isc_buffer_putuint32(&envbuf, sig.originalttl);
+
+ ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ isc_buffer_usedregion(&envbuf, &r);
+
+ for (i = 0; i < nrdatas; i++) {
+ isc_uint16_t len;
+ isc_buffer_t lenbuf;
+ isc_region_t lenr;
+
+ /*
+ * Skip duplicates.
+ */
+ if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
+ continue;
+
+ /*
+ * Digest the envelope.
+ */
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_array;
+
+ /*
+ * Digest the rdata length.
+ */
+ isc_buffer_init(&lenbuf, &len, sizeof(len));
+ INSIST(rdatas[i].length < 65536);
+ isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
+ isc_buffer_usedregion(&lenbuf, &lenr);
+
+ /*
+ * Digest the rdata.
+ */
+ ret = dst_context_adddata(ctx, &lenr);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_array;
+ ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_array;
+ }
+
+ r.base = sig.signature;
+ r.length = sig.siglen;
+ ret = dst_context_verify(ctx, &r);
+ if (ret == DST_R_VERIFYFAILURE)
+ ret = DNS_R_SIGINVALID;
+
+cleanup_array:
+ isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
+cleanup_context:
+ dst_context_destroy(&ctx);
+cleanup_struct:
+ dns_rdata_freestruct(&sig);
+
+ if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
+ if (wild != NULL)
+ RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname,
+ dns_fixedname_name(&fnewname),
+ wild, NULL) == ISC_R_SUCCESS);
+ ret = DNS_R_FROMWILDCARD;
+ }
+ return (ret);
+}
+
+isc_result_t
+dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
+ isc_boolean_t ignoretime, isc_mem_t *mctx,
+ dns_rdata_t *sigrdata)
+{
+ isc_result_t result;
+
+ result = dns_dnssec_verify2(name, set, key, ignoretime, mctx,
+ sigrdata, NULL);
+ if (result == DNS_R_FROMWILDCARD)
+ result = ISC_R_SUCCESS;
+ return (result);
+}
+
+#define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
+ == DNS_KEYOWNER_ZONE)
+
+isc_result_t
+dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
+ dns_dbnode_t *node, dns_name_t *name,
+ const char *directory, isc_mem_t *mctx,
+ unsigned int maxkeys, dst_key_t **keys,
+ unsigned int *nkeys)
+{
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_result_t result;
+ dst_key_t *pubkey = NULL;
+ unsigned int count = 0;
+
+ REQUIRE(nkeys != NULL);
+ REQUIRE(keys != NULL);
+
+ *nkeys = 0;
+ dns_rdataset_init(&rdataset);
+ RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
+ &rdataset, NULL));
+ RETERR(dns_rdataset_first(&rdataset));
+ while (result == ISC_R_SUCCESS && count < maxkeys) {
+ pubkey = NULL;
+ dns_rdataset_current(&rdataset, &rdata);
+ RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
+ if (!is_zone_key(pubkey) ||
+ (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
+ goto next;
+ keys[count] = NULL;
+ result = dst_key_fromfile(dst_key_name(pubkey),
+ dst_key_id(pubkey),
+ dst_key_alg(pubkey),
+ DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
+ directory,
+ mctx, &keys[count]);
+ if (result == ISC_R_FILENOTFOUND) {
+ keys[count] = pubkey;
+ pubkey = NULL;
+ count++;
+ goto next;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
+ /* We should never get here. */
+ dst_key_free(&keys[count]);
+ goto next;
+ }
+ count++;
+ next:
+ if (pubkey != NULL)
+ dst_key_free(&pubkey);
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(&rdataset);
+ }
+ if (result != ISC_R_NOMORE)
+ goto failure;
+ if (count == 0)
+ result = ISC_R_NOTFOUND;
+ else
+ result = ISC_R_SUCCESS;
+
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (pubkey != NULL)
+ dst_key_free(&pubkey);
+ if (result != ISC_R_SUCCESS)
+ while (count > 0)
+ dst_key_free(&keys[--count]);
+ *nkeys = count;
+ return (result);
+}
+
+isc_result_t
+dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
+ dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx,
+ unsigned int maxkeys, dst_key_t **keys,
+ unsigned int *nkeys)
+{
+ return (dns_dnssec_findzonekeys2(db, ver, node, name, NULL, mctx,
+ maxkeys, keys, nkeys));
+}
+
+isc_result_t
+dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
+ dns_rdata_sig_t sig; /* SIG(0) */
+ unsigned char data[512];
+ unsigned char header[DNS_MESSAGE_HEADERLEN];
+ isc_buffer_t headerbuf, databuf, sigbuf;
+ unsigned int sigsize;
+ isc_buffer_t *dynbuf = NULL;
+ dns_rdata_t *rdata;
+ dns_rdatalist_t *datalist;
+ dns_rdataset_t *dataset;
+ isc_region_t r;
+ isc_stdtime_t now;
+ dst_context_t *ctx = NULL;
+ isc_mem_t *mctx;
+ isc_result_t result;
+ isc_boolean_t signeedsfree = ISC_TRUE;
+
+ REQUIRE(msg != NULL);
+ REQUIRE(key != NULL);
+
+ if (is_response(msg))
+ REQUIRE(msg->query.base != NULL);
+
+ mctx = msg->mctx;
+
+ memset(&sig, 0, sizeof(sig));
+
+ sig.mctx = mctx;
+ sig.common.rdclass = dns_rdataclass_any;
+ sig.common.rdtype = dns_rdatatype_sig; /* SIG(0) */
+ ISC_LINK_INIT(&sig.common, link);
+
+ sig.covered = 0;
+ sig.algorithm = dst_key_alg(key);
+ sig.labels = 0; /* the root name */
+ sig.originalttl = 0;
+
+ isc_stdtime_get(&now);
+ sig.timesigned = now - DNS_TSIG_FUDGE;
+ sig.timeexpire = now + DNS_TSIG_FUDGE;
+
+ sig.keyid = dst_key_id(key);
+
+ dns_name_init(&sig.signer, NULL);
+ dns_name_clone(dst_key_name(key), &sig.signer);
+
+ sig.siglen = 0;
+ sig.signature = NULL;
+
+ isc_buffer_init(&databuf, data, sizeof(data));
+
+ RETERR(dst_context_create(key, mctx, &ctx));
+
+ /*
+ * Digest the fields of the SIG - we can cheat and use
+ * dns_rdata_fromstruct. Since siglen is 0, the digested data
+ * is identical to dns format.
+ */
+ RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
+ dns_rdatatype_sig /* SIG(0) */,
+ &sig, &databuf));
+ isc_buffer_usedregion(&databuf, &r);
+ RETERR(dst_context_adddata(ctx, &r));
+
+ /*
+ * If this is a response, digest the query.
+ */
+ if (is_response(msg))
+ RETERR(dst_context_adddata(ctx, &msg->query));
+
+ /*
+ * Digest the header.
+ */
+ isc_buffer_init(&headerbuf, header, sizeof(header));
+ dns_message_renderheader(msg, &headerbuf);
+ isc_buffer_usedregion(&headerbuf, &r);
+ RETERR(dst_context_adddata(ctx, &r));
+
+ /*
+ * Digest the remainder of the message.
+ */
+ isc_buffer_usedregion(msg->buffer, &r);
+ isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
+ RETERR(dst_context_adddata(ctx, &r));
+
+ RETERR(dst_key_sigsize(key, &sigsize));
+ sig.siglen = sigsize;
+ sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
+ if (sig.signature == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto failure;
+ }
+
+ isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
+ RETERR(dst_context_sign(ctx, &sigbuf));
+ dst_context_destroy(&ctx);
+
+ rdata = NULL;
+ RETERR(dns_message_gettemprdata(msg, &rdata));
+ RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
+ RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
+ dns_rdatatype_sig /* SIG(0) */,
+ &sig, dynbuf));
+
+ isc_mem_put(mctx, sig.signature, sig.siglen);
+ signeedsfree = ISC_FALSE;
+
+ dns_message_takebuffer(msg, &dynbuf);
+
+ datalist = NULL;
+ RETERR(dns_message_gettemprdatalist(msg, &datalist));
+ datalist->rdclass = dns_rdataclass_any;
+ datalist->type = dns_rdatatype_sig; /* SIG(0) */
+ datalist->covers = 0;
+ datalist->ttl = 0;
+ ISC_LIST_INIT(datalist->rdata);
+ ISC_LIST_APPEND(datalist->rdata, rdata, link);
+ dataset = NULL;
+ RETERR(dns_message_gettemprdataset(msg, &dataset));
+ dns_rdataset_init(dataset);
+ RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
+ msg->sig0 = dataset;
+
+ return (ISC_R_SUCCESS);
+
+failure:
+ if (dynbuf != NULL)
+ isc_buffer_free(&dynbuf);
+ if (signeedsfree)
+ isc_mem_put(mctx, sig.signature, sig.siglen);
+ if (ctx != NULL)
+ dst_context_destroy(&ctx);
+
+ return (result);
+}
+
+isc_result_t
+dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
+ dst_key_t *key)
+{
+ dns_rdata_sig_t sig; /* SIG(0) */
+ unsigned char header[DNS_MESSAGE_HEADERLEN];
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_region_t r, source_r, sig_r, header_r;
+ isc_stdtime_t now;
+ dst_context_t *ctx = NULL;
+ isc_mem_t *mctx;
+ isc_result_t result;
+ isc_uint16_t addcount;
+ isc_boolean_t signeedsfree = ISC_FALSE;
+
+ REQUIRE(source != NULL);
+ REQUIRE(msg != NULL);
+ REQUIRE(key != NULL);
+
+ mctx = msg->mctx;
+
+ msg->verify_attempted = 1;
+
+ if (is_response(msg)) {
+ if (msg->query.base == NULL)
+ return (DNS_R_UNEXPECTEDTSIG);
+ }
+
+ isc_buffer_usedregion(source, &source_r);
+
+ RETERR(dns_rdataset_first(msg->sig0));
+ dns_rdataset_current(msg->sig0, &rdata);
+
+ RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
+ signeedsfree = ISC_TRUE;
+
+ if (sig.labels != 0) {
+ result = DNS_R_SIGINVALID;
+ goto failure;
+ }
+
+ if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
+ result = DNS_R_SIGINVALID;
+ msg->sig0status = dns_tsigerror_badtime;
+ goto failure;
+ }
+
+ isc_stdtime_get(&now);
+ if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
+ result = DNS_R_SIGFUTURE;
+ msg->sig0status = dns_tsigerror_badtime;
+ goto failure;
+ }
+ else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
+ result = DNS_R_SIGEXPIRED;
+ msg->sig0status = dns_tsigerror_badtime;
+ goto failure;
+ }
+
+ if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
+ result = DNS_R_SIGINVALID;
+ msg->sig0status = dns_tsigerror_badkey;
+ goto failure;
+ }
+
+ RETERR(dst_context_create(key, mctx, &ctx));
+
+ /*
+ * Digest the SIG(0) record, except for the signature.
+ */
+ dns_rdata_toregion(&rdata, &r);
+ r.length -= sig.siglen;
+ RETERR(dst_context_adddata(ctx, &r));
+
+ /*
+ * If this is a response, digest the query.
+ */
+ if (is_response(msg))
+ RETERR(dst_context_adddata(ctx, &msg->query));
+
+ /*
+ * Extract the header.
+ */
+ memcpy(header, source_r.base, DNS_MESSAGE_HEADERLEN);
+
+ /*
+ * Decrement the additional field counter.
+ */
+ memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
+ addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
+ memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
+
+ /*
+ * Digest the modified header.
+ */
+ header_r.base = (unsigned char *) header;
+ header_r.length = DNS_MESSAGE_HEADERLEN;
+ RETERR(dst_context_adddata(ctx, &header_r));
+
+ /*
+ * Digest all non-SIG(0) records.
+ */
+ r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
+ r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
+ RETERR(dst_context_adddata(ctx, &r));
+
+ sig_r.base = sig.signature;
+ sig_r.length = sig.siglen;
+ result = dst_context_verify(ctx, &sig_r);
+ if (result != ISC_R_SUCCESS) {
+ msg->sig0status = dns_tsigerror_badsig;
+ goto failure;
+ }
+
+ msg->verified_sig = 1;
+
+ dst_context_destroy(&ctx);
+ dns_rdata_freestruct(&sig);
+
+ return (ISC_R_SUCCESS);
+
+failure:
+ if (signeedsfree)
+ dns_rdata_freestruct(&sig);
+ if (ctx != NULL)
+ dst_context_destroy(&ctx);
+
+ return (result);
+}
diff --git a/lib/dns/ds.c b/lib/dns/ds.c
new file mode 100644
index 0000000..7cd1609
--- /dev/null
+++ b/lib/dns/ds.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2002, 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: ds.c,v 1.4.20.5 2006/02/22 23:50:09 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <isc/buffer.h>
+#include <isc/region.h>
+#include <isc/sha1.h>
+#include <isc/sha2.h>
+#include <isc/util.h>
+
+#include <dns/ds.h>
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdatastruct.h>
+#include <dns/result.h>
+
+#include <dst/dst.h>
+
+isc_result_t
+dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key,
+ unsigned int digest_type, unsigned char *buffer,
+ dns_rdata_t *rdata)
+{
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ unsigned char digest[ISC_SHA256_DIGESTLENGTH];
+ isc_region_t r;
+ isc_buffer_t b;
+ dns_rdata_ds_t ds;
+
+ REQUIRE(key != NULL);
+ REQUIRE(key->type == dns_rdatatype_dnskey);
+
+ if (!dns_ds_digest_supported(digest_type))
+ return (ISC_R_NOTIMPLEMENTED);
+
+ dns_fixedname_init(&fname);
+ name = dns_fixedname_name(&fname);
+ (void)dns_name_downcase(owner, name, NULL);
+
+ memset(buffer, 0, DNS_DS_BUFFERSIZE);
+ isc_buffer_init(&b, buffer, DNS_DS_BUFFERSIZE);
+
+ if (digest_type == DNS_DSDIGEST_SHA1) {
+ isc_sha1_t sha1;
+ isc_sha1_init(&sha1);
+ dns_name_toregion(name, &r);
+ isc_sha1_update(&sha1, r.base, r.length);
+ dns_rdata_toregion(key, &r);
+ INSIST(r.length >= 4);
+ isc_sha1_update(&sha1, r.base, r.length);
+ isc_sha1_final(&sha1, digest);
+ } else {
+ isc_sha256_t sha256;
+ isc_sha256_init(&sha256);
+ dns_name_toregion(name, &r);
+ isc_sha256_update(&sha256, r.base, r.length);
+ dns_rdata_toregion(key, &r);
+ INSIST(r.length >= 4);
+ isc_sha256_update(&sha256, r.base, r.length);
+ isc_sha256_final(digest, &sha256);
+ }
+
+ ds.mctx = NULL;
+ ds.common.rdclass = key->rdclass;
+ ds.common.rdtype = dns_rdatatype_ds;
+ ds.algorithm = r.base[3];
+ ds.key_tag = dst_region_computeid(&r, ds.algorithm);
+ ds.digest_type = digest_type;
+ ds.length = (digest_type == DNS_DSDIGEST_SHA1) ?
+ ISC_SHA1_DIGESTLENGTH : ISC_SHA256_DIGESTLENGTH;
+ ds.digest = digest;
+
+ return (dns_rdata_fromstruct(rdata, key->rdclass, dns_rdatatype_ds,
+ &ds, &b));
+}
+
+isc_boolean_t
+dns_ds_digest_supported(unsigned int digest_type) {
+ return (ISC_TF(digest_type == DNS_DSDIGEST_SHA1 ||
+ digest_type == DNS_DSDIGEST_SHA256));
+}
diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c
new file mode 100644
index 0000000..7d98e10
--- /dev/null
+++ b/lib/dns/dst_api.c
@@ -0,0 +1,1221 @@
+/*
+ * Portions Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1999-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.
+ */
+
+/*
+ * Principal Author: Brian Wellington
+ * $Id: dst_api.c,v 1.1.6.7 2006/01/27 23:57:44 marka Exp $
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/dir.h>
+#include <isc/entropy.h>
+#include <isc/fsaccess.h>
+#include <isc/hmacsha.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include <dns/fixedname.h>
+#include <dns/keyvalues.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/ttl.h>
+#include <dns/types.h>
+
+#include <dst/result.h>
+
+#include "dst_internal.h"
+
+#define DST_AS_STR(t) ((t).value.as_textregion.base)
+
+static dst_func_t *dst_t_func[DST_MAX_ALGS];
+static isc_entropy_t *dst_entropy_pool = NULL;
+static unsigned int dst_entropy_flags = 0;
+static isc_boolean_t dst_initialized = ISC_FALSE;
+
+isc_mem_t *dst__memory_pool = NULL;
+
+/*
+ * Static functions.
+ */
+static dst_key_t * get_key_struct(dns_name_t *name,
+ unsigned int alg,
+ unsigned int flags,
+ unsigned int protocol,
+ unsigned int bits,
+ dns_rdataclass_t rdclass,
+ isc_mem_t *mctx);
+static isc_result_t write_public_key(const dst_key_t *key, int type,
+ const char *directory);
+static isc_result_t buildfilename(dns_name_t *name,
+ dns_keytag_t id,
+ unsigned int alg,
+ unsigned int type,
+ const char *directory,
+ isc_buffer_t *out);
+static isc_result_t computeid(dst_key_t *key);
+static isc_result_t frombuffer(dns_name_t *name,
+ unsigned int alg,
+ unsigned int flags,
+ unsigned int protocol,
+ dns_rdataclass_t rdclass,
+ isc_buffer_t *source,
+ isc_mem_t *mctx,
+ dst_key_t **keyp);
+
+static isc_result_t algorithm_status(unsigned int alg);
+
+static isc_result_t addsuffix(char *filename, unsigned int len,
+ const char *ofilename, const char *suffix);
+
+#define RETERR(x) \
+ do { \
+ result = (x); \
+ if (result != ISC_R_SUCCESS) \
+ goto out; \
+ } while (0)
+
+#define CHECKALG(alg) \
+ do { \
+ isc_result_t _r; \
+ _r = algorithm_status(alg); \
+ if (_r != ISC_R_SUCCESS) \
+ return (_r); \
+ } while (0); \
+
+static void *
+default_memalloc(void *arg, size_t size) {
+ UNUSED(arg);
+ if (size == 0U)
+ size = 1;
+ return (malloc(size));
+}
+
+static void
+default_memfree(void *arg, void *ptr) {
+ UNUSED(arg);
+ free(ptr);
+}
+
+isc_result_t
+dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) {
+ isc_result_t result;
+
+ REQUIRE(mctx != NULL && ectx != NULL);
+ REQUIRE(dst_initialized == ISC_FALSE);
+
+ dst__memory_pool = NULL;
+
+#ifdef OPENSSL
+ UNUSED(mctx);
+ /*
+ * When using --with-openssl, there seems to be no good way of not
+ * leaking memory due to the openssl error handling mechanism.
+ * Avoid assertions by using a local memory context and not checking
+ * for leaks on exit. Note: as there are leaks we cannot use
+ * ISC_MEMFLAG_INTERNAL as it will free up memory still being used
+ * by libcrypto.
+ */
+ result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
+ NULL, &dst__memory_pool, 0);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE);
+#else
+ isc_mem_attach(mctx, &dst__memory_pool);
+#endif
+ isc_entropy_attach(ectx, &dst_entropy_pool);
+ dst_entropy_flags = eflags;
+
+ dst_result_register();
+
+ memset(dst_t_func, 0, sizeof(dst_t_func));
+ RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5]));
+ RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1]));
+ RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224]));
+ RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256]));
+ RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
+ RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
+#ifdef OPENSSL
+ RETERR(dst__openssl_init());
+ RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5]));
+ RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1]));
+#ifdef HAVE_OPENSSL_DSA
+ RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA]));
+#endif
+ RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
+#endif /* OPENSSL */
+#ifdef GSSAPI
+ RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
+#endif
+ dst_initialized = ISC_TRUE;
+ return (ISC_R_SUCCESS);
+
+ out:
+ dst_lib_destroy();
+ return (result);
+}
+
+void
+dst_lib_destroy(void) {
+ int i;
+ RUNTIME_CHECK(dst_initialized == ISC_TRUE);
+ dst_initialized = ISC_FALSE;
+
+ for (i = 0; i < DST_MAX_ALGS; i++)
+ if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL)
+ dst_t_func[i]->cleanup();
+#ifdef OPENSSL
+ dst__openssl_destroy();
+#endif
+ if (dst__memory_pool != NULL)
+ isc_mem_detach(&dst__memory_pool);
+ if (dst_entropy_pool != NULL)
+ isc_entropy_detach(&dst_entropy_pool);
+
+}
+
+isc_boolean_t
+dst_algorithm_supported(unsigned int alg) {
+ REQUIRE(dst_initialized == ISC_TRUE);
+
+ if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
+ return (ISC_FALSE);
+ return (ISC_TRUE);
+}
+
+isc_result_t
+dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) {
+ dst_context_t *dctx;
+ isc_result_t result;
+
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(VALID_KEY(key));
+ REQUIRE(mctx != NULL);
+ REQUIRE(dctxp != NULL && *dctxp == NULL);
+
+ if (key->func->createctx == NULL)
+ return (DST_R_UNSUPPORTEDALG);
+ if (key->opaque == NULL)
+ return (DST_R_NULLKEY);
+
+ dctx = isc_mem_get(mctx, sizeof(dst_context_t));
+ if (dctx == NULL)
+ return (ISC_R_NOMEMORY);
+ dctx->key = key;
+ dctx->mctx = mctx;
+ result = key->func->createctx(key, dctx);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, dctx, sizeof(dst_context_t));
+ return (result);
+ }
+ dctx->magic = CTX_MAGIC;
+ *dctxp = dctx;
+ return (ISC_R_SUCCESS);
+}
+
+void
+dst_context_destroy(dst_context_t **dctxp) {
+ dst_context_t *dctx;
+
+ REQUIRE(dctxp != NULL && VALID_CTX(*dctxp));
+
+ dctx = *dctxp;
+ INSIST(dctx->key->func->destroyctx != NULL);
+ dctx->key->func->destroyctx(dctx);
+ dctx->magic = 0;
+ isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t));
+ *dctxp = NULL;
+}
+
+isc_result_t
+dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ REQUIRE(VALID_CTX(dctx));
+ REQUIRE(data != NULL);
+ INSIST(dctx->key->func->adddata != NULL);
+
+ return (dctx->key->func->adddata(dctx, data));
+}
+
+isc_result_t
+dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ dst_key_t *key;
+
+ REQUIRE(VALID_CTX(dctx));
+ REQUIRE(sig != NULL);
+
+ key = dctx->key;
+ CHECKALG(key->key_alg);
+ if (key->opaque == NULL)
+ return (DST_R_NULLKEY);
+ if (key->func->sign == NULL)
+ return (DST_R_NOTPRIVATEKEY);
+ if (key->func->isprivate == NULL ||
+ key->func->isprivate(key) == ISC_FALSE)
+ return (DST_R_NOTPRIVATEKEY);
+
+ return (key->func->sign(dctx, sig));
+}
+
+isc_result_t
+dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
+ REQUIRE(VALID_CTX(dctx));
+ REQUIRE(sig != NULL);
+
+ CHECKALG(dctx->key->key_alg);
+ if (dctx->key->opaque == NULL)
+ return (DST_R_NULLKEY);
+ if (dctx->key->func->verify == NULL)
+ return (DST_R_NOTPUBLICKEY);
+
+ return (dctx->key->func->verify(dctx, sig));
+}
+
+isc_result_t
+dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
+ isc_buffer_t *secret)
+{
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(VALID_KEY(pub) && VALID_KEY(priv));
+ REQUIRE(secret != NULL);
+
+ CHECKALG(pub->key_alg);
+ CHECKALG(priv->key_alg);
+
+ if (pub->opaque == NULL || priv->opaque == NULL)
+ return (DST_R_NULLKEY);
+
+ if (pub->key_alg != priv->key_alg ||
+ pub->func->computesecret == NULL ||
+ priv->func->computesecret == NULL)
+ return (DST_R_KEYCANNOTCOMPUTESECRET);
+
+ if (dst_key_isprivate(priv) == ISC_FALSE)
+ return (DST_R_NOTPRIVATEKEY);
+
+ return (pub->func->computesecret(pub, priv, secret));
+}
+
+isc_result_t
+dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
+ isc_result_t ret = ISC_R_SUCCESS;
+
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(VALID_KEY(key));
+ REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
+
+ CHECKALG(key->key_alg);
+
+ if (key->func->tofile == NULL)
+ return (DST_R_UNSUPPORTEDALG);
+
+ if (type & DST_TYPE_PUBLIC) {
+ ret = write_public_key(key, type, directory);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ }
+
+ if ((type & DST_TYPE_PRIVATE) &&
+ (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
+ return (key->func->tofile(key, directory));
+ else
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
+ unsigned int alg, int type, const char *directory,
+ isc_mem_t *mctx, dst_key_t **keyp)
+{
+ char filename[ISC_DIR_NAMEMAX];
+ isc_buffer_t b;
+ dst_key_t *key;
+ isc_result_t result;
+
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(dns_name_isabsolute(name));
+ REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
+ REQUIRE(mctx != NULL);
+ REQUIRE(keyp != NULL && *keyp == NULL);
+
+ CHECKALG(alg);
+
+ isc_buffer_init(&b, filename, sizeof(filename));
+ result = buildfilename(name, id, alg, type, directory, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ key = NULL;
+ result = dst_key_fromnamedfile(filename, type, mctx, &key);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = computeid(key);
+ if (result != ISC_R_SUCCESS) {
+ dst_key_free(&key);
+ return (result);
+ }
+
+ if (!dns_name_equal(name, key->key_name) ||
+ id != key->key_id ||
+ alg != key->key_alg)
+ {
+ dst_key_free(&key);
+ return (DST_R_INVALIDPRIVATEKEY);
+ }
+ key->key_id = id;
+
+ *keyp = key;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx,
+ dst_key_t **keyp)
+{
+ isc_result_t result;
+ dst_key_t *pubkey = NULL, *key = NULL;
+ dns_keytag_t id;
+ char *newfilename = NULL;
+ int newfilenamelen = 0;
+ isc_lex_t *lex = NULL;
+
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(filename != NULL);
+ REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
+ REQUIRE(mctx != NULL);
+ REQUIRE(keyp != NULL && *keyp == NULL);
+
+ newfilenamelen = strlen(filename) + 5;
+ newfilename = isc_mem_get(mctx, newfilenamelen);
+ if (newfilename == NULL)
+ return (ISC_R_NOMEMORY);
+ result = addsuffix(newfilename, newfilenamelen, filename, ".key");
+ INSIST(result == ISC_R_SUCCESS);
+
+ result = dst_key_read_public(newfilename, type, mctx, &pubkey);
+ isc_mem_put(mctx, newfilename, newfilenamelen);
+ newfilename = NULL;
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC ||
+ (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY)
+ {
+ result = computeid(pubkey);
+ if (result != ISC_R_SUCCESS) {
+ dst_key_free(&pubkey);
+ return (result);
+ }
+
+ *keyp = pubkey;
+ return (ISC_R_SUCCESS);
+ }
+
+ result = algorithm_status(pubkey->key_alg);
+ if (result != ISC_R_SUCCESS) {
+ dst_key_free(&pubkey);
+ return (result);
+ }
+
+ key = get_key_struct(pubkey->key_name, pubkey->key_alg,
+ pubkey->key_flags, pubkey->key_proto, 0,
+ pubkey->key_class, mctx);
+ id = pubkey->key_id;
+ dst_key_free(&pubkey);
+
+ if (key == NULL)
+ return (ISC_R_NOMEMORY);
+
+ if (key->func->parse == NULL)
+ RETERR(DST_R_UNSUPPORTEDALG);
+
+ newfilenamelen = strlen(filename) + 9;
+ newfilename = isc_mem_get(mctx, newfilenamelen);
+ if (newfilename == NULL)
+ RETERR(ISC_R_NOMEMORY);
+ result = addsuffix(newfilename, newfilenamelen, filename, ".private");
+ INSIST(result == ISC_R_SUCCESS);
+
+ RETERR(isc_lex_create(mctx, 1500, &lex));
+ RETERR(isc_lex_openfile(lex, newfilename));
+ isc_mem_put(mctx, newfilename, newfilenamelen);
+
+ RETERR(key->func->parse(key, lex));
+ isc_lex_destroy(&lex);
+
+ RETERR(computeid(key));
+
+ if (id != key->key_id)
+ RETERR(DST_R_INVALIDPRIVATEKEY);
+
+ *keyp = key;
+ return (ISC_R_SUCCESS);
+ out:
+ if (newfilename != NULL)
+ isc_mem_put(mctx, newfilename, newfilenamelen);
+ if (lex != NULL)
+ isc_lex_destroy(&lex);
+ dst_key_free(&key);
+ return (result);
+}
+
+isc_result_t
+dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(VALID_KEY(key));
+ REQUIRE(target != NULL);
+
+ CHECKALG(key->key_alg);
+
+ if (key->func->todns == NULL)
+ return (DST_R_UNSUPPORTEDALG);
+
+ if (isc_buffer_availablelength(target) < 4)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff));
+ isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto);
+ isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg);
+
+ if (key->key_flags & DNS_KEYFLAG_EXTENDED) {
+ if (isc_buffer_availablelength(target) < 2)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint16(target,
+ (isc_uint16_t)((key->key_flags >> 16)
+ & 0xffff));
+ }
+
+ if (key->opaque == NULL) /*%< NULL KEY */
+ return (ISC_R_SUCCESS);
+
+ return (key->func->todns(key, target));
+}
+
+isc_result_t
+dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass,
+ isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
+{
+ isc_uint8_t alg, proto;
+ isc_uint32_t flags, extflags;
+ dst_key_t *key = NULL;
+ dns_keytag_t id;
+ isc_region_t r;
+ isc_result_t result;
+
+ REQUIRE(dst_initialized);
+
+ isc_buffer_remainingregion(source, &r);
+
+ if (isc_buffer_remaininglength(source) < 4)
+ return (DST_R_INVALIDPUBLICKEY);
+ flags = isc_buffer_getuint16(source);
+ proto = isc_buffer_getuint8(source);
+ alg = isc_buffer_getuint8(source);
+
+ id = dst_region_computeid(&r, alg);
+
+ if (flags & DNS_KEYFLAG_EXTENDED) {
+ if (isc_buffer_remaininglength(source) < 2)
+ return (DST_R_INVALIDPUBLICKEY);
+ extflags = isc_buffer_getuint16(source);
+ flags |= (extflags << 16);
+ }
+
+ result = frombuffer(name, alg, flags, proto, rdclass, source,
+ mctx, &key);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ key->key_id = id;
+
+ *keyp = key;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dst_key_frombuffer(dns_name_t *name, unsigned int alg,
+ unsigned int flags, unsigned int protocol,
+ dns_rdataclass_t rdclass,
+ isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
+{
+ dst_key_t *key = NULL;
+ isc_result_t result;
+
+ REQUIRE(dst_initialized);
+
+ result = frombuffer(name, alg, flags, protocol, rdclass, source,
+ mctx, &key);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = computeid(key);
+ if (result != ISC_R_SUCCESS) {
+ dst_key_free(&key);
+ return (result);
+ }
+
+ *keyp = key;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) {
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(VALID_KEY(key));
+ REQUIRE(target != NULL);
+
+ CHECKALG(key->key_alg);
+
+ if (key->func->todns == NULL)
+ return (DST_R_UNSUPPORTEDALG);
+
+ return (key->func->todns(key, target));
+}
+
+isc_result_t
+dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) {
+ isc_lex_t *lex = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(VALID_KEY(key));
+ REQUIRE(!dst_key_isprivate(key));
+ REQUIRE(buffer != NULL);
+
+ if (key->func->parse == NULL)
+ RETERR(DST_R_UNSUPPORTEDALG);
+
+ RETERR(isc_lex_create(key->mctx, 1500, &lex));
+ RETERR(isc_lex_openbuffer(lex, buffer));
+ RETERR(key->func->parse(key, lex));
+ out:
+ if (lex != NULL)
+ isc_lex_destroy(&lex);
+ return (result);
+}
+
+isc_result_t
+dst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx,
+ dst_key_t **keyp)
+{
+ dst_key_t *key;
+
+ REQUIRE(opaque != NULL);
+ REQUIRE(keyp != NULL && *keyp == NULL);
+
+ key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC,
+ 0, dns_rdataclass_in, mctx);
+ if (key == NULL)
+ return (ISC_R_NOMEMORY);
+ key->opaque = opaque;
+ *keyp = key;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dst_key_generate(dns_name_t *name, unsigned int alg,
+ unsigned int bits, unsigned int param,
+ unsigned int flags, unsigned int protocol,
+ dns_rdataclass_t rdclass,
+ isc_mem_t *mctx, dst_key_t **keyp)
+{
+ dst_key_t *key;
+ isc_result_t ret;
+
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(dns_name_isabsolute(name));
+ REQUIRE(mctx != NULL);
+ REQUIRE(keyp != NULL && *keyp == NULL);
+
+ CHECKALG(alg);
+
+ key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx);
+ if (key == NULL)
+ return (ISC_R_NOMEMORY);
+
+ if (bits == 0) { /*%< NULL KEY */
+ key->key_flags |= DNS_KEYTYPE_NOKEY;
+ *keyp = key;
+ return (ISC_R_SUCCESS);
+ }
+
+ if (key->func->generate == NULL) {
+ dst_key_free(&key);
+ return (DST_R_UNSUPPORTEDALG);
+ }
+
+ ret = key->func->generate(key, param);
+ if (ret != ISC_R_SUCCESS) {
+ dst_key_free(&key);
+ return (ret);
+ }
+
+ ret = computeid(key);
+ if (ret != ISC_R_SUCCESS) {
+ dst_key_free(&key);
+ return (ret);
+ }
+
+ *keyp = key;
+ return (ISC_R_SUCCESS);
+}
+
+isc_boolean_t
+dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(VALID_KEY(key1));
+ REQUIRE(VALID_KEY(key2));
+
+ if (key1 == key2)
+ return (ISC_TRUE);
+ if (key1 == NULL || key2 == NULL)
+ return (ISC_FALSE);
+ if (key1->key_alg == key2->key_alg &&
+ key1->key_id == key2->key_id &&
+ key1->func->compare != NULL &&
+ key1->func->compare(key1, key2) == ISC_TRUE)
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(VALID_KEY(key1));
+ REQUIRE(VALID_KEY(key2));
+
+ if (key1 == key2)
+ return (ISC_TRUE);
+ if (key1 == NULL || key2 == NULL)
+ return (ISC_FALSE);
+ if (key1->key_alg == key2->key_alg &&
+ key1->func->paramcompare != NULL &&
+ key1->func->paramcompare(key1, key2) == ISC_TRUE)
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+}
+
+void
+dst_key_free(dst_key_t **keyp) {
+ isc_mem_t *mctx;
+ dst_key_t *key;
+
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(keyp != NULL && VALID_KEY(*keyp));
+
+ key = *keyp;
+ mctx = key->mctx;
+
+ if (key->opaque != NULL) {
+ INSIST(key->func->destroy != NULL);
+ key->func->destroy(key);
+ }
+
+ dns_name_free(key->key_name, mctx);
+ isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
+ memset(key, 0, sizeof(dst_key_t));
+ isc_mem_put(mctx, key, sizeof(dst_key_t));
+ *keyp = NULL;
+}
+
+isc_boolean_t
+dst_key_isprivate(const dst_key_t *key) {
+ REQUIRE(VALID_KEY(key));
+ INSIST(key->func->isprivate != NULL);
+ return (key->func->isprivate(key));
+}
+
+isc_result_t
+dst_key_buildfilename(const dst_key_t *key, int type,
+ const char *directory, isc_buffer_t *out) {
+
+ REQUIRE(VALID_KEY(key));
+ REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
+ type == 0);
+
+ return (buildfilename(key->key_name, key->key_id, key->key_alg,
+ type, directory, out));
+}
+
+isc_result_t
+dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(VALID_KEY(key));
+ REQUIRE(n != NULL);
+
+ /* XXXVIX this switch statement is too sparse to gen a jump table. */
+ switch (key->key_alg) {
+ case DST_ALG_RSAMD5:
+ case DST_ALG_RSASHA1:
+ *n = (key->key_size + 7) / 8;
+ break;
+ case DST_ALG_DSA:
+ *n = DNS_SIG_DSASIGSIZE;
+ break;
+ case DST_ALG_HMACMD5:
+ *n = 16;
+ break;
+ case DST_ALG_HMACSHA1:
+ *n = ISC_SHA1_DIGESTLENGTH;
+ break;
+ case DST_ALG_HMACSHA224:
+ *n = ISC_SHA224_DIGESTLENGTH;
+ break;
+ case DST_ALG_HMACSHA256:
+ *n = ISC_SHA256_DIGESTLENGTH;
+ break;
+ case DST_ALG_HMACSHA384:
+ *n = ISC_SHA384_DIGESTLENGTH;
+ break;
+ case DST_ALG_HMACSHA512:
+ *n = ISC_SHA512_DIGESTLENGTH;
+ break;
+ case DST_ALG_GSSAPI:
+ *n = 128; /*%< XXX */
+ break;
+ case DST_ALG_DH:
+ default:
+ return (DST_R_UNSUPPORTEDALG);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(VALID_KEY(key));
+ REQUIRE(n != NULL);
+
+ if (key->key_alg == DST_ALG_DH)
+ *n = (key->key_size + 7) / 8;
+ else
+ return (DST_R_UNSUPPORTEDALG);
+ return (ISC_R_SUCCESS);
+}
+
+/***
+ *** Static methods
+ ***/
+
+/*%
+ * Allocates a key structure and fills in some of the fields.
+ */
+static dst_key_t *
+get_key_struct(dns_name_t *name, unsigned int alg,
+ unsigned int flags, unsigned int protocol,
+ unsigned int bits, dns_rdataclass_t rdclass,
+ isc_mem_t *mctx)
+{
+ dst_key_t *key;
+ isc_result_t result;
+
+ key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t));
+ if (key == NULL)
+ return (NULL);
+
+ memset(key, 0, sizeof(dst_key_t));
+ key->magic = KEY_MAGIC;
+
+ key->key_name = isc_mem_get(mctx, sizeof(dns_name_t));
+ if (key->key_name == NULL) {
+ isc_mem_put(mctx, key, sizeof(dst_key_t));
+ return (NULL);
+ }
+ dns_name_init(key->key_name, NULL);
+ result = dns_name_dup(name, mctx, key->key_name);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
+ isc_mem_put(mctx, key, sizeof(dst_key_t));
+ return (NULL);
+ }
+ key->key_alg = alg;
+ key->key_flags = flags;
+ key->key_proto = protocol;
+ key->mctx = mctx;
+ key->opaque = NULL;
+ key->key_size = bits;
+ key->key_class = rdclass;
+ key->func = dst_t_func[alg];
+ return (key);
+}
+
+/*%
+ * Reads a public key from disk
+ */
+isc_result_t
+dst_key_read_public(const char *filename, int type,
+ isc_mem_t *mctx, dst_key_t **keyp)
+{
+ u_char rdatabuf[DST_KEY_MAXSIZE];
+ isc_buffer_t b;
+ dns_fixedname_t name;
+ isc_lex_t *lex = NULL;
+ isc_token_t token;
+ isc_result_t ret;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
+ dns_rdataclass_t rdclass = dns_rdataclass_in;
+ isc_lexspecials_t specials;
+ isc_uint32_t ttl;
+ isc_result_t result;
+ dns_rdatatype_t keytype;
+
+ /*
+ * Open the file and read its formatted contents
+ * File format:
+ * domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key>
+ */
+
+ /* 1500 should be large enough for any key */
+ ret = isc_lex_create(mctx, 1500, &lex);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup;
+
+ memset(specials, 0, sizeof(specials));
+ specials['('] = 1;
+ specials[')'] = 1;
+ specials['"'] = 1;
+ isc_lex_setspecials(lex, specials);
+ isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
+
+ ret = isc_lex_openfile(lex, filename);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup;
+
+#define NEXTTOKEN(lex, opt, token) { \
+ ret = isc_lex_gettoken(lex, opt, token); \
+ if (ret != ISC_R_SUCCESS) \
+ goto cleanup; \
+ }
+
+#define BADTOKEN() { \
+ ret = ISC_R_UNEXPECTEDTOKEN; \
+ goto cleanup; \
+ }
+
+ /* Read the domain name */
+ NEXTTOKEN(lex, opt, &token);
+ if (token.type != isc_tokentype_string)
+ BADTOKEN();
+ dns_fixedname_init(&name);
+ isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token)));
+ isc_buffer_add(&b, strlen(DST_AS_STR(token)));
+ ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname,
+ ISC_FALSE, NULL);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup;
+
+ /* Read the next word: either TTL, class, or 'KEY' */
+ NEXTTOKEN(lex, opt, &token);
+
+ /* If it's a TTL, read the next one */
+ result = dns_ttl_fromtext(&token.value.as_textregion, &ttl);
+ if (result == ISC_R_SUCCESS)
+ NEXTTOKEN(lex, opt, &token);
+
+ if (token.type != isc_tokentype_string)
+ BADTOKEN();
+
+ ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
+ if (ret == ISC_R_SUCCESS)
+ NEXTTOKEN(lex, opt, &token);
+
+ if (token.type != isc_tokentype_string)
+ BADTOKEN();
+
+ if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0)
+ keytype = dns_rdatatype_dnskey;
+ else if (strcasecmp(DST_AS_STR(token), "KEY") == 0)
+ keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */
+ else
+ BADTOKEN();
+
+ if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) ||
+ ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) {
+ ret = DST_R_BADKEYTYPE;
+ goto cleanup;
+ }
+
+ isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
+ ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL,
+ ISC_FALSE, mctx, &b, NULL);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup;
+
+ ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx,
+ keyp);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup;
+
+ cleanup:
+ if (lex != NULL)
+ isc_lex_destroy(&lex);
+ return (ret);
+}
+
+static isc_boolean_t
+issymmetric(const dst_key_t *key) {
+ REQUIRE(dst_initialized == ISC_TRUE);
+ REQUIRE(VALID_KEY(key));
+
+ /* XXXVIX this switch statement is too sparse to gen a jump table. */
+ switch (key->key_alg) {
+ case DST_ALG_RSAMD5:
+ case DST_ALG_RSASHA1:
+ case DST_ALG_DSA:
+ case DST_ALG_DH:
+ return (ISC_FALSE);
+ case DST_ALG_HMACMD5:
+ case DST_ALG_GSSAPI:
+ return (ISC_TRUE);
+ default:
+ return (ISC_FALSE);
+ }
+}
+
+/*%
+ * Writes a public key to disk in DNS format.
+ */
+static isc_result_t
+write_public_key(const dst_key_t *key, int type, const char *directory) {
+ FILE *fp;
+ isc_buffer_t keyb, textb, fileb, classb;
+ isc_region_t r;
+ char filename[ISC_DIR_NAMEMAX];
+ unsigned char key_array[DST_KEY_MAXSIZE];
+ char text_array[DST_KEY_MAXTEXTSIZE];
+ char class_array[10];
+ isc_result_t ret;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_fsaccess_t access;
+
+ REQUIRE(VALID_KEY(key));
+
+ isc_buffer_init(&keyb, key_array, sizeof(key_array));
+ isc_buffer_init(&textb, text_array, sizeof(text_array));
+ isc_buffer_init(&classb, class_array, sizeof(class_array));
+
+ ret = dst_key_todns(key, &keyb);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ isc_buffer_usedregion(&keyb, &r);
+ dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r);
+
+ ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb);
+ if (ret != ISC_R_SUCCESS)
+ return (DST_R_INVALIDPUBLICKEY);
+
+ ret = dns_rdataclass_totext(key->key_class, &classb);
+ if (ret != ISC_R_SUCCESS)
+ return (DST_R_INVALIDPUBLICKEY);
+
+ /*
+ * Make the filename.
+ */
+ isc_buffer_init(&fileb, filename, sizeof(filename));
+ ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ /*
+ * Create public key file.
+ */
+ if ((fp = fopen(filename, "w")) == NULL)
+ return (DST_R_WRITEERROR);
+
+ if (issymmetric(key)) {
+ access = 0;
+ isc_fsaccess_add(ISC_FSACCESS_OWNER,
+ ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
+ &access);
+ (void)isc_fsaccess_set(filename, access);
+ }
+
+ ret = dns_name_print(key->key_name, fp);
+ if (ret != ISC_R_SUCCESS) {
+ fclose(fp);
+ return (ret);
+ }
+
+ fprintf(fp, " ");
+
+ isc_buffer_usedregion(&classb, &r);
+ fwrite(r.base, 1, r.length, fp);
+
+ if ((type & DST_TYPE_KEY) != 0)
+ fprintf(fp, " KEY ");
+ else
+ fprintf(fp, " DNSKEY ");
+
+ isc_buffer_usedregion(&textb, &r);
+ fwrite(r.base, 1, r.length, fp);
+
+ fputc('\n', fp);
+ fclose(fp);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+buildfilename(dns_name_t *name, dns_keytag_t id,
+ unsigned int alg, unsigned int type,
+ const char *directory, isc_buffer_t *out)
+{
+ const char *suffix = "";
+ unsigned int len;
+ isc_result_t result;
+
+ REQUIRE(out != NULL);
+ if ((type & DST_TYPE_PRIVATE) != 0)
+ suffix = ".private";
+ else if (type == DST_TYPE_PUBLIC)
+ suffix = ".key";
+ if (directory != NULL) {
+ if (isc_buffer_availablelength(out) < strlen(directory))
+ return (ISC_R_NOSPACE);
+ isc_buffer_putstr(out, directory);
+ if (strlen(directory) > 0U &&
+ directory[strlen(directory) - 1] != '/')
+ isc_buffer_putstr(out, "/");
+ }
+ if (isc_buffer_availablelength(out) < 1)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putstr(out, "K");
+ result = dns_name_tofilenametext(name, ISC_FALSE, out);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ len = 1 + 3 + 1 + 5 + strlen(suffix) + 1;
+ if (isc_buffer_availablelength(out) < len)
+ return (ISC_R_NOSPACE);
+ sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, suffix);
+ isc_buffer_add(out, len);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+computeid(dst_key_t *key) {
+ isc_buffer_t dnsbuf;
+ unsigned char dns_array[DST_KEY_MAXSIZE];
+ isc_region_t r;
+ isc_result_t ret;
+
+ isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
+ ret = dst_key_todns(key, &dnsbuf);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ isc_buffer_usedregion(&dnsbuf, &r);
+ key->key_id = dst_region_computeid(&r, key->key_alg);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags,
+ unsigned int protocol, dns_rdataclass_t rdclass,
+ isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
+{
+ dst_key_t *key;
+ isc_result_t ret;
+
+ REQUIRE(dns_name_isabsolute(name));
+ REQUIRE(source != NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(keyp != NULL && *keyp == NULL);
+
+ key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx);
+ if (key == NULL)
+ return (ISC_R_NOMEMORY);
+
+ if (isc_buffer_remaininglength(source) > 0) {
+ ret = algorithm_status(alg);
+ if (ret != ISC_R_SUCCESS) {
+ dst_key_free(&key);
+ return (ret);
+ }
+ if (key->func->fromdns == NULL) {
+ dst_key_free(&key);
+ return (DST_R_UNSUPPORTEDALG);
+ }
+
+ ret = key->func->fromdns(key, source);
+ if (ret != ISC_R_SUCCESS) {
+ dst_key_free(&key);
+ return (ret);
+ }
+ }
+
+ *keyp = key;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+algorithm_status(unsigned int alg) {
+ REQUIRE(dst_initialized == ISC_TRUE);
+
+ if (dst_algorithm_supported(alg))
+ return (ISC_R_SUCCESS);
+#ifndef OPENSSL
+ if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 ||
+ alg == DST_ALG_DSA || alg == DST_ALG_DH ||
+ alg == DST_ALG_HMACMD5)
+ return (DST_R_NOCRYPTO);
+#endif
+ return (DST_R_UNSUPPORTEDALG);
+}
+
+static isc_result_t
+addsuffix(char *filename, unsigned int len, const char *ofilename,
+ const char *suffix)
+{
+ int olen = strlen(ofilename);
+ int n;
+
+ if (olen > 1 && ofilename[olen - 1] == '.')
+ olen -= 1;
+ else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0)
+ olen -= 8;
+ else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0)
+ olen -= 4;
+
+ n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix);
+ if (n < 0)
+ return (ISC_R_NOSPACE);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
+ unsigned int flags = dst_entropy_flags;
+ if (pseudo)
+ flags &= ~ISC_ENTROPY_GOODONLY;
+ return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags));
+}
diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h
new file mode 100644
index 0000000..f2deb72
--- /dev/null
+++ b/lib/dns/dst_internal.h
@@ -0,0 +1,142 @@
+/*
+ * Portions Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2000-2002 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: dst_internal.h,v 1.1.6.5 2006/01/27 23:57:44 marka Exp $ */
+
+#ifndef DST_DST_INTERNAL_H
+#define DST_DST_INTERNAL_H 1
+
+#include <isc/lang.h>
+#include <isc/buffer.h>
+#include <isc/int.h>
+#include <isc/magic.h>
+#include <isc/region.h>
+#include <isc/types.h>
+
+#include <dst/dst.h>
+
+ISC_LANG_BEGINDECLS
+
+#define KEY_MAGIC ISC_MAGIC('D','S','T','K')
+#define CTX_MAGIC ISC_MAGIC('D','S','T','C')
+
+#define VALID_KEY(x) ISC_MAGIC_VALID(x, KEY_MAGIC)
+#define VALID_CTX(x) ISC_MAGIC_VALID(x, CTX_MAGIC)
+
+extern isc_mem_t *dst__memory_pool;
+
+/***
+ *** Types
+ ***/
+
+typedef struct dst_func dst_func_t;
+
+/*% DST Key Structure */
+struct dst_key {
+ unsigned int magic;
+ dns_name_t * key_name; /*%< name of the key */
+ unsigned int key_size; /*%< size of the key in bits */
+ unsigned int key_proto; /*%< protocols this key is used for */
+ unsigned int key_alg; /*%< algorithm of the key */
+ isc_uint32_t key_flags; /*%< flags of the public key */
+ isc_uint16_t key_id; /*%< identifier of the key */
+ isc_uint16_t key_bits; /*%< hmac digest bits */
+ dns_rdataclass_t key_class; /*%< class of the key record */
+ isc_mem_t *mctx; /*%< memory context */
+ void * opaque; /*%< pointer to key in crypto pkg fmt */
+ dst_func_t * func; /*%< crypto package specific functions */
+};
+
+struct dst_context {
+ unsigned int magic;
+ dst_key_t *key;
+ isc_mem_t *mctx;
+ void *opaque;
+};
+
+struct dst_func {
+ /*
+ * Context functions
+ */
+ isc_result_t (*createctx)(dst_key_t *key, dst_context_t *dctx);
+ void (*destroyctx)(dst_context_t *dctx);
+ isc_result_t (*adddata)(dst_context_t *dctx, const isc_region_t *data);
+
+ /*
+ * Key operations
+ */
+ isc_result_t (*sign)(dst_context_t *dctx, isc_buffer_t *sig);
+ isc_result_t (*verify)(dst_context_t *dctx, const isc_region_t *sig);
+ isc_result_t (*computesecret)(const dst_key_t *pub,
+ const dst_key_t *priv,
+ isc_buffer_t *secret);
+ isc_boolean_t (*compare)(const dst_key_t *key1, const dst_key_t *key2);
+ isc_boolean_t (*paramcompare)(const dst_key_t *key1,
+ const dst_key_t *key2);
+ isc_result_t (*generate)(dst_key_t *key, int parms);
+ isc_boolean_t (*isprivate)(const dst_key_t *key);
+ void (*destroy)(dst_key_t *key);
+
+ /* conversion functions */
+ isc_result_t (*todns)(const dst_key_t *key, isc_buffer_t *data);
+ isc_result_t (*fromdns)(dst_key_t *key, isc_buffer_t *data);
+ isc_result_t (*tofile)(const dst_key_t *key, const char *directory);
+ isc_result_t (*parse)(dst_key_t *key, isc_lex_t *lexer);
+
+ /* cleanup */
+ void (*cleanup)(void);
+};
+
+/*%
+ * Initializers
+ */
+isc_result_t dst__openssl_init(void);
+
+isc_result_t dst__hmacmd5_init(struct dst_func **funcp);
+isc_result_t dst__hmacsha1_init(struct dst_func **funcp);
+isc_result_t dst__hmacsha224_init(struct dst_func **funcp);
+isc_result_t dst__hmacsha256_init(struct dst_func **funcp);
+isc_result_t dst__hmacsha384_init(struct dst_func **funcp);
+isc_result_t dst__hmacsha512_init(struct dst_func **funcp);
+isc_result_t dst__opensslrsa_init(struct dst_func **funcp);
+isc_result_t dst__openssldsa_init(struct dst_func **funcp);
+isc_result_t dst__openssldh_init(struct dst_func **funcp);
+isc_result_t dst__gssapi_init(struct dst_func **funcp);
+
+/*%
+ * Destructors
+ */
+void dst__openssl_destroy(void);
+
+/*%
+ * Memory allocators using the DST memory pool.
+ */
+void * dst__mem_alloc(size_t size);
+void dst__mem_free(void *ptr);
+void * dst__mem_realloc(void *ptr, size_t size);
+
+/*%
+ * Entropy retriever using the DST entropy pool.
+ */
+isc_result_t dst__entropy_getdata(void *buf, unsigned int len,
+ isc_boolean_t pseudo);
+
+ISC_LANG_ENDDECLS
+
+#endif /* DST_DST_INTERNAL_H */
+/*! \file */
diff --git a/lib/dns/dst_lib.c b/lib/dns/dst_lib.c
new file mode 100644
index 0000000..305051c
--- /dev/null
+++ b/lib/dns/dst_lib.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+/*
+ * Principal Author: Brian Wellington
+ * $Id: dst_lib.c,v 1.1.6.3 2005/04/29 00:15:51 marka Exp $
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/once.h>
+#include <isc/msgcat.h>
+#include <isc/util.h>
+
+#include <dst/lib.h>
+
+/***
+ *** Globals
+ ***/
+
+LIBDNS_EXTERNAL_DATA isc_msgcat_t * dst_msgcat = NULL;
+
+
+/***
+ *** Private
+ ***/
+
+static isc_once_t msgcat_once = ISC_ONCE_INIT;
+
+
+/***
+ *** Functions
+ ***/
+
+static void
+open_msgcat(void) {
+ isc_msgcat_open("libdst.cat", &dst_msgcat);
+}
+
+void
+dst_lib_initmsgcat(void) {
+
+ /*
+ * Initialize the DST library's message catalog, dst_msgcat, if it
+ * has not already been initialized.
+ */
+
+ RUNTIME_CHECK(isc_once_do(&msgcat_once, open_msgcat) == ISC_R_SUCCESS);
+}
diff --git a/lib/dns/dst_openssl.h b/lib/dns/dst_openssl.h
new file mode 100644
index 0000000..79e10b0
--- /dev/null
+++ b/lib/dns/dst_openssl.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: dst_openssl.h,v 1.1.4.3 2005/04/29 00:15:52 marka Exp $ */
+
+#ifndef DST_OPENSSL_H
+#define DST_OPENSSL_H 1
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dst__openssl_toresult(isc_result_t fallback);
+
+ISC_LANG_ENDDECLS
+
+#endif /* DST_OPENSSL_H */
+/*! \file */
diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c
new file mode 100644
index 0000000..aad7998
--- /dev/null
+++ b/lib/dns/dst_parse.c
@@ -0,0 +1,493 @@
+/*
+ * Portions Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1999-2002 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.
+ */
+
+/*%
+ * Principal Author: Brian Wellington
+ * $Id: dst_parse.c,v 1.1.6.7 2006/05/16 03:59:26 marka Exp $
+ */
+
+#include <config.h>
+
+#include <isc/base64.h>
+#include <isc/dir.h>
+#include <isc/fsaccess.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include "dst_internal.h"
+#include "dst_parse.h"
+#include "dst/result.h"
+
+#define DST_AS_STR(t) ((t).value.as_textregion.base)
+
+#define PRIVATE_KEY_STR "Private-key-format:"
+#define ALGORITHM_STR "Algorithm:"
+
+struct parse_map {
+ const int value;
+ const char *tag;
+};
+
+static struct parse_map map[] = {
+ {TAG_RSA_MODULUS, "Modulus:"},
+ {TAG_RSA_PUBLICEXPONENT, "PublicExponent:"},
+ {TAG_RSA_PRIVATEEXPONENT, "PrivateExponent:"},
+ {TAG_RSA_PRIME1, "Prime1:"},
+ {TAG_RSA_PRIME2, "Prime2:"},
+ {TAG_RSA_EXPONENT1, "Exponent1:"},
+ {TAG_RSA_EXPONENT2, "Exponent2:"},
+ {TAG_RSA_COEFFICIENT, "Coefficient:"},
+
+ {TAG_DH_PRIME, "Prime(p):"},
+ {TAG_DH_GENERATOR, "Generator(g):"},
+ {TAG_DH_PRIVATE, "Private_value(x):"},
+ {TAG_DH_PUBLIC, "Public_value(y):"},
+
+ {TAG_DSA_PRIME, "Prime(p):"},
+ {TAG_DSA_SUBPRIME, "Subprime(q):"},
+ {TAG_DSA_BASE, "Base(g):"},
+ {TAG_DSA_PRIVATE, "Private_value(x):"},
+ {TAG_DSA_PUBLIC, "Public_value(y):"},
+
+ {TAG_HMACMD5_KEY, "Key:"},
+ {TAG_HMACMD5_BITS, "Bits:"},
+
+ {TAG_HMACSHA1_KEY, "Key:"},
+ {TAG_HMACSHA1_BITS, "Bits:"},
+
+ {TAG_HMACSHA224_KEY, "Key:"},
+ {TAG_HMACSHA224_BITS, "Bits:"},
+
+ {TAG_HMACSHA256_KEY, "Key:"},
+ {TAG_HMACSHA256_BITS, "Bits:"},
+
+ {TAG_HMACSHA384_KEY, "Key:"},
+ {TAG_HMACSHA384_BITS, "Bits:"},
+
+ {TAG_HMACSHA512_KEY, "Key:"},
+ {TAG_HMACSHA512_BITS, "Bits:"},
+
+ {0, NULL}
+};
+
+static int
+find_value(const char *s, const unsigned int alg) {
+ int i;
+
+ for (i = 0; ; i++) {
+ if (map[i].tag == NULL)
+ return (-1);
+ else if (strcasecmp(s, map[i].tag) == 0 &&
+ TAG_ALG(map[i].value) == alg)
+ return (map[i].value);
+ }
+}
+
+static const char *
+find_tag(const int value) {
+ int i;
+
+ for (i = 0; ; i++) {
+ if (map[i].tag == NULL)
+ return (NULL);
+ else if (value == map[i].value)
+ return (map[i].tag);
+ }
+}
+
+static int
+check_rsa(const dst_private_t *priv) {
+ int i, j;
+ if (priv->nelements != RSA_NTAGS)
+ return (-1);
+ for (i = 0; i < RSA_NTAGS; i++) {
+ for (j = 0; j < priv->nelements; j++)
+ if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i))
+ break;
+ if (j == priv->nelements)
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+check_dh(const dst_private_t *priv) {
+ int i, j;
+ if (priv->nelements != DH_NTAGS)
+ return (-1);
+ for (i = 0; i < DH_NTAGS; i++) {
+ for (j = 0; j < priv->nelements; j++)
+ if (priv->elements[j].tag == TAG(DST_ALG_DH, i))
+ break;
+ if (j == priv->nelements)
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+check_dsa(const dst_private_t *priv) {
+ int i, j;
+ if (priv->nelements != DSA_NTAGS)
+ return (-1);
+ for (i = 0; i < DSA_NTAGS; i++) {
+ for (j = 0; j < priv->nelements; j++)
+ if (priv->elements[j].tag == TAG(DST_ALG_DSA, i))
+ break;
+ if (j == priv->nelements)
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+check_hmac_md5(const dst_private_t *priv, isc_boolean_t old) {
+ int i, j;
+
+ if (priv->nelements != HMACMD5_NTAGS) {
+ /*
+ * If this is a good old format and we are accepting
+ * the old format return success.
+ */
+ if (old && priv->nelements == OLD_HMACMD5_NTAGS &&
+ priv->elements[0].tag == TAG_HMACMD5_KEY)
+ return (0);
+ return (-1);
+ }
+ /*
+ * We must be new format at this point.
+ */
+ for (i = 0; i < HMACMD5_NTAGS; i++) {
+ for (j = 0; j < priv->nelements; j++)
+ if (priv->elements[j].tag == TAG(DST_ALG_HMACMD5, i))
+ break;
+ if (j == priv->nelements)
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+check_hmac_sha(const dst_private_t *priv, unsigned int ntags,
+ unsigned int alg)
+{
+ unsigned int i, j;
+ if (priv->nelements != ntags)
+ return (-1);
+ for (i = 0; i < ntags; i++) {
+ for (j = 0; j < priv->nelements; j++)
+ if (priv->elements[j].tag == TAG(alg, i))
+ break;
+ if (j == priv->nelements)
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+check_data(const dst_private_t *priv, const unsigned int alg,
+ isc_boolean_t old)
+{
+ /* XXXVIX this switch statement is too sparse to gen a jump table. */
+ switch (alg) {
+ case DST_ALG_RSAMD5:
+ case DST_ALG_RSASHA1:
+ return (check_rsa(priv));
+ case DST_ALG_DH:
+ return (check_dh(priv));
+ case DST_ALG_DSA:
+ return (check_dsa(priv));
+ case DST_ALG_HMACMD5:
+ return (check_hmac_md5(priv, old));
+ case DST_ALG_HMACSHA1:
+ return (check_hmac_sha(priv, HMACSHA1_NTAGS, alg));
+ case DST_ALG_HMACSHA224:
+ return (check_hmac_sha(priv, HMACSHA224_NTAGS, alg));
+ case DST_ALG_HMACSHA256:
+ return (check_hmac_sha(priv, HMACSHA256_NTAGS, alg));
+ case DST_ALG_HMACSHA384:
+ return (check_hmac_sha(priv, HMACSHA384_NTAGS, alg));
+ case DST_ALG_HMACSHA512:
+ return (check_hmac_sha(priv, HMACSHA512_NTAGS, alg));
+ default:
+ return (DST_R_UNSUPPORTEDALG);
+ }
+}
+
+void
+dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx) {
+ int i;
+
+ if (priv == NULL)
+ return;
+ for (i = 0; i < priv->nelements; i++) {
+ if (priv->elements[i].data == NULL)
+ continue;
+ memset(priv->elements[i].data, 0, MAXFIELDSIZE);
+ isc_mem_put(mctx, priv->elements[i].data, MAXFIELDSIZE);
+ }
+ priv->nelements = 0;
+}
+
+int
+dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
+ isc_mem_t *mctx, dst_private_t *priv)
+{
+ int n = 0, major, minor;
+ isc_buffer_t b;
+ isc_token_t token;
+ unsigned char *data = NULL;
+ unsigned int opt = ISC_LEXOPT_EOL;
+ isc_result_t ret;
+
+ REQUIRE(priv != NULL);
+
+ priv->nelements = 0;
+
+#define NEXTTOKEN(lex, opt, token) \
+ do { \
+ ret = isc_lex_gettoken(lex, opt, token); \
+ if (ret != ISC_R_SUCCESS) \
+ goto fail; \
+ } while (0)
+
+#define READLINE(lex, opt, token) \
+ do { \
+ ret = isc_lex_gettoken(lex, opt, token); \
+ if (ret == ISC_R_EOF) \
+ break; \
+ else if (ret != ISC_R_SUCCESS) \
+ goto fail; \
+ } while ((*token).type != isc_tokentype_eol)
+
+ /*
+ * Read the description line.
+ */
+ NEXTTOKEN(lex, opt, &token);
+ if (token.type != isc_tokentype_string ||
+ strcmp(DST_AS_STR(token), PRIVATE_KEY_STR) != 0)
+ {
+ ret = DST_R_INVALIDPRIVATEKEY;
+ goto fail;
+ }
+
+ NEXTTOKEN(lex, opt, &token);
+ if (token.type != isc_tokentype_string ||
+ (DST_AS_STR(token))[0] != 'v')
+ {
+ ret = DST_R_INVALIDPRIVATEKEY;
+ goto fail;
+ }
+ if (sscanf(DST_AS_STR(token), "v%d.%d", &major, &minor) != 2)
+ {
+ ret = DST_R_INVALIDPRIVATEKEY;
+ goto fail;
+ }
+
+ if (major > MAJOR_VERSION ||
+ (major == MAJOR_VERSION && minor > MINOR_VERSION))
+ {
+ ret = DST_R_INVALIDPRIVATEKEY;
+ goto fail;
+ }
+
+ READLINE(lex, opt, &token);
+
+ /*
+ * Read the algorithm line.
+ */
+ NEXTTOKEN(lex, opt, &token);
+ if (token.type != isc_tokentype_string ||
+ strcmp(DST_AS_STR(token), ALGORITHM_STR) != 0)
+ {
+ ret = DST_R_INVALIDPRIVATEKEY;
+ goto fail;
+ }
+
+ NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
+ if (token.type != isc_tokentype_number ||
+ token.value.as_ulong != (unsigned long) dst_key_alg(key))
+ {
+ ret = DST_R_INVALIDPRIVATEKEY;
+ goto fail;
+ }
+
+ READLINE(lex, opt, &token);
+
+ /*
+ * Read the key data.
+ */
+ for (n = 0; n < MAXFIELDS; n++) {
+ int tag;
+ isc_region_t r;
+
+ do {
+ ret = isc_lex_gettoken(lex, opt, &token);
+ if (ret == ISC_R_EOF)
+ goto done;
+ if (ret != ISC_R_SUCCESS)
+ goto fail;
+ } while (token.type == isc_tokentype_eol);
+
+ if (token.type != isc_tokentype_string) {
+ ret = DST_R_INVALIDPRIVATEKEY;
+ goto fail;
+ }
+
+ memset(&priv->elements[n], 0, sizeof(dst_private_element_t));
+ tag = find_value(DST_AS_STR(token), alg);
+ if (tag < 0 || TAG_ALG(tag) != alg) {
+ ret = DST_R_INVALIDPRIVATEKEY;
+ goto fail;
+ }
+ priv->elements[n].tag = tag;
+
+ data = (unsigned char *) isc_mem_get(mctx, MAXFIELDSIZE);
+ if (data == NULL)
+ goto fail;
+
+ isc_buffer_init(&b, data, MAXFIELDSIZE);
+ ret = isc_base64_tobuffer(lex, &b, -1);
+ if (ret != ISC_R_SUCCESS)
+ goto fail;
+ isc_buffer_usedregion(&b, &r);
+ priv->elements[n].length = r.length;
+ priv->elements[n].data = r.base;
+
+ READLINE(lex, opt, &token);
+ data = NULL;
+ }
+ done:
+ priv->nelements = n;
+
+ if (check_data(priv, alg, ISC_TRUE) < 0)
+ goto fail;
+
+ return (ISC_R_SUCCESS);
+
+fail:
+ priv->nelements = n;
+ dst__privstruct_free(priv, mctx);
+ if (data != NULL)
+ isc_mem_put(mctx, data, MAXFIELDSIZE);
+
+ return (ret);
+}
+
+int
+dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
+ const char *directory)
+{
+ FILE *fp;
+ int ret, i;
+ isc_result_t iret;
+ char filename[ISC_DIR_NAMEMAX];
+ char buffer[MAXFIELDSIZE * 2];
+ isc_buffer_t b;
+ isc_fsaccess_t access;
+
+ REQUIRE(priv != NULL);
+
+ if (check_data(priv, dst_key_alg(key), ISC_FALSE) < 0)
+ return (DST_R_INVALIDPRIVATEKEY);
+
+ isc_buffer_init(&b, filename, sizeof(filename));
+ ret = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &b);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ if ((fp = fopen(filename, "w")) == NULL)
+ return (DST_R_WRITEERROR);
+
+ access = 0;
+ isc_fsaccess_add(ISC_FSACCESS_OWNER,
+ ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
+ &access);
+ (void)isc_fsaccess_set(filename, access);
+
+ /* XXXDCL return value should be checked for full filesystem */
+ fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, MAJOR_VERSION,
+ MINOR_VERSION);
+
+ fprintf(fp, "%s %d ", ALGORITHM_STR, dst_key_alg(key));
+ /* XXXVIX this switch statement is too sparse to gen a jump table. */
+ switch (dst_key_alg(key)) {
+ case DST_ALG_RSAMD5:
+ fprintf(fp, "(RSA)\n");
+ break;
+ case DST_ALG_DH:
+ fprintf(fp, "(DH)\n");
+ break;
+ case DST_ALG_DSA:
+ fprintf(fp, "(DSA)\n");
+ break;
+ case DST_ALG_RSASHA1:
+ fprintf(fp, "(RSASHA1)\n");
+ break;
+ case DST_ALG_HMACMD5:
+ fprintf(fp, "(HMAC_MD5)\n");
+ break;
+ case DST_ALG_HMACSHA1:
+ fprintf(fp, "(HMAC_SHA1)\n");
+ break;
+ case DST_ALG_HMACSHA224:
+ fprintf(fp, "(HMAC_SHA224)\n");
+ break;
+ case DST_ALG_HMACSHA256:
+ fprintf(fp, "(HMAC_SHA256)\n");
+ break;
+ case DST_ALG_HMACSHA384:
+ fprintf(fp, "(HMAC_SHA384)\n");
+ break;
+ case DST_ALG_HMACSHA512:
+ fprintf(fp, "(HMAC_SHA512)\n");
+ break;
+ default:
+ fprintf(fp, "(?)\n");
+ break;
+ }
+
+ for (i = 0; i < priv->nelements; i++) {
+ isc_buffer_t b;
+ isc_region_t r;
+ const char *s;
+
+ s = find_tag(priv->elements[i].tag);
+
+ r.base = priv->elements[i].data;
+ r.length = priv->elements[i].length;
+ isc_buffer_init(&b, buffer, sizeof(buffer));
+ iret = isc_base64_totext(&r, sizeof(buffer), "", &b);
+ if (iret != ISC_R_SUCCESS) {
+ fclose(fp);
+ return (DST_R_INVALIDPRIVATEKEY);
+ }
+ isc_buffer_usedregion(&b, &r);
+
+ fprintf(fp, "%s ", s);
+ fwrite(r.base, 1, r.length, fp);
+ fprintf(fp, "\n");
+ }
+
+ fclose(fp);
+ return (ISC_R_SUCCESS);
+}
+
+/*! \file */
diff --git a/lib/dns/dst_parse.h b/lib/dns/dst_parse.h
new file mode 100644
index 0000000..8656f59
--- /dev/null
+++ b/lib/dns/dst_parse.h
@@ -0,0 +1,118 @@
+/*
+ * Portions Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2000-2002 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: dst_parse.h,v 1.1.6.5 2006/01/27 23:57:44 marka Exp $ */
+
+/*! \file */
+#ifndef DST_DST_PARSE_H
+#define DST_DST_PARSE_H 1
+
+#include <isc/lang.h>
+
+#include <dst/dst.h>
+
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 2
+
+#define MAXFIELDSIZE 512
+#define MAXFIELDS 12
+
+#define TAG_SHIFT 4
+#define TAG_ALG(tag) ((unsigned int)(tag) >> TAG_SHIFT)
+#define TAG(alg, off) (((alg) << TAG_SHIFT) + (off))
+
+/* These are used by both RSA-MD5 and RSA-SHA1 */
+#define RSA_NTAGS 8
+#define TAG_RSA_MODULUS ((DST_ALG_RSAMD5 << TAG_SHIFT) + 0)
+#define TAG_RSA_PUBLICEXPONENT ((DST_ALG_RSAMD5 << TAG_SHIFT) + 1)
+#define TAG_RSA_PRIVATEEXPONENT ((DST_ALG_RSAMD5 << TAG_SHIFT) + 2)
+#define TAG_RSA_PRIME1 ((DST_ALG_RSAMD5 << TAG_SHIFT) + 3)
+#define TAG_RSA_PRIME2 ((DST_ALG_RSAMD5 << TAG_SHIFT) + 4)
+#define TAG_RSA_EXPONENT1 ((DST_ALG_RSAMD5 << TAG_SHIFT) + 5)
+#define TAG_RSA_EXPONENT2 ((DST_ALG_RSAMD5 << TAG_SHIFT) + 6)
+#define TAG_RSA_COEFFICIENT ((DST_ALG_RSAMD5 << TAG_SHIFT) + 7)
+
+#define DH_NTAGS 4
+#define TAG_DH_PRIME ((DST_ALG_DH << TAG_SHIFT) + 0)
+#define TAG_DH_GENERATOR ((DST_ALG_DH << TAG_SHIFT) + 1)
+#define TAG_DH_PRIVATE ((DST_ALG_DH << TAG_SHIFT) + 2)
+#define TAG_DH_PUBLIC ((DST_ALG_DH << TAG_SHIFT) + 3)
+
+#define DSA_NTAGS 5
+#define TAG_DSA_PRIME ((DST_ALG_DSA << TAG_SHIFT) + 0)
+#define TAG_DSA_SUBPRIME ((DST_ALG_DSA << TAG_SHIFT) + 1)
+#define TAG_DSA_BASE ((DST_ALG_DSA << TAG_SHIFT) + 2)
+#define TAG_DSA_PRIVATE ((DST_ALG_DSA << TAG_SHIFT) + 3)
+#define TAG_DSA_PUBLIC ((DST_ALG_DSA << TAG_SHIFT) + 4)
+
+#define OLD_HMACMD5_NTAGS 1
+#define HMACMD5_NTAGS 2
+#define TAG_HMACMD5_KEY ((DST_ALG_HMACMD5 << TAG_SHIFT) + 0)
+#define TAG_HMACMD5_BITS ((DST_ALG_HMACMD5 << TAG_SHIFT) + 1)
+
+#define HMACSHA1_NTAGS 2
+#define TAG_HMACSHA1_KEY ((DST_ALG_HMACSHA1 << TAG_SHIFT) + 0)
+#define TAG_HMACSHA1_BITS ((DST_ALG_HMACSHA1 << TAG_SHIFT) + 1)
+
+#define HMACSHA224_NTAGS 2
+#define TAG_HMACSHA224_KEY ((DST_ALG_HMACSHA224 << TAG_SHIFT) + 0)
+#define TAG_HMACSHA224_BITS ((DST_ALG_HMACSHA224 << TAG_SHIFT) + 1)
+
+#define HMACSHA256_NTAGS 2
+#define TAG_HMACSHA256_KEY ((DST_ALG_HMACSHA256 << TAG_SHIFT) + 0)
+#define TAG_HMACSHA256_BITS ((DST_ALG_HMACSHA224 << TAG_SHIFT) + 1)
+
+#define HMACSHA384_NTAGS 2
+#define TAG_HMACSHA384_KEY ((DST_ALG_HMACSHA384 << TAG_SHIFT) + 0)
+#define TAG_HMACSHA384_BITS ((DST_ALG_HMACSHA384 << TAG_SHIFT) + 1)
+
+#define HMACSHA512_NTAGS 2
+#define TAG_HMACSHA512_KEY ((DST_ALG_HMACSHA512 << TAG_SHIFT) + 0)
+#define TAG_HMACSHA512_BITS ((DST_ALG_HMACSHA512 << TAG_SHIFT) + 1)
+
+struct dst_private_element {
+ unsigned short tag;
+ unsigned short length;
+ unsigned char *data;
+};
+
+typedef struct dst_private_element dst_private_element_t;
+
+struct dst_private {
+ unsigned short nelements;
+ dst_private_element_t elements[MAXFIELDS];
+};
+
+typedef struct dst_private dst_private_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx);
+
+int
+dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
+ isc_mem_t *mctx, dst_private_t *priv);
+
+int
+dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
+ const char *directory);
+
+ISC_LANG_ENDDECLS
+
+#endif /* DST_DST_PARSE_H */
diff --git a/lib/dns/dst_result.c b/lib/dns/dst_result.c
new file mode 100644
index 0000000..c9bf073
--- /dev/null
+++ b/lib/dns/dst_result.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+/*%
+ * Principal Author: Brian Wellington
+ * $Id: dst_result.c,v 1.1.6.3 2005/04/29 00:15:52 marka Exp $
+ */
+
+#include <config.h>
+
+#include <isc/once.h>
+#include <isc/util.h>
+
+#include <dst/result.h>
+#include <dst/lib.h>
+
+static const char *text[DST_R_NRESULTS] = {
+ "algorithm is unsupported", /*%< 0 */
+ "openssl failure", /*%< 1 */
+ "built with no crypto support", /*%< 2 */
+ "illegal operation for a null key", /*%< 3 */
+ "public key is invalid", /*%< 4 */
+ "private key is invalid", /*%< 5 */
+ "UNUSED6", /*%< 6 */
+ "error occurred writing key to disk", /*%< 7 */
+ "invalid algorithm specific parameter", /*%< 8 */
+ "UNUSED9", /*%< 9 */
+ "UNUSED10", /*%< 10 */
+ "sign failure", /*%< 11 */
+ "UNUSED12", /*%< 12 */
+ "UNUSED13", /*%< 13 */
+ "verify failure", /*%< 14 */
+ "not a public key", /*%< 15 */
+ "not a private key", /*%< 16 */
+ "not a key that can compute a secret", /*%< 17 */
+ "failure computing a shared secret", /*%< 18 */
+ "no randomness available", /*%< 19 */
+ "bad key type" /*%< 20 */
+};
+
+#define DST_RESULT_RESULTSET 2
+
+static isc_once_t once = ISC_ONCE_INIT;
+
+static void
+initialize_action(void) {
+ isc_result_t result;
+
+ result = isc_result_register(ISC_RESULTCLASS_DST, DST_R_NRESULTS,
+ text, dst_msgcat, DST_RESULT_RESULTSET);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_result_register() failed: %u", result);
+}
+
+static void
+initialize(void) {
+ dst_lib_initmsgcat();
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+const char *
+dst_result_totext(isc_result_t result) {
+ initialize();
+
+ return (isc_result_totext(result));
+}
+
+void
+dst_result_register(void) {
+ initialize();
+}
+
+/*! \file */
diff --git a/lib/dns/forward.c b/lib/dns/forward.c
new file mode 100644
index 0000000..e80a477
--- /dev/null
+++ b/lib/dns/forward.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2004, 2005 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: forward.c,v 1.6.18.4 2005/07/12 01:22:20 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/rwlock.h>
+#include <isc/sockaddr.h>
+#include <isc/util.h>
+
+#include <dns/forward.h>
+#include <dns/rbt.h>
+#include <dns/result.h>
+#include <dns/types.h>
+
+struct dns_fwdtable {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_rwlock_t rwlock;
+ /* Locked by lock. */
+ dns_rbt_t *table;
+};
+
+#define FWDTABLEMAGIC ISC_MAGIC('F', 'w', 'd', 'T')
+#define VALID_FWDTABLE(ft) ISC_MAGIC_VALID(ft, FWDTABLEMAGIC)
+
+static void
+auto_detach(void *, void *);
+
+isc_result_t
+dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep) {
+ dns_fwdtable_t *fwdtable;
+ isc_result_t result;
+
+ REQUIRE(fwdtablep != NULL && *fwdtablep == NULL);
+
+ fwdtable = isc_mem_get(mctx, sizeof(dns_fwdtable_t));
+ if (fwdtable == NULL)
+ return (ISC_R_NOMEMORY);
+
+ fwdtable->table = NULL;
+ result = dns_rbt_create(mctx, auto_detach, fwdtable, &fwdtable->table);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_fwdtable;
+
+ result = isc_rwlock_init(&fwdtable->rwlock, 0, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_rbt;
+
+ fwdtable->mctx = NULL;
+ isc_mem_attach(mctx, &fwdtable->mctx);
+ fwdtable->magic = FWDTABLEMAGIC;
+ *fwdtablep = fwdtable;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_rbt:
+ dns_rbt_destroy(&fwdtable->table);
+
+ cleanup_fwdtable:
+ isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t));
+
+ return (result);
+}
+
+isc_result_t
+dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name,
+ isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy)
+{
+ isc_result_t result;
+ dns_forwarders_t *forwarders;
+ isc_sockaddr_t *sa, *nsa;
+
+ REQUIRE(VALID_FWDTABLE(fwdtable));
+
+ forwarders = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarders_t));
+ if (forwarders == NULL)
+ return (ISC_R_NOMEMORY);
+
+ ISC_LIST_INIT(forwarders->addrs);
+ for (sa = ISC_LIST_HEAD(*addrs);
+ sa != NULL;
+ sa = ISC_LIST_NEXT(sa, link))
+ {
+ nsa = isc_mem_get(fwdtable->mctx, sizeof(isc_sockaddr_t));
+ if (nsa == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ *nsa = *sa;
+ ISC_LINK_INIT(nsa, link);
+ ISC_LIST_APPEND(forwarders->addrs, nsa, link);
+ }
+ forwarders->fwdpolicy = fwdpolicy;
+
+ RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
+ result = dns_rbt_addname(fwdtable->table, name, forwarders);
+ RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
+
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ while (!ISC_LIST_EMPTY(forwarders->addrs)) {
+ sa = ISC_LIST_HEAD(forwarders->addrs);
+ ISC_LIST_UNLINK(forwarders->addrs, sa, link);
+ isc_mem_put(fwdtable->mctx, sa, sizeof(isc_sockaddr_t));
+ }
+ isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
+ return (result);
+}
+
+isc_result_t
+dns_fwdtable_find(dns_fwdtable_t *fwdtable, dns_name_t *name,
+ dns_forwarders_t **forwardersp)
+{
+ return (dns_fwdtable_find2(fwdtable, name, NULL, forwardersp));
+}
+
+isc_result_t
+dns_fwdtable_find2(dns_fwdtable_t *fwdtable, dns_name_t *name,
+ dns_name_t *foundname, dns_forwarders_t **forwardersp)
+{
+ isc_result_t result;
+
+ REQUIRE(VALID_FWDTABLE(fwdtable));
+
+ RWLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
+
+ result = dns_rbt_findname(fwdtable->table, name, 0, foundname,
+ (void **)forwardersp);
+ if (result == DNS_R_PARTIALMATCH)
+ result = ISC_R_SUCCESS;
+
+ RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
+
+ return (result);
+}
+
+void
+dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep) {
+ dns_fwdtable_t *fwdtable;
+ isc_mem_t *mctx;
+
+ REQUIRE(fwdtablep != NULL && VALID_FWDTABLE(*fwdtablep));
+
+ fwdtable = *fwdtablep;
+
+ dns_rbt_destroy(&fwdtable->table);
+ isc_rwlock_destroy(&fwdtable->rwlock);
+ fwdtable->magic = 0;
+ mctx = fwdtable->mctx;
+ isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t));
+ isc_mem_detach(&mctx);
+
+ *fwdtablep = NULL;
+}
+
+/***
+ *** Private
+ ***/
+
+static void
+auto_detach(void *data, void *arg) {
+ dns_forwarders_t *forwarders = data;
+ dns_fwdtable_t *fwdtable = arg;
+ isc_sockaddr_t *sa;
+
+ UNUSED(arg);
+
+ while (!ISC_LIST_EMPTY(forwarders->addrs)) {
+ sa = ISC_LIST_HEAD(forwarders->addrs);
+ ISC_LIST_UNLINK(forwarders->addrs, sa, link);
+ isc_mem_put(fwdtable->mctx, sa, sizeof(isc_sockaddr_t));
+ }
+ isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
+}
diff --git a/lib/dns/gen-unix.h b/lib/dns/gen-unix.h
new file mode 100644
index 0000000..fc2dbf2
--- /dev/null
+++ b/lib/dns/gen-unix.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2004, 2005 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: gen-unix.h,v 1.14.18.3 2005/06/08 02:07:54 marka Exp $ */
+
+/*! \file
+ * \brief
+ * This file is responsible for defining two operations that are not
+ * directly portable between Unix-like systems and Windows NT, option
+ * parsing and directory scanning. It is here because it was decided
+ * that the "gen" build utility was not to depend on libisc.a, so
+ * the functions delcared in isc/commandline.h and isc/dir.h could not
+ * be used.
+ *
+ * The commandline stuff is really just a wrapper around getopt().
+ * The dir stuff was shrunk to fit the needs of gen.c.
+ */
+
+#ifndef DNS_GEN_UNIX_H
+#define DNS_GEN_UNIX_H 1
+
+#include <sys/types.h> /* Required on some systems for dirent.h. */
+
+#include <dirent.h>
+#include <unistd.h> /* XXXDCL Required for ?. */
+
+#include <isc/boolean.h>
+#include <isc/lang.h>
+
+#ifdef NEED_OPTARG
+extern char *optarg;
+#endif
+
+#define isc_commandline_parse getopt
+#define isc_commandline_argument optarg
+
+typedef struct {
+ DIR *handle;
+ char *filename;
+} isc_dir_t;
+
+ISC_LANG_BEGINDECLS
+
+static isc_boolean_t
+start_directory(const char *path, isc_dir_t *dir) {
+ dir->handle = opendir(path);
+
+ if (dir->handle != NULL)
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+
+}
+
+static isc_boolean_t
+next_file(isc_dir_t *dir) {
+ struct dirent *dirent;
+
+ dir->filename = NULL;
+
+ if (dir->handle != NULL) {
+ dirent = readdir(dir->handle);
+ if (dirent != NULL)
+ dir->filename = dirent->d_name;
+ }
+
+ if (dir->filename != NULL)
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+}
+
+static void
+end_directory(isc_dir_t *dir) {
+ if (dir->handle != NULL)
+ (void)closedir(dir->handle);
+
+ dir->handle = NULL;
+}
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_GEN_UNIX_H */
diff --git a/lib/dns/gen.c b/lib/dns/gen.c
new file mode 100644
index 0000000..1e6212a
--- /dev/null
+++ b/lib/dns/gen.c
@@ -0,0 +1,884 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: gen.c,v 1.73.18.6 2006/10/02 06:36:43 marka Exp $ */
+
+/*! \file */
+
+#ifdef WIN32
+/*
+ * Silence compiler warnings about using strcpy and friends.
+ */
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef WIN32
+#include "gen-win32.h"
+#else
+#include "gen-unix.h"
+#endif
+
+#define FROMTEXTARGS "rdclass, type, lexer, origin, options, target, callbacks"
+#define FROMTEXTCLASS "rdclass"
+#define FROMTEXTTYPE "type"
+#define FROMTEXTDEF "result = DNS_R_UNKNOWN"
+
+#define TOTEXTARGS "rdata, tctx, target"
+#define TOTEXTCLASS "rdata->rdclass"
+#define TOTEXTTYPE "rdata->type"
+#define TOTEXTDEF "use_default = ISC_TRUE"
+
+#define FROMWIREARGS "rdclass, type, source, dctx, options, target"
+#define FROMWIRECLASS "rdclass"
+#define FROMWIRETYPE "type"
+#define FROMWIREDEF "use_default = ISC_TRUE"
+
+#define TOWIREARGS "rdata, cctx, target"
+#define TOWIRECLASS "rdata->rdclass"
+#define TOWIRETYPE "rdata->type"
+#define TOWIREDEF "use_default = ISC_TRUE"
+
+#define FROMSTRUCTARGS "rdclass, type, source, target"
+#define FROMSTRUCTCLASS "rdclass"
+#define FROMSTRUCTTYPE "type"
+#define FROMSTRUCTDEF "use_default = ISC_TRUE"
+
+#define TOSTRUCTARGS "rdata, target, mctx"
+#define TOSTRUCTCLASS "rdata->rdclass"
+#define TOSTRUCTTYPE "rdata->type"
+#define TOSTRUCTDEF "use_default = ISC_TRUE"
+
+#define FREESTRUCTARGS "source"
+#define FREESTRUCTCLASS "common->rdclass"
+#define FREESTRUCTTYPE "common->rdtype"
+#define FREESTRUCTDEF NULL
+
+#define COMPAREARGS "rdata1, rdata2"
+#define COMPARECLASS "rdata1->rdclass"
+#define COMPARETYPE "rdata1->type"
+#define COMPAREDEF "use_default = ISC_TRUE"
+
+#define ADDITIONALDATAARGS "rdata, add, arg"
+#define ADDITIONALDATACLASS "rdata->rdclass"
+#define ADDITIONALDATATYPE "rdata->type"
+#define ADDITIONALDATADEF "use_default = ISC_TRUE"
+
+#define DIGESTARGS "rdata, digest, arg"
+#define DIGESTCLASS "rdata->rdclass"
+#define DIGESTTYPE "rdata->type"
+#define DIGESTDEF "use_default = ISC_TRUE"
+
+#define CHECKOWNERARGS "name, rdclass, type, wildcard"
+#define CHECKOWNERCLASS "rdclass"
+#define CHECKOWNERTYPE "type"
+#define CHECKOWNERDEF "result = ISC_TRUE"
+
+#define CHECKNAMESARGS "rdata, owner, bad"
+#define CHECKNAMESCLASS "rdata->rdclass"
+#define CHECKNAMESTYPE "rdata->type"
+#define CHECKNAMESDEF "result = ISC_TRUE"
+
+const char copyright[] =
+"/*\n"
+" * Copyright (C) 2004%s Internet Systems Consortium, Inc. (\"ISC\")\n"
+" * Copyright (C) 1998-2003 Internet Software Consortium.\n"
+" *\n"
+" * Permission to use, copy, modify, and distribute this software for any\n"
+" * purpose with or without fee is hereby granted, provided that the above\n"
+" * copyright notice and this permission notice appear in all copies.\n"
+" *\n"
+" * THE SOFTWARE IS PROVIDED \"AS IS\" AND ISC DISCLAIMS ALL WARRANTIES WITH\n"
+" * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n"
+" * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,\n"
+" * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n"
+" * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE\n"
+" * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n"
+" * PERFORMANCE OF THIS SOFTWARE.\n"
+" */\n"
+"\n"
+"/***************\n"
+" ***************\n"
+" *************** THIS FILE IS AUTOMATICALLY GENERATED BY gen.c.\n"
+" *************** DO NOT EDIT!\n"
+" ***************\n"
+" ***************/\n"
+"\n"
+"/*! \\file */\n"
+"\n";
+
+#define TYPENAMES 256
+
+struct cc {
+ struct cc *next;
+ int rdclass;
+ char classname[11];
+} *classes;
+
+struct tt {
+ struct tt *next;
+ int rdclass;
+ int type;
+ char classname[11];
+ char typename[11];
+ char dirname[256]; /* XXX Should be max path length */
+} *types;
+
+struct ttnam {
+ char typename[11];
+ char macroname[11];
+ char attr[256];
+ unsigned int sorted;
+ int type;
+} typenames[TYPENAMES];
+
+int maxtype = -1;
+
+char *
+upper(char *);
+char *
+funname(const char *, char *);
+void
+doswitch(const char *, const char *, const char *, const char *,
+ const char *, const char *);
+void
+dodecl(char *, char *, char *);
+void
+add(int, const char *, int, const char *, const char *);
+void
+sd(int, const char *, const char *, char);
+void
+insert_into_typenames(int, const char *, const char *);
+
+/*%
+ * If you use more than 10 of these in, say, a printf(), you'll have problems.
+ */
+char *
+upper(char *s) {
+ static int buf_to_use = 0;
+ static char buf[10][256];
+ char *b;
+ int c;
+
+ buf_to_use++;
+ if (buf_to_use > 9)
+ buf_to_use = 0;
+
+ b = buf[buf_to_use];
+ memset(b, 0, 256);
+
+ while ((c = (*s++) & 0xff))
+ *b++ = islower(c) ? toupper(c) : c;
+ *b = '\0';
+ return (buf[buf_to_use]);
+}
+
+char *
+funname(const char *s, char *buf) {
+ char *b = buf;
+ char c;
+
+ while ((c = *s++)) {
+ *b++ = (c == '-') ? '_' : c;
+ }
+ *b = '\0';
+ return (buf);
+}
+
+void
+doswitch(const char *name, const char *function, const char *args,
+ const char *tsw, const char *csw, const char *res)
+{
+ struct tt *tt;
+ int first = 1;
+ int lasttype = 0;
+ int subswitch = 0;
+ char buf1[11], buf2[11];
+ const char *result = " result =";
+
+ if (res == NULL)
+ result = "";
+
+ for (tt = types; tt != NULL; tt = tt->next) {
+ if (first) {
+ fprintf(stdout, "\n#define %s \\\n", name);
+ fprintf(stdout, "\tswitch (%s) { \\\n" /*}*/, tsw);
+ first = 0;
+ }
+ if (tt->type != lasttype && subswitch) {
+ if (res == NULL)
+ fprintf(stdout, "\t\tdefault: break; \\\n");
+ else
+ fprintf(stdout,
+ "\t\tdefault: %s; break; \\\n", res);
+ fputs(/*{*/ "\t\t} \\\n", stdout);
+ fputs("\t\tbreak; \\\n", stdout);
+ subswitch = 0;
+ }
+ if (tt->rdclass && tt->type != lasttype) {
+ fprintf(stdout, "\tcase %d: switch (%s) { \\\n" /*}*/,
+ tt->type, csw);
+ subswitch = 1;
+ }
+ if (tt->rdclass == 0)
+ fprintf(stdout,
+ "\tcase %d:%s %s_%s(%s); break;",
+ tt->type, result, function,
+ funname(tt->typename, buf1), args);
+ else
+ fprintf(stdout,
+ "\t\tcase %d:%s %s_%s_%s(%s); break;",
+ tt->rdclass, result, function,
+ funname(tt->classname, buf1),
+ funname(tt->typename, buf2), args);
+ fputs(" \\\n", stdout);
+ lasttype = tt->type;
+ }
+ if (subswitch) {
+ if (res == NULL)
+ fprintf(stdout, "\t\tdefault: break; \\\n");
+ else
+ fprintf(stdout, "\t\tdefault: %s; break; \\\n", res);
+ fputs(/*{*/ "\t\t} \\\n", stdout);
+ fputs("\t\tbreak; \\\n", stdout);
+ }
+ if (first) {
+ if (res == NULL)
+ fprintf(stdout, "\n#define %s\n", name);
+ else
+ fprintf(stdout, "\n#define %s %s;\n", name, res);
+ } else {
+ if (res == NULL)
+ fprintf(stdout, "\tdefault: break; \\\n");
+ else
+ fprintf(stdout, "\tdefault: %s; break; \\\n", res);
+ fputs(/*{*/ "\t}\n", stdout);
+ }
+}
+
+void
+dodecl(char *type, char *function, char *args) {
+ struct tt *tt;
+ char buf1[11], buf2[11];
+
+ fputs("\n", stdout);
+ for (tt = types; tt; tt = tt->next)
+ if (tt->rdclass)
+ fprintf(stdout,
+ "static inline %s %s_%s_%s(%s);\n",
+ type, function,
+ funname(tt->classname, buf1),
+ funname(tt->typename, buf2), args);
+ else
+ fprintf(stdout,
+ "static inline %s %s_%s(%s);\n",
+ type, function,
+ funname(tt->typename, buf1), args);
+}
+
+static struct ttnam *
+find_typename(int type) {
+ int i;
+
+ for (i = 0; i < TYPENAMES; i++) {
+ if (typenames[i].typename[0] != 0 &&
+ typenames[i].type == type)
+ return (&typenames[i]);
+ }
+ return (NULL);
+}
+
+void
+insert_into_typenames(int type, const char *typename, const char *attr) {
+ struct ttnam *ttn = NULL;
+ int c, i;
+ char tmp[256];
+
+ for (i = 0; i < TYPENAMES; i++) {
+ if (typenames[i].typename[0] != 0 &&
+ typenames[i].type == type &&
+ strcmp(typename, typenames[i].typename) != 0) {
+ fprintf(stderr,
+ "Error: type %d has two names: %s, %s\n",
+ type, typenames[i].typename, typename);
+ exit(1);
+ }
+ if (typenames[i].typename[0] == 0 && ttn == NULL)
+ ttn = &typenames[i];
+ }
+ if (ttn == NULL) {
+ fprintf(stderr, "Error: typenames array too small\n");
+ exit(1);
+ }
+
+ if (strlen(typename) > sizeof(ttn->typename) - 1) {
+ fprintf(stderr, "Error: type name %s is too long\n",
+ typename);
+ exit(1);
+ }
+ strcpy(ttn->typename, typename);
+ ttn->type = type;
+
+ strcpy(ttn->macroname, ttn->typename);
+ c = strlen(ttn->macroname);
+ while (c > 0) {
+ if (ttn->macroname[c - 1] == '-')
+ ttn->macroname[c - 1] = '_';
+ c--;
+ }
+
+ if (attr == NULL) {
+ sprintf(tmp, "RRTYPE_%s_ATTRIBUTES", upper(ttn->macroname));
+ attr = tmp;
+ }
+
+ if (ttn->attr[0] != 0 && strcmp(attr, ttn->attr) != 0) {
+ fprintf(stderr, "Error: type %d has different attributes: "
+ "%s, %s\n", type, ttn->attr, attr);
+ exit(1);
+ }
+
+ if (strlen(attr) > sizeof(ttn->attr) - 1) {
+ fprintf(stderr, "Error: attr (%s) [name %s] is too long\n",
+ attr, typename);
+ exit(1);
+ }
+ strcpy(ttn->attr, attr);
+ ttn->sorted = 0;
+ if (maxtype < type)
+ maxtype = type;
+}
+
+void
+add(int rdclass, const char *classname, int type, const char *typename,
+ const char *dirname)
+{
+ struct tt *newtt = (struct tt *)malloc(sizeof(*newtt));
+ struct tt *tt, *oldtt;
+ struct cc *newcc;
+ struct cc *cc, *oldcc;
+
+ insert_into_typenames(type, typename, NULL);
+
+ if (newtt == NULL) {
+ fprintf(stderr, "malloc() failed\n");
+ exit(1);
+ }
+
+ newtt->next = NULL;
+ newtt->rdclass = rdclass;
+ newtt->type = type;
+ strcpy(newtt->classname, classname);
+ strcpy(newtt->typename, typename);
+ strcpy(newtt->dirname, dirname);
+
+ tt = types;
+ oldtt = NULL;
+
+ while ((tt != NULL) && (tt->type < type)) {
+ oldtt = tt;
+ tt = tt->next;
+ }
+
+ while ((tt != NULL) && (tt->type == type) && (tt->rdclass < rdclass)) {
+ if (strcmp(tt->typename, typename) != 0)
+ exit(1);
+ oldtt = tt;
+ tt = tt->next;
+ }
+
+ if ((tt != NULL) && (tt->type == type) && (tt->rdclass == rdclass))
+ exit(1);
+
+ newtt->next = tt;
+ if (oldtt != NULL)
+ oldtt->next = newtt;
+ else
+ types = newtt;
+
+ /*
+ * Do a class switch for this type.
+ */
+ if (rdclass == 0)
+ return;
+
+ newcc = (struct cc *)malloc(sizeof(*newcc));
+ newcc->rdclass = rdclass;
+ strcpy(newcc->classname, classname);
+ cc = classes;
+ oldcc = NULL;
+
+ while ((cc != NULL) && (cc->rdclass < rdclass)) {
+ oldcc = cc;
+ cc = cc->next;
+ }
+
+ if ((cc != NULL) && cc->rdclass == rdclass) {
+ free((char *)newcc);
+ return;
+ }
+
+ newcc->next = cc;
+ if (oldcc != NULL)
+ oldcc->next = newcc;
+ else
+ classes = newcc;
+}
+
+void
+sd(int rdclass, const char *classname, const char *dirname, char filetype) {
+ char buf[sizeof("0123456789_65535.h")];
+ char fmt[sizeof("%10[-0-9a-z]_%d.h")];
+ int type;
+ char typename[11];
+ isc_dir_t dir;
+
+ if (!start_directory(dirname, &dir))
+ return;
+
+ sprintf(fmt,"%s%c", "%10[-0-9a-z]_%d.", filetype);
+ while (next_file(&dir)) {
+ if (sscanf(dir.filename, fmt, typename, &type) != 2)
+ continue;
+ if ((type > 65535) || (type < 0))
+ continue;
+
+ sprintf(buf, "%s_%d.%c", typename, type, filetype);
+ if (strcmp(buf, dir.filename) != 0)
+ continue;
+ add(rdclass, classname, type, typename, dirname);
+ }
+
+ end_directory(&dir);
+}
+
+static unsigned int
+HASH(char *string) {
+ unsigned int n;
+ unsigned char a, b;
+
+ n = strlen(string);
+ if (n == 0) {
+ fprintf(stderr, "n == 0?\n");
+ exit(1);
+ }
+ a = tolower((unsigned char)string[0]);
+ b = tolower((unsigned char)string[n - 1]);
+
+ return ((a + n) * b) % 256;
+}
+
+int
+main(int argc, char **argv) {
+ char buf[256]; /* XXX Should be max path length */
+ char srcdir[256]; /* XXX Should be max path length */
+ int rdclass;
+ char classname[11];
+ struct tt *tt;
+ struct cc *cc;
+ struct ttnam *ttn, *ttn2;
+ unsigned int hash;
+ struct tm *tm;
+ time_t now;
+ char year[11];
+ int lasttype;
+ int code = 1;
+ int class_enum = 0;
+ int type_enum = 0;
+ int structs = 0;
+ int depend = 0;
+ int c, i, j;
+ char buf1[11];
+ char filetype = 'c';
+ FILE *fd;
+ char *prefix = NULL;
+ char *suffix = NULL;
+ char *file = NULL;
+ isc_dir_t dir;
+
+ for (i = 0; i < TYPENAMES; i++)
+ memset(&typenames[i], 0, sizeof(typenames[i]));
+
+ strcpy(srcdir, "");
+ while ((c = isc_commandline_parse(argc, argv, "cdits:F:P:S:")) != -1)
+ switch (c) {
+ case 'c':
+ code = 0;
+ depend = 0;
+ type_enum = 0;
+ class_enum = 1;
+ filetype = 'c';
+ structs = 0;
+ break;
+ case 'd':
+ code = 0;
+ depend = 1;
+ class_enum = 0;
+ type_enum = 0;
+ structs = 0;
+ filetype = 'h';
+ break;
+ case 't':
+ code = 0;
+ depend = 0;
+ class_enum = 0;
+ type_enum = 1;
+ filetype = 'c';
+ structs = 0;
+ break;
+ case 'i':
+ code = 0;
+ depend = 0;
+ class_enum = 0;
+ type_enum = 0;
+ structs = 1;
+ filetype = 'h';
+ break;
+ case 's':
+ sprintf(srcdir, "%s/", isc_commandline_argument);
+ break;
+ case 'F':
+ file = isc_commandline_argument;
+ break;
+ case 'P':
+ prefix = isc_commandline_argument;
+ break;
+ case 'S':
+ suffix = isc_commandline_argument;
+ break;
+ case '?':
+ exit(1);
+ }
+
+ sprintf(buf, "%srdata", srcdir);
+
+ if (!start_directory(buf, &dir))
+ exit(1);
+
+ while (next_file(&dir)) {
+ if (sscanf(dir.filename, "%10[0-9a-z]_%d",
+ classname, &rdclass) != 2)
+ continue;
+ if ((rdclass > 65535) || (rdclass < 0))
+ continue;
+
+ sprintf(buf, "%srdata/%s_%d", srcdir, classname, rdclass);
+ if (strcmp(buf + 6 + strlen(srcdir), dir.filename) != 0)
+ continue;
+ sd(rdclass, classname, buf, filetype);
+ }
+ end_directory(&dir);
+ sprintf(buf, "%srdata/generic", srcdir);
+ sd(0, "", buf, filetype);
+
+ if (time(&now) != -1) {
+ if ((tm = localtime(&now)) != NULL && tm->tm_year > 104)
+ sprintf(year, "-%d", tm->tm_year + 1900);
+ else
+ year[0] = 0;
+ } else
+ year[0] = 0;
+
+ if (!depend) fprintf(stdout, copyright, year);
+
+ if (code) {
+ fputs("#ifndef DNS_CODE_H\n", stdout);
+ fputs("#define DNS_CODE_H 1\n\n", stdout);
+
+ fputs("#include <isc/boolean.h>\n", stdout);
+ fputs("#include <isc/result.h>\n\n", stdout);
+ fputs("#include <dns/name.h>\n\n", stdout);
+
+ for (tt = types; tt != NULL; tt = tt->next)
+ fprintf(stdout, "#include \"%s/%s_%d.c\"\n",
+ tt->dirname, tt->typename, tt->type);
+
+ fputs("\n\n", stdout);
+
+ doswitch("FROMTEXTSWITCH", "fromtext", FROMTEXTARGS,
+ FROMTEXTTYPE, FROMTEXTCLASS, FROMTEXTDEF);
+ doswitch("TOTEXTSWITCH", "totext", TOTEXTARGS,
+ TOTEXTTYPE, TOTEXTCLASS, TOTEXTDEF);
+ doswitch("FROMWIRESWITCH", "fromwire", FROMWIREARGS,
+ FROMWIRETYPE, FROMWIRECLASS, FROMWIREDEF);
+ doswitch("TOWIRESWITCH", "towire", TOWIREARGS,
+ TOWIRETYPE, TOWIRECLASS, TOWIREDEF);
+ doswitch("COMPARESWITCH", "compare", COMPAREARGS,
+ COMPARETYPE, COMPARECLASS, COMPAREDEF);
+ doswitch("FROMSTRUCTSWITCH", "fromstruct", FROMSTRUCTARGS,
+ FROMSTRUCTTYPE, FROMSTRUCTCLASS, FROMSTRUCTDEF);
+ doswitch("TOSTRUCTSWITCH", "tostruct", TOSTRUCTARGS,
+ TOSTRUCTTYPE, TOSTRUCTCLASS, TOSTRUCTDEF);
+ doswitch("FREESTRUCTSWITCH", "freestruct", FREESTRUCTARGS,
+ FREESTRUCTTYPE, FREESTRUCTCLASS, FREESTRUCTDEF);
+ doswitch("ADDITIONALDATASWITCH", "additionaldata",
+ ADDITIONALDATAARGS, ADDITIONALDATATYPE,
+ ADDITIONALDATACLASS, ADDITIONALDATADEF);
+ doswitch("DIGESTSWITCH", "digest",
+ DIGESTARGS, DIGESTTYPE,
+ DIGESTCLASS, DIGESTDEF);
+ doswitch("CHECKOWNERSWITCH", "checkowner",
+ CHECKOWNERARGS, CHECKOWNERTYPE,
+ CHECKOWNERCLASS, CHECKOWNERDEF);
+ doswitch("CHECKNAMESSWITCH", "checknames",
+ CHECKNAMESARGS, CHECKNAMESTYPE,
+ CHECKNAMESCLASS, CHECKNAMESDEF);
+
+ /*
+ * From here down, we are processing the rdata names and
+ * attributes.
+ */
+
+#define PRINT_COMMA(x) (x == maxtype ? "" : ",")
+
+#define METANOTQUESTION "DNS_RDATATYPEATTR_META | " \
+ "DNS_RDATATYPEATTR_NOTQUESTION"
+#define METAQUESTIONONLY "DNS_RDATATYPEATTR_META | " \
+ "DNS_RDATATYPEATTR_QUESTIONONLY"
+#define RESERVED "DNS_RDATATYPEATTR_RESERVED"
+
+ /*
+ * Add in reserved/special types. This will let us
+ * sort them without special cases.
+ */
+ insert_into_typenames(0, "reserved0", RESERVED);
+ insert_into_typenames(31, "eid", RESERVED);
+ insert_into_typenames(32, "nimloc", RESERVED);
+ insert_into_typenames(34, "atma", RESERVED);
+ insert_into_typenames(100, "uinfo", RESERVED);
+ insert_into_typenames(101, "uid", RESERVED);
+ insert_into_typenames(102, "gid", RESERVED);
+ insert_into_typenames(251, "ixfr", METAQUESTIONONLY);
+ insert_into_typenames(252, "axfr", METAQUESTIONONLY);
+ insert_into_typenames(253, "mailb", METAQUESTIONONLY);
+ insert_into_typenames(254, "maila", METAQUESTIONONLY);
+ insert_into_typenames(255, "any", METAQUESTIONONLY);
+
+ /*
+ * Spit out a quick and dirty hash function. Here,
+ * we walk through the list of type names, and calculate
+ * a hash. This isn't perfect, but it will generate "pretty
+ * good" estimates. Lowercase the characters before
+ * computing in all cases.
+ *
+ * Here, walk the list from top to bottom, calculating
+ * the hash (mod 256) for each name.
+ */
+ fprintf(stdout, "#define RDATATYPE_COMPARE(_s, _d, _tn, _n, _tp) \\\n");
+ fprintf(stdout, "\tdo { \\\n");
+ fprintf(stdout, "\t\tif (sizeof(_s) - 1 == _n && \\\n"
+ "\t\t strncasecmp(_s,(_tn),"
+ "(sizeof(_s) - 1)) == 0) { \\\n");
+ fprintf(stdout, "\t\t\tif ((dns_rdatatype_attributes(_d) & "
+ "DNS_RDATATYPEATTR_RESERVED) != 0) \\\n");
+ fprintf(stdout, "\t\t\t\treturn (ISC_R_NOTIMPLEMENTED); \\\n");
+ fprintf(stdout, "\t\t\t*(_tp) = _d; \\\n");
+ fprintf(stdout, "\t\t\treturn (ISC_R_SUCCESS); \\\n");
+ fprintf(stdout, "\t\t} \\\n");
+ fprintf(stdout, "\t} while (0)\n\n");
+
+ fprintf(stdout, "#define RDATATYPE_FROMTEXT_SW(_hash,"
+ "_typename,_length,_typep) \\\n");
+ fprintf(stdout, "\tswitch (_hash) { \\\n");
+ for (i = 0; i <= maxtype; i++) {
+ ttn = find_typename(i);
+ if (ttn == NULL)
+ continue;
+
+ /*
+ * Skip entries we already processed.
+ */
+ if (ttn->sorted != 0)
+ continue;
+
+ hash = HASH(ttn->typename);
+ fprintf(stdout, "\t\tcase %u: \\\n", hash);
+
+ /*
+ * Find all other entries that happen to match
+ * this hash.
+ */
+ for (j = 0; j <= maxtype; j++) {
+ ttn2 = find_typename(j);
+ if (ttn2 == NULL)
+ continue;
+ if (hash == HASH(ttn2->typename)) {
+ fprintf(stdout, "\t\t\tRDATATYPE_COMPARE"
+ "(\"%s\", %u, "
+ "_typename, _length, _typep); \\\n",
+ ttn2->typename, ttn2->type);
+ ttn2->sorted = 1;
+ }
+ }
+ fprintf(stdout, "\t\t\tbreak; \\\n");
+ }
+ fprintf(stdout, "\t}\n");
+
+ fprintf(stdout, "#define RDATATYPE_ATTRIBUTE_SW \\\n");
+ fprintf(stdout, "\tswitch (type) { \\\n");
+ for (i = 0; i <= maxtype; i++) {
+ ttn = find_typename(i);
+ if (ttn == NULL)
+ continue;
+ fprintf(stdout, "\tcase %u: return (%s); \\\n",
+ i, upper(ttn->attr));
+ }
+ fprintf(stdout, "\t}\n");
+
+ fprintf(stdout, "#define RDATATYPE_TOTEXT_SW \\\n");
+ fprintf(stdout, "\tswitch (type) { \\\n");
+ for (i = 0; i <= maxtype; i++) {
+ ttn = find_typename(i);
+ if (ttn == NULL)
+ continue;
+ fprintf(stdout, "\tcase %u: return "
+ "(str_totext(\"%s\", target)); \\\n",
+ i, upper(ttn->typename));
+ }
+ fprintf(stdout, "\t}\n");
+
+ fputs("#endif /* DNS_CODE_H */\n", stdout);
+ } else if (type_enum) {
+ char *s;
+
+ fprintf(stdout, "#ifndef DNS_ENUMTYPE_H\n");
+ fprintf(stdout, "#define DNS_ENUMTYPE_H 1\n\n");
+
+ fprintf(stdout, "enum {\n");
+ fprintf(stdout, "\tdns_rdatatype_none = 0,\n");
+
+ lasttype = 0;
+ for (tt = types; tt != NULL; tt = tt->next)
+ if (tt->type != lasttype)
+ fprintf(stdout,
+ "\tdns_rdatatype_%s = %d,\n",
+ funname(tt->typename, buf1),
+ lasttype = tt->type);
+
+ fprintf(stdout, "\tdns_rdatatype_ixfr = 251,\n");
+ fprintf(stdout, "\tdns_rdatatype_axfr = 252,\n");
+ fprintf(stdout, "\tdns_rdatatype_mailb = 253,\n");
+ fprintf(stdout, "\tdns_rdatatype_maila = 254,\n");
+ fprintf(stdout, "\tdns_rdatatype_any = 255\n");
+
+ fprintf(stdout, "};\n\n");
+
+ fprintf(stdout, "#define dns_rdatatype_none\t"
+ "((dns_rdatatype_t)dns_rdatatype_none)\n");
+
+ for (tt = types; tt != NULL; tt = tt->next)
+ if (tt->type != lasttype) {
+ s = funname(tt->typename, buf1);
+ fprintf(stdout,
+ "#define dns_rdatatype_%s\t%s"
+ "((dns_rdatatype_t)dns_rdatatype_%s)"
+ "\n",
+ s, strlen(s) < 2U ? "\t" : "", s);
+ lasttype = tt->type;
+ }
+
+ fprintf(stdout, "#define dns_rdatatype_ixfr\t"
+ "((dns_rdatatype_t)dns_rdatatype_ixfr)\n");
+ fprintf(stdout, "#define dns_rdatatype_axfr\t"
+ "((dns_rdatatype_t)dns_rdatatype_axfr)\n");
+ fprintf(stdout, "#define dns_rdatatype_mailb\t"
+ "((dns_rdatatype_t)dns_rdatatype_mailb)\n");
+ fprintf(stdout, "#define dns_rdatatype_maila\t"
+ "((dns_rdatatype_t)dns_rdatatype_maila)\n");
+ fprintf(stdout, "#define dns_rdatatype_any\t"
+ "((dns_rdatatype_t)dns_rdatatype_any)\n");
+
+ fprintf(stdout, "\n#endif /* DNS_ENUMTYPE_H */\n");
+
+ } else if (class_enum) {
+ char *s;
+ int classnum;
+
+ fprintf(stdout, "#ifndef DNS_ENUMCLASS_H\n");
+ fprintf(stdout, "#define DNS_ENUMCLASS_H 1\n\n");
+
+ fprintf(stdout, "enum {\n");
+
+ fprintf(stdout, "\tdns_rdataclass_reserved0 = 0,\n");
+ fprintf(stdout, "#define dns_rdataclass_reserved0 \\\n\t\t\t\t"
+ "((dns_rdataclass_t)dns_rdataclass_reserved0)\n");
+
+#define PRINTCLASS(name, num) \
+ do { \
+ s = funname(name, buf1); \
+ classnum = num; \
+ fprintf(stdout, "\tdns_rdataclass_%s = %d%s\n", s, classnum, \
+ classnum != 255 ? "," : ""); \
+ fprintf(stdout, "#define dns_rdataclass_%s\t" \
+ "((dns_rdataclass_t)dns_rdataclass_%s)\n", s, s); \
+ } while (0)
+
+ for (cc = classes; cc != NULL; cc = cc->next) {
+ if (cc->rdclass == 3)
+ PRINTCLASS("chaos", 3);
+ else if (cc->rdclass == 255)
+ PRINTCLASS("none", 254);
+ PRINTCLASS(cc->classname, cc->rdclass);
+ }
+
+#undef PRINTCLASS
+
+ fprintf(stdout, "};\n\n");
+ fprintf(stdout, "#endif /* DNS_ENUMCLASS_H */\n");
+ } else if (structs) {
+ if (prefix != NULL) {
+ if ((fd = fopen(prefix,"r")) != NULL) {
+ while (fgets(buf, sizeof(buf), fd) != NULL)
+ fputs(buf, stdout);
+ fclose(fd);
+ }
+ }
+ for (tt = types; tt != NULL; tt = tt->next) {
+ sprintf(buf, "%s/%s_%d.h",
+ tt->dirname, tt->typename, tt->type);
+ if ((fd = fopen(buf,"r")) != NULL) {
+ while (fgets(buf, sizeof(buf), fd) != NULL)
+ fputs(buf, stdout);
+ fclose(fd);
+ }
+ }
+ if (suffix != NULL) {
+ if ((fd = fopen(suffix,"r")) != NULL) {
+ while (fgets(buf, sizeof(buf), fd) != NULL)
+ fputs(buf, stdout);
+ fclose(fd);
+ }
+ }
+ } else if (depend) {
+ for (tt = types; tt != NULL; tt = tt->next)
+ fprintf(stdout, "%s:\t%s/%s_%d.h\n", file,
+ tt->dirname, tt->typename, tt->type);
+ }
+
+ if (ferror(stdout) != 0)
+ exit(1);
+
+ return (0);
+}
diff --git a/lib/dns/gssapi_link.c b/lib/dns/gssapi_link.c
new file mode 100644
index 0000000..a6a367a
--- /dev/null
+++ b/lib/dns/gssapi_link.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2004, 2005 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: gssapi_link.c,v 1.1.6.3 2005/04/29 00:15:53 marka Exp $
+ */
+
+#ifdef GSSAPI
+
+#include <config.h>
+
+#include <isc/buffer.h>
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dst/result.h>
+
+#include "dst_internal.h"
+#include "dst_parse.h"
+
+#include <gssapi/gssapi.h>
+
+#define INITIAL_BUFFER_SIZE 1024
+#define BUFFER_EXTRA 1024
+
+#define REGION_TO_GBUFFER(r, gb) \
+ do { \
+ (gb).length = (r).length; \
+ (gb).value = (r).base; \
+ } while (0)
+
+typedef struct gssapi_ctx {
+ isc_buffer_t *buffer;
+ gss_ctx_id_t *context_id;
+} gssapi_ctx_t;
+
+
+static isc_result_t
+gssapi_createctx(dst_key_t *key, dst_context_t *dctx) {
+ gssapi_ctx_t *ctx;
+ isc_result_t result;
+
+ UNUSED(key);
+
+ ctx = isc_mem_get(dctx->mctx, sizeof(gssapi_ctx_t));
+ if (ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ ctx->buffer = NULL;
+ result = isc_buffer_allocate(dctx->mctx, &ctx->buffer,
+ INITIAL_BUFFER_SIZE);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(dctx->mctx, ctx, sizeof(gssapi_ctx_t));
+ return (result);
+ }
+ ctx->context_id = key->opaque;
+ dctx->opaque = ctx;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+gssapi_destroyctx(dst_context_t *dctx) {
+ gssapi_ctx_t *ctx = dctx->opaque;
+
+ if (ctx != NULL) {
+ if (ctx->buffer != NULL)
+ isc_buffer_free(&ctx->buffer);
+ isc_mem_put(dctx->mctx, ctx, sizeof(gssapi_ctx_t));
+ dctx->opaque = NULL;
+ }
+}
+
+static isc_result_t
+gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ gssapi_ctx_t *ctx = dctx->opaque;
+ isc_buffer_t *newbuffer = NULL;
+ isc_region_t r;
+ unsigned int length;
+ isc_result_t result;
+
+ result = isc_buffer_copyregion(ctx->buffer, data);
+ if (result == ISC_R_SUCCESS)
+ return (ISC_R_SUCCESS);
+
+ length = isc_buffer_length(ctx->buffer) + data->length + BUFFER_EXTRA;
+
+ result = isc_buffer_allocate(dctx->mctx, &newbuffer, length);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ isc_buffer_usedregion(ctx->buffer, &r);
+ (void) isc_buffer_copyregion(newbuffer, &r);
+ (void) isc_buffer_copyregion(newbuffer, data);
+
+ isc_buffer_free(&ctx->buffer);
+ ctx->buffer = newbuffer;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ gssapi_ctx_t *ctx = dctx->opaque;
+ isc_region_t message;
+ gss_buffer_desc gmessage, gsig;
+ OM_uint32 minor, gret;
+
+ isc_buffer_usedregion(ctx->buffer, &message);
+ REGION_TO_GBUFFER(message, gmessage);
+
+ gret = gss_get_mic(&minor, ctx->context_id,
+ GSS_C_QOP_DEFAULT, &gmessage, &gsig);
+ if (gret != 0)
+ return (ISC_R_FAILURE);
+
+ if (gsig.length > isc_buffer_availablelength(sig)) {
+ gss_release_buffer(&minor, &gsig);
+ return (ISC_R_NOSPACE);
+ }
+
+ isc_buffer_putmem(sig, gsig.value, gsig.length);
+
+ gss_release_buffer(&minor, &gsig);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
+ gssapi_ctx_t *ctx = dctx->opaque;
+ isc_region_t message;
+ gss_buffer_desc gmessage, gsig;
+ OM_uint32 minor, gret;
+
+ isc_buffer_usedregion(ctx->buffer, &message);
+ REGION_TO_GBUFFER(message, gmessage);
+
+ REGION_TO_GBUFFER(*sig, gsig);
+
+ gret = gss_verify_mic(&minor, ctx->context_id, &gmessage, &gsig, NULL);
+ if (gret != 0)
+ return (ISC_R_FAILURE);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_boolean_t
+gssapi_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ gss_ctx_id_t gsskey1 = key1->opaque;
+ gss_ctx_id_t gsskey2 = key2->opaque;
+
+ /* No idea */
+ return (ISC_TF(gsskey1 == gsskey2));
+}
+
+static isc_result_t
+gssapi_generate(dst_key_t *key, int unused) {
+ UNUSED(key);
+ UNUSED(unused);
+
+ /* No idea */
+ return (ISC_R_FAILURE);
+}
+
+static isc_boolean_t
+gssapi_isprivate(const dst_key_t *key) {
+ UNUSED(key);
+ return (ISC_TRUE);
+}
+
+static void
+gssapi_destroy(dst_key_t *key) {
+ UNUSED(key);
+ /* No idea */
+}
+
+static dst_func_t gssapi_functions = {
+ gssapi_createctx,
+ gssapi_destroyctx,
+ gssapi_adddata,
+ gssapi_sign,
+ gssapi_verify,
+ NULL, /*%< computesecret */
+ gssapi_compare,
+ NULL, /*%< paramcompare */
+ gssapi_generate,
+ gssapi_isprivate,
+ gssapi_destroy,
+ NULL, /*%< todns */
+ NULL, /*%< fromdns */
+ NULL, /*%< tofile */
+ NULL, /*%< parse */
+ NULL, /*%< cleanup */
+};
+
+isc_result_t
+dst__gssapi_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL)
+ *funcp = &gssapi_functions;
+ return (ISC_R_SUCCESS);
+}
+
+#else
+int gssapi_link_unneeded = 1;
+#endif
+
+/*! \file */
diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c
new file mode 100644
index 0000000..ce5d6fa
--- /dev/null
+++ b/lib/dns/gssapictx.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2004, 2005 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: gssapictx.c,v 1.1.6.3 2005/04/29 00:15:54 marka Exp $ */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/dir.h>
+#include <isc/entropy.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/random.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/result.h>
+#include <dns/types.h>
+#include <dns/keyvalues.h>
+
+#include <dst/gssapi.h>
+#include <dst/result.h>
+
+#include "dst_internal.h"
+
+#ifdef GSSAPI
+
+#include <gssapi/gssapi.h>
+
+#define RETERR(x) do { \
+ result = (x); \
+ if (result != ISC_R_SUCCESS) \
+ goto out; \
+ } while (0)
+
+#define REGION_TO_GBUFFER(r, gb) \
+ do { \
+ (gb).length = (r).length; \
+ (gb).value = (r).base; \
+ } while (0)
+
+#define GBUFFER_TO_REGION(gb, r) \
+ do { \
+ (r).length = (gb).length; \
+ (r).base = (gb).value; \
+ } while (0)
+
+static inline void
+name_to_gbuffer(dns_name_t *name, isc_buffer_t *buffer,
+ gss_buffer_desc *gbuffer)
+{
+ dns_name_t tname, *namep;
+ isc_region_t r;
+ isc_result_t result;
+
+ if (!dns_name_isabsolute(name))
+ namep = name;
+ else {
+ unsigned int labels;
+ dns_name_init(&tname, NULL);
+ labels = dns_name_countlabels(name);
+ dns_name_getlabelsequence(name, 0, labels - 1, &tname);
+ namep = &tname;
+ }
+
+ result = dns_name_totext(namep, ISC_FALSE, buffer);
+ isc_buffer_putuint8(buffer, 0);
+ isc_buffer_usedregion(buffer, &r);
+ REGION_TO_GBUFFER(r, *gbuffer);
+}
+
+isc_result_t
+dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred) {
+ isc_buffer_t namebuf;
+ gss_name_t gname;
+ gss_buffer_desc gnamebuf;
+ unsigned char array[DNS_NAME_MAXTEXT + 1];
+ OM_uint32 gret, minor;
+ gss_OID_set mechs;
+ OM_uint32 lifetime;
+ gss_cred_usage_t usage;
+
+ REQUIRE(cred != NULL && *cred == NULL);
+
+ if (name != NULL) {
+ isc_buffer_init(&namebuf, array, sizeof(array));
+ name_to_gbuffer(name, &namebuf, &gnamebuf);
+ gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID,
+ &gname);
+ if (gret != GSS_S_COMPLETE)
+ return (ISC_R_FAILURE);
+ } else
+ gname = NULL;
+
+ if (initiate)
+ usage = GSS_C_INITIATE;
+ else
+ usage = GSS_C_ACCEPT;
+
+ gret = gss_acquire_cred(&minor, gname, GSS_C_INDEFINITE,
+ GSS_C_NO_OID_SET, usage,
+ cred, &mechs, &lifetime);
+ if (gret != GSS_S_COMPLETE)
+ return (ISC_R_FAILURE);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dst_gssapi_initctx(dns_name_t *name, void *cred,
+ isc_region_t *intoken, isc_buffer_t *outtoken,
+ void **context)
+{
+ isc_region_t r;
+ isc_buffer_t namebuf;
+ gss_buffer_desc gnamebuf, gintoken, *gintokenp, gouttoken;
+ OM_uint32 gret, minor, flags, ret_flags;
+ gss_OID mech_type, ret_mech_type;
+ OM_uint32 lifetime;
+ gss_name_t gname;
+ isc_result_t result;
+ unsigned char array[DNS_NAME_MAXTEXT + 1];
+
+ isc_buffer_init(&namebuf, array, sizeof(array));
+ name_to_gbuffer(name, &namebuf, &gnamebuf);
+ gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname);
+ if (gret != GSS_S_COMPLETE)
+ return (ISC_R_FAILURE);
+
+ if (intoken != NULL) {
+ REGION_TO_GBUFFER(*intoken, gintoken);
+ gintokenp = &gintoken;
+ } else
+ gintokenp = NULL;
+
+ if (*context == NULL)
+ *context = GSS_C_NO_CONTEXT;
+ flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG |
+ GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG;
+ mech_type = GSS_C_NO_OID;
+
+ gret = gss_init_sec_context(&minor, cred, context, gname,
+ mech_type, flags, 0,
+ GSS_C_NO_CHANNEL_BINDINGS, gintokenp,
+ &ret_mech_type, &gouttoken, &ret_flags,
+ &lifetime);
+ if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED)
+ return (ISC_R_FAILURE);
+
+ GBUFFER_TO_REGION(gouttoken, r);
+ RETERR(isc_buffer_copyregion(outtoken, &r));
+
+ if (gret == GSS_S_COMPLETE)
+ return (ISC_R_SUCCESS);
+ else
+ return (DNS_R_CONTINUE);
+
+ out:
+ return (result);
+}
+
+isc_result_t
+dst_gssapi_acceptctx(dns_name_t *name, void *cred,
+ isc_region_t *intoken, isc_buffer_t *outtoken,
+ void **context)
+{
+ isc_region_t r;
+ isc_buffer_t namebuf;
+ gss_buffer_desc gnamebuf, gintoken, gouttoken;
+ OM_uint32 gret, minor, flags;
+ gss_OID mech_type;
+ OM_uint32 lifetime;
+ gss_cred_id_t delegated_cred;
+ gss_name_t gname;
+ isc_result_t result;
+ unsigned char array[DNS_NAME_MAXTEXT + 1];
+
+ isc_buffer_init(&namebuf, array, sizeof(array));
+ name_to_gbuffer(name, &namebuf, &gnamebuf);
+ gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname);
+ if (gret != GSS_S_COMPLETE)
+ return (ISC_R_FAILURE);
+
+ REGION_TO_GBUFFER(*intoken, gintoken);
+
+ if (*context == NULL)
+ *context = GSS_C_NO_CONTEXT;
+
+ gret = gss_accept_sec_context(&minor, context, cred, &gintoken,
+ GSS_C_NO_CHANNEL_BINDINGS, gname,
+ &mech_type, &gouttoken, &flags,
+ &lifetime, &delegated_cred);
+ if (gret != GSS_S_COMPLETE)
+ return (ISC_R_FAILURE);
+
+ GBUFFER_TO_REGION(gouttoken, r);
+ RETERR(isc_buffer_copyregion(outtoken, &r));
+
+ return (ISC_R_SUCCESS);
+
+ out:
+ return (result);
+}
+
+#else
+
+isc_result_t
+dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred) {
+ UNUSED(name);
+ UNUSED(initiate);
+ UNUSED(cred);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+isc_result_t
+dst_gssapi_initctx(dns_name_t *name, void *cred,
+ isc_region_t *intoken, isc_buffer_t *outtoken,
+ void **context)
+{
+ UNUSED(name);
+ UNUSED(cred);
+ UNUSED(intoken);
+ UNUSED(outtoken);
+ UNUSED(context);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+isc_result_t
+dst_gssapi_acceptctx(dns_name_t *name, void *cred,
+ isc_region_t *intoken, isc_buffer_t *outtoken,
+ void **context)
+{
+ UNUSED(name);
+ UNUSED(cred);
+ UNUSED(intoken);
+ UNUSED(outtoken);
+ UNUSED(context);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+#endif
+
+/*! \file */
diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c
new file mode 100644
index 0000000..9655c89
--- /dev/null
+++ b/lib/dns/hmac_link.c
@@ -0,0 +1,1668 @@
+/*
+ * Portions Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1999-2002 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.
+ */
+
+/*
+ * Principal Author: Brian Wellington
+ * $Id: hmac_link.c,v 1.1.6.5 2006/01/27 23:57:44 marka Exp $
+ */
+
+#include <config.h>
+
+#include <isc/buffer.h>
+#include <isc/hmacmd5.h>
+#include <isc/hmacsha.h>
+#include <isc/md5.h>
+#include <isc/sha1.h>
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dst/result.h>
+
+#include "dst_internal.h"
+#include "dst_parse.h"
+
+#define HMAC_LEN 64
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5c
+
+static isc_result_t hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data);
+
+typedef struct hmackey {
+ unsigned char key[HMAC_LEN];
+} HMAC_Key;
+
+static isc_result_t
+getkeybits(dst_key_t *key, struct dst_private_element *element) {
+
+ if (element->length != 2)
+ return (DST_R_INVALIDPRIVATEKEY);
+
+ key->key_bits = (element->data[0] << 8) + element->data[1];
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacmd5_createctx(dst_key_t *key, dst_context_t *dctx) {
+ isc_hmacmd5_t *hmacmd5ctx;
+ HMAC_Key *hkey = key->opaque;
+
+ hmacmd5ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacmd5_t));
+ if (hmacmd5ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_hmacmd5_init(hmacmd5ctx, hkey->key, HMAC_LEN);
+ dctx->opaque = hmacmd5ctx;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+hmacmd5_destroyctx(dst_context_t *dctx) {
+ isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
+
+ if (hmacmd5ctx != NULL) {
+ isc_hmacmd5_invalidate(hmacmd5ctx);
+ isc_mem_put(dctx->mctx, hmacmd5ctx, sizeof(isc_hmacmd5_t));
+ dctx->opaque = NULL;
+ }
+}
+
+static isc_result_t
+hmacmd5_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
+
+ isc_hmacmd5_update(hmacmd5ctx, data->base, data->length);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacmd5_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
+ unsigned char *digest;
+
+ if (isc_buffer_availablelength(sig) < ISC_MD5_DIGESTLENGTH)
+ return (ISC_R_NOSPACE);
+ digest = isc_buffer_used(sig);
+ isc_hmacmd5_sign(hmacmd5ctx, digest);
+ isc_buffer_add(sig, ISC_MD5_DIGESTLENGTH);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacmd5_verify(dst_context_t *dctx, const isc_region_t *sig) {
+ isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
+
+ if (sig->length > ISC_MD5_DIGESTLENGTH)
+ return (DST_R_VERIFYFAILURE);
+
+ if (isc_hmacmd5_verify2(hmacmd5ctx, sig->base, sig->length))
+ return (ISC_R_SUCCESS);
+ else
+ return (DST_R_VERIFYFAILURE);
+}
+
+static isc_boolean_t
+hmacmd5_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ HMAC_Key *hkey1, *hkey2;
+
+ hkey1 = (HMAC_Key *)key1->opaque;
+ hkey2 = (HMAC_Key *)key2->opaque;
+
+ if (hkey1 == NULL && hkey2 == NULL)
+ return (ISC_TRUE);
+ else if (hkey1 == NULL || hkey2 == NULL)
+ return (ISC_FALSE);
+
+ if (memcmp(hkey1->key, hkey2->key, HMAC_LEN) == 0)
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+hmacmd5_generate(dst_key_t *key, int pseudorandom_ok) {
+ isc_buffer_t b;
+ isc_result_t ret;
+ int bytes;
+ unsigned char data[HMAC_LEN];
+
+ bytes = (key->key_size + 7) / 8;
+ if (bytes > HMAC_LEN) {
+ bytes = HMAC_LEN;
+ key->key_size = HMAC_LEN * 8;
+ }
+
+ memset(data, 0, HMAC_LEN);
+ ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0));
+
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ isc_buffer_init(&b, data, bytes);
+ isc_buffer_add(&b, bytes);
+ ret = hmacmd5_fromdns(key, &b);
+ memset(data, 0, HMAC_LEN);
+
+ return (ret);
+}
+
+static isc_boolean_t
+hmacmd5_isprivate(const dst_key_t *key) {
+ UNUSED(key);
+ return (ISC_TRUE);
+}
+
+static void
+hmacmd5_destroy(dst_key_t *key) {
+ HMAC_Key *hkey = key->opaque;
+ memset(hkey, 0, sizeof(HMAC_Key));
+ isc_mem_put(key->mctx, hkey, sizeof(HMAC_Key));
+ key->opaque = NULL;
+}
+
+static isc_result_t
+hmacmd5_todns(const dst_key_t *key, isc_buffer_t *data) {
+ HMAC_Key *hkey;
+ unsigned int bytes;
+
+ REQUIRE(key->opaque != NULL);
+
+ hkey = (HMAC_Key *) key->opaque;
+
+ bytes = (key->key_size + 7) / 8;
+ if (isc_buffer_availablelength(data) < bytes)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putmem(data, hkey->key, bytes);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ HMAC_Key *hkey;
+ int keylen;
+ isc_region_t r;
+ isc_md5_t md5ctx;
+
+ isc_buffer_remainingregion(data, &r);
+ if (r.length == 0)
+ return (ISC_R_SUCCESS);
+
+ hkey = (HMAC_Key *) isc_mem_get(key->mctx, sizeof(HMAC_Key));
+ if (hkey == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(hkey->key, 0, sizeof(hkey->key));
+
+ if (r.length > HMAC_LEN) {
+ isc_md5_init(&md5ctx);
+ isc_md5_update(&md5ctx, r.base, r.length);
+ isc_md5_final(&md5ctx, hkey->key);
+ keylen = ISC_MD5_DIGESTLENGTH;
+ }
+ else {
+ memcpy(hkey->key, r.base, r.length);
+ keylen = r.length;
+ }
+
+ key->key_size = keylen * 8;
+ key->opaque = hkey;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacmd5_tofile(const dst_key_t *key, const char *directory) {
+ int cnt = 0;
+ HMAC_Key *hkey;
+ dst_private_t priv;
+ int bytes = (key->key_size + 7) / 8;
+ unsigned char buf[2];
+
+ if (key->opaque == NULL)
+ return (DST_R_NULLKEY);
+
+ hkey = (HMAC_Key *) key->opaque;
+
+ priv.elements[cnt].tag = TAG_HMACMD5_KEY;
+ priv.elements[cnt].length = bytes;
+ priv.elements[cnt++].data = hkey->key;
+
+ buf[0] = (key->key_bits >> 8) & 0xffU;
+ buf[1] = key->key_bits & 0xffU;
+ priv.elements[cnt].tag = TAG_HMACMD5_BITS;
+ priv.elements[cnt].data = buf;
+ priv.elements[cnt++].length = 2;
+
+ priv.nelements = cnt;
+ return (dst__privstruct_writefile(key, &priv, directory));
+}
+
+static isc_result_t
+hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer) {
+ dst_private_t priv;
+ isc_result_t result, tresult;
+ isc_buffer_t b;
+ isc_mem_t *mctx = key->mctx;
+ unsigned int i;
+
+ /* read private key file */
+ result = dst__privstruct_parse(key, DST_ALG_HMACMD5, lexer, mctx, &priv);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ key->key_bits = 0;
+ for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) {
+ switch (priv.elements[i].tag) {
+ case TAG_HMACMD5_KEY:
+ isc_buffer_init(&b, priv.elements[i].data,
+ priv.elements[i].length);
+ isc_buffer_add(&b, priv.elements[i].length);
+ tresult = hmacmd5_fromdns(key, &b);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ case TAG_HMACMD5_BITS:
+ tresult = getkeybits(key, &priv.elements[i]);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ default:
+ result = DST_R_INVALIDPRIVATEKEY;
+ break;
+ }
+ }
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (result);
+}
+
+static dst_func_t hmacmd5_functions = {
+ hmacmd5_createctx,
+ hmacmd5_destroyctx,
+ hmacmd5_adddata,
+ hmacmd5_sign,
+ hmacmd5_verify,
+ NULL, /*%< computesecret */
+ hmacmd5_compare,
+ NULL, /*%< paramcompare */
+ hmacmd5_generate,
+ hmacmd5_isprivate,
+ hmacmd5_destroy,
+ hmacmd5_todns,
+ hmacmd5_fromdns,
+ hmacmd5_tofile,
+ hmacmd5_parse,
+ NULL, /*%< cleanup */
+};
+
+isc_result_t
+dst__hmacmd5_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL)
+ *funcp = &hmacmd5_functions;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data);
+
+typedef struct {
+ unsigned char key[ISC_SHA1_DIGESTLENGTH];
+} HMACSHA1_Key;
+
+static isc_result_t
+hmacsha1_createctx(dst_key_t *key, dst_context_t *dctx) {
+ isc_hmacsha1_t *hmacsha1ctx;
+ HMACSHA1_Key *hkey = key->opaque;
+
+ hmacsha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha1_t));
+ if (hmacsha1ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_hmacsha1_init(hmacsha1ctx, hkey->key, ISC_SHA1_DIGESTLENGTH);
+ dctx->opaque = hmacsha1ctx;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+hmacsha1_destroyctx(dst_context_t *dctx) {
+ isc_hmacsha1_t *hmacsha1ctx = dctx->opaque;
+
+ if (hmacsha1ctx != NULL) {
+ isc_hmacsha1_invalidate(hmacsha1ctx);
+ isc_mem_put(dctx->mctx, hmacsha1ctx, sizeof(isc_hmacsha1_t));
+ dctx->opaque = NULL;
+ }
+}
+
+static isc_result_t
+hmacsha1_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ isc_hmacsha1_t *hmacsha1ctx = dctx->opaque;
+
+ isc_hmacsha1_update(hmacsha1ctx, data->base, data->length);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha1_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ isc_hmacsha1_t *hmacsha1ctx = dctx->opaque;
+ unsigned char *digest;
+
+ if (isc_buffer_availablelength(sig) < ISC_SHA1_DIGESTLENGTH)
+ return (ISC_R_NOSPACE);
+ digest = isc_buffer_used(sig);
+ isc_hmacsha1_sign(hmacsha1ctx, digest, ISC_SHA1_DIGESTLENGTH);
+ isc_buffer_add(sig, ISC_SHA1_DIGESTLENGTH);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha1_verify(dst_context_t *dctx, const isc_region_t *sig) {
+ isc_hmacsha1_t *hmacsha1ctx = dctx->opaque;
+
+ if (sig->length > ISC_SHA1_DIGESTLENGTH || sig->length == 0)
+ return (DST_R_VERIFYFAILURE);
+
+ if (isc_hmacsha1_verify(hmacsha1ctx, sig->base, sig->length))
+ return (ISC_R_SUCCESS);
+ else
+ return (DST_R_VERIFYFAILURE);
+}
+
+static isc_boolean_t
+hmacsha1_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ HMACSHA1_Key *hkey1, *hkey2;
+
+ hkey1 = (HMACSHA1_Key *)key1->opaque;
+ hkey2 = (HMACSHA1_Key *)key2->opaque;
+
+ if (hkey1 == NULL && hkey2 == NULL)
+ return (ISC_TRUE);
+ else if (hkey1 == NULL || hkey2 == NULL)
+ return (ISC_FALSE);
+
+ if (memcmp(hkey1->key, hkey2->key, ISC_SHA1_DIGESTLENGTH) == 0)
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+hmacsha1_generate(dst_key_t *key, int pseudorandom_ok) {
+ isc_buffer_t b;
+ isc_result_t ret;
+ int bytes;
+ unsigned char data[HMAC_LEN];
+
+ bytes = (key->key_size + 7) / 8;
+ if (bytes > HMAC_LEN) {
+ bytes = HMAC_LEN;
+ key->key_size = HMAC_LEN * 8;
+ }
+
+ memset(data, 0, HMAC_LEN);
+ ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0));
+
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ isc_buffer_init(&b, data, bytes);
+ isc_buffer_add(&b, bytes);
+ ret = hmacsha1_fromdns(key, &b);
+ memset(data, 0, ISC_SHA1_DIGESTLENGTH);
+
+ return (ret);
+}
+
+static isc_boolean_t
+hmacsha1_isprivate(const dst_key_t *key) {
+ UNUSED(key);
+ return (ISC_TRUE);
+}
+
+static void
+hmacsha1_destroy(dst_key_t *key) {
+ HMACSHA1_Key *hkey = key->opaque;
+ memset(hkey, 0, sizeof(HMACSHA1_Key));
+ isc_mem_put(key->mctx, hkey, sizeof(HMACSHA1_Key));
+ key->opaque = NULL;
+}
+
+static isc_result_t
+hmacsha1_todns(const dst_key_t *key, isc_buffer_t *data) {
+ HMACSHA1_Key *hkey;
+ unsigned int bytes;
+
+ REQUIRE(key->opaque != NULL);
+
+ hkey = (HMACSHA1_Key *) key->opaque;
+
+ bytes = (key->key_size + 7) / 8;
+ if (isc_buffer_availablelength(data) < bytes)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putmem(data, hkey->key, bytes);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ HMACSHA1_Key *hkey;
+ int keylen;
+ isc_region_t r;
+ isc_sha1_t sha1ctx;
+
+ isc_buffer_remainingregion(data, &r);
+ if (r.length == 0)
+ return (ISC_R_SUCCESS);
+
+ hkey = (HMACSHA1_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA1_Key));
+ if (hkey == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(hkey->key, 0, sizeof(hkey->key));
+
+ if (r.length > ISC_SHA1_DIGESTLENGTH) {
+ isc_sha1_init(&sha1ctx);
+ isc_sha1_update(&sha1ctx, r.base, r.length);
+ isc_sha1_final(&sha1ctx, hkey->key);
+ keylen = ISC_SHA1_DIGESTLENGTH;
+ }
+ else {
+ memcpy(hkey->key, r.base, r.length);
+ keylen = r.length;
+ }
+
+ key->key_size = keylen * 8;
+ key->opaque = hkey;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha1_tofile(const dst_key_t *key, const char *directory) {
+ int cnt = 0;
+ HMACSHA1_Key *hkey;
+ dst_private_t priv;
+ int bytes = (key->key_size + 7) / 8;
+ unsigned char buf[2];
+
+ if (key->opaque == NULL)
+ return (DST_R_NULLKEY);
+
+ hkey = (HMACSHA1_Key *) key->opaque;
+
+ priv.elements[cnt].tag = TAG_HMACSHA1_KEY;
+ priv.elements[cnt].length = bytes;
+ priv.elements[cnt++].data = hkey->key;
+
+ buf[0] = (key->key_bits >> 8) & 0xffU;
+ buf[1] = key->key_bits & 0xffU;
+ priv.elements[cnt].tag = TAG_HMACSHA1_BITS;
+ priv.elements[cnt].data = buf;
+ priv.elements[cnt++].length = 2;
+
+ priv.nelements = cnt;
+ return (dst__privstruct_writefile(key, &priv, directory));
+}
+
+static isc_result_t
+hmacsha1_parse(dst_key_t *key, isc_lex_t *lexer) {
+ dst_private_t priv;
+ isc_result_t result, tresult;
+ isc_buffer_t b;
+ isc_mem_t *mctx = key->mctx;
+ unsigned int i;
+
+ /* read private key file */
+ result = dst__privstruct_parse(key, DST_ALG_HMACSHA1, lexer, mctx,
+ &priv);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ key->key_bits = 0;
+ for (i = 0; i < priv.nelements; i++) {
+ switch (priv.elements[i].tag) {
+ case TAG_HMACSHA1_KEY:
+ isc_buffer_init(&b, priv.elements[i].data,
+ priv.elements[i].length);
+ isc_buffer_add(&b, priv.elements[i].length);
+ tresult = hmacsha1_fromdns(key, &b);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ case TAG_HMACSHA1_BITS:
+ tresult = getkeybits(key, &priv.elements[i]);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ default:
+ result = DST_R_INVALIDPRIVATEKEY;
+ break;
+ }
+ }
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (result);
+}
+
+static dst_func_t hmacsha1_functions = {
+ hmacsha1_createctx,
+ hmacsha1_destroyctx,
+ hmacsha1_adddata,
+ hmacsha1_sign,
+ hmacsha1_verify,
+ NULL, /* computesecret */
+ hmacsha1_compare,
+ NULL, /* paramcompare */
+ hmacsha1_generate,
+ hmacsha1_isprivate,
+ hmacsha1_destroy,
+ hmacsha1_todns,
+ hmacsha1_fromdns,
+ hmacsha1_tofile,
+ hmacsha1_parse,
+ NULL, /* cleanup */
+};
+
+isc_result_t
+dst__hmacsha1_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL)
+ *funcp = &hmacsha1_functions;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data);
+
+typedef struct {
+ unsigned char key[ISC_SHA224_DIGESTLENGTH];
+} HMACSHA224_Key;
+
+static isc_result_t
+hmacsha224_createctx(dst_key_t *key, dst_context_t *dctx) {
+ isc_hmacsha224_t *hmacsha224ctx;
+ HMACSHA224_Key *hkey = key->opaque;
+
+ hmacsha224ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha224_t));
+ if (hmacsha224ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_hmacsha224_init(hmacsha224ctx, hkey->key, ISC_SHA224_DIGESTLENGTH);
+ dctx->opaque = hmacsha224ctx;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+hmacsha224_destroyctx(dst_context_t *dctx) {
+ isc_hmacsha224_t *hmacsha224ctx = dctx->opaque;
+
+ if (hmacsha224ctx != NULL) {
+ isc_hmacsha224_invalidate(hmacsha224ctx);
+ isc_mem_put(dctx->mctx, hmacsha224ctx, sizeof(isc_hmacsha224_t));
+ dctx->opaque = NULL;
+ }
+}
+
+static isc_result_t
+hmacsha224_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ isc_hmacsha224_t *hmacsha224ctx = dctx->opaque;
+
+ isc_hmacsha224_update(hmacsha224ctx, data->base, data->length);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha224_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ isc_hmacsha224_t *hmacsha224ctx = dctx->opaque;
+ unsigned char *digest;
+
+ if (isc_buffer_availablelength(sig) < ISC_SHA224_DIGESTLENGTH)
+ return (ISC_R_NOSPACE);
+ digest = isc_buffer_used(sig);
+ isc_hmacsha224_sign(hmacsha224ctx, digest, ISC_SHA224_DIGESTLENGTH);
+ isc_buffer_add(sig, ISC_SHA224_DIGESTLENGTH);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha224_verify(dst_context_t *dctx, const isc_region_t *sig) {
+ isc_hmacsha224_t *hmacsha224ctx = dctx->opaque;
+
+ if (sig->length > ISC_SHA224_DIGESTLENGTH || sig->length == 0)
+ return (DST_R_VERIFYFAILURE);
+
+ if (isc_hmacsha224_verify(hmacsha224ctx, sig->base, sig->length))
+ return (ISC_R_SUCCESS);
+ else
+ return (DST_R_VERIFYFAILURE);
+}
+
+static isc_boolean_t
+hmacsha224_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ HMACSHA224_Key *hkey1, *hkey2;
+
+ hkey1 = (HMACSHA224_Key *)key1->opaque;
+ hkey2 = (HMACSHA224_Key *)key2->opaque;
+
+ if (hkey1 == NULL && hkey2 == NULL)
+ return (ISC_TRUE);
+ else if (hkey1 == NULL || hkey2 == NULL)
+ return (ISC_FALSE);
+
+ if (memcmp(hkey1->key, hkey2->key, ISC_SHA224_DIGESTLENGTH) == 0)
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+hmacsha224_generate(dst_key_t *key, int pseudorandom_ok) {
+ isc_buffer_t b;
+ isc_result_t ret;
+ int bytes;
+ unsigned char data[HMAC_LEN];
+
+ bytes = (key->key_size + 7) / 8;
+ if (bytes > HMAC_LEN) {
+ bytes = HMAC_LEN;
+ key->key_size = HMAC_LEN * 8;
+ }
+
+ memset(data, 0, HMAC_LEN);
+ ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0));
+
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ isc_buffer_init(&b, data, bytes);
+ isc_buffer_add(&b, bytes);
+ ret = hmacsha224_fromdns(key, &b);
+ memset(data, 0, ISC_SHA224_DIGESTLENGTH);
+
+ return (ret);
+}
+
+static isc_boolean_t
+hmacsha224_isprivate(const dst_key_t *key) {
+ UNUSED(key);
+ return (ISC_TRUE);
+}
+
+static void
+hmacsha224_destroy(dst_key_t *key) {
+ HMACSHA224_Key *hkey = key->opaque;
+ memset(hkey, 0, sizeof(HMACSHA224_Key));
+ isc_mem_put(key->mctx, hkey, sizeof(HMACSHA224_Key));
+ key->opaque = NULL;
+}
+
+static isc_result_t
+hmacsha224_todns(const dst_key_t *key, isc_buffer_t *data) {
+ HMACSHA224_Key *hkey;
+ unsigned int bytes;
+
+ REQUIRE(key->opaque != NULL);
+
+ hkey = (HMACSHA224_Key *) key->opaque;
+
+ bytes = (key->key_size + 7) / 8;
+ if (isc_buffer_availablelength(data) < bytes)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putmem(data, hkey->key, bytes);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ HMACSHA224_Key *hkey;
+ int keylen;
+ isc_region_t r;
+ isc_sha224_t sha224ctx;
+
+ isc_buffer_remainingregion(data, &r);
+ if (r.length == 0)
+ return (ISC_R_SUCCESS);
+
+ hkey = (HMACSHA224_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA224_Key));
+ if (hkey == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(hkey->key, 0, sizeof(hkey->key));
+
+ if (r.length > ISC_SHA224_DIGESTLENGTH) {
+ isc_sha224_init(&sha224ctx);
+ isc_sha224_update(&sha224ctx, r.base, r.length);
+ isc_sha224_final(hkey->key, &sha224ctx);
+ keylen = ISC_SHA224_DIGESTLENGTH;
+ }
+ else {
+ memcpy(hkey->key, r.base, r.length);
+ keylen = r.length;
+ }
+
+ key->key_size = keylen * 8;
+ key->opaque = hkey;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha224_tofile(const dst_key_t *key, const char *directory) {
+ int cnt = 0;
+ HMACSHA224_Key *hkey;
+ dst_private_t priv;
+ int bytes = (key->key_size + 7) / 8;
+ unsigned char buf[2];
+
+ if (key->opaque == NULL)
+ return (DST_R_NULLKEY);
+
+ hkey = (HMACSHA224_Key *) key->opaque;
+
+ priv.elements[cnt].tag = TAG_HMACSHA224_KEY;
+ priv.elements[cnt].length = bytes;
+ priv.elements[cnt++].data = hkey->key;
+
+ buf[0] = (key->key_bits >> 8) & 0xffU;
+ buf[1] = key->key_bits & 0xffU;
+ priv.elements[cnt].tag = TAG_HMACSHA224_BITS;
+ priv.elements[cnt].data = buf;
+ priv.elements[cnt++].length = 2;
+
+ priv.nelements = cnt;
+ return (dst__privstruct_writefile(key, &priv, directory));
+}
+
+static isc_result_t
+hmacsha224_parse(dst_key_t *key, isc_lex_t *lexer) {
+ dst_private_t priv;
+ isc_result_t result, tresult;
+ isc_buffer_t b;
+ isc_mem_t *mctx = key->mctx;
+ unsigned int i;
+
+ /* read private key file */
+ result = dst__privstruct_parse(key, DST_ALG_HMACSHA224, lexer, mctx,
+ &priv);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ key->key_bits = 0;
+ for (i = 0; i < priv.nelements; i++) {
+ switch (priv.elements[i].tag) {
+ case TAG_HMACSHA224_KEY:
+ isc_buffer_init(&b, priv.elements[i].data,
+ priv.elements[i].length);
+ isc_buffer_add(&b, priv.elements[i].length);
+ tresult = hmacsha224_fromdns(key, &b);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ case TAG_HMACSHA224_BITS:
+ tresult = getkeybits(key, &priv.elements[i]);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ default:
+ result = DST_R_INVALIDPRIVATEKEY;
+ break;
+ }
+ }
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (result);
+}
+
+static dst_func_t hmacsha224_functions = {
+ hmacsha224_createctx,
+ hmacsha224_destroyctx,
+ hmacsha224_adddata,
+ hmacsha224_sign,
+ hmacsha224_verify,
+ NULL, /* computesecret */
+ hmacsha224_compare,
+ NULL, /* paramcompare */
+ hmacsha224_generate,
+ hmacsha224_isprivate,
+ hmacsha224_destroy,
+ hmacsha224_todns,
+ hmacsha224_fromdns,
+ hmacsha224_tofile,
+ hmacsha224_parse,
+ NULL, /* cleanup */
+};
+
+isc_result_t
+dst__hmacsha224_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL)
+ *funcp = &hmacsha224_functions;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data);
+
+typedef struct {
+ unsigned char key[ISC_SHA256_DIGESTLENGTH];
+} HMACSHA256_Key;
+
+static isc_result_t
+hmacsha256_createctx(dst_key_t *key, dst_context_t *dctx) {
+ isc_hmacsha256_t *hmacsha256ctx;
+ HMACSHA256_Key *hkey = key->opaque;
+
+ hmacsha256ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha256_t));
+ if (hmacsha256ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_hmacsha256_init(hmacsha256ctx, hkey->key, ISC_SHA256_DIGESTLENGTH);
+ dctx->opaque = hmacsha256ctx;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+hmacsha256_destroyctx(dst_context_t *dctx) {
+ isc_hmacsha256_t *hmacsha256ctx = dctx->opaque;
+
+ if (hmacsha256ctx != NULL) {
+ isc_hmacsha256_invalidate(hmacsha256ctx);
+ isc_mem_put(dctx->mctx, hmacsha256ctx, sizeof(isc_hmacsha256_t));
+ dctx->opaque = NULL;
+ }
+}
+
+static isc_result_t
+hmacsha256_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ isc_hmacsha256_t *hmacsha256ctx = dctx->opaque;
+
+ isc_hmacsha256_update(hmacsha256ctx, data->base, data->length);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha256_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ isc_hmacsha256_t *hmacsha256ctx = dctx->opaque;
+ unsigned char *digest;
+
+ if (isc_buffer_availablelength(sig) < ISC_SHA256_DIGESTLENGTH)
+ return (ISC_R_NOSPACE);
+ digest = isc_buffer_used(sig);
+ isc_hmacsha256_sign(hmacsha256ctx, digest, ISC_SHA256_DIGESTLENGTH);
+ isc_buffer_add(sig, ISC_SHA256_DIGESTLENGTH);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha256_verify(dst_context_t *dctx, const isc_region_t *sig) {
+ isc_hmacsha256_t *hmacsha256ctx = dctx->opaque;
+
+ if (sig->length > ISC_SHA256_DIGESTLENGTH || sig->length == 0)
+ return (DST_R_VERIFYFAILURE);
+
+ if (isc_hmacsha256_verify(hmacsha256ctx, sig->base, sig->length))
+ return (ISC_R_SUCCESS);
+ else
+ return (DST_R_VERIFYFAILURE);
+}
+
+static isc_boolean_t
+hmacsha256_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ HMACSHA256_Key *hkey1, *hkey2;
+
+ hkey1 = (HMACSHA256_Key *)key1->opaque;
+ hkey2 = (HMACSHA256_Key *)key2->opaque;
+
+ if (hkey1 == NULL && hkey2 == NULL)
+ return (ISC_TRUE);
+ else if (hkey1 == NULL || hkey2 == NULL)
+ return (ISC_FALSE);
+
+ if (memcmp(hkey1->key, hkey2->key, ISC_SHA256_DIGESTLENGTH) == 0)
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+hmacsha256_generate(dst_key_t *key, int pseudorandom_ok) {
+ isc_buffer_t b;
+ isc_result_t ret;
+ int bytes;
+ unsigned char data[HMAC_LEN];
+
+ bytes = (key->key_size + 7) / 8;
+ if (bytes > HMAC_LEN) {
+ bytes = HMAC_LEN;
+ key->key_size = HMAC_LEN * 8;
+ }
+
+ memset(data, 0, HMAC_LEN);
+ ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0));
+
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ isc_buffer_init(&b, data, bytes);
+ isc_buffer_add(&b, bytes);
+ ret = hmacsha256_fromdns(key, &b);
+ memset(data, 0, ISC_SHA256_DIGESTLENGTH);
+
+ return (ret);
+}
+
+static isc_boolean_t
+hmacsha256_isprivate(const dst_key_t *key) {
+ UNUSED(key);
+ return (ISC_TRUE);
+}
+
+static void
+hmacsha256_destroy(dst_key_t *key) {
+ HMACSHA256_Key *hkey = key->opaque;
+ memset(hkey, 0, sizeof(HMACSHA256_Key));
+ isc_mem_put(key->mctx, hkey, sizeof(HMACSHA256_Key));
+ key->opaque = NULL;
+}
+
+static isc_result_t
+hmacsha256_todns(const dst_key_t *key, isc_buffer_t *data) {
+ HMACSHA256_Key *hkey;
+ unsigned int bytes;
+
+ REQUIRE(key->opaque != NULL);
+
+ hkey = (HMACSHA256_Key *) key->opaque;
+
+ bytes = (key->key_size + 7) / 8;
+ if (isc_buffer_availablelength(data) < bytes)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putmem(data, hkey->key, bytes);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ HMACSHA256_Key *hkey;
+ int keylen;
+ isc_region_t r;
+ isc_sha256_t sha256ctx;
+
+ isc_buffer_remainingregion(data, &r);
+ if (r.length == 0)
+ return (ISC_R_SUCCESS);
+
+ hkey = (HMACSHA256_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA256_Key));
+ if (hkey == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(hkey->key, 0, sizeof(hkey->key));
+
+ if (r.length > ISC_SHA256_DIGESTLENGTH) {
+ isc_sha256_init(&sha256ctx);
+ isc_sha256_update(&sha256ctx, r.base, r.length);
+ isc_sha256_final(hkey->key, &sha256ctx);
+ keylen = ISC_SHA256_DIGESTLENGTH;
+ }
+ else {
+ memcpy(hkey->key, r.base, r.length);
+ keylen = r.length;
+ }
+
+ key->key_size = keylen * 8;
+ key->opaque = hkey;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha256_tofile(const dst_key_t *key, const char *directory) {
+ int cnt = 0;
+ HMACSHA256_Key *hkey;
+ dst_private_t priv;
+ int bytes = (key->key_size + 7) / 8;
+ unsigned char buf[2];
+
+ if (key->opaque == NULL)
+ return (DST_R_NULLKEY);
+
+ hkey = (HMACSHA256_Key *) key->opaque;
+
+ priv.elements[cnt].tag = TAG_HMACSHA256_KEY;
+ priv.elements[cnt].length = bytes;
+ priv.elements[cnt++].data = hkey->key;
+
+ buf[0] = (key->key_bits >> 8) & 0xffU;
+ buf[1] = key->key_bits & 0xffU;
+ priv.elements[cnt].tag = TAG_HMACSHA256_BITS;
+ priv.elements[cnt].data = buf;
+ priv.elements[cnt++].length = 2;
+
+ priv.nelements = cnt;
+ return (dst__privstruct_writefile(key, &priv, directory));
+}
+
+static isc_result_t
+hmacsha256_parse(dst_key_t *key, isc_lex_t *lexer) {
+ dst_private_t priv;
+ isc_result_t result, tresult;
+ isc_buffer_t b;
+ isc_mem_t *mctx = key->mctx;
+ unsigned int i;
+
+ /* read private key file */
+ result = dst__privstruct_parse(key, DST_ALG_HMACSHA256, lexer, mctx,
+ &priv);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ key->key_bits = 0;
+ for (i = 0; i < priv.nelements; i++) {
+ switch (priv.elements[i].tag) {
+ case TAG_HMACSHA256_KEY:
+ isc_buffer_init(&b, priv.elements[i].data,
+ priv.elements[i].length);
+ isc_buffer_add(&b, priv.elements[i].length);
+ tresult = hmacsha256_fromdns(key, &b);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ case TAG_HMACSHA256_BITS:
+ tresult = getkeybits(key, &priv.elements[i]);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ default:
+ result = DST_R_INVALIDPRIVATEKEY;
+ break;
+ }
+ }
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (result);
+}
+
+static dst_func_t hmacsha256_functions = {
+ hmacsha256_createctx,
+ hmacsha256_destroyctx,
+ hmacsha256_adddata,
+ hmacsha256_sign,
+ hmacsha256_verify,
+ NULL, /* computesecret */
+ hmacsha256_compare,
+ NULL, /* paramcompare */
+ hmacsha256_generate,
+ hmacsha256_isprivate,
+ hmacsha256_destroy,
+ hmacsha256_todns,
+ hmacsha256_fromdns,
+ hmacsha256_tofile,
+ hmacsha256_parse,
+ NULL, /* cleanup */
+};
+
+isc_result_t
+dst__hmacsha256_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL)
+ *funcp = &hmacsha256_functions;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data);
+
+typedef struct {
+ unsigned char key[ISC_SHA384_DIGESTLENGTH];
+} HMACSHA384_Key;
+
+static isc_result_t
+hmacsha384_createctx(dst_key_t *key, dst_context_t *dctx) {
+ isc_hmacsha384_t *hmacsha384ctx;
+ HMACSHA384_Key *hkey = key->opaque;
+
+ hmacsha384ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha384_t));
+ if (hmacsha384ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_hmacsha384_init(hmacsha384ctx, hkey->key, ISC_SHA384_DIGESTLENGTH);
+ dctx->opaque = hmacsha384ctx;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+hmacsha384_destroyctx(dst_context_t *dctx) {
+ isc_hmacsha384_t *hmacsha384ctx = dctx->opaque;
+
+ if (hmacsha384ctx != NULL) {
+ isc_hmacsha384_invalidate(hmacsha384ctx);
+ isc_mem_put(dctx->mctx, hmacsha384ctx, sizeof(isc_hmacsha384_t));
+ dctx->opaque = NULL;
+ }
+}
+
+static isc_result_t
+hmacsha384_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ isc_hmacsha384_t *hmacsha384ctx = dctx->opaque;
+
+ isc_hmacsha384_update(hmacsha384ctx, data->base, data->length);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha384_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ isc_hmacsha384_t *hmacsha384ctx = dctx->opaque;
+ unsigned char *digest;
+
+ if (isc_buffer_availablelength(sig) < ISC_SHA384_DIGESTLENGTH)
+ return (ISC_R_NOSPACE);
+ digest = isc_buffer_used(sig);
+ isc_hmacsha384_sign(hmacsha384ctx, digest, ISC_SHA384_DIGESTLENGTH);
+ isc_buffer_add(sig, ISC_SHA384_DIGESTLENGTH);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha384_verify(dst_context_t *dctx, const isc_region_t *sig) {
+ isc_hmacsha384_t *hmacsha384ctx = dctx->opaque;
+
+ if (sig->length > ISC_SHA384_DIGESTLENGTH || sig->length == 0)
+ return (DST_R_VERIFYFAILURE);
+
+ if (isc_hmacsha384_verify(hmacsha384ctx, sig->base, sig->length))
+ return (ISC_R_SUCCESS);
+ else
+ return (DST_R_VERIFYFAILURE);
+}
+
+static isc_boolean_t
+hmacsha384_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ HMACSHA384_Key *hkey1, *hkey2;
+
+ hkey1 = (HMACSHA384_Key *)key1->opaque;
+ hkey2 = (HMACSHA384_Key *)key2->opaque;
+
+ if (hkey1 == NULL && hkey2 == NULL)
+ return (ISC_TRUE);
+ else if (hkey1 == NULL || hkey2 == NULL)
+ return (ISC_FALSE);
+
+ if (memcmp(hkey1->key, hkey2->key, ISC_SHA384_DIGESTLENGTH) == 0)
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+hmacsha384_generate(dst_key_t *key, int pseudorandom_ok) {
+ isc_buffer_t b;
+ isc_result_t ret;
+ int bytes;
+ unsigned char data[HMAC_LEN];
+
+ bytes = (key->key_size + 7) / 8;
+ if (bytes > HMAC_LEN) {
+ bytes = HMAC_LEN;
+ key->key_size = HMAC_LEN * 8;
+ }
+
+ memset(data, 0, HMAC_LEN);
+ ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0));
+
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ isc_buffer_init(&b, data, bytes);
+ isc_buffer_add(&b, bytes);
+ ret = hmacsha384_fromdns(key, &b);
+ memset(data, 0, ISC_SHA384_DIGESTLENGTH);
+
+ return (ret);
+}
+
+static isc_boolean_t
+hmacsha384_isprivate(const dst_key_t *key) {
+ UNUSED(key);
+ return (ISC_TRUE);
+}
+
+static void
+hmacsha384_destroy(dst_key_t *key) {
+ HMACSHA384_Key *hkey = key->opaque;
+ memset(hkey, 0, sizeof(HMACSHA384_Key));
+ isc_mem_put(key->mctx, hkey, sizeof(HMACSHA384_Key));
+ key->opaque = NULL;
+}
+
+static isc_result_t
+hmacsha384_todns(const dst_key_t *key, isc_buffer_t *data) {
+ HMACSHA384_Key *hkey;
+ unsigned int bytes;
+
+ REQUIRE(key->opaque != NULL);
+
+ hkey = (HMACSHA384_Key *) key->opaque;
+
+ bytes = (key->key_size + 7) / 8;
+ if (isc_buffer_availablelength(data) < bytes)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putmem(data, hkey->key, bytes);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ HMACSHA384_Key *hkey;
+ int keylen;
+ isc_region_t r;
+ isc_sha384_t sha384ctx;
+
+ isc_buffer_remainingregion(data, &r);
+ if (r.length == 0)
+ return (ISC_R_SUCCESS);
+
+ hkey = (HMACSHA384_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA384_Key));
+ if (hkey == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(hkey->key, 0, sizeof(hkey->key));
+
+ if (r.length > ISC_SHA384_DIGESTLENGTH) {
+ isc_sha384_init(&sha384ctx);
+ isc_sha384_update(&sha384ctx, r.base, r.length);
+ isc_sha384_final(hkey->key, &sha384ctx);
+ keylen = ISC_SHA384_DIGESTLENGTH;
+ }
+ else {
+ memcpy(hkey->key, r.base, r.length);
+ keylen = r.length;
+ }
+
+ key->key_size = keylen * 8;
+ key->opaque = hkey;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha384_tofile(const dst_key_t *key, const char *directory) {
+ int cnt = 0;
+ HMACSHA384_Key *hkey;
+ dst_private_t priv;
+ int bytes = (key->key_size + 7) / 8;
+ unsigned char buf[2];
+
+ if (key->opaque == NULL)
+ return (DST_R_NULLKEY);
+
+ hkey = (HMACSHA384_Key *) key->opaque;
+
+ priv.elements[cnt].tag = TAG_HMACSHA384_KEY;
+ priv.elements[cnt].length = bytes;
+ priv.elements[cnt++].data = hkey->key;
+
+ buf[0] = (key->key_bits >> 8) & 0xffU;
+ buf[1] = key->key_bits & 0xffU;
+ priv.elements[cnt].tag = TAG_HMACSHA384_BITS;
+ priv.elements[cnt].data = buf;
+ priv.elements[cnt++].length = 2;
+
+ priv.nelements = cnt;
+ return (dst__privstruct_writefile(key, &priv, directory));
+}
+
+static isc_result_t
+hmacsha384_parse(dst_key_t *key, isc_lex_t *lexer) {
+ dst_private_t priv;
+ isc_result_t result, tresult;
+ isc_buffer_t b;
+ isc_mem_t *mctx = key->mctx;
+ unsigned int i;
+
+ /* read private key file */
+ result = dst__privstruct_parse(key, DST_ALG_HMACSHA384, lexer, mctx,
+ &priv);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ key->key_bits = 0;
+ for (i = 0; i < priv.nelements; i++) {
+ switch (priv.elements[i].tag) {
+ case TAG_HMACSHA384_KEY:
+ isc_buffer_init(&b, priv.elements[i].data,
+ priv.elements[i].length);
+ isc_buffer_add(&b, priv.elements[i].length);
+ tresult = hmacsha384_fromdns(key, &b);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ case TAG_HMACSHA384_BITS:
+ tresult = getkeybits(key, &priv.elements[i]);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ default:
+ result = DST_R_INVALIDPRIVATEKEY;
+ break;
+ }
+ }
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (result);
+}
+
+static dst_func_t hmacsha384_functions = {
+ hmacsha384_createctx,
+ hmacsha384_destroyctx,
+ hmacsha384_adddata,
+ hmacsha384_sign,
+ hmacsha384_verify,
+ NULL, /* computesecret */
+ hmacsha384_compare,
+ NULL, /* paramcompare */
+ hmacsha384_generate,
+ hmacsha384_isprivate,
+ hmacsha384_destroy,
+ hmacsha384_todns,
+ hmacsha384_fromdns,
+ hmacsha384_tofile,
+ hmacsha384_parse,
+ NULL, /* cleanup */
+};
+
+isc_result_t
+dst__hmacsha384_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL)
+ *funcp = &hmacsha384_functions;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data);
+
+typedef struct {
+ unsigned char key[ISC_SHA512_DIGESTLENGTH];
+} HMACSHA512_Key;
+
+static isc_result_t
+hmacsha512_createctx(dst_key_t *key, dst_context_t *dctx) {
+ isc_hmacsha512_t *hmacsha512ctx;
+ HMACSHA512_Key *hkey = key->opaque;
+
+ hmacsha512ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha512_t));
+ if (hmacsha512ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_hmacsha512_init(hmacsha512ctx, hkey->key, ISC_SHA512_DIGESTLENGTH);
+ dctx->opaque = hmacsha512ctx;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+hmacsha512_destroyctx(dst_context_t *dctx) {
+ isc_hmacsha512_t *hmacsha512ctx = dctx->opaque;
+
+ if (hmacsha512ctx != NULL) {
+ isc_hmacsha512_invalidate(hmacsha512ctx);
+ isc_mem_put(dctx->mctx, hmacsha512ctx, sizeof(isc_hmacsha512_t));
+ dctx->opaque = NULL;
+ }
+}
+
+static isc_result_t
+hmacsha512_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ isc_hmacsha512_t *hmacsha512ctx = dctx->opaque;
+
+ isc_hmacsha512_update(hmacsha512ctx, data->base, data->length);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha512_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ isc_hmacsha512_t *hmacsha512ctx = dctx->opaque;
+ unsigned char *digest;
+
+ if (isc_buffer_availablelength(sig) < ISC_SHA512_DIGESTLENGTH)
+ return (ISC_R_NOSPACE);
+ digest = isc_buffer_used(sig);
+ isc_hmacsha512_sign(hmacsha512ctx, digest, ISC_SHA512_DIGESTLENGTH);
+ isc_buffer_add(sig, ISC_SHA512_DIGESTLENGTH);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha512_verify(dst_context_t *dctx, const isc_region_t *sig) {
+ isc_hmacsha512_t *hmacsha512ctx = dctx->opaque;
+
+ if (sig->length > ISC_SHA512_DIGESTLENGTH || sig->length == 0)
+ return (DST_R_VERIFYFAILURE);
+
+ if (isc_hmacsha512_verify(hmacsha512ctx, sig->base, sig->length))
+ return (ISC_R_SUCCESS);
+ else
+ return (DST_R_VERIFYFAILURE);
+}
+
+static isc_boolean_t
+hmacsha512_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ HMACSHA512_Key *hkey1, *hkey2;
+
+ hkey1 = (HMACSHA512_Key *)key1->opaque;
+ hkey2 = (HMACSHA512_Key *)key2->opaque;
+
+ if (hkey1 == NULL && hkey2 == NULL)
+ return (ISC_TRUE);
+ else if (hkey1 == NULL || hkey2 == NULL)
+ return (ISC_FALSE);
+
+ if (memcmp(hkey1->key, hkey2->key, ISC_SHA512_DIGESTLENGTH) == 0)
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+hmacsha512_generate(dst_key_t *key, int pseudorandom_ok) {
+ isc_buffer_t b;
+ isc_result_t ret;
+ int bytes;
+ unsigned char data[HMAC_LEN];
+
+ bytes = (key->key_size + 7) / 8;
+ if (bytes > HMAC_LEN) {
+ bytes = HMAC_LEN;
+ key->key_size = HMAC_LEN * 8;
+ }
+
+ memset(data, 0, HMAC_LEN);
+ ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0));
+
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ isc_buffer_init(&b, data, bytes);
+ isc_buffer_add(&b, bytes);
+ ret = hmacsha512_fromdns(key, &b);
+ memset(data, 0, ISC_SHA512_DIGESTLENGTH);
+
+ return (ret);
+}
+
+static isc_boolean_t
+hmacsha512_isprivate(const dst_key_t *key) {
+ UNUSED(key);
+ return (ISC_TRUE);
+}
+
+static void
+hmacsha512_destroy(dst_key_t *key) {
+ HMACSHA512_Key *hkey = key->opaque;
+ memset(hkey, 0, sizeof(HMACSHA512_Key));
+ isc_mem_put(key->mctx, hkey, sizeof(HMACSHA512_Key));
+ key->opaque = NULL;
+}
+
+static isc_result_t
+hmacsha512_todns(const dst_key_t *key, isc_buffer_t *data) {
+ HMACSHA512_Key *hkey;
+ unsigned int bytes;
+
+ REQUIRE(key->opaque != NULL);
+
+ hkey = (HMACSHA512_Key *) key->opaque;
+
+ bytes = (key->key_size + 7) / 8;
+ if (isc_buffer_availablelength(data) < bytes)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putmem(data, hkey->key, bytes);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ HMACSHA512_Key *hkey;
+ int keylen;
+ isc_region_t r;
+ isc_sha512_t sha512ctx;
+
+ isc_buffer_remainingregion(data, &r);
+ if (r.length == 0)
+ return (ISC_R_SUCCESS);
+
+ hkey = (HMACSHA512_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA512_Key));
+ if (hkey == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(hkey->key, 0, sizeof(hkey->key));
+
+ if (r.length > ISC_SHA512_DIGESTLENGTH) {
+ isc_sha512_init(&sha512ctx);
+ isc_sha512_update(&sha512ctx, r.base, r.length);
+ isc_sha512_final(hkey->key, &sha512ctx);
+ keylen = ISC_SHA512_DIGESTLENGTH;
+ }
+ else {
+ memcpy(hkey->key, r.base, r.length);
+ keylen = r.length;
+ }
+
+ key->key_size = keylen * 8;
+ key->opaque = hkey;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+hmacsha512_tofile(const dst_key_t *key, const char *directory) {
+ int cnt = 0;
+ HMACSHA512_Key *hkey;
+ dst_private_t priv;
+ int bytes = (key->key_size + 7) / 8;
+ unsigned char buf[2];
+
+ if (key->opaque == NULL)
+ return (DST_R_NULLKEY);
+
+ hkey = (HMACSHA512_Key *) key->opaque;
+
+ priv.elements[cnt].tag = TAG_HMACSHA512_KEY;
+ priv.elements[cnt].length = bytes;
+ priv.elements[cnt++].data = hkey->key;
+
+ buf[0] = (key->key_bits >> 8) & 0xffU;
+ buf[1] = key->key_bits & 0xffU;
+ priv.elements[cnt].tag = TAG_HMACSHA512_BITS;
+ priv.elements[cnt].data = buf;
+ priv.elements[cnt++].length = 2;
+
+ priv.nelements = cnt;
+ return (dst__privstruct_writefile(key, &priv, directory));
+}
+
+static isc_result_t
+hmacsha512_parse(dst_key_t *key, isc_lex_t *lexer) {
+ dst_private_t priv;
+ isc_result_t result, tresult;
+ isc_buffer_t b;
+ isc_mem_t *mctx = key->mctx;
+ unsigned int i;
+
+ /* read private key file */
+ result = dst__privstruct_parse(key, DST_ALG_HMACSHA512, lexer, mctx,
+ &priv);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ key->key_bits = 0;
+ for (i = 0; i < priv.nelements; i++) {
+ switch (priv.elements[i].tag) {
+ case TAG_HMACSHA512_KEY:
+ isc_buffer_init(&b, priv.elements[i].data,
+ priv.elements[i].length);
+ isc_buffer_add(&b, priv.elements[i].length);
+ tresult = hmacsha512_fromdns(key, &b);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ case TAG_HMACSHA512_BITS:
+ tresult = getkeybits(key, &priv.elements[i]);
+ if (tresult != ISC_R_SUCCESS)
+ result = tresult;
+ break;
+ default:
+ result = DST_R_INVALIDPRIVATEKEY;
+ break;
+ }
+ }
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (result);
+}
+
+static dst_func_t hmacsha512_functions = {
+ hmacsha512_createctx,
+ hmacsha512_destroyctx,
+ hmacsha512_adddata,
+ hmacsha512_sign,
+ hmacsha512_verify,
+ NULL, /* computesecret */
+ hmacsha512_compare,
+ NULL, /* paramcompare */
+ hmacsha512_generate,
+ hmacsha512_isprivate,
+ hmacsha512_destroy,
+ hmacsha512_todns,
+ hmacsha512_fromdns,
+ hmacsha512_tofile,
+ hmacsha512_parse,
+ NULL, /* cleanup */
+};
+
+isc_result_t
+dst__hmacsha512_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL)
+ *funcp = &hmacsha512_functions;
+ return (ISC_R_SUCCESS);
+}
+
+/*! \file */
diff --git a/lib/dns/include/Makefile.in b/lib/dns/include/Makefile.in
new file mode 100644
index 0000000..593ad5a
--- /dev/null
+++ b/lib/dns/include/Makefile.in
@@ -0,0 +1,25 @@
+# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-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: Makefile.in,v 1.12.18.1 2004/12/09 04:41:46 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = dns dst
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/dns/include/dns/Makefile.in b/lib/dns/include/dns/Makefile.in
new file mode 100644
index 0000000..3f367bc
--- /dev/null
+++ b/lib/dns/include/dns/Makefile.in
@@ -0,0 +1,54 @@
+# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-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.50 2004/03/05 05:09:40 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = acl.h adb.h byaddr.h cache.h callbacks.h \
+ cert.h compress.h \
+ db.h dbiterator.h dbtable.h diff.h dispatch.h \
+ dnssec.h ds.h events.h fixedname.h journal.h keyflags.h \
+ keytable.h keyvalues.h lib.h log.h master.h masterdump.h \
+ message.h name.h ncache.h \
+ nsec.h peer.h portlist.h rbt.h rcode.h \
+ rdata.h rdataclass.h rdatalist.h rdataset.h rdatasetiter.h \
+ rdataslab.h rdatatype.h request.h resolver.h result.h \
+ rootns.h sdb.h secalg.h secproto.h soa.h ssu.h \
+ tcpmsg.h time.h tkey.h \
+ tsig.h ttl.h types.h validator.h version.h view.h xfrin.h \
+ zone.h zonekey.h zt.h
+
+GENHEADERS = enumclass.h enumtype.h rdatastruct.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/dns
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/dns ; \
+ done
+ for i in ${GENHEADERS}; do \
+ ${INSTALL_DATA} $$i ${DESTDIR}${includedir}/dns ; \
+ done
diff --git a/lib/dns/include/dns/acache.h b/lib/dns/include/dns/acache.h
new file mode 100644
index 0000000..50d7fc1
--- /dev/null
+++ b/lib/dns/include/dns/acache.h
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: acache.h,v 1.3.2.4 2006/05/03 00:07:49 marka Exp $ */
+
+#ifndef DNS_ACACHE_H
+#define DNS_ACACHE_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * Acache
+ *
+ * The Additional Cache Object
+ *
+ * This module manages internal caching entries that correspond to
+ * the additional section data of a DNS DB node (an RRset header, more
+ * accurately). An additional cache entry is expected to be (somehow)
+ * attached to a particular RR in a particular DB node, and contains a set
+ * of information of an additional data for the DB node.
+ *
+ * An additional cache object is intended to be created as a per-view
+ * object, and manages all cache entries within the view.
+ *
+ * The intended usage of the additional caching is to provide a short cut
+ * to additional glue RRs of an NS RR. For each NS RR, it is often
+ * necessary to look for glue RRs to make a proper response. Once the
+ * glue RRs are known, the additional caching allows the client to
+ * associate the information to the original NS RR so that further
+ * expensive lookups can be avoided for the NS RR.
+ *
+ * Each additional cache entry contains information to identify a
+ * particular DB node and (optionally) an associated RRset. The
+ * information consists of its zone, database, the version of the
+ * database, database node, and RRset.
+ *
+ * A "negative" information can also be cached. For example, if a glue
+ * RR does not exist as an authoritative data in the same zone as that
+ * of the NS RR, this fact can be cached by specifying a NULL pointer
+ * for the database, version, and node. (See the description for
+ * dns_acache_getentry() below for more details.)
+ *
+ * Since each member stored in an additional cache entry holds a reference
+ * to a corresponding object, a stale cache entry may cause unnecessary
+ * memory consumption. For instance, when a zone is reloaded, additional
+ * cache entries that have a reference to the zone (and its DB and/or
+ * DB nodes) can delay the cleanup of the referred objects. In order to
+ * minimize such a bad effect, this module provides several cleanup
+ * mechanisms.
+ *
+ * The first one is a shutdown procedure called when the associated view
+ * is shut down. In this case, dns_acache_shutdown() will be called and
+ * all cache entries will be purged. This mechanism will help the
+ * situation when the configuration is reloaded or the main server is
+ * stopped.
+ *
+ * Per-DB cleanup mechanism is also provided. Each additional cache entry
+ * is associated with related DB, which is expected to have been
+ * registered when the DB was created by dns_acache_setdb(). If a
+ * particular DB is going to be destroyed, the primary holder of the DB,
+ * a typical example of which is a zone, will call dns_acache_putdb().
+ * Then this module will clean-up all cache entries associated with the
+ * DB. This mechanism is effective when a secondary zone DB is going to
+ * be stale after a zone transfer.
+ *
+ * Finally, this module supports for periodic clean-up of stale entries.
+ * Each cache entry has a timestamp field, which is updated every time
+ * the entry is referred. A periodically invoked cleaner checks the
+ * timestamp of each entry, and purge entries that have not been referred
+ * for a certain period. The cleaner interval can be specified by
+ * dns_acache_setcleaninginterval(). If the periodic clean-up is not
+ * enough, it is also possible to specify the upper limit of entries
+ * in terms of the memory consumption. If the maximum value is
+ * specified, the cleaner is invoked when the memory consumption reaches
+ * the high watermark inferred from the maximum value. In this case,
+ * the cleaner will use more aggressive algorithm to decide the "victim"
+ * entries. The maximum value can be specified by
+ * dns_acache_setcachesize().
+ *
+ * When a cache entry is going to be purged within this module, the
+ * callback function specified at the creation time will be called.
+ * The callback function is expected to release all internal resources
+ * related to the entry, which will typically be specific to DB
+ * implementation, and to call dns_acache_detachentry(). The callback
+ * mechanism is very important, since the holder of an additional cache
+ * entry may not be able to initiate the clean-up of the entry, due to
+ * the reference ordering. For example, as long as an additional cache
+ * entry has a reference to a DB object, the DB cannot be freed, in which
+ * a DB node may have a reference to the cache entry.
+ *
+ * Credits:
+ * The basic idea of this kind of short-cut for frequently used
+ * information is similar to the "pre-compiled answer" approach adopted
+ * in nsd by NLnet LABS with RIPE NCC. Our work here is an independent
+ * effort, but the success of nsd encouraged us to pursue this path.
+ *
+ * The design and implementation of the periodic memory management and
+ * the upper limitation of memory consumption was derived from the cache
+ * DB implementation of BIND9.
+ *
+ * MP:
+ * There are two main locks in this module. One is for each entry, and
+ * the other is for the additional cache object.
+ *
+ * Reliability:
+ * The callback function for a cache entry is called with holding the
+ * entry lock. Thus, it implicitly assumes the callback function does not
+ * call a function that can require the lock. Typically, the only
+ * function that can be called from the callback function safely is
+ * dns_acache_detachentry(). The breakage of this implicit assumption
+ * may cause a deadlock.
+ *
+ * Resources:
+ * In a 32-bit architecture (such as i386), the following additional
+ * memory is required comparing to the case that disables this module.
+ * - 76 bytes for each additional cache entry
+ * - if the entry has a DNS name and associated RRset,
+ * * 44 bytes + size of the name (1-255 bytes)
+ * * 52 bytes x number_of_RRs
+ * - 28 bytes for each DB related to this module
+ *
+ * Using the additional cache also requires extra memory consumption in
+ * the DB implementation. In the current implementation for rbtdb, we
+ * need:
+ * - two additional pointers for each DB node (8 bytes for a 32-bit
+ * architecture
+ * - for each RR associated to an RR in a DB node, we also need
+ * a pointer and management objects to support the additional cache
+ * function. These are allocated on-demand. The total size is
+ * 32 bytes for a 32-bit architecture.
+ *
+ * Security:
+ * Since this module does not handle any low-level data directly,
+ * no security issue specific to this module is anticipated.
+ *
+ * Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/mutex.h>
+#include <isc/lang.h>
+#include <isc/refcount.h>
+#include <isc/stdtime.h>
+
+#include <dns/types.h>
+
+/***
+ *** Functions
+ ***/
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx,
+ isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr);
+/*
+ * Create a new DNS additional cache object.
+ *
+ * Requires:
+ *
+ * 'mctx' is a valid memory context
+ *
+ * 'taskmgr' is a valid task manager
+ *
+ * 'timermgr' is a valid timer or NULL. If NULL, no periodic cleaning of
+ * the cache will take place.
+ *
+ * 'acachep' is a valid pointer, and *acachep == NULL
+ *
+ * Ensures:
+ *
+ * '*acachep' is attached to the newly created cache
+ *
+ * Returns:
+ *
+ * ISC_R_SUCCESS
+ * ISC_R_NOMEMORY
+ * ISC_R_UNEXPECTED
+ */
+
+void
+dns_acache_attach(dns_acache_t *source, dns_acache_t **targetp);
+/*
+ * Attach *targetp to cache.
+ *
+ * Requires:
+ *
+ * 'acache' is a valid additional cache.
+ *
+ * 'targetp' points to a NULL dns_acache_t *.
+ *
+ * Ensures:
+ *
+ * *targetp is attached to the 'source' additional cache.
+ */
+
+void
+dns_acache_detach(dns_acache_t **acachep);
+/*
+ * Detach *acachep from its cache.
+ *
+ * Requires:
+ *
+ * '*acachep' points to a valid additional cache.
+ *
+ * Ensures:
+ *
+ * *acachep is NULL.
+ *
+ * If '*acachep' is the last reference to the cache and the additional
+ * cache does not have an outstanding task, all resources used by the
+ * cache will be freed.
+ */
+
+void
+dns_acache_setcleaninginterval(dns_acache_t *acache, unsigned int t);
+/*
+ * Set the periodic cleaning interval of an additional cache to 'interval'
+ * seconds.
+ */
+
+void
+dns_acache_setcachesize(dns_acache_t *acache, isc_uint32_t size);
+/*
+ * Set the maximum additional cache size. 0 means unlimited.
+ */
+
+isc_result_t
+dns_acache_setdb(dns_acache_t *acache, dns_db_t *db);
+/*
+ * Set 'db' in 'acache' when the db can be referred from acache, in order
+ * to provide a hint for resolving the back reference.
+ *
+ * Requires:
+ * 'acache' is a valid acache pointer.
+ * 'db' is a valid DNS DB pointer.
+ *
+ * Ensures:
+ * 'acache' will have a reference to 'db'.
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_EXISTS (which means the specified 'db' is already set)
+ * ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_acache_putdb(dns_acache_t *acache, dns_db_t *db);
+/*
+ * Release 'db' from 'acache' if it has been set by dns_acache_setdb().
+ *
+ * Requires:
+ * 'acache' is a valid acache pointer.
+ * 'db' is a valid DNS DB pointer.
+ *
+ * Ensures:
+ * 'acache' will release the reference to 'db'. Additionally, the content
+ * of each cache entry that is related to the 'db' will be released via
+ * the callback function.
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_NOTFOUND (which means the specified 'db' is not set in 'acache')
+ * ISC_R_NOMEMORY
+ */
+
+void
+dns_acache_shutdown(dns_acache_t *acache);
+/*
+ * Shutdown 'acache'.
+ *
+ * Requires:
+ *
+ * '*acache' is a valid additional cache.
+ */
+
+isc_result_t
+dns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb,
+ void (*callback)(dns_acacheentry_t *, void **),
+ void *cbarg, dns_acacheentry_t **entryp);
+/*
+ * Create an additional cache entry. A new entry is created and attached to
+ * the given additional cache object. A callback function is also associated
+ * with the created entry, which will be called when the cache entry is purged
+ * for some reason.
+ *
+ * Requires:
+ *
+ * 'acache' is a valid additional cache.
+ * 'entryp' is a valid pointer, and *entryp == NULL
+ * 'origdb' is a valid DNS DB pointer.
+ * 'callback' and 'cbarg' can be NULL. In this case, however, the entry
+ * is meaningless (and will be cleaned-up in the next periodical
+ * cleaning).
+ *
+ * Ensures:
+ * '*entryp' will point to a new additional cache entry.
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep,
+ dns_db_t **dbp, dns_dbversion_t **versionp,
+ dns_dbnode_t **nodep, dns_name_t *fname,
+ dns_message_t *msg, isc_stdtime_t now);
+/*
+ * Get content from a particular additional cache entry.
+ *
+ * Requires:
+ *
+ * 'entry' is a valid additional cache entry.
+ * 'zonep' is a NULL pointer or '*zonep' == NULL (this is the only
+ * optional parameter.)
+ * 'dbp' is a valid pointer, and '*dbp' == NULL
+ * 'versionp' is a valid pointer, and '*versionp' == NULL
+ * 'nodep' is a valid pointer, and '*nodep' == NULL
+ * 'fname' is a valid DNS name.
+ * 'msg' is a valid DNS message.
+ *
+ * Ensures:
+ * Several possible cases can happen according to the content.
+ * 1. For a positive cache entry,
+ * '*zonep' will point to the corresponding zone (if zonep is a valid
+ * pointer),
+ * '*dbp' will point to a DB for the zone,
+ * '*versionp' will point to its version, and
+ * '*nodep' will point to the corresponding DB node.
+ * 'fname' will have the DNS name of the DB node and contain a list of
+ * rdataset for the node (which can be an empty list).
+ *
+ * 2. For a negative cache entry that means no corresponding zone exists,
+ * '*zonep' == NULL (if zonep is a valid pointer)
+ * '*dbp', '*versionp', and '*nodep' will be NULL.
+ *
+ * 3. For a negative cache entry that means no corresponding DB node
+ * exists, '*zonep' will point to the corresponding zone (if zonep is a
+ * valid pointer),
+ * '*dbp' will point to a corresponding DB for zone,
+ * '*versionp' will point to its version.
+ * '*nodep' will be kept as NULL.
+ * 'fname' will not change.
+ *
+ * On failure, no new references will be created.
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_acache_setentry(dns_acache_t *acache, dns_acacheentry_t *entry,
+ dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
+ dns_dbnode_t *node, dns_name_t *fname);
+/*
+ * Set content to a particular additional cache entry.
+ *
+ * Requires:
+ * 'acache' is a valid additional cache.
+ * 'entry' is a valid additional cache entry.
+ * All the others pointers are NULL or a valid pointer of the
+ * corresponding type.
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_NOMEMORY
+ * ISC_R_NOTFOUND
+ */
+
+void
+dns_acache_cancelentry(dns_acacheentry_t *entry);
+/*
+ * Cancel the use of the cache entry 'entry'. This function is supposed to
+ * be called when the node that holds the entry finds the content is not
+ * correct any more. This function will try to release as much dependency as
+ * possible, and will be ready to be cleaned-up. The registered callback
+ * function will be canceled and will never called.
+ *
+ * Requires:
+ * 'entry' is a valid additional cache entry.
+ */
+
+void
+dns_acache_attachentry(dns_acacheentry_t *source, dns_acacheentry_t **targetp);
+/*
+ * Attach *targetp to the cache entry 'source'.
+ *
+ * Requires:
+ *
+ * 'source' is a valid additional cache entry.
+ *
+ * 'targetp' points to a NULL dns_acacheentry_t *.
+ *
+ * Ensures:
+ *
+ * *targetp is attached to 'source'.
+ */
+
+void
+dns_acache_detachentry(dns_acacheentry_t **entryp);
+/*
+ * Detach *entryp from its cache.
+ *
+ * Requires:
+ *
+ * '*entryp' points to a valid additional cache entry.
+ *
+ * Ensures:
+ *
+ * *entryp is NULL.
+ *
+ * If '*entryp' is the last reference to the entry,
+ * cache does not have an outstanding task, all resources used by the
+ * entry (including the entry object itself) will be freed.
+ */
+
+void
+dns_acache_countquerymiss(dns_acache_t *acache);
+/*
+ * Count up a missed acache query. XXXMLG need more docs.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_ACACHE_H */
diff --git a/lib/dns/include/dns/acl.h b/lib/dns/include/dns/acl.h
new file mode 100644
index 0000000..34e394f
--- /dev/null
+++ b/lib/dns/include/dns/acl.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2004-2006 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: acl.h,v 1.22.18.4 2006/03/02 00:37:21 marka Exp $ */
+
+#ifndef DNS_ACL_H
+#define DNS_ACL_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Address match list handling.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/netaddr.h>
+#include <isc/refcount.h>
+
+#include <dns/name.h>
+#include <dns/types.h>
+
+/***
+ *** Types
+ ***/
+
+typedef enum {
+ dns_aclelementtype_ipprefix,
+ dns_aclelementtype_keyname,
+ dns_aclelementtype_nestedacl,
+ dns_aclelementtype_localhost,
+ dns_aclelementtype_localnets,
+ dns_aclelementtype_any
+} dns_aclelemettype_t;
+
+typedef struct dns_aclipprefix dns_aclipprefix_t;
+
+struct dns_aclipprefix {
+ isc_netaddr_t address; /* IP4/IP6 */
+ unsigned int prefixlen;
+};
+
+struct dns_aclelement {
+ dns_aclelemettype_t type;
+ isc_boolean_t negative;
+ union {
+ dns_aclipprefix_t ip_prefix;
+ dns_name_t keyname;
+ dns_acl_t *nestedacl;
+ } u;
+};
+
+struct dns_acl {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_refcount_t refcount;
+ dns_aclelement_t *elements;
+ unsigned int alloc; /*%< Elements allocated */
+ unsigned int length; /*%< Elements initialized */
+ char *name; /*%< Temporary use only */
+ ISC_LINK(dns_acl_t) nextincache; /*%< Ditto */
+};
+
+struct dns_aclenv {
+ dns_acl_t *localhost;
+ dns_acl_t *localnets;
+ isc_boolean_t match_mapped;
+};
+
+#define DNS_ACL_MAGIC ISC_MAGIC('D','a','c','l')
+#define DNS_ACL_VALID(a) ISC_MAGIC_VALID(a, DNS_ACL_MAGIC)
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target);
+/*%<
+ * Create a new ACL with room for 'n' elements.
+ * The elements are uninitialized and the length is 0.
+ */
+
+isc_result_t
+dns_acl_appendelement(dns_acl_t *acl, const dns_aclelement_t *elt);
+/*%<
+ * Append an element to an existing ACL.
+ */
+
+isc_result_t
+dns_acl_any(isc_mem_t *mctx, dns_acl_t **target);
+/*%<
+ * Create a new ACL that matches everything.
+ */
+
+isc_result_t
+dns_acl_none(isc_mem_t *mctx, dns_acl_t **target);
+/*%<
+ * Create a new ACL that matches nothing.
+ */
+
+void
+dns_acl_attach(dns_acl_t *source, dns_acl_t **target);
+
+void
+dns_acl_detach(dns_acl_t **aclp);
+
+isc_boolean_t
+dns_aclelement_equal(const dns_aclelement_t *ea, const dns_aclelement_t *eb);
+
+isc_boolean_t
+dns_acl_equal(const dns_acl_t *a, const dns_acl_t *b);
+
+isc_boolean_t
+dns_acl_isinsecure(const dns_acl_t *a);
+/*%<
+ * Return #ISC_TRUE iff the acl 'a' is considered insecure, that is,
+ * if it contains IP addresses other than those of the local host.
+ * This is intended for applications such as printing warning
+ * messages for suspect ACLs; it is not intended for making access
+ * control decisions. We make no guarantee that an ACL for which
+ * this function returns #ISC_FALSE is safe.
+ */
+
+isc_result_t
+dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env);
+
+void
+dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s);
+
+void
+dns_aclenv_destroy(dns_aclenv_t *env);
+
+isc_result_t
+dns_acl_match(const isc_netaddr_t *reqaddr,
+ const dns_name_t *reqsigner,
+ const dns_acl_t *acl,
+ const dns_aclenv_t *env,
+ int *match,
+ const dns_aclelement_t **matchelt);
+/*%<
+ * General, low-level ACL matching. This is expected to
+ * be useful even for weird stuff like the topology and sortlist statements.
+ *
+ * Match the address 'reqaddr', and optionally the key name 'reqsigner',
+ * against 'acl'. 'reqsigner' may be NULL.
+ *
+ * If there is a positive match, '*match' will be set to a positive value
+ * indicating the distance from the beginning of the list.
+ *
+ * If there is a negative match, '*match' will be set to a negative value
+ * whose absolute value indicates the distance from the beginning of
+ * the list.
+ *
+ * If there is a match (either positive or negative) and 'matchelt' is
+ * non-NULL, *matchelt will be attached to the primitive
+ * (non-indirect) address match list element that matched.
+ *
+ * If there is no match, *match will be set to zero.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Always succeeds.
+ */
+
+isc_boolean_t
+dns_aclelement_match(const isc_netaddr_t *reqaddr,
+ const dns_name_t *reqsigner,
+ const dns_aclelement_t *e,
+ const dns_aclenv_t *env,
+ const dns_aclelement_t **matchelt);
+/*%<
+ * Like dns_acl_match, but matches against the single ACL element 'e'
+ * rather than a complete list and returns ISC_TRUE iff it matched.
+ * To determine whether the match was prositive or negative, the
+ * caller should examine e->negative. Since the element 'e' may be
+ * a reference to a named ACL or a nested ACL, the matching element
+ * returned through 'matchelt' is not necessarily 'e' itself.
+ */
+
+isc_result_t
+dns_acl_elementmatch(const dns_acl_t *acl,
+ const dns_aclelement_t *elt,
+ const dns_aclelement_t **matchelt);
+/*%<
+ * Search for an ACL element in 'acl' which is exactly the same as 'elt'.
+ * If there is one, and 'matchelt' is non NULL, then '*matchelt' will point
+ * to the entry.
+ *
+ * This function is intended to be used for avoiding duplicated ACL entries
+ * before adding an entry.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Match succeeds.
+ *\li #ISC_R_NOTFOUND Match fails.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_ACL_H */
diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h
new file mode 100644
index 0000000..1e3cd61
--- /dev/null
+++ b/lib/dns/include/dns/adb.h
@@ -0,0 +1,635 @@
+/*
+ * Copyright (C) 2004, 2005 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: adb.h,v 1.76.18.3 2005/06/23 04:23:16 marka Exp $ */
+
+#ifndef DNS_ADB_H
+#define DNS_ADB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ *\brief
+ * DNS Address Database
+ *
+ * This module implements an address database (ADB) for mapping a name
+ * to an isc_sockaddr_t. It also provides statistical information on
+ * how good that address might be.
+ *
+ * A client will pass in a dns_name_t, and the ADB will walk through
+ * the rdataset looking up addresses associated with the name. If it
+ * is found on the internal lists, a structure is filled in with the
+ * address information and stats for found addresses.
+ *
+ * If the name cannot be found on the internal lists, a new entry will
+ * be created for a name if all the information needed can be found
+ * in the zone table or cache. This new address will then be returned.
+ *
+ * If a request must be made to remote servers to satisfy a name lookup,
+ * this module will start fetches to try to complete these addresses. When
+ * at least one more completes, an event is sent to the caller. If none of
+ * them resolve before the fetch times out, an event indicating this is
+ * sent instead.
+ *
+ * Records are stored internally until a timer expires. The timer is the
+ * smaller of the TTL or signature validity period.
+ *
+ * Lameness is stored per <qname,qtype> tuple, and this data hangs off each
+ * address field. When an address is marked lame for a given tuple the address
+ * will not be returned to a caller.
+ *
+ *
+ * MP:
+ *
+ *\li The ADB takes care of all necessary locking.
+ *
+ *\li Only the task which initiated the name lookup can cancel the lookup.
+ *
+ *
+ * Security:
+ *
+ *\li None, since all data stored is required to be pre-filtered.
+ * (Cache needs to be sane, fetches return bounds-checked and sanity-
+ * checked data, caller passes a good dns_name_t for the zone, etc)
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/sockaddr.h>
+
+#include <dns/types.h>
+#include <dns/view.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Magic number checks
+ ***/
+
+#define DNS_ADBFIND_MAGIC ISC_MAGIC('a','d','b','H')
+#define DNS_ADBFIND_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFIND_MAGIC)
+#define DNS_ADBADDRINFO_MAGIC ISC_MAGIC('a','d','A','I')
+#define DNS_ADBADDRINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBADDRINFO_MAGIC)
+
+
+/***
+ *** TYPES
+ ***/
+
+typedef struct dns_adbname dns_adbname_t;
+
+/*!
+ *\brief
+ * Represents a lookup for a single name.
+ *
+ * On return, the client can safely use "list", and can reorder the list.
+ * Items may not be _deleted_ from this list, however, or added to it
+ * other than by using the dns_adb_*() API.
+ */
+struct dns_adbfind {
+ /* Public */
+ unsigned int magic; /*%< RO: magic */
+ dns_adbaddrinfolist_t list; /*%< RO: list of addrs */
+ unsigned int query_pending; /*%< RO: partial list */
+ unsigned int partial_result; /*%< RO: addrs missing */
+ unsigned int options; /*%< RO: options */
+ isc_result_t result_v4; /*%< RO: v4 result */
+ isc_result_t result_v6; /*%< RO: v6 result */
+ ISC_LINK(dns_adbfind_t) publink; /*%< RW: client use */
+
+ /* Private */
+ isc_mutex_t lock; /* locks all below */
+ in_port_t port;
+ int name_bucket;
+ unsigned int flags;
+ dns_adbname_t *adbname;
+ dns_adb_t *adb;
+ isc_event_t event;
+ ISC_LINK(dns_adbfind_t) plink;
+};
+
+/*
+ * _INET:
+ * _INET6:
+ * return addresses of that type.
+ *
+ * _EMPTYEVENT:
+ * Only schedule an event if no addresses are known.
+ * Must set _WANTEVENT for this to be meaningful.
+ *
+ * _WANTEVENT:
+ * An event is desired. Check this bit in the returned find to see
+ * if one will actually be generated.
+ *
+ * _AVOIDFETCHES:
+ * If set, fetches will not be generated unless no addresses are
+ * available in any of the address families requested.
+ *
+ * _STARTATZONE:
+ * Fetches will start using the closest zone data or use the root servers.
+ * This is useful for reestablishing glue that has expired.
+ *
+ * _GLUEOK:
+ * _HINTOK:
+ * Glue or hints are ok. These are used when matching names already
+ * in the adb, and when dns databases are searched.
+ *
+ * _RETURNLAME:
+ * Return lame servers in a find, so that all addresses are returned.
+ *
+ * _LAMEPRUNED:
+ * At least one address was omitted from the list because it was lame.
+ * This bit will NEVER be set if _RETURNLAME is set in the createfind().
+ */
+/*% Return addresses of type INET. */
+#define DNS_ADBFIND_INET 0x00000001
+/*% Return addresses of type INET6. */
+#define DNS_ADBFIND_INET6 0x00000002
+#define DNS_ADBFIND_ADDRESSMASK 0x00000003
+/*%
+ * Only schedule an event if no addresses are known.
+ * Must set _WANTEVENT for this to be meaningful.
+ */
+#define DNS_ADBFIND_EMPTYEVENT 0x00000004
+/*%
+ * An event is desired. Check this bit in the returned find to see
+ * if one will actually be generated.
+ */
+#define DNS_ADBFIND_WANTEVENT 0x00000008
+/*%
+ * If set, fetches will not be generated unless no addresses are
+ * available in any of the address families requested.
+ */
+#define DNS_ADBFIND_AVOIDFETCHES 0x00000010
+/*%
+ * Fetches will start using the closest zone data or use the root servers.
+ * This is useful for reestablishing glue that has expired.
+ */
+#define DNS_ADBFIND_STARTATZONE 0x00000020
+/*%
+ * Glue or hints are ok. These are used when matching names already
+ * in the adb, and when dns databases are searched.
+ */
+#define DNS_ADBFIND_GLUEOK 0x00000040
+/*%
+ * Glue or hints are ok. These are used when matching names already
+ * in the adb, and when dns databases are searched.
+ */
+#define DNS_ADBFIND_HINTOK 0x00000080
+/*%
+ * Return lame servers in a find, so that all addresses are returned.
+ */
+#define DNS_ADBFIND_RETURNLAME 0x00000100
+/*%
+ * Only schedule an event if no addresses are known.
+ * Must set _WANTEVENT for this to be meaningful.
+ */
+#define DNS_ADBFIND_LAMEPRUNED 0x00000200
+
+/*%
+ * The answers to queries come back as a list of these.
+ */
+struct dns_adbaddrinfo {
+ unsigned int magic; /*%< private */
+
+ isc_sockaddr_t sockaddr; /*%< [rw] */
+ unsigned int srtt; /*%< [rw] microseconds */
+ unsigned int flags; /*%< [rw] */
+ dns_adbentry_t *entry; /*%< private */
+ ISC_LINK(dns_adbaddrinfo_t) publink;
+};
+
+/*!<
+ * The event sent to the caller task is just a plain old isc_event_t. It
+ * contains no data other than a simple status, passed in the "type" field
+ * to indicate that another address resolved, or all partially resolved
+ * addresses have failed to resolve.
+ *
+ * "sender" is the dns_adbfind_t used to issue this query.
+ *
+ * This is simply a standard event, with the "type" set to:
+ *
+ *\li #DNS_EVENT_ADBMOREADDRESSES -- another address resolved.
+ *\li #DNS_EVENT_ADBNOMOREADDRESSES -- all pending addresses failed,
+ * were canceled, or otherwise will
+ * not be usable.
+ *\li #DNS_EVENT_ADBCANCELED -- The request was canceled by a
+ * 3rd party.
+ *\li #DNS_EVENT_ADBNAMEDELETED -- The name was deleted, so this request
+ * was canceled.
+ *
+ * In each of these cases, the addresses returned by the initial call
+ * to dns_adb_createfind() can still be used until they are no longer needed.
+ */
+
+/****
+ **** FUNCTIONS
+ ****/
+
+
+isc_result_t
+dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *tmgr,
+ isc_taskmgr_t *taskmgr, dns_adb_t **newadb);
+/*%<
+ * Create a new ADB.
+ *
+ * Notes:
+ *
+ *\li Generally, applications should not create an ADB directly, but
+ * should instead call dns_view_createresolver().
+ *
+ * Requires:
+ *
+ *\li 'mem' must be a valid memory context.
+ *
+ *\li 'view' be a pointer to a valid view.
+ *
+ *\li 'tmgr' be a pointer to a valid timer manager.
+ *
+ *\li 'taskmgr' be a pointer to a valid task manager.
+ *
+ *\li 'newadb' != NULL && '*newadb' == NULL.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS after happiness.
+ *\li #ISC_R_NOMEMORY after resource allocation failure.
+ */
+
+void
+dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbp);
+/*%
+ * Attach to an 'adb' to 'adbp'.
+ *
+ * Requires:
+ *\li 'adb' to be a valid dns_adb_t, created via dns_adb_create().
+ *\li 'adbp' to be a valid pointer to a *dns_adb_t which is initialized
+ * to NULL.
+ */
+
+void
+dns_adb_detach(dns_adb_t **adb);
+/*%
+ * Delete the ADB. Sets *ADB to NULL. Cancels any outstanding requests.
+ *
+ * Requires:
+ *
+ *\li 'adb' be non-NULL and '*adb' be a valid dns_adb_t, created via
+ * dns_adb_create().
+ */
+
+void
+dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp);
+/*%
+ * Send '*eventp' to 'task' when 'adb' has shutdown.
+ *
+ * Requires:
+ *
+ *\li '*adb' is a valid dns_adb_t.
+ *
+ *\li eventp != NULL && *eventp is a valid event.
+ *
+ * Ensures:
+ *
+ *\li *eventp == NULL
+ *
+ *\li The event's sender field is set to the value of adb when the event
+ * is sent.
+ */
+
+void
+dns_adb_shutdown(dns_adb_t *adb);
+/*%<
+ * Shutdown 'adb'.
+ *
+ * Requires:
+ *
+ * \li '*adb' is a valid dns_adb_t.
+ */
+
+isc_result_t
+dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
+ void *arg, dns_name_t *name, dns_name_t *qname,
+ dns_rdatatype_t qtype, unsigned int options,
+ isc_stdtime_t now, dns_name_t *target,
+ in_port_t port, dns_adbfind_t **find);
+/*%<
+ * Main interface for clients. The adb will look up the name given in
+ * "name" and will build up a list of found addresses, and perhaps start
+ * internal fetches to resolve names that are unknown currently.
+ *
+ * If other addresses resolve after this call completes, an event will
+ * be sent to the <task, taskaction, arg> with the sender of that event
+ * set to a pointer to the dns_adbfind_t returned by this function.
+ *
+ * If no events will be generated, the *find->result_v4 and/or result_v6
+ * members may be examined for address lookup status. The usual #ISC_R_SUCCESS,
+ * #ISC_R_FAILURE, and #DNS_R_NX{DOMAIN,RRSET} are returned, along with
+ * #ISC_R_NOTFOUND meaning the ADB has not _yet_ found the values. In this
+ * latter case, retrying may produce more addresses.
+ *
+ * If events will be returned, the result_v[46] members are only valid
+ * when that event is actually returned.
+ *
+ * The list of addresses returned is unordered. The caller must impose
+ * any ordering required. The list will not contain "known bad" addresses,
+ * however. For instance, it will not return hosts that are known to be
+ * lame for the zone in question.
+ *
+ * The caller cannot (directly) modify the contents of the address list's
+ * fields other than the "link" field. All values can be read at any
+ * time, however.
+ *
+ * The "now" parameter is used only for determining which entries that
+ * have a specific time to live or expire time should be removed from
+ * the running database. If specified as zero, the current time will
+ * be retrieved and used.
+ *
+ * If 'target' is not NULL and 'name' is an alias (i.e. the name is
+ * CNAME'd or DNAME'd to another name), then 'target' will be updated with
+ * the domain name that 'name' is aliased to.
+ *
+ * All addresses returned will have the sockaddr's port set to 'port.'
+ * The caller may change them directly in the dns_adbaddrinfo_t since
+ * they are copies of the internal address only.
+ *
+ * XXXMLG Document options, especially the flags which control how
+ * events are sent.
+ *
+ * Requires:
+ *
+ *\li *adb be a valid isc_adb_t object.
+ *
+ *\li If events are to be sent, *task be a valid task,
+ * and isc_taskaction_t != NULL.
+ *
+ *\li *name is a valid dns_name_t.
+ *
+ *\li qname != NULL and *qname be a valid dns_name_t.
+ *
+ *\li target == NULL or target is a valid name with a buffer.
+ *
+ *\li find != NULL && *find == NULL.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS Addresses might have been returned, and events will be
+ * delivered for unresolved addresses.
+ *\li #ISC_R_NOMORE Addresses might have been returned, but no events
+ * will ever be posted for this context. This is only
+ * returned if task != NULL.
+ *\li #ISC_R_NOMEMORY insufficient resources
+ *\li #DNS_R_ALIAS 'name' is an alias for another name.
+ *
+ * Calls, and returns error codes from:
+ *
+ *\li isc_stdtime_get()
+ *
+ * Notes:
+ *
+ *\li No internal reference to "name" exists after this function
+ * returns.
+ */
+
+void
+dns_adb_cancelfind(dns_adbfind_t *find);
+/*%<
+ * Cancels the find, and sends the event off to the caller.
+ *
+ * It is an error to call dns_adb_cancelfind() on a find where
+ * no event is wanted, or will ever be sent.
+ *
+ * Note:
+ *
+ *\li It is possible that the real completion event was posted just
+ * before the dns_adb_cancelfind() call was made. In this case,
+ * dns_adb_cancelfind() will do nothing. The event callback needs
+ * to be prepared to find this situation (i.e. result is valid but
+ * the caller expects it to be canceled).
+ *
+ * Requires:
+ *
+ *\li 'find' be a valid dns_adbfind_t pointer.
+ *
+ *\li events would have been posted to the task. This can be checked
+ * with (find->options & DNS_ADBFIND_WANTEVENT).
+ *
+ * Ensures:
+ *
+ *\li The event was posted to the task.
+ */
+
+void
+dns_adb_destroyfind(dns_adbfind_t **find);
+/*%<
+ * Destroys the find reference.
+ *
+ * Note:
+ *
+ *\li This can only be called after the event was delivered for a
+ * find. Additionally, the event MUST have been freed via
+ * isc_event_free() BEFORE this function is called.
+ *
+ * Requires:
+ *
+ *\li 'find' != NULL and *find be valid dns_adbfind_t pointer.
+ *
+ * Ensures:
+ *
+ *\li No "address found" events will be posted to the originating task
+ * after this function returns.
+ */
+
+void
+dns_adb_dump(dns_adb_t *adb, FILE *f);
+/*%<
+ * This function is only used for debugging. It will dump as much of the
+ * state of the running system as possible.
+ *
+ * Requires:
+ *
+ *\li adb be valid.
+ *
+ *\li f != NULL, and is a file open for writing.
+ */
+
+void
+dns_adb_dumpfind(dns_adbfind_t *find, FILE *f);
+/*%<
+ * This function is only used for debugging. Dump the data associated
+ * with a find.
+ *
+ * Requires:
+ *
+ *\li find is valid.
+ *
+ * \li f != NULL, and is a file open for writing.
+ */
+
+isc_result_t
+dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname,
+ dns_rdatatype_t type, isc_stdtime_t expire_time);
+/*%<
+ * Mark the given address as lame for the <qname,qtype>. expire_time should
+ * be set to the time when the entry should expire. That is, if it is to
+ * expire 10 minutes in the future, it should set it to (now + 10 * 60).
+ *
+ * Requires:
+ *
+ *\li adb be valid.
+ *
+ *\li addr be valid.
+ *
+ *\li qname be the qname used in the dns_adb_createfind() call.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS -- all is well.
+ *\li #ISC_R_NOMEMORY -- could not mark address as lame.
+ */
+
+/*
+ * A reasonable default for RTT adjustments
+ */
+#define DNS_ADB_RTTADJDEFAULT 7 /*%< default scale */
+#define DNS_ADB_RTTADJREPLACE 0 /*%< replace with our rtt */
+#define DNS_ADB_RTTADJAGE 10 /*%< age this rtt */
+
+void
+dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
+ unsigned int rtt, unsigned int factor);
+/*%<
+ * Mix the round trip time into the existing smoothed rtt.
+
+ * The formula used
+ * (where srtt is the existing rtt value, and rtt and factor are arguments to
+ * this function):
+ *
+ *\code
+ * new_srtt = (old_srtt / 10 * factor) + (rtt / 10 * (10 - factor));
+ *\endcode
+ *
+ * XXXRTH Do we want to publish the formula? What if we want to change how
+ * this works later on? Recommend/require that the units are
+ * microseconds?
+ *
+ * Requires:
+ *
+ *\li adb be valid.
+ *
+ *\li addr be valid.
+ *
+ *\li 0 <= factor <= 10
+ *
+ * Note:
+ *
+ *\li The srtt in addr will be updated to reflect the new global
+ * srtt value. This may include changes made by others.
+ */
+
+void
+dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
+ unsigned int bits, unsigned int mask);
+/*%
+ * Change Flags.
+ *
+ * Set the flags as given by:
+ *
+ *\li newflags = (oldflags & ~mask) | (bits & mask);
+ *
+ * Requires:
+ *
+ *\li adb be valid.
+ *
+ *\li addr be valid.
+ */
+
+isc_result_t
+dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
+ dns_adbaddrinfo_t **addrp, isc_stdtime_t now);
+/*%<
+ * Return a dns_adbaddrinfo_t that is associated with address 'sa'.
+ *
+ * Requires:
+ *
+ *\li adb is valid.
+ *
+ *\li sa is valid.
+ *
+ *\li addrp != NULL && *addrp == NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_SHUTTINGDOWN
+ */
+
+void
+dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp);
+/*%<
+ * Free a dns_adbaddrinfo_t allocated by dns_adb_findaddrinfo().
+ *
+ * Requires:
+ *
+ *\li adb is valid.
+ *
+ *\li *addrp is a valid dns_adbaddrinfo_t *.
+ */
+
+void
+dns_adb_flush(dns_adb_t *adb);
+/*%<
+ * Flushes all cached data from the adb.
+ *
+ * Requires:
+ *\li adb is valid.
+ */
+
+void
+dns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size);
+/*%<
+ * Set a target memory size. If memory usage exceeds the target
+ * size entries will be removed before they would have expired on
+ * a random basis.
+ *
+ * If 'size' is 0 then memory usage is unlimited.
+ *
+ * Requires:
+ *\li 'adb' is valid.
+ */
+
+void
+dns_adb_flushname(dns_adb_t *adb, dns_name_t *name);
+/*%<
+ * Flush 'name' from the adb cache.
+ *
+ * Requires:
+ *\li 'adb' is valid.
+ *\li 'name' is valid.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_ADB_H */
diff --git a/lib/dns/include/dns/bit.h b/lib/dns/include/dns/bit.h
new file mode 100644
index 0000000..770f294
--- /dev/null
+++ b/lib/dns/include/dns/bit.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2004, 2005 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: bit.h,v 1.8.18.2 2005/04/29 00:16:09 marka Exp $ */
+
+#ifndef DNS_BIT_H
+#define DNS_BIT_H 1
+
+/*! \file */
+
+#include <isc/int.h>
+#include <isc/boolean.h>
+
+typedef isc_uint64_t dns_bitset_t;
+
+#define DNS_BIT_SET(bit, bitset) \
+ (*(bitset) |= ((dns_bitset_t)1 << (bit)))
+#define DNS_BIT_CLEAR(bit, bitset) \
+ (*(bitset) &= ~((dns_bitset_t)1 << (bit)))
+#define DNS_BIT_CHECK(bit, bitset) \
+ ISC_TF((*(bitset) & ((dns_bitset_t)1 << (bit))) \
+ == ((dns_bitset_t)1 << (bit)))
+
+#endif /* DNS_BIT_H */
+
diff --git a/lib/dns/include/dns/byaddr.h b/lib/dns/include/dns/byaddr.h
new file mode 100644
index 0000000..1f1e88c
--- /dev/null
+++ b/lib/dns/include/dns/byaddr.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2004, 2005 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: byaddr.h,v 1.16.18.2 2005/04/29 00:16:09 marka Exp $ */
+
+#ifndef DNS_BYADDR_H
+#define DNS_BYADDR_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * The byaddr module provides reverse lookup services for IPv4 and IPv6
+ * addresses.
+ *
+ * MP:
+ *\li The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li RFCs: 1034, 1035, 2181, TBS
+ *\li Drafts: TBS
+ */
+
+#include <isc/lang.h>
+#include <isc/event.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * A 'dns_byaddrevent_t' is returned when a byaddr completes.
+ * The sender field will be set to the byaddr that completed. If 'result'
+ * is ISC_R_SUCCESS, then 'names' will contain a list of names associated
+ * with the address. The recipient of the event must not change the list
+ * and must not refer to any of the name data after the event is freed.
+ */
+typedef struct dns_byaddrevent {
+ ISC_EVENT_COMMON(struct dns_byaddrevent);
+ isc_result_t result;
+ dns_namelist_t names;
+} dns_byaddrevent_t;
+
+/*
+ * This option is deprecated since we now only consider nibbles.
+#define DNS_BYADDROPT_IPV6NIBBLE 0x0001
+ */
+/*% Note DNS_BYADDROPT_IPV6NIBBLE is now deprecated. */
+#define DNS_BYADDROPT_IPV6INT 0x0002
+
+isc_result_t
+dns_byaddr_create(isc_mem_t *mctx, isc_netaddr_t *address, dns_view_t *view,
+ unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg, dns_byaddr_t **byaddrp);
+/*%<
+ * Find the domain name of 'address'.
+ *
+ * Notes:
+ *
+ *\li There is a reverse lookup format for IPv6 addresses, 'nibble'
+ *
+ *\li The 'nibble' format for that address is
+ *
+ * \code
+ * 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa.
+ * \endcode
+ *
+ *\li #DNS_BYADDROPT_IPV6INT can be used to get nibble lookups under ip6.int.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid mctx.
+ *
+ *\li 'address' is a valid IPv4 or IPv6 address.
+ *
+ *\li 'view' is a valid view which has a resolver.
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li byaddrp != NULL && *byaddrp == NULL
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *
+ *\li Any resolver-related error (e.g. #ISC_R_SHUTTINGDOWN) may also be
+ * returned.
+ */
+
+void
+dns_byaddr_cancel(dns_byaddr_t *byaddr);
+/*%<
+ * Cancel 'byaddr'.
+ *
+ * Notes:
+ *
+ *\li If 'byaddr' has not completed, post its #BYADDRDONE event with a
+ * result code of #ISC_R_CANCELED.
+ *
+ * Requires:
+ *
+ *\li 'byaddr' is a valid byaddr.
+ */
+
+void
+dns_byaddr_destroy(dns_byaddr_t **byaddrp);
+/*%<
+ * Destroy 'byaddr'.
+ *
+ * Requires:
+ *
+ *\li '*byaddrp' is a valid byaddr.
+ *
+ *\li The caller has received the BYADDRDONE event (either because the
+ * byaddr completed or because dns_byaddr_cancel() was called).
+ *
+ * Ensures:
+ *
+ *\li *byaddrp == NULL.
+ */
+
+isc_result_t
+dns_byaddr_createptrname(isc_netaddr_t *address, isc_boolean_t nibble,
+ dns_name_t *name);
+
+isc_result_t
+dns_byaddr_createptrname2(isc_netaddr_t *address, unsigned int options,
+ dns_name_t *name);
+/*%<
+ * Creates a name that would be used in a PTR query for this address. The
+ * nibble flag indicates that the 'nibble' format is to be used if an IPv6
+ * address is provided, instead of the 'bitstring' format. Since we dropped
+ * the support of the bitstring labels, it is expected that the flag is always
+ * set. 'options' are the same as for dns_byaddr_create().
+ *
+ * Requires:
+ *
+ * \li 'address' is a valid address.
+ * \li 'name' is a valid name with a dedicated buffer.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_BYADDR_H */
diff --git a/lib/dns/include/dns/cache.h b/lib/dns/include/dns/cache.h
new file mode 100644
index 0000000..fc4f78e
--- /dev/null
+++ b/lib/dns/include/dns/cache.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2004, 2005 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: cache.h,v 1.19.18.3 2005/08/23 02:31:38 marka Exp $ */
+
+#ifndef DNS_CACHE_H
+#define DNS_CACHE_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Defines dns_cache_t, the cache object.
+ *
+ * Notes:
+ *\li A cache object contains DNS data of a single class.
+ * Multiple classes will be handled by creating multiple
+ * views, each with a different class and its own cache.
+ *
+ * MP:
+ *\li See notes at the individual functions.
+ *
+ * Reliability:
+ *
+ * Resources:
+ *
+ * Security:
+ *
+ * Standards:
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/stdtime.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
+ isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
+ const char *db_type, unsigned int db_argc, char **db_argv,
+ dns_cache_t **cachep);
+/*%<
+ * Create a new DNS cache.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context
+ *
+ *\li 'taskmgr' is a valid task manager and 'timermgr' is a valid timer
+ * manager, or both are NULL. If NULL, no periodic cleaning of the
+ * cache will take place.
+ *
+ *\li 'cachep' is a valid pointer, and *cachep == NULL
+ *
+ * Ensures:
+ *
+ *\li '*cachep' is attached to the newly created cache
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+void
+dns_cache_attach(dns_cache_t *cache, dns_cache_t **targetp);
+/*%<
+ * Attach *targetp to cache.
+ *
+ * Requires:
+ *
+ *\li 'cache' is a valid cache.
+ *
+ *\li 'targetp' points to a NULL dns_cache_t *.
+ *
+ * Ensures:
+ *
+ *\li *targetp is attached to cache.
+ */
+
+void
+dns_cache_detach(dns_cache_t **cachep);
+/*%<
+ * Detach *cachep from its cache.
+ *
+ * Requires:
+ *
+ *\li 'cachep' points to a valid cache.
+ *
+ * Ensures:
+ *
+ *\li *cachep is NULL.
+ *
+ *\li If '*cachep' is the last reference to the cache,
+ * all resources used by the cache will be freed
+ */
+
+void
+dns_cache_attachdb(dns_cache_t *cache, dns_db_t **dbp);
+/*%<
+ * Attach *dbp to the cache's database.
+ *
+ * Notes:
+ *
+ *\li This may be used to get a reference to the database for
+ * the purpose of cache lookups (XXX currently it is also
+ * the way to add data to the cache, but having a
+ * separate dns_cache_add() interface instead would allow
+ * more control over memory usage).
+ * The caller should call dns_db_detach() on the reference
+ * when it is no longer needed.
+ *
+ * Requires:
+ *
+ *\li 'cache' is a valid cache.
+ *
+ *\li 'dbp' points to a NULL dns_db *.
+ *
+ * Ensures:
+ *
+ *\li *dbp is attached to the database.
+ */
+
+
+isc_result_t
+dns_cache_setfilename(dns_cache_t *cache, const char *filename);
+/*%<
+ * If 'filename' is non-NULL, make the cache persistent.
+ * The cache's data will be stored in the given file.
+ * If 'filename' is NULL, make the cache non-persistent.
+ * Files that are no longer used are not unlinked automatically.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li Various file-related failures
+ */
+
+isc_result_t
+dns_cache_load(dns_cache_t *cache);
+/*%<
+ * If the cache has a file name, load the cache contents from the file.
+ * Previous cache contents are not discarded.
+ * If no file name has been set, do nothing and return success.
+ *
+ * MT:
+ *\li Multiple simultaneous attempts to load or dump the cache
+ * will be serialized with respect to one another, but
+ * the cache may be read and updated while the dump is
+ * in progress. Updates performed during loading
+ * may or may not be preserved, and reads may return
+ * either the old or the newly loaded data.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ * \li Various failures depending on the database implementation type
+ */
+
+isc_result_t
+dns_cache_dump(dns_cache_t *cache);
+/*%<
+ * If the cache has a file name, write the cache contents to disk,
+ * overwriting any preexisting file. If no file name has been set,
+ * do nothing and return success.
+ *
+ * MT:
+ *\li Multiple simultaneous attempts to load or dump the cache
+ * will be serialized with respect to one another, but
+ * the cache may be read and updated while the dump is
+ * in progress. Updates performed during the dump may
+ * or may not be reflected in the dumped file.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ * \li Various failures depending on the database implementation type
+ */
+
+isc_result_t
+dns_cache_clean(dns_cache_t *cache, isc_stdtime_t now);
+/*%<
+ * Force immediate cleaning of the cache, freeing all rdatasets
+ * whose TTL has expired as of 'now' and that have no pending
+ * references.
+ */
+
+void
+dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int interval);
+/*%<
+ * Set the periodic cache cleaning interval to 'interval' seconds.
+ */
+
+void
+dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size);
+/*%<
+ * Set the maximum cache size. 0 means unlimited.
+ */
+
+isc_result_t
+dns_cache_flush(dns_cache_t *cache);
+/*%<
+ * Flushes all data from the cache.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_cache_flushname(dns_cache_t *cache, dns_name_t *name);
+/*
+ * Flushes a given name from the cache.
+ *
+ * Requires:
+ *\li 'cache' to be valid.
+ *\li 'name' to be valid.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li other error returns.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_CACHE_H */
diff --git a/lib/dns/include/dns/callbacks.h b/lib/dns/include/dns/callbacks.h
new file mode 100644
index 0000000..6aee70b
--- /dev/null
+++ b/lib/dns/include/dns/callbacks.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2004, 2005 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: callbacks.h,v 1.18.18.2 2005/04/29 00:16:10 marka Exp $ */
+
+#ifndef DNS_CALLBACKS_H
+#define DNS_CALLBACKS_H 1
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+struct dns_rdatacallbacks {
+ /*%
+ * dns_load_master calls this when it has rdatasets to commit.
+ */
+ dns_addrdatasetfunc_t add;
+ /*%
+ * dns_load_master / dns_rdata_fromtext call this to issue a error.
+ */
+ void (*error)(struct dns_rdatacallbacks *, const char *, ...);
+ /*%
+ * dns_load_master / dns_rdata_fromtext call this to issue a warning.
+ */
+ void (*warn)(struct dns_rdatacallbacks *, const char *, ...);
+ /*%
+ * Private data handles for use by the above callback functions.
+ */
+ void *add_private;
+ void *error_private;
+ void *warn_private;
+};
+
+/***
+ *** Initialization
+ ***/
+
+void
+dns_rdatacallbacks_init(dns_rdatacallbacks_t *callbacks);
+/*%<
+ * Initialize 'callbacks'.
+ *
+ *
+ * \li 'error' and 'warn' are set to default callbacks that print the
+ * error message through the DNS library log context.
+ *
+ *\li All other elements are initialized to NULL.
+ *
+ * Requires:
+ * \li 'callbacks' is a valid dns_rdatacallbacks_t,
+ */
+
+void
+dns_rdatacallbacks_init_stdio(dns_rdatacallbacks_t *callbacks);
+/*%<
+ * Like dns_rdatacallbacks_init, but logs to stdio.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_CALLBACKS_H */
diff --git a/lib/dns/include/dns/cert.h b/lib/dns/include/dns/cert.h
new file mode 100644
index 0000000..4de1aec
--- /dev/null
+++ b/lib/dns/include/dns/cert.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2004, 2005 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: cert.h,v 1.13.18.2 2005/04/29 00:16:10 marka Exp $ */
+
+#ifndef DNS_CERT_H
+#define DNS_CERT_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_cert_fromtext(dns_cert_t *certp, isc_textregion_t *source);
+/*%<
+ * Convert the text 'source' refers to into a certificate type.
+ * The text may contain either a mnemonic type name or a decimal type number.
+ *
+ * Requires:
+ *\li 'certp' is a valid pointer.
+ *
+ *\li 'source' is a valid text region.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS on success
+ *\li #ISC_R_RANGE numeric type is out of range
+ *\li #DNS_R_UNKNOWN mnemonic type is unknown
+ */
+
+isc_result_t
+dns_cert_totext(dns_cert_t cert, isc_buffer_t *target);
+/*%<
+ * Put a textual representation of certificate type 'cert' into 'target'.
+ *
+ * Requires:
+ *\li 'cert' is a valid cert.
+ *
+ *\li 'target' is a valid text buffer.
+ *
+ * Ensures:
+ *\li If the result is success:
+ * The used space in 'target' is updated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS on success
+ *\li #ISC_R_NOSPACE target buffer is too small
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_CERT_H */
diff --git a/lib/dns/include/dns/compress.h b/lib/dns/include/dns/compress.h
new file mode 100644
index 0000000..4d9c011
--- /dev/null
+++ b/lib/dns/include/dns/compress.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2004-2006 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: compress.h,v 1.32.18.6 2006/03/02 00:37:21 marka Exp $ */
+
+#ifndef DNS_COMPRESS_H
+#define DNS_COMPRESS_H 1
+
+#include <isc/lang.h>
+#include <isc/region.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+#define DNS_COMPRESS_NONE 0x00 /*%< no compression */
+#define DNS_COMPRESS_GLOBAL14 0x01 /*%< "normal" compression. */
+#define DNS_COMPRESS_ALL 0x01 /*%< all compression. */
+#define DNS_COMPRESS_CASESENSITIVE 0x02 /*%< case sensitive compression. */
+
+/*! \file
+ * Direct manipulation of the structures is strongly discouraged.
+ */
+
+#define DNS_COMPRESS_TABLESIZE 64
+#define DNS_COMPRESS_INITIALNODES 16
+
+typedef struct dns_compressnode dns_compressnode_t;
+
+struct dns_compressnode {
+ isc_region_t r;
+ isc_uint16_t offset;
+ isc_uint16_t count;
+ isc_uint8_t labels;
+ dns_compressnode_t *next;
+};
+
+struct dns_compress {
+ unsigned int magic; /*%< Magic number. */
+ unsigned int allowed; /*%< Allowed methods. */
+ int edns; /*%< Edns version or -1. */
+ /*% Global compression table. */
+ dns_compressnode_t *table[DNS_COMPRESS_TABLESIZE];
+ /*% Preallocated nodes for the table. */
+ dns_compressnode_t initialnodes[DNS_COMPRESS_INITIALNODES];
+ isc_uint16_t count; /*%< Number of nodes. */
+ isc_mem_t *mctx; /*%< Memory context. */
+};
+
+typedef enum {
+ DNS_DECOMPRESS_ANY, /*%< Any compression */
+ DNS_DECOMPRESS_STRICT, /*%< Allowed compression */
+ DNS_DECOMPRESS_NONE /*%< No compression */
+} dns_decompresstype_t;
+
+struct dns_decompress {
+ unsigned int magic; /*%< Magic number. */
+ unsigned int allowed; /*%< Allowed methods. */
+ int edns; /*%< Edns version or -1. */
+ dns_decompresstype_t type; /*%< Strict checking */
+};
+
+isc_result_t
+dns_compress_init(dns_compress_t *cctx, int edns, isc_mem_t *mctx);
+/*%<
+ * Inialise the compression context structure pointed to by 'cctx'.
+ *
+ * Requires:
+ * \li 'cctx' is a valid dns_compress_t structure.
+ * \li 'mctx' is an initialized memory context.
+ * Ensures:
+ * \li cctx->global is initialized.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li failures from dns_rbt_create()
+ */
+
+void
+dns_compress_invalidate(dns_compress_t *cctx);
+
+/*%<
+ * Invalidate the compression structure pointed to by cctx.
+ *
+ * Requires:
+ *\li 'cctx' to be initialized.
+ */
+
+void
+dns_compress_setmethods(dns_compress_t *cctx, unsigned int allowed);
+
+/*%<
+ * Sets allowed compression methods.
+ *
+ * Requires:
+ *\li 'cctx' to be initialized.
+ */
+
+unsigned int
+dns_compress_getmethods(dns_compress_t *cctx);
+
+/*%<
+ * Gets allowed compression methods.
+ *
+ * Requires:
+ *\li 'cctx' to be initialized.
+ *
+ * Returns:
+ *\li allowed compression bitmap.
+ */
+
+void
+dns_compress_setsensitive(dns_compress_t *cctx, isc_boolean_t sensitive);
+
+/*
+ * Preserve the case of compressed domain names.
+ *
+ * Requires:
+ * 'cctx' to be initialized.
+ */
+
+isc_boolean_t
+dns_compress_getsensitive(dns_compress_t *cctx);
+/*
+ * Return whether case is to be preservered when compressing
+ * domain names.
+ *
+ * Requires:
+ * 'cctx' to be initialized.
+ */
+
+int
+dns_compress_getedns(dns_compress_t *cctx);
+
+/*%<
+ * Gets edns value.
+ *
+ * Requires:
+ *\li 'cctx' to be initialized.
+ *
+ * Returns:
+ *\li -1 .. 255
+ */
+
+isc_boolean_t
+dns_compress_findglobal(dns_compress_t *cctx, const dns_name_t *name,
+ dns_name_t *prefix, isc_uint16_t *offset);
+/*%<
+ * Finds longest possible match of 'name' in the global compression table.
+ *
+ * Requires:
+ *\li 'cctx' to be initialized.
+ *\li 'name' to be a absolute name.
+ *\li 'prefix' to be initialized.
+ *\li 'offset' to point to an isc_uint16_t.
+ *
+ * Ensures:
+ *\li 'prefix' and 'offset' are valid if ISC_TRUE is returned.
+ *
+ * Returns:
+ *\li #ISC_TRUE / #ISC_FALSE
+ */
+
+void
+dns_compress_add(dns_compress_t *cctx, const dns_name_t *name,
+ const dns_name_t *prefix, isc_uint16_t offset);
+/*%<
+ * Add compression pointers for 'name' to the compression table,
+ * not replacing existing pointers.
+ *
+ * Requires:
+ *\li 'cctx' initialized
+ *
+ *\li 'name' must be initialized and absolute, and must remain
+ * valid until the message compression is complete.
+ *
+ *\li 'prefix' must be a prefix returned by
+ * dns_compress_findglobal(), or the same as 'name'.
+ */
+
+void
+dns_compress_rollback(dns_compress_t *cctx, isc_uint16_t offset);
+
+/*%<
+ * Remove any compression pointers from global table >= offset.
+ *
+ * Requires:
+ *\li 'cctx' is initialized.
+ */
+
+void
+dns_decompress_init(dns_decompress_t *dctx, int edns,
+ dns_decompresstype_t type);
+
+/*%<
+ * Initializes 'dctx'.
+ * Records 'edns' and 'type' into the structure.
+ *
+ * Requires:
+ *\li 'dctx' to be a valid pointer.
+ */
+
+void
+dns_decompress_invalidate(dns_decompress_t *dctx);
+
+/*%<
+ * Invalidates 'dctx'.
+ *
+ * Requires:
+ *\li 'dctx' to be initialized
+ */
+
+void
+dns_decompress_setmethods(dns_decompress_t *dctx, unsigned int allowed);
+
+/*%<
+ * Sets 'dctx->allowed' to 'allowed'.
+ *
+ * Requires:
+ *\li 'dctx' to be initialized
+ */
+
+unsigned int
+dns_decompress_getmethods(dns_decompress_t *dctx);
+
+/*%<
+ * Returns 'dctx->allowed'
+ *
+ * Requires:
+ *\li 'dctx' to be initialized
+ */
+
+int
+dns_decompress_edns(dns_decompress_t *dctx);
+
+/*%<
+ * Returns 'dctx->edns'
+ *
+ * Requires:
+ *\li 'dctx' to be initialized
+ */
+
+dns_decompresstype_t
+dns_decompress_type(dns_decompress_t *dctx);
+
+/*%<
+ * Returns 'dctx->type'
+ *
+ * Requires:
+ *\li 'dctx' to be initialized
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_COMPRESS_H */
diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h
new file mode 100644
index 0000000..b03ae57
--- /dev/null
+++ b/lib/dns/include/dns/db.h
@@ -0,0 +1,1299 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: db.h,v 1.76.18.10 2007/08/28 07:20:05 tbox Exp $ */
+
+#ifndef DNS_DB_H
+#define DNS_DB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * The DNS DB interface allows named rdatasets to be stored and retrieved.
+ *
+ * The dns_db_t type is like a "virtual class". To actually use
+ * DBs, an implementation of the class is required.
+ *
+ * XXX more XXX
+ *
+ * MP:
+ * \li The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ *
+ * Reliability:
+ * \li No anticipated impact.
+ *
+ * Resources:
+ * \li TBS
+ *
+ * Security:
+ * \li No anticipated impact.
+ *
+ * Standards:
+ * \li None.
+ */
+
+/*****
+ ***** Imports
+ *****/
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/ondestroy.h>
+#include <isc/stdtime.h>
+
+#include <dns/name.h>
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Types
+ *****/
+
+typedef struct dns_dbmethods {
+ void (*attach)(dns_db_t *source, dns_db_t **targetp);
+ void (*detach)(dns_db_t **dbp);
+ isc_result_t (*beginload)(dns_db_t *db, dns_addrdatasetfunc_t *addp,
+ dns_dbload_t **dbloadp);
+ isc_result_t (*endload)(dns_db_t *db, dns_dbload_t **dbloadp);
+ isc_result_t (*dump)(dns_db_t *db, dns_dbversion_t *version,
+ const char *filename,
+ dns_masterformat_t masterformat);
+ void (*currentversion)(dns_db_t *db,
+ dns_dbversion_t **versionp);
+ isc_result_t (*newversion)(dns_db_t *db,
+ dns_dbversion_t **versionp);
+ void (*attachversion)(dns_db_t *db, dns_dbversion_t *source,
+ dns_dbversion_t **targetp);
+ void (*closeversion)(dns_db_t *db,
+ dns_dbversion_t **versionp,
+ isc_boolean_t commit);
+ isc_result_t (*findnode)(dns_db_t *db, dns_name_t *name,
+ isc_boolean_t create,
+ dns_dbnode_t **nodep);
+ isc_result_t (*find)(dns_db_t *db, dns_name_t *name,
+ dns_dbversion_t *version,
+ dns_rdatatype_t type, unsigned int options,
+ isc_stdtime_t now,
+ dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset);
+ isc_result_t (*findzonecut)(dns_db_t *db, dns_name_t *name,
+ unsigned int options, isc_stdtime_t now,
+ dns_dbnode_t **nodep,
+ dns_name_t *foundname,
+ dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset);
+ void (*attachnode)(dns_db_t *db,
+ dns_dbnode_t *source,
+ dns_dbnode_t **targetp);
+ void (*detachnode)(dns_db_t *db,
+ dns_dbnode_t **targetp);
+ isc_result_t (*expirenode)(dns_db_t *db, dns_dbnode_t *node,
+ isc_stdtime_t now);
+ void (*printnode)(dns_db_t *db, dns_dbnode_t *node,
+ FILE *out);
+ isc_result_t (*createiterator)(dns_db_t *db,
+ isc_boolean_t relative_names,
+ dns_dbiterator_t **iteratorp);
+ isc_result_t (*findrdataset)(dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version,
+ dns_rdatatype_t type,
+ dns_rdatatype_t covers,
+ isc_stdtime_t now,
+ dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset);
+ isc_result_t (*allrdatasets)(dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version,
+ isc_stdtime_t now,
+ dns_rdatasetiter_t **iteratorp);
+ isc_result_t (*addrdataset)(dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version,
+ isc_stdtime_t now,
+ dns_rdataset_t *rdataset,
+ unsigned int options,
+ dns_rdataset_t *addedrdataset);
+ isc_result_t (*subtractrdataset)(dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version,
+ dns_rdataset_t *rdataset,
+ unsigned int options,
+ dns_rdataset_t *newrdataset);
+ isc_result_t (*deleterdataset)(dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version,
+ dns_rdatatype_t type,
+ dns_rdatatype_t covers);
+ isc_boolean_t (*issecure)(dns_db_t *db);
+ unsigned int (*nodecount)(dns_db_t *db);
+ isc_boolean_t (*ispersistent)(dns_db_t *db);
+ void (*overmem)(dns_db_t *db, isc_boolean_t overmem);
+ void (*settask)(dns_db_t *db, isc_task_t *);
+ isc_result_t (*getoriginnode)(dns_db_t *db, dns_dbnode_t **nodep);
+} dns_dbmethods_t;
+
+typedef isc_result_t
+(*dns_dbcreatefunc_t)(isc_mem_t *mctx, dns_name_t *name,
+ dns_dbtype_t type, dns_rdataclass_t rdclass,
+ unsigned int argc, char *argv[], void *driverarg,
+ dns_db_t **dbp);
+
+#define DNS_DB_MAGIC ISC_MAGIC('D','N','S','D')
+#define DNS_DB_VALID(db) ISC_MAGIC_VALID(db, DNS_DB_MAGIC)
+
+/*%
+ * This structure is actually just the common prefix of a DNS db
+ * implementation's version of a dns_db_t.
+ * \brief
+ * Direct use of this structure by clients is forbidden. DB implementations
+ * may change the structure. 'magic' must be DNS_DB_MAGIC for any of the
+ * dns_db_ routines to work. DB implementations must maintain all DB
+ * invariants.
+ */
+struct dns_db {
+ unsigned int magic;
+ unsigned int impmagic;
+ dns_dbmethods_t * methods;
+ isc_uint16_t attributes;
+ dns_rdataclass_t rdclass;
+ dns_name_t origin;
+ isc_ondestroy_t ondest;
+ isc_mem_t * mctx;
+};
+
+#define DNS_DBATTR_CACHE 0x01
+#define DNS_DBATTR_STUB 0x02
+
+/*@{*/
+/*%
+ * Options that can be specified for dns_db_find().
+ */
+#define DNS_DBFIND_GLUEOK 0x01
+#define DNS_DBFIND_VALIDATEGLUE 0x02
+#define DNS_DBFIND_NOWILD 0x04
+#define DNS_DBFIND_PENDINGOK 0x08
+#define DNS_DBFIND_NOEXACT 0x10
+#define DNS_DBFIND_FORCENSEC 0x20
+#define DNS_DBFIND_COVERINGNSEC 0x40
+/*@}*/
+
+/*@{*/
+/*%
+ * Options that can be specified for dns_db_addrdataset().
+ */
+#define DNS_DBADD_MERGE 0x01
+#define DNS_DBADD_FORCE 0x02
+#define DNS_DBADD_EXACT 0x04
+#define DNS_DBADD_EXACTTTL 0x08
+/*@}*/
+
+/*%
+ * Options that can be specified for dns_db_subtractrdataset().
+ */
+#define DNS_DBSUB_EXACT 0x01
+
+/*****
+ ***** Methods
+ *****/
+
+/***
+ *** Basic DB Methods
+ ***/
+
+isc_result_t
+dns_db_create(isc_mem_t *mctx, const char *db_type, dns_name_t *origin,
+ dns_dbtype_t type, dns_rdataclass_t rdclass,
+ unsigned int argc, char *argv[], dns_db_t **dbp);
+/*%<
+ * Create a new database using implementation 'db_type'.
+ *
+ * Notes:
+ * \li All names in the database must be subdomains of 'origin' and in class
+ * 'rdclass'. The database makes its own copy of the origin, so the
+ * caller may do whatever they like with 'origin' and its storage once the
+ * call returns.
+ *
+ * \li DB implementation-specific parameters are passed using argc and argv.
+ *
+ * Requires:
+ *
+ * \li dbp != NULL and *dbp == NULL
+ *
+ * \li 'origin' is a valid absolute domain name.
+ *
+ * \li mctx is a valid memory context
+ *
+ * Ensures:
+ *
+ * \li A copy of 'origin' has been made for the databases use, and the
+ * caller is free to do whatever they want with the name and storage
+ * associated with 'origin'.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ * \li #ISC_R_NOTFOUND db_type not found
+ *
+ * \li Many other errors are possible, depending on what db_type was
+ * specified.
+ */
+
+void
+dns_db_attach(dns_db_t *source, dns_db_t **targetp);
+/*%<
+ * Attach *targetp to source.
+ *
+ * Requires:
+ *
+ * \li 'source' is a valid database.
+ *
+ * \li 'targetp' points to a NULL dns_db_t *.
+ *
+ * Ensures:
+ *
+ * \li *targetp is attached to source.
+ */
+
+void
+dns_db_detach(dns_db_t **dbp);
+/*%<
+ * Detach *dbp from its database.
+ *
+ * Requires:
+ *
+ * \li 'dbp' points to a valid database.
+ *
+ * Ensures:
+ *
+ * \li *dbp is NULL.
+ *
+ * \li If '*dbp' is the last reference to the database,
+ * all resources used by the database will be freed
+ */
+
+isc_result_t
+dns_db_ondestroy(dns_db_t *db, isc_task_t *task, isc_event_t **eventp);
+/*%<
+ * Causes 'eventp' to be sent to be sent to 'task' when the database is
+ * destroyed.
+ *
+ * Note; ownership of the eventp is taken from the caller (and *eventp is
+ * set to NULL). The sender field of the event is set to 'db' before it is
+ * sent to the task.
+ */
+
+isc_boolean_t
+dns_db_iscache(dns_db_t *db);
+/*%<
+ * Does 'db' have cache semantics?
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * Returns:
+ * \li #ISC_TRUE 'db' has cache semantics
+ * \li #ISC_FALSE otherwise
+ */
+
+isc_boolean_t
+dns_db_iszone(dns_db_t *db);
+/*%<
+ * Does 'db' have zone semantics?
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * Returns:
+ * \li #ISC_TRUE 'db' has zone semantics
+ * \li #ISC_FALSE otherwise
+ */
+
+isc_boolean_t
+dns_db_isstub(dns_db_t *db);
+/*%<
+ * Does 'db' have stub semantics?
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * Returns:
+ * \li #ISC_TRUE 'db' has zone semantics
+ * \li #ISC_FALSE otherwise
+ */
+
+isc_boolean_t
+dns_db_issecure(dns_db_t *db);
+/*%<
+ * Is 'db' secure?
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database with zone semantics.
+ *
+ * Returns:
+ * \li #ISC_TRUE 'db' is secure.
+ * \li #ISC_FALSE 'db' is not secure.
+ */
+
+dns_name_t *
+dns_db_origin(dns_db_t *db);
+/*%<
+ * The origin of the database.
+ *
+ * Note: caller must not try to change this name.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * Returns:
+ *
+ * \li The origin of the database.
+ */
+
+dns_rdataclass_t
+dns_db_class(dns_db_t *db);
+/*%<
+ * The class of the database.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * Returns:
+ *
+ * \li The class of the database.
+ */
+
+isc_result_t
+dns_db_beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp,
+ dns_dbload_t **dbloadp);
+/*%<
+ * Begin loading 'db'.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li This is the first attempt to load 'db'.
+ *
+ * \li addp != NULL && *addp == NULL
+ *
+ * \li dbloadp != NULL && *dbloadp == NULL
+ *
+ * Ensures:
+ *
+ * \li On success, *addp will be a valid dns_addrdatasetfunc_t suitable
+ * for loading 'db'. *dbloadp will be a valid DB load context which
+ * should be used as 'arg' when *addp is called.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used, syntax errors in the master file, etc.
+ */
+
+isc_result_t
+dns_db_endload(dns_db_t *db, dns_dbload_t **dbloadp);
+/*%<
+ * Finish loading 'db'.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database that is being loaded.
+ *
+ * \li dbloadp != NULL and *dbloadp is a valid database load context.
+ *
+ * Ensures:
+ *
+ * \li *dbloadp == NULL
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used, syntax errors in the master file, etc.
+ */
+
+isc_result_t
+dns_db_load(dns_db_t *db, const char *filename);
+
+isc_result_t
+dns_db_load2(dns_db_t *db, const char *filename, dns_masterformat_t format);
+/*%<
+ * Load master file 'filename' into 'db'.
+ *
+ * Notes:
+ * \li This routine is equivalent to calling
+ *
+ *\code
+ * dns_db_beginload();
+ * dns_master_loadfile();
+ * dns_db_endload();
+ *\endcode
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li This is the first attempt to load 'db'.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used, syntax errors in the master file, etc.
+ */
+
+isc_result_t
+dns_db_dump(dns_db_t *db, dns_dbversion_t *version, const char *filename);
+
+isc_result_t
+dns_db_dump2(dns_db_t *db, dns_dbversion_t *version, const char *filename,
+ dns_masterformat_t masterformat);
+/*%<
+ * Dump version 'version' of 'db' to master file 'filename'.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'version' is a valid version.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used, OS file errors, etc.
+ */
+
+/***
+ *** Version Methods
+ ***/
+
+void
+dns_db_currentversion(dns_db_t *db, dns_dbversion_t **versionp);
+/*%<
+ * Open the current version for reading.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database with zone semantics.
+ *
+ * \li versionp != NULL && *verisonp == NULL
+ *
+ * Ensures:
+ *
+ * \li On success, '*versionp' is attached to the current version.
+ *
+ */
+
+isc_result_t
+dns_db_newversion(dns_db_t *db, dns_dbversion_t **versionp);
+/*%<
+ * Open a new version for reading and writing.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database with zone semantics.
+ *
+ * \li versionp != NULL && *verisonp == NULL
+ *
+ * Ensures:
+ *
+ * \li On success, '*versionp' is attached to the current version.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used.
+ */
+
+void
+dns_db_attachversion(dns_db_t *db, dns_dbversion_t *source,
+ dns_dbversion_t **targetp);
+/*%<
+ * Attach '*targetp' to 'source'.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database with zone semantics.
+ *
+ * \li source is a valid open version
+ *
+ * \li targetp != NULL && *targetp == NULL
+ *
+ * Ensures:
+ *
+ * \li '*targetp' is attached to source.
+ */
+
+void
+dns_db_closeversion(dns_db_t *db, dns_dbversion_t **versionp,
+ isc_boolean_t commit);
+/*%<
+ * Close version '*versionp'.
+ *
+ * Note: if '*versionp' is a read-write version and 'commit' is ISC_TRUE,
+ * then all changes made in the version will take effect, otherwise they
+ * will be rolled back. The value if 'commit' is ignored for read-only
+ * versions.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database with zone semantics.
+ *
+ * \li '*versionp' refers to a valid version.
+ *
+ * \li If committing a writable version, then there must be no other
+ * outstanding references to the version (e.g. an active rdataset
+ * iterator).
+ *
+ * Ensures:
+ *
+ * \li *versionp == NULL
+ *
+ * \li If *versionp is a read-write version, and commit is ISC_TRUE, then
+ * the version will become the current version. If !commit, then all
+ * changes made in the version will be undone, and the version will
+ * not become the current version.
+ */
+
+/***
+ *** Node Methods
+ ***/
+
+isc_result_t
+dns_db_findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
+ dns_dbnode_t **nodep);
+/*%<
+ * Find the node with name 'name'.
+ *
+ * Notes:
+ * \li If 'create' is ISC_TRUE and no node with name 'name' exists, then
+ * such a node will be created.
+ *
+ * \li This routine is for finding or creating a node with the specified
+ * name. There are no partial matches. It is not suitable for use
+ * in building responses to ordinary DNS queries; clients which wish
+ * to do that should use dns_db_find() instead.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'name' is a valid, non-empty, absolute name.
+ *
+ * \li nodep != NULL && *nodep == NULL
+ *
+ * Ensures:
+ *
+ * \li On success, *nodep is attached to the node with name 'name'.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND If !create and name not found.
+ * \li #ISC_R_NOMEMORY Can only happen if create is ISC_TRUE.
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used.
+ */
+
+isc_result_t
+dns_db_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
+ dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
+ dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
+/*%<
+ * Find the best match for 'name' and 'type' in version 'version' of 'db'.
+ *
+ * Notes:
+ *
+ * \li If type == dns_rdataset_any, then rdataset will not be bound.
+ *
+ * \li If 'options' does not have #DNS_DBFIND_GLUEOK set, then no glue will
+ * be returned. For zone databases, glue is as defined in RFC2181.
+ * For cache databases, glue is any rdataset with a trust of
+ * dns_trust_glue.
+ *
+ * \li If 'options' does not have #DNS_DBFIND_PENDINGOK set, then no
+ * pending data will be returned. This option is only meaningful for
+ * cache databases.
+ *
+ * \li If the #DNS_DBFIND_NOWILD option is set, then wildcard matching will
+ * be disabled. This option is only meaningful for zone databases.
+ *
+ * \li If the #DNS_DBFIND_FORCENSEC option is set, the database is assumed to
+ * have NSEC records, and these will be returned when appropriate. This
+ * is only necessary when querying a database that was not secure
+ * when created.
+ *
+ * \li If the DNS_DBFIND_COVERINGNSEC option is set, then look for a
+ * NSEC record that potentially covers 'name' if a answer cannot
+ * be found. Note the returned NSEC needs to be checked to ensure
+ * that it is correct. This only affects answers returned from the
+ * cache.
+ *
+ * \li To respond to a query for SIG records, the caller should create a
+ * rdataset iterator and extract the signatures from each rdataset.
+ *
+ * \li Making queries of type ANY with #DNS_DBFIND_GLUEOK is not recommended,
+ * because the burden of determining whether a given rdataset is valid
+ * glue or not falls upon the caller.
+ *
+ * \li The 'now' field is ignored if 'db' is a zone database. If 'db' is a
+ * cache database, an rdataset will not be found unless it expires after
+ * 'now'. Any ANY query will not match unless at least one rdataset at
+ * the node expires after 'now'. If 'now' is zero, then the current time
+ * will be used.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'type' is not SIG, or a meta-RR type other than 'ANY' (e.g. 'OPT').
+ *
+ * \li 'nodep' is NULL, or nodep is a valid pointer and *nodep == NULL.
+ *
+ * \li 'foundname' is a valid name with a dedicated buffer.
+ *
+ * \li 'rdataset' is NULL, or is a valid unassociated rdataset.
+ *
+ * Ensures,
+ * on a non-error completion:
+ *
+ * \li If nodep != NULL, then it is bound to the found node.
+ *
+ * \li If foundname != NULL, then it contains the full name of the
+ * found node.
+ *
+ * \li If rdataset != NULL and type != dns_rdatatype_any, then
+ * rdataset is bound to the found rdataset.
+ *
+ * Non-error results are:
+ *
+ * \li #ISC_R_SUCCESS The desired node and type were
+ * found.
+ *
+ * \li #DNS_R_WILDCARD The desired node and type were
+ * found after performing
+ * wildcard matching. This is
+ * only returned if the
+ * #DNS_DBFIND_INDICATEWILD
+ * option is set; otherwise
+ * #ISC_R_SUCCESS is returned.
+ *
+ * \li #DNS_R_GLUE The desired node and type were
+ * found, but are glue. This
+ * result can only occur if
+ * the DNS_DBFIND_GLUEOK option
+ * is set. This result can only
+ * occur if 'db' is a zone
+ * database. If type ==
+ * dns_rdatatype_any, then the
+ * node returned may contain, or
+ * consist entirely of invalid
+ * glue (i.e. data occluded by a
+ * zone cut). The caller must
+ * take care not to return invalid
+ * glue to a client.
+ *
+ * \li #DNS_R_DELEGATION The data requested is beneath
+ * a zone cut. node, foundname,
+ * and rdataset reference the
+ * NS RRset of the zone cut.
+ * If 'db' is a cache database,
+ * then this is the deepest known
+ * delegation.
+ *
+ * \li #DNS_R_ZONECUT type == dns_rdatatype_any, and
+ * the desired node is a zonecut.
+ * The caller must take care not
+ * to return inappropriate glue
+ * to a client. This result can
+ * only occur if 'db' is a zone
+ * database and DNS_DBFIND_GLUEOK
+ * is set.
+ *
+ * \li #DNS_R_DNAME The data requested is beneath
+ * a DNAME. node, foundname,
+ * and rdataset reference the
+ * DNAME RRset.
+ *
+ * \li #DNS_R_CNAME The rdataset requested was not
+ * found, but there is a CNAME
+ * at the desired name. node,
+ * foundname, and rdataset
+ * reference the CNAME RRset.
+ *
+ * \li #DNS_R_NXDOMAIN The desired name does not
+ * exist.
+ *
+ * \li #DNS_R_NXRRSET The desired name exists, but
+ * the desired type does not.
+ *
+ * \li #ISC_R_NOTFOUND The desired name does not
+ * exist, and no delegation could
+ * be found. This result can only
+ * occur if 'db' is a cache
+ * database. The caller should
+ * use its nameserver(s) of last
+ * resort (e.g. root hints).
+ *
+ * \li #DNS_R_NCACHENXDOMAIN The desired name does not
+ * exist. 'node' is bound to the
+ * cache node with the desired
+ * name, and 'rdataset' contains
+ * the negative caching proof.
+ *
+ * \li #DNS_R_NCACHENXRRSET The desired type does not
+ * exist. 'node' is bound to the
+ * cache node with the desired
+ * name, and 'rdataset' contains
+ * the negative caching proof.
+ *
+ * \li #DNS_R_EMPTYNAME The name exists but there is
+ * no data at the name.
+ *
+ * \li #DNS_R_COVERINGNSEC The returned data is a NSEC
+ * that potentially covers 'name'.
+ *
+ * Error results:
+ *
+ * \li #ISC_R_NOMEMORY
+ *
+ * \li #DNS_R_BADDB Data that is required to be
+ * present in the DB, e.g. an NSEC
+ * record in a secure zone, is not
+ * present.
+ *
+ * \li Other results are possible, and should all be treated as
+ * errors.
+ */
+
+isc_result_t
+dns_db_findzonecut(dns_db_t *db, dns_name_t *name,
+ unsigned int options, isc_stdtime_t now,
+ dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
+/*%<
+ * Find the deepest known zonecut which encloses 'name' in 'db'.
+ *
+ * Notes:
+ *
+ * \li If the #DNS_DBFIND_NOEXACT option is set, then the zonecut returned
+ * (if any) will be the deepest known ancestor of 'name'.
+ *
+ * \li If 'now' is zero, then the current time will be used.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database with cache semantics.
+ *
+ * \li 'nodep' is NULL, or nodep is a valid pointer and *nodep == NULL.
+ *
+ * \li 'foundname' is a valid name with a dedicated buffer.
+ *
+ * \li 'rdataset' is NULL, or is a valid unassociated rdataset.
+ *
+ * Ensures, on a non-error completion:
+ *
+ * \li If nodep != NULL, then it is bound to the found node.
+ *
+ * \li If foundname != NULL, then it contains the full name of the
+ * found node.
+ *
+ * \li If rdataset != NULL and type != dns_rdatatype_any, then
+ * rdataset is bound to the found rdataset.
+ *
+ * Non-error results are:
+ *
+ * \li #ISC_R_SUCCESS
+ *
+ * \li #ISC_R_NOTFOUND
+ *
+ * \li Other results are possible, and should all be treated as
+ * errors.
+ */
+
+void
+dns_db_attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp);
+/*%<
+ * Attach *targetp to source.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'source' is a valid node.
+ *
+ * \li 'targetp' points to a NULL dns_dbnode_t *.
+ *
+ * Ensures:
+ *
+ * \li *targetp is attached to source.
+ */
+
+void
+dns_db_detachnode(dns_db_t *db, dns_dbnode_t **nodep);
+/*%<
+ * Detach *nodep from its node.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'nodep' points to a valid node.
+ *
+ * Ensures:
+ *
+ * \li *nodep is NULL.
+ */
+
+isc_result_t
+dns_db_expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now);
+/*%<
+ * Mark as stale all records at 'node' which expire at or before 'now'.
+ *
+ * Note: if 'now' is zero, then the current time will be used.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid cache database.
+ *
+ * \li 'node' is a valid node.
+ */
+
+void
+dns_db_printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out);
+/*%<
+ * Print a textual representation of the contents of the node to
+ * 'out'.
+ *
+ * Note: this function is intended for debugging, not general use.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'node' is a valid node.
+ */
+
+/***
+ *** DB Iterator Creation
+ ***/
+
+isc_result_t
+dns_db_createiterator(dns_db_t *db, isc_boolean_t relative_names,
+ dns_dbiterator_t **iteratorp);
+/*%<
+ * Create an iterator for version 'version' of 'db'.
+ *
+ * Notes:
+ *
+ * \li If 'relative_names' is ISC_TRUE, then node names returned by the
+ * iterator will be relative to the iterator's current origin. If
+ * #ISC_FALSE, then the node names will be absolute.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li iteratorp != NULL && *iteratorp == NULL
+ *
+ * Ensures:
+ *
+ * \li On success, *iteratorp will be a valid database iterator.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ */
+
+/***
+ *** Rdataset Methods
+ ***/
+
+/*
+ * XXXRTH Should we check for glue and pending data in dns_db_findrdataset()?
+ */
+
+isc_result_t
+dns_db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers,
+ isc_stdtime_t now, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset);
+/*%<
+ * Search for an rdataset of type 'type' at 'node' that are in version
+ * 'version' of 'db'. If found, make 'rdataset' refer to it.
+ *
+ * Notes:
+ *
+ * \li If 'version' is NULL, then the current version will be used.
+ *
+ * \li Care must be used when using this routine to build a DNS response:
+ * 'node' should have been found with dns_db_find(), not
+ * dns_db_findnode(). No glue checking is done. No checking for
+ * pending data is done.
+ *
+ * \li The 'now' field is ignored if 'db' is a zone database. If 'db' is a
+ * cache database, an rdataset will not be found unless it expires after
+ * 'now'. If 'now' is zero, then the current time will be used.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'node' is a valid node.
+ *
+ * \li 'rdataset' is a valid, disassociated rdataset.
+ *
+ * \li 'sigrdataset' is a valid, disassociated rdataset, or it is NULL.
+ *
+ * \li If 'covers' != 0, 'type' must be SIG.
+ *
+ * \li 'type' is not a meta-RR type such as 'ANY' or 'OPT'.
+ *
+ * Ensures:
+ *
+ * \li On success, 'rdataset' is associated with the found rdataset.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used.
+ */
+
+isc_result_t
+dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdatasetiter_t **iteratorp);
+/*%<
+ * Make '*iteratorp' an rdataset iteratator for all rdatasets at 'node' in
+ * version 'version' of 'db'.
+ *
+ * Notes:
+ *
+ * \li If 'version' is NULL, then the current version will be used.
+ *
+ * \li The 'now' field is ignored if 'db' is a zone database. If 'db' is a
+ * cache database, an rdataset will not be found unless it expires after
+ * 'now'. Any ANY query will not match unless at least one rdataset at
+ * the node expires after 'now'. If 'now' is zero, then the current time
+ * will be used.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'node' is a valid node.
+ *
+ * \li iteratorp != NULL && *iteratorp == NULL
+ *
+ * Ensures:
+ *
+ * \li On success, '*iteratorp' is a valid rdataset iterator.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used.
+ */
+
+isc_result_t
+dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdataset_t *rdataset,
+ unsigned int options, dns_rdataset_t *addedrdataset);
+/*%<
+ * Add 'rdataset' to 'node' in version 'version' of 'db'.
+ *
+ * Notes:
+ *
+ * \li If the database has zone semantics, the #DNS_DBADD_MERGE option is set,
+ * and an rdataset of the same type as 'rdataset' already exists at
+ * 'node' then the contents of 'rdataset' will be merged with the existing
+ * rdataset. If the option is not set, then rdataset will replace any
+ * existing rdataset of the same type. If not merging and the
+ * #DNS_DBADD_FORCE option is set, then the data will update the database
+ * without regard to trust levels. If not forcing the data, then the
+ * rdataset will only be added if its trust level is >= the trust level of
+ * any existing rdataset. Forcing is only meaningful for cache databases.
+ * If #DNS_DBADD_EXACT is set then there must be no rdata in common between
+ * the old and new rdata sets. If #DNS_DBADD_EXACTTTL is set then both
+ * the old and new rdata sets must have the same ttl.
+ *
+ * \li The 'now' field is ignored if 'db' is a zone database. If 'db' is
+ * a cache database, then the added rdataset will expire no later than
+ * now + rdataset->ttl.
+ *
+ * \li If 'addedrdataset' is not NULL, then it will be attached to the
+ * resulting new rdataset in the database, or to the existing data if
+ * the existing data was better.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'node' is a valid node.
+ *
+ * \li 'rdataset' is a valid, associated rdataset with the same class
+ * as 'db'.
+ *
+ * \li 'addedrdataset' is NULL, or a valid, unassociated rdataset.
+ *
+ * \li The database has zone semantics and 'version' is a valid
+ * read-write version, or the database has cache semantics
+ * and version is NULL.
+ *
+ * \li If the database has cache semantics, the #DNS_DBADD_MERGE option must
+ * not be set.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #DNS_R_UNCHANGED The operation did not change anything.
+ * \li #ISC_R_NOMEMORY
+ * \li #DNS_R_NOTEXACT
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used.
+ */
+
+isc_result_t
+dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version, dns_rdataset_t *rdataset,
+ unsigned int options, dns_rdataset_t *newrdataset);
+/*%<
+ * Remove any rdata in 'rdataset' from 'node' in version 'version' of
+ * 'db'.
+ *
+ * Notes:
+ *
+ * \li If 'newrdataset' is not NULL, then it will be attached to the
+ * resulting new rdataset in the database, unless the rdataset has
+ * become nonexistent. If DNS_DBSUB_EXACT is set then all elements
+ * of 'rdataset' must exist at 'node'.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'node' is a valid node.
+ *
+ * \li 'rdataset' is a valid, associated rdataset with the same class
+ * as 'db'.
+ *
+ * \li 'newrdataset' is NULL, or a valid, unassociated rdataset.
+ *
+ * \li The database has zone semantics and 'version' is a valid
+ * read-write version.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #DNS_R_UNCHANGED The operation did not change anything.
+ * \li #DNS_R_NXRRSET All rdata of the same type as those
+ * in 'rdataset' have been deleted.
+ * \li #DNS_R_NOTEXACT Some part of 'rdataset' did not
+ * exist and DNS_DBSUB_EXACT was set.
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used.
+ */
+
+isc_result_t
+dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version, dns_rdatatype_t type,
+ dns_rdatatype_t covers);
+/*%<
+ * Make it so that no rdataset of type 'type' exists at 'node' in version
+ * version 'version' of 'db'.
+ *
+ * Notes:
+ *
+ * \li If 'type' is dns_rdatatype_any, then no rdatasets will exist in
+ * 'version' (provided that the dns_db_deleterdataset() isn't followed
+ * by one or more dns_db_addrdataset() calls).
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'node' is a valid node.
+ *
+ * \li The database has zone semantics and 'version' is a valid
+ * read-write version, or the database has cache semantics
+ * and version is NULL.
+ *
+ * \li 'type' is not a meta-RR type, except for dns_rdatatype_any, which is
+ * allowed.
+ *
+ * \li If 'covers' != 0, 'type' must be SIG.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #DNS_R_UNCHANGED No rdatasets of 'type' existed before
+ * the operation was attempted.
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used.
+ */
+
+isc_result_t
+dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, isc_uint32_t *serialp);
+/*%<
+ * Get the current SOA serial number from a zone database.
+ *
+ * Requires:
+ * \li 'db' is a valid database with zone semantics.
+ * \li 'ver' is a valid version.
+ */
+
+void
+dns_db_overmem(dns_db_t *db, isc_boolean_t overmem);
+/*%<
+ * Enable / disable agressive cache cleaning.
+ */
+
+unsigned int
+dns_db_nodecount(dns_db_t *db);
+/*%<
+ * Count the number of nodes in 'db'.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * Returns:
+ * \li The number of nodes in the database
+ */
+
+void
+dns_db_settask(dns_db_t *db, isc_task_t *task);
+/*%<
+ * If task is set then the final detach maybe performed asynchronously.
+ *
+ * Requires:
+ * \li 'db' is a valid database.
+ * \li 'task' to be valid or NULL.
+ */
+
+isc_boolean_t
+dns_db_ispersistent(dns_db_t *db);
+/*%<
+ * Is 'db' persistent? A persistent database does not need to be loaded
+ * from disk or written to disk.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * Returns:
+ * \li #ISC_TRUE 'db' is persistent.
+ * \li #ISC_FALSE 'db' is not persistent.
+ */
+
+isc_result_t
+dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg,
+ isc_mem_t *mctx, dns_dbimplementation_t **dbimp);
+
+/*%<
+ * Register a new database implementation and add it to the list of
+ * supported implementations.
+ *
+ * Requires:
+ *
+ * \li 'name' is not NULL
+ * \li 'order' is a valid function pointer
+ * \li 'mctx' is a valid memory context
+ * \li dbimp != NULL && *dbimp == NULL
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS The registration succeeded
+ * \li #ISC_R_NOMEMORY Out of memory
+ * \li #ISC_R_EXISTS A database implementation with the same name exists
+ *
+ * Ensures:
+ *
+ * \li *dbimp points to an opaque structure which must be passed to
+ * dns_db_unregister().
+ */
+
+void
+dns_db_unregister(dns_dbimplementation_t **dbimp);
+/*%<
+ * Remove a database implementation from the the list of supported
+ * implementations. No databases of this type can be active when this
+ * is called.
+ *
+ * Requires:
+ * \li dbimp != NULL && *dbimp == NULL
+ *
+ * Ensures:
+ *
+ * \li Any memory allocated in *dbimp will be freed.
+ */
+
+isc_result_t
+dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep);
+/*%<
+ * Get the origin DB node corresponding to the DB's zone. This function
+ * should typically succeed unless the underlying DB implementation doesn't
+ * support the feature.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid zone database.
+ * \li 'nodep' != NULL && '*nodep' == NULL
+ *
+ * Ensures:
+ * \li On success, '*nodep' will point to the DB node of the zone's origin.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND - the DB implementation does not support this feature.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_DB_H */
diff --git a/lib/dns/include/dns/dbiterator.h b/lib/dns/include/dns/dbiterator.h
new file mode 100644
index 0000000..47ce082
--- /dev/null
+++ b/lib/dns/include/dns/dbiterator.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2004, 2005 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: dbiterator.h,v 1.19.18.2 2005/04/29 00:16:11 marka Exp $ */
+
+#ifndef DNS_DBITERATOR_H
+#define DNS_DBITERATOR_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * The DNS DB Iterator interface allows iteration of all of the nodes in a
+ * database.
+ *
+ * The dns_dbiterator_t type is like a "virtual class". To actually use
+ * it, an implementation of the class is required. This implementation is
+ * supplied by the database.
+ *
+ * It is the client's responsibility to call dns_db_detachnode() on all
+ * nodes returned.
+ *
+ * XXX &lt;more&gt; XXX
+ *
+ * MP:
+ *\li The iterator itself is not locked. The caller must ensure
+ * synchronization.
+ *
+ *\li The iterator methods ensure appropriate database locking.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li None.
+ */
+
+/*****
+ ***** Imports
+ *****/
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Types
+ *****/
+
+typedef struct dns_dbiteratormethods {
+ void (*destroy)(dns_dbiterator_t **iteratorp);
+ isc_result_t (*first)(dns_dbiterator_t *iterator);
+ isc_result_t (*last)(dns_dbiterator_t *iterator);
+ isc_result_t (*seek)(dns_dbiterator_t *iterator, dns_name_t *name);
+ isc_result_t (*prev)(dns_dbiterator_t *iterator);
+ isc_result_t (*next)(dns_dbiterator_t *iterator);
+ isc_result_t (*current)(dns_dbiterator_t *iterator,
+ dns_dbnode_t **nodep, dns_name_t *name);
+ isc_result_t (*pause)(dns_dbiterator_t *iterator);
+ isc_result_t (*origin)(dns_dbiterator_t *iterator,
+ dns_name_t *name);
+} dns_dbiteratormethods_t;
+
+#define DNS_DBITERATOR_MAGIC ISC_MAGIC('D','N','S','I')
+#define DNS_DBITERATOR_VALID(dbi) ISC_MAGIC_VALID(dbi, DNS_DBITERATOR_MAGIC)
+/*%
+ * This structure is actually just the common prefix of a DNS db
+ * implementation's version of a dns_dbiterator_t.
+ *
+ * Clients may use the 'db' field of this structure. Except for that field,
+ * direct use of this structure by clients is forbidden. DB implementations
+ * may change the structure. 'magic' must be DNS_DBITERATOR_MAGIC for any of
+ * the dns_dbiterator routines to work. DB iterator implementations must
+ * maintain all DB iterator invariants.
+ */
+struct dns_dbiterator {
+ /* Unlocked. */
+ unsigned int magic;
+ dns_dbiteratormethods_t * methods;
+ dns_db_t * db;
+ isc_boolean_t relative_names;
+ isc_boolean_t cleaning;
+};
+
+void
+dns_dbiterator_destroy(dns_dbiterator_t **iteratorp);
+/*%<
+ * Destroy '*iteratorp'.
+ *
+ * Requires:
+ *
+ *\li '*iteratorp' is a valid iterator.
+ *
+ * Ensures:
+ *
+ *\li All resources used by the iterator are freed.
+ *
+ *\li *iteratorp == NULL.
+ */
+
+isc_result_t
+dns_dbiterator_first(dns_dbiterator_t *iterator);
+/*%<
+ * Move the node cursor to the first node in the database (if any).
+ *
+ * Requires:
+ *\li 'iterator' is a valid iterator.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMORE There are no nodes in the database.
+ *
+ *\li Other results are possible, depending on the DB implementation.
+ */
+
+isc_result_t
+dns_dbiterator_last(dns_dbiterator_t *iterator);
+/*%<
+ * Move the node cursor to the last node in the database (if any).
+ *
+ * Requires:
+ *\li 'iterator' is a valid iterator.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMORE There are no nodes in the database.
+ *
+ *\li Other results are possible, depending on the DB implementation.
+ */
+
+isc_result_t
+dns_dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name);
+/*%<
+ * Move the node cursor to the node with name 'name'.
+ *
+ * Requires:
+ *\li 'iterator' is a valid iterator.
+ *
+ *\li 'name' is a valid name.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOTFOUND
+ *
+ *\li Other results are possible, depending on the DB implementation.
+ */
+
+isc_result_t
+dns_dbiterator_prev(dns_dbiterator_t *iterator);
+/*%<
+ * Move the node cursor to the previous node in the database (if any).
+ *
+ * Requires:
+ *\li 'iterator' is a valid iterator.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMORE There are no more nodes in the
+ * database.
+ *
+ *\li Other results are possible, depending on the DB implementation.
+ */
+
+isc_result_t
+dns_dbiterator_next(dns_dbiterator_t *iterator);
+/*%<
+ * Move the node cursor to the next node in the database (if any).
+ *
+ * Requires:
+ *\li 'iterator' is a valid iterator.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMORE There are no more nodes in the
+ * database.
+ *
+ *\li Other results are possible, depending on the DB implementation.
+ */
+
+isc_result_t
+dns_dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
+ dns_name_t *name);
+/*%<
+ * Return the current node.
+ *
+ * Notes:
+ *\li If 'name' is not NULL, it will be set to the name of the node.
+ *
+ * Requires:
+ *\li 'iterator' is a valid iterator.
+ *
+ *\li nodep != NULL && *nodep == NULL
+ *
+ *\li The node cursor of 'iterator' is at a valid location (i.e. the
+ * result of last call to a cursor movement command was ISC_R_SUCCESS).
+ *
+ *\li 'name' is NULL, or is a valid name with a dedicated buffer.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #DNS_R_NEWORIGIN If this iterator was created with
+ * 'relative_names' set to ISC_TRUE,
+ * then #DNS_R_NEWORIGIN will be returned
+ * when the origin the names are
+ * relative to changes. This result
+ * can occur only when 'name' is not
+ * NULL. This is also a successful
+ * result.
+ *
+ *\li Other results are possible, depending on the DB implementation.
+ */
+
+isc_result_t
+dns_dbiterator_pause(dns_dbiterator_t *iterator);
+/*%<
+ * Pause iteration.
+ *
+ * Calling a cursor movement method or dns_dbiterator_current() may cause
+ * database locks to be acquired. Rather than reacquire these locks every
+ * time one of these routines is called, the locks may simply be held.
+ * Calling dns_dbiterator_pause() releases any such locks. Iterator clients
+ * should call this routine any time they are not going to execute another
+ * iterator method in the immediate future.
+ *
+ * Requires:
+ *\li 'iterator' is a valid iterator.
+ *
+ * Ensures:
+ *\li Any database locks being held for efficiency of iterator access are
+ * released.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *
+ *\li Other results are possible, depending on the DB implementation.
+ */
+
+isc_result_t
+dns_dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
+/*%<
+ * Return the origin to which returned node names are relative.
+ *
+ * Requires:
+ *
+ *\li 'iterator' is a valid relative_names iterator.
+ *
+ *\li 'name' is a valid name with a dedicated buffer.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE
+ *
+ *\li Other results are possible, depending on the DB implementation.
+ */
+
+void
+dns_dbiterator_setcleanmode(dns_dbiterator_t *iterator, isc_boolean_t mode);
+/*%<
+ * Indicate that the given iterator is/is not cleaning the DB.
+ *
+ * Notes:
+ *\li When 'mode' is ISC_TRUE,
+ *
+ * Requires:
+ *\li 'iterator' is a valid iterator.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_DBITERATOR_H */
diff --git a/lib/dns/include/dns/dbtable.h b/lib/dns/include/dns/dbtable.h
new file mode 100644
index 0000000..18d3e50
--- /dev/null
+++ b/lib/dns/include/dns/dbtable.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2004, 2005 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: dbtable.h,v 1.17.18.2 2005/04/29 00:16:11 marka Exp $ */
+
+#ifndef DNS_DBTABLE_H
+#define DNS_DBTABLE_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * DNS DB Tables
+ *
+ * XXX TBS XXX
+ *
+ * MP:
+ *\li The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li None.
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li None.
+ */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+#define DNS_DBTABLEFIND_NOEXACT 0x01
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
+ dns_dbtable_t **dbtablep);
+/*%<
+ * Make a new dbtable of class 'rdclass'
+ *
+ * Requires:
+ *\li mctx != NULL
+ * \li dbtablep != NULL && *dptablep == NULL
+ *\li 'rdclass' is a valid class
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ */
+
+void
+dns_dbtable_attach(dns_dbtable_t *source, dns_dbtable_t **targetp);
+/*%<
+ * Attach '*targetp' to 'source'.
+ *
+ * Requires:
+ *
+ *\li 'source' is a valid dbtable.
+ *
+ *\li 'targetp' points to a NULL dns_dbtable_t *.
+ *
+ * Ensures:
+ *
+ *\li *targetp is attached to source.
+ */
+
+void
+dns_dbtable_detach(dns_dbtable_t **dbtablep);
+/*%<
+ * Detach *dbtablep from its dbtable.
+ *
+ * Requires:
+ *
+ *\li '*dbtablep' points to a valid dbtable.
+ *
+ * Ensures:
+ *
+ *\li *dbtablep is NULL.
+ *
+ *\li If '*dbtablep' is the last reference to the dbtable,
+ * all resources used by the dbtable will be freed
+ */
+
+isc_result_t
+dns_dbtable_add(dns_dbtable_t *dbtable, dns_db_t *db);
+/*%<
+ * Add 'db' to 'dbtable'.
+ *
+ * Requires:
+ *\li 'dbtable' is a valid dbtable.
+ *
+ *\li 'db' is a valid database with the same class as 'dbtable'
+ */
+
+void
+dns_dbtable_remove(dns_dbtable_t *dbtable, dns_db_t *db);
+/*%<
+ * Remove 'db' from 'dbtable'.
+ *
+ * Requires:
+ *\li 'db' was previously added to 'dbtable'.
+ */
+
+void
+dns_dbtable_adddefault(dns_dbtable_t *dbtable, dns_db_t *db);
+/*%<
+ * Use 'db' as the result of a dns_dbtable_find() if no better match is
+ * available.
+ */
+
+void
+dns_dbtable_getdefault(dns_dbtable_t *dbtable, dns_db_t **db);
+/*%<
+ * Get the 'db' used as the result of a dns_dbtable_find()
+ * if no better match is available.
+ */
+
+void
+dns_dbtable_removedefault(dns_dbtable_t *dbtable);
+/*%<
+ * Remove the default db from 'dbtable'.
+ */
+
+isc_result_t
+dns_dbtable_find(dns_dbtable_t *dbtable, dns_name_t *name,
+ unsigned int options, dns_db_t **dbp);
+/*%<
+ * Find the deepest match to 'name' in the dbtable, and return it
+ *
+ * Notes:
+ *\li If the DNS_DBTABLEFIND_NOEXACT option is set, the best partial
+ * match (if any) to 'name' will be returned.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS on success
+ *\li something else: no default and match
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_DBTABLE_H */
diff --git a/lib/dns/include/dns/diff.h b/lib/dns/include/dns/diff.h
new file mode 100644
index 0000000..cd96a0b
--- /dev/null
+++ b/lib/dns/include/dns/diff.h
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2004, 2005 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: diff.h,v 1.6.18.2 2005/04/29 00:16:12 marka Exp $ */
+
+#ifndef DNS_DIFF_H
+#define DNS_DIFF_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * A diff is a convenience type representing a list of changes to be
+ * made to a database.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/types.h>
+
+/***
+ *** Types
+ ***/
+
+/*%
+ * A dns_difftuple_t represents a single RR being added or deleted.
+ * The RR type and class are in the 'rdata' member; the class is always
+ * the real one, not a DynDNS meta-class, so that the rdatas can be
+ * compared using dns_rdata_compare(). The TTL is significant
+ * even for deletions, because a deletion/addition pair cannot
+ * be canceled out if the TTL differs (it might be an explicit
+ * TTL update).
+ *
+ * Tuples are also used to represent complete RRs with owner
+ * names for a couple of other purposes, such as the
+ * individual RRs of a "RRset exists (value dependent)"
+ * prerequisite set. In this case, op==DNS_DIFFOP_EXISTS,
+ * and the TTL is ignored.
+ */
+
+typedef enum {
+ DNS_DIFFOP_ADD, /*%< Add an RR. */
+ DNS_DIFFOP_DEL, /*%< Delete an RR. */
+ DNS_DIFFOP_EXISTS /*%< Assert RR existence. */
+} dns_diffop_t;
+
+typedef struct dns_difftuple dns_difftuple_t;
+
+#define DNS_DIFFTUPLE_MAGIC ISC_MAGIC('D','I','F','T')
+#define DNS_DIFFTUPLE_VALID(t) ISC_MAGIC_VALID(t, DNS_DIFFTUPLE_MAGIC)
+
+struct dns_difftuple {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ dns_diffop_t op;
+ dns_name_t name;
+ dns_ttl_t ttl;
+ dns_rdata_t rdata;
+ ISC_LINK(dns_difftuple_t) link;
+ /* Variable-size name data and rdata follows. */
+};
+
+/*%
+ * A dns_diff_t represents a set of changes being applied to
+ * a zone. Diffs are also used to represent "RRset exists
+ * (value dependent)" prerequisites.
+ */
+typedef struct dns_diff dns_diff_t;
+
+#define DNS_DIFF_MAGIC ISC_MAGIC('D','I','F','F')
+#define DNS_DIFF_VALID(t) ISC_MAGIC_VALID(t, DNS_DIFF_MAGIC)
+
+struct dns_diff {
+ unsigned int magic;
+ isc_mem_t * mctx;
+ ISC_LIST(dns_difftuple_t) tuples;
+};
+
+/* Type of comparision function for sorting diffs. */
+typedef int dns_diff_compare_func(const void *, const void *);
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+/**************************************************************************/
+/*
+ * Maniuplation of diffs and tuples.
+ */
+
+isc_result_t
+dns_difftuple_create(isc_mem_t *mctx,
+ dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
+ dns_rdata_t *rdata, dns_difftuple_t **tp);
+/*%<
+ * Create a tuple. Deep copies are made of the name and rdata, so
+ * they need not remain valid after the call.
+ *
+ * Requires:
+ *\li *tp != NULL && *tp == NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ * \li ISC_R_NOMEMORY
+ */
+
+void
+dns_difftuple_free(dns_difftuple_t **tp);
+/*%<
+ * Free a tuple.
+ *
+ * Requires:
+ * \li **tp is a valid tuple.
+ *
+ * Ensures:
+ * \li *tp == NULL
+ * \li All memory used by the tuple is freed.
+ */
+
+isc_result_t
+dns_difftuple_copy(dns_difftuple_t *orig, dns_difftuple_t **copyp);
+/*%<
+ * Copy a tuple.
+ *
+ * Requires:
+ * \li 'orig' points to a valid tuple
+ *\li copyp != NULL && *copyp == NULL
+ */
+
+void
+dns_diff_init(isc_mem_t *mctx, dns_diff_t *diff);
+/*%<
+ * Initialize a diff.
+ *
+ * Requires:
+ * \li 'diff' points to an uninitialized dns_diff_t
+ * \li allocated by the caller.
+ *
+ * Ensures:
+ * \li '*diff' is a valid, empty diff.
+ */
+
+void
+dns_diff_clear(dns_diff_t *diff);
+/*%<
+ * Clear a diff, destroying all its tuples.
+ *
+ * Requires:
+ * \li 'diff' points to a valid dns_diff_t.
+ *
+ * Ensures:
+ * \li Any tuples in the diff are destroyed.
+ * The diff now empty, but it is still valid
+ * and may be reused without calling dns_diff_init
+ * again. The only memory used is that of the
+ * dns_diff_t structure itself.
+ *
+ * Notes:
+ * \li Managing the memory of the dns_diff_t structure itself
+ * is the caller's responsibility.
+ */
+
+void
+dns_diff_append(dns_diff_t *diff, dns_difftuple_t **tuple);
+/*%<
+ * Append a single tuple to a diff.
+ *
+ *\li 'diff' is a valid diff.
+ * \li '*tuple' is a valid tuple.
+ *
+ * Ensures:
+ *\li *tuple is NULL.
+ *\li The tuple has been freed, or will be freed when the diff is cleared.
+ */
+
+void
+dns_diff_appendminimal(dns_diff_t *diff, dns_difftuple_t **tuple);
+/*%<
+ * Append 'tuple' to 'diff', removing any duplicate
+ * or conflicting updates as needed to create a minimal diff.
+ *
+ * Requires:
+ *\li 'diff' is a minimal diff.
+ *
+ * Ensures:
+ *\li 'diff' is still a minimal diff.
+ * \li *tuple is NULL.
+ * \li The tuple has been freed, or will be freed when the diff is cleared.
+ *
+ */
+
+isc_result_t
+dns_diff_sort(dns_diff_t *diff, dns_diff_compare_func *compare);
+/*%<
+ * Sort 'diff' in-place according to the comparison function 'compare'.
+ */
+
+isc_result_t
+dns_diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver);
+isc_result_t
+dns_diff_applysilently(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver);
+/*%<
+ * Apply 'diff' to the database 'db'.
+ *
+ * dns_diff_apply() logs warnings about updates with no effect or
+ * with inconsistent TTLs; dns_diff_applysilently() does not.
+ *
+ * For efficiency, the diff should be sorted by owner name.
+ * If it is not sorted, operation will still be correct,
+ * but less efficient.
+ *
+ * Requires:
+ *\li *diff is a valid diff (possibly empty), containing
+ * tuples of type #DNS_DIFFOP_ADD and/or
+ * For #DNS_DIFFOP_DEL tuples, the TTL is ignored.
+ *
+ */
+
+isc_result_t
+dns_diff_load(dns_diff_t *diff, dns_addrdatasetfunc_t addfunc,
+ void *add_private);
+/*%<
+ * Like dns_diff_apply, but for use when loading a new database
+ * instead of modifying an existing one. This bypasses the
+ * database transaction mechanisms.
+ *
+ * Requires:
+ *\li 'addfunc' is a valid dns_addradatasetfunc_t obtained from
+ * dns_db_beginload()
+ *
+ *\li 'add_private' points to a corresponding dns_dbload_t *
+ * (XXX why is it a void pointer, then?)
+ */
+
+isc_result_t
+dns_diff_print(dns_diff_t *diff, FILE *file);
+
+/*%<
+ * Print the differences to 'file' or if 'file' is NULL via the
+ * logging system.
+ *
+ * Require:
+ *\li 'diff' to be valid.
+ *\li 'file' to refer to a open file or NULL.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ *\li any error from dns_rdataset_totext()
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_DIFF_H */
diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h
new file mode 100644
index 0000000..3938f94
--- /dev/null
+++ b/lib/dns/include/dns/dispatch.h
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: dispatch.h,v 1.48.18.5 2007/08/28 07:20:05 tbox Exp $ */
+
+#ifndef DNS_DISPATCH_H
+#define DNS_DISPATCH_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * DNS Dispatch Management
+ * Shared UDP and single-use TCP dispatches for queries and responses.
+ *
+ * MP:
+ *
+ *\li All locking is performed internally to each dispatch.
+ * Restrictions apply to dns_dispatch_removeresponse().
+ *
+ * Reliability:
+ *
+ * Resources:
+ *
+ * Security:
+ *
+ *\li Depends on the isc_socket_t and dns_message_t for prevention of
+ * buffer overruns.
+ *
+ * Standards:
+ *
+ *\li None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/buffer.h>
+#include <isc/lang.h>
+#include <isc/socket.h>
+#include <dns/types.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * This event is sent to a task when a response comes in.
+ * No part of this structure should ever be modified by the caller,
+ * other than parts of the buffer. The holy parts of the buffer are
+ * the base and size of the buffer. All other parts of the buffer may
+ * be used. On event delivery the used region contains the packet.
+ *
+ * "id" is the received message id,
+ *
+ * "addr" is the host that sent it to us,
+ *
+ * "buffer" holds state on the received data.
+ *
+ * The "free" routine for this event will clean up itself as well as
+ * any buffer space allocated from common pools.
+ */
+
+struct dns_dispatchevent {
+ ISC_EVENT_COMMON(dns_dispatchevent_t); /*%< standard event common */
+ isc_result_t result; /*%< result code */
+ isc_int32_t id; /*%< message id */
+ isc_sockaddr_t addr; /*%< address recv'd from */
+ struct in6_pktinfo pktinfo; /*%< reply info for v6 */
+ isc_buffer_t buffer; /*%< data buffer */
+ isc_uint32_t attributes; /*%< mirrored from socket.h */
+};
+
+/*@{*/
+/*%
+ * Attributes for added dispatchers.
+ *
+ * Values with the mask 0xffff0000 are application defined.
+ * Values with the mask 0x0000ffff are library defined.
+ *
+ * Insane values (like setting both TCP and UDP) are not caught. Don't
+ * do that.
+ *
+ * _PRIVATE
+ * The dispatcher cannot be shared.
+ *
+ * _TCP, _UDP
+ * The dispatcher is a TCP or UDP socket.
+ *
+ * _IPV4, _IPV6
+ * The dispatcher uses an ipv4 or ipv6 socket.
+ *
+ * _NOLISTEN
+ * The dispatcher should not listen on the socket.
+ *
+ * _MAKEQUERY
+ * The dispatcher can be used to issue queries to other servers, and
+ * accept replies from them.
+ */
+#define DNS_DISPATCHATTR_PRIVATE 0x00000001U
+#define DNS_DISPATCHATTR_TCP 0x00000002U
+#define DNS_DISPATCHATTR_UDP 0x00000004U
+#define DNS_DISPATCHATTR_IPV4 0x00000008U
+#define DNS_DISPATCHATTR_IPV6 0x00000010U
+#define DNS_DISPATCHATTR_NOLISTEN 0x00000020U
+#define DNS_DISPATCHATTR_MAKEQUERY 0x00000040U
+#define DNS_DISPATCHATTR_CONNECTED 0x00000080U
+/*@}*/
+
+isc_result_t
+dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
+ dns_dispatchmgr_t **mgrp);
+/*%<
+ * Creates a new dispatchmgr object.
+ *
+ * Requires:
+ *\li "mctx" be a valid memory context.
+ *
+ *\li mgrp != NULL && *mgrp == NULL
+ *
+ *\li "entropy" may be NULL, in which case an insecure random generator
+ * will be used. If it is non-NULL, it must be a valid entropy
+ * source.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS -- all ok
+ *
+ *\li anything else -- failure
+ */
+
+
+void
+dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp);
+/*%<
+ * Destroys the dispatchmgr when it becomes empty. This could be
+ * immediately.
+ *
+ * Requires:
+ *\li mgrp != NULL && *mgrp is a valid dispatchmgr.
+ */
+
+
+void
+dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole);
+/*%<
+ * Sets the dispatcher's "blackhole list," a list of addresses that will
+ * be ignored by all dispatchers created by the dispatchmgr.
+ *
+ * Requires:
+ * \li mgrp is a valid dispatchmgr
+ * \li blackhole is a valid acl
+ */
+
+
+dns_acl_t *
+dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr);
+/*%<
+ * Gets a pointer to the dispatcher's current blackhole list,
+ * without incrementing its reference count.
+ *
+ * Requires:
+ *\li mgr is a valid dispatchmgr
+ * Returns:
+ *\li A pointer to the current blackhole list, or NULL.
+ */
+
+void
+dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr,
+ dns_portlist_t *portlist);
+/*%<
+ * Sets a list of UDP ports that won't be used when creating a udp
+ * dispatch with a wildcard port.
+ *
+ * Requires:
+ *\li mgr is a valid dispatchmgr
+ *\li portlist to be NULL or a valid port list.
+ */
+
+dns_portlist_t *
+dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr);
+/*%<
+ * Return the current port list.
+ *
+ * Requires:
+ *\li mgr is a valid dispatchmgr
+ */
+
+
+
+isc_result_t
+dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
+ isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
+ unsigned int buffersize,
+ unsigned int maxbuffers, unsigned int maxrequests,
+ unsigned int buckets, unsigned int increment,
+ unsigned int attributes, unsigned int mask,
+ dns_dispatch_t **dispp);
+/*%<
+ * Attach to existing dns_dispatch_t if one is found with dns_dispatchmgr_find,
+ * otherwise create a new UDP dispatch.
+ *
+ * Requires:
+ *\li All pointer parameters be valid for their respective types.
+ *
+ *\li dispp != NULL && *disp == NULL
+ *
+ *\li 512 <= buffersize <= 64k
+ *
+ *\li maxbuffers > 0
+ *
+ *\li buckets < 2097169
+ *
+ *\li increment > buckets
+ *
+ *\li (attributes & DNS_DISPATCHATTR_TCP) == 0
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS -- success.
+ *
+ *\li Anything else -- failure.
+ */
+
+isc_result_t
+dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
+ isc_taskmgr_t *taskmgr, unsigned int buffersize,
+ unsigned int maxbuffers, unsigned int maxrequests,
+ unsigned int buckets, unsigned int increment,
+ unsigned int attributes, dns_dispatch_t **dispp);
+/*%<
+ * Create a new dns_dispatch and attach it to the provided isc_socket_t.
+ *
+ * For all dispatches, "buffersize" is the maximum packet size we will
+ * accept.
+ *
+ * "maxbuffers" and "maxrequests" control the number of buffers in the
+ * overall system and the number of buffers which can be allocated to
+ * requests.
+ *
+ * "buckets" is the number of buckets to use, and should be prime.
+ *
+ * "increment" is used in a collision avoidance function, and needs to be
+ * a prime > buckets, and not 2.
+ *
+ * Requires:
+ *
+ *\li mgr is a valid dispatch manager.
+ *
+ *\li sock is a valid.
+ *
+ *\li task is a valid task that can be used internally to this dispatcher.
+ *
+ * \li 512 <= buffersize <= 64k
+ *
+ *\li maxbuffers > 0.
+ *
+ *\li maxrequests <= maxbuffers.
+ *
+ *\li buckets < 2097169 (the next prime after 65536 * 32)
+ *
+ *\li increment > buckets (and prime).
+ *
+ *\li attributes includes #DNS_DISPATCHATTR_TCP and does not include
+ * #DNS_DISPATCHATTR_UDP.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS -- success.
+ *
+ *\li Anything else -- failure.
+ */
+
+void
+dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp);
+/*%<
+ * Attach to a dispatch handle.
+ *
+ * Requires:
+ *\li disp is valid.
+ *
+ *\li dispp != NULL && *dispp == NULL
+ */
+
+void
+dns_dispatch_detach(dns_dispatch_t **dispp);
+/*%<
+ * Detaches from the dispatch.
+ *
+ * Requires:
+ *\li dispp != NULL and *dispp be a valid dispatch.
+ */
+
+void
+dns_dispatch_starttcp(dns_dispatch_t *disp);
+/*%<
+ * Start processing of a TCP dispatch once the socket connects.
+ *
+ * Requires:
+ *\li 'disp' is valid.
+ */
+
+isc_result_t
+dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_uint16_t *idp, dns_dispentry_t **resp);
+/*%<
+ * Add a response entry for this dispatch.
+ *
+ * "*idp" is filled in with the assigned message ID, and *resp is filled in
+ * to contain the magic token used to request event flow stop.
+ *
+ * Arranges for the given task to get a callback for response packets. When
+ * the event is delivered, it must be returned using dns_dispatch_freeevent()
+ * or through dns_dispatch_removeresponse() for another to be delivered.
+ *
+ * Requires:
+ *\li "idp" be non-NULL.
+ *
+ *\li "task" "action" and "arg" be set as appropriate.
+ *
+ *\li "dest" be non-NULL and valid.
+ *
+ *\li "resp" be non-NULL and *resp be NULL
+ *
+ * Ensures:
+ *
+ *\li &lt;id, dest> is a unique tuple. That means incoming messages
+ * are identifiable.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS -- all is well.
+ *\li ISC_R_NOMEMORY -- memory could not be allocated.
+ *\li ISC_R_NOMORE -- no more message ids can be allocated
+ * for this destination.
+ */
+
+
+void
+dns_dispatch_removeresponse(dns_dispentry_t **resp,
+ dns_dispatchevent_t **sockevent);
+/*%<
+ * Stops the flow of responses for the provided id and destination.
+ * If "sockevent" is non-NULL, the dispatch event and associated buffer is
+ * also returned to the system.
+ *
+ * Requires:
+ *\li "resp" != NULL and "*resp" contain a value previously allocated
+ * by dns_dispatch_addresponse();
+ *
+ *\li May only be called from within the task given as the 'task'
+ * argument to dns_dispatch_addresponse() when allocating '*resp'.
+ */
+
+
+isc_socket_t *
+dns_dispatch_getsocket(dns_dispatch_t *disp);
+/*%<
+ * Return the socket associated with this dispatcher.
+ *
+ * Requires:
+ *\li disp is valid.
+ *
+ * Returns:
+ *\li The socket the dispatcher is using.
+ */
+
+isc_result_t
+dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp);
+/*%<
+ * Return the local address for this dispatch.
+ * This currently only works for dispatches using UDP sockets.
+ *
+ * Requires:
+ *\li disp is valid.
+ *\li addrp to be non null.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOTIMPLEMENTED
+ */
+
+void
+dns_dispatch_cancel(dns_dispatch_t *disp);
+/*%<
+ * cancel outstanding clients
+ *
+ * Requires:
+ *\li disp is valid.
+ */
+
+void
+dns_dispatch_changeattributes(dns_dispatch_t *disp,
+ unsigned int attributes, unsigned int mask);
+/*%<
+ * Set the bits described by "mask" to the corresponding values in
+ * "attributes".
+ *
+ * That is:
+ *
+ * \code
+ * new = (old & ~mask) | (attributes & mask)
+ * \endcode
+ *
+ * This function has a side effect when #DNS_DISPATCHATTR_NOLISTEN changes.
+ * When the flag becomes off, the dispatch will start receiving on the
+ * corresponding socket. When the flag becomes on, receive events on the
+ * corresponding socket will be canceled.
+ *
+ * Requires:
+ *\li disp is valid.
+ *
+ *\li attributes are reasonable for the dispatch. That is, setting the UDP
+ * attribute on a TCP socket isn't reasonable.
+ */
+
+void
+dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event);
+/*%<
+ * Inform the dispatcher of a socket receive. This is used for sockets
+ * shared between dispatchers and clients. If the dispatcher fails to copy
+ * or send the event, nothing happens.
+ *
+ * Requires:
+ *\li disp is valid, and the attribute DNS_DISPATCHATTR_NOLISTEN is set.
+ * event != NULL
+ */
+
+void
+dns_dispatch_hash(void *data, size_t len);
+/*%<
+ * Feed 'data' to the dispatch query id generator where 'len' is the size
+ * of 'data'.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_DISPATCH_H */
diff --git a/lib/dns/include/dns/dlz.h b/lib/dns/include/dns/dlz.h
new file mode 100644
index 0000000..4c61c91
--- /dev/null
+++ b/lib/dns/include/dns/dlz.h
@@ -0,0 +1,290 @@
+/*
+ * Portions Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions 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.
+ */
+
+/*
+ * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER 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 development of Dynamically Loadable Zones (DLZ) for Bind 9 was
+ * conceived and contributed by Rob Butler.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: dlz.h,v 1.2.2.2 2005/09/06 03:47:18 marka Exp $ */
+
+/*! \file */
+
+#ifndef DLZ_H
+#define DLZ_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * DLZ Interface
+ *
+ * The DLZ interface allows zones to be looked up using a driver instead of
+ * Bind's default in memory zone table.
+ *
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ * Standards:
+ * None.
+ */
+
+/*****
+ ***** Imports
+ *****/
+
+#include <dns/name.h>
+#include <dns/types.h>
+#include <dns/view.h>
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+#define DNS_DLZ_MAGIC ISC_MAGIC('D','L','Z','D')
+#define DNS_DLZ_VALID(dlz) ISC_MAGIC_VALID(dlz, DNS_DLZ_MAGIC)
+
+typedef isc_result_t
+(*dns_dlzallowzonexfr_t)(void *driverarg, void *dbdata, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_name_t *name,
+ isc_sockaddr_t *clientaddr,
+ dns_db_t **dbp);
+
+/*%<
+ * Method prototype. Drivers implementing the DLZ interface MUST
+ * supply an allow zone transfer method. This method is called when
+ * the DNS server is performing a zone transfer query. The driver's
+ * method should return ISC_R_SUCCESS and a database pointer to the
+ * name server if the zone is supported by the database, and zone
+ * transfer is allowed. Otherwise it will return ISC_R_NOTFOUND if
+ * the zone is not supported by the database, or ISC_R_NOPERM if zone
+ * transfers are not allowed. If an error occurs it should return a
+ * result code indicating the type of error.
+ */
+
+typedef isc_result_t
+(*dns_dlzcreate_t)(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
+ char *argv[], void *driverarg, void **dbdata);
+
+/*%<
+ * Method prototype. Drivers implementing the DLZ interface MUST
+ * supply a create method. This method is called when the DNS server
+ * is starting up and creating drivers for use later.
+ */
+
+typedef void
+(*dns_dlzdestroy_t)(void *driverarg, void **dbdata);
+
+/*%<
+ * Method prototype. Drivers implementing the DLZ interface MUST
+ * supply a destroy method. This method is called when the DNS server
+ * is shuting down and no longer needs the driver.
+ */
+
+typedef isc_result_t
+(*dns_dlzfindzone_t)(void *driverarg, void *dbdata, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_name_t *name,
+ dns_db_t **dbp);
+
+/*%<
+
+ * Method prototype. Drivers implementing the DLZ interface MUST
+ * supply a find zone method. This method is called when the DNS
+ * server is performing a query. The find zone method will be called
+ * with the longest possible name first, and continue to be called
+ * with successively shorter domain names, until any of the following
+ * occur:
+ *
+ * \li 1) a match is found, and the function returns (ISC_R_SUCCESS)
+ *
+ * \li 2) a problem occurs, and the functions returns anything other
+ * than (ISC_R_NOTFOUND)
+ * \li 3) we run out of domain name labels. I.E. we have tried the
+ * shortest domain name
+ * \li 4) the number of labels in the domain name is less than
+ * min_lables for dns_dlzfindzone
+ *
+ * The driver's find zone method should return ISC_R_SUCCESS and a
+ * database pointer to the name server if the zone is supported by the
+ * database. Otherwise it will return ISC_R_NOTFOUND, and a null
+ * pointer if the zone is not supported. If an error occurs it should
+ * return a result code indicating the type of error.
+ */
+
+/*% the methods supplied by a DLZ driver */
+typedef struct dns_dlzmethods {
+ dns_dlzcreate_t create;
+ dns_dlzdestroy_t destroy;
+ dns_dlzfindzone_t findzone;
+ dns_dlzallowzonexfr_t allowzonexfr;
+} dns_dlzmethods_t;
+
+/*% information about a DLZ driver */
+struct dns_dlzimplementation {
+ const char *name;
+ const dns_dlzmethods_t *methods;
+ isc_mem_t *mctx;
+ void *driverarg;
+ ISC_LINK(dns_dlzimplementation_t) link;
+};
+
+/*% an instance of a DLZ driver */
+struct dns_dlzdb {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ dns_dlzimplementation_t *implementation;
+ void *dbdata;
+};
+
+
+/***
+ *** Method declarations
+ ***/
+
+isc_result_t
+dns_dlzallowzonexfr(dns_view_t *view, dns_name_t *name,
+ isc_sockaddr_t *clientaddr, dns_db_t **dbp);
+
+/*%<
+ * This method is called when the DNS server is performing a zone
+ * transfer query. It will call the DLZ driver's allow zone tranfer
+ * method.
+ */
+
+isc_result_t
+dns_dlzcreate(isc_mem_t *mctx, const char *dlzname,
+ const char *drivername, unsigned int argc,
+ char *argv[], dns_dlzdb_t **dbp);
+
+/*%<
+ * This method is called when the DNS server is starting up and
+ * creating drivers for use later. It will search the DLZ driver list
+ * for 'drivername' and return a DLZ driver via dbp if a match is
+ * found. If the DLZ driver supplies a create method, this function
+ * will call it.
+ */
+
+void
+dns_dlzdestroy(dns_dlzdb_t **dbp);
+
+/*%<
+ * This method is called when the DNS server is shuting down and no
+ * longer needs the driver. If the DLZ driver supplies a destroy
+ * methods, this function will call it.
+ */
+
+isc_result_t
+dns_dlzfindzone(dns_view_t *view, dns_name_t *name,
+ unsigned int minlabels, dns_db_t **dbp);
+
+/*%<
+ * This method is called when the DNS server is performing a query.
+ * It will call the DLZ driver's find zone method.
+ */
+
+isc_result_t
+dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods,
+ void *driverarg, isc_mem_t *mctx,
+ dns_dlzimplementation_t **dlzimp);
+
+/*%<
+ * Register a dynamically loadable zones (DLZ) driver for the database
+ * type 'drivername', implemented by the functions in '*methods'.
+ *
+ * dlzimp must point to a NULL dlz_implementation_t pointer. That is,
+ * dlzimp != NULL && *dlzimp == NULL. It will be assigned a value that
+ * will later be used to identify the driver when deregistering it.
+ */
+
+isc_result_t
+dns_dlzstrtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp);
+
+/*%<
+ * This method is called when the name server is starting up to parse
+ * the DLZ driver command line from named.conf. Basically it splits
+ * up a string into and argc / argv. The primary difference of this
+ * method is items between braces { } are considered only 1 word. for
+ * example the command line "this is { one grouped phrase } and this
+ * isn't" would be parsed into:
+ *
+ * \li argv[0]: "this"
+ * \li argv[1]: "is"
+ * \li argv{2]: " one grouped phrase "
+ * \li argv[3]: "and"
+ * \li argv[4]: "this"
+ * \li argv{5}: "isn't"
+ *
+ * braces should NOT be nested, more than one grouping in the command
+ * line is allowed. Notice, argv[2] has an extra space at the
+ * beginning and end. Extra spaces are not stripped between a
+ * grouping. You can do so in your driver if needed, or be sure not
+ * to put extra spaces before / after the braces.
+ */
+
+void
+dns_dlzunregister(dns_dlzimplementation_t **dlzimp);
+
+/*%<
+ * Removes the dlz driver from the list of registered dlz drivers.
+ * There must be no active dlz drivers of this type when this function
+ * is called.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DLZ_H */
diff --git a/lib/dns/include/dns/dnssec.h b/lib/dns/include/dns/dnssec.h
new file mode 100644
index 0000000..2804e03
--- /dev/null
+++ b/lib/dns/include/dns/dnssec.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2004, 2005 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: dnssec.h,v 1.26.18.2 2005/04/29 00:16:12 marka Exp $ */
+
+#ifndef DNS_DNSSEC_H
+#define DNS_DNSSEC_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/stdtime.h>
+
+#include <dns/types.h>
+
+#include <dst/dst.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx,
+ dst_key_t **key);
+/*%<
+ * Creates a DST key from a DNS record. Basically a wrapper around
+ * dst_key_fromdns().
+ *
+ * Requires:
+ *\li 'name' is not NULL
+ *\li 'rdata' is not NULL
+ *\li 'mctx' is not NULL
+ *\li 'key' is not NULL
+ *\li '*key' is NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li DST_R_INVALIDPUBLICKEY
+ *\li various errors from dns_name_totext
+ */
+
+isc_result_t
+dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
+ isc_stdtime_t *inception, isc_stdtime_t *expire,
+ isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata);
+/*%<
+ * Generates a SIG record covering this rdataset. This has no effect
+ * on existing SIG records.
+ *
+ * Requires:
+ *\li 'name' (the owner name of the record) is a valid name
+ *\li 'set' is a valid rdataset
+ *\li 'key' is a valid key
+ *\li 'inception' is not NULL
+ *\li 'expire' is not NULL
+ *\li 'mctx' is not NULL
+ *\li 'buffer' is not NULL
+ *\li 'sigrdata' is not NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_NOSPACE
+ *\li #DNS_R_INVALIDTIME - the expiration is before the inception
+ *\li #DNS_R_KEYUNAUTHORIZED - the key cannot sign this data (either
+ * it is not a zone key or its flags prevent
+ * authentication)
+ *\li DST_R_*
+ */
+
+isc_result_t
+dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
+ isc_boolean_t ignoretime, isc_mem_t *mctx,
+ dns_rdata_t *sigrdata);
+
+isc_result_t
+dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
+ isc_boolean_t ignoretime, isc_mem_t *mctx,
+ dns_rdata_t *sigrdata, dns_name_t *wild);
+/*%<
+ * Verifies the SIG record covering this rdataset signed by a specific
+ * key. This does not determine if the key's owner is authorized to
+ * sign this record, as this requires a resolver or database.
+ * If 'ignoretime' is ISC_TRUE, temporal validity will not be checked.
+ *
+ * Requires:
+ *\li 'name' (the owner name of the record) is a valid name
+ *\li 'set' is a valid rdataset
+ *\li 'key' is a valid key
+ *\li 'mctx' is not NULL
+ *\li 'sigrdata' is a valid rdata containing a SIG record
+ *\li 'wild' if non-NULL then is a valid and has a buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #DNS_R_FROMWILDCARD - the signature is valid and is from
+ * a wildcard expansion. dns_dnssec_verify2() only.
+ * 'wild' contains the name of the wildcard if non-NULL.
+ *\li #DNS_R_SIGINVALID - the signature fails to verify
+ *\li #DNS_R_SIGEXPIRED - the signature has expired
+ *\li #DNS_R_SIGFUTURE - the signature's validity period has not begun
+ *\li #DNS_R_KEYUNAUTHORIZED - the key cannot sign this data (either
+ * it is not a zone key or its flags prevent
+ * authentication)
+ *\li DST_R_*
+ */
+
+/*@{*/
+isc_result_t
+dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
+ dns_name_t *name, isc_mem_t *mctx,
+ unsigned int maxkeys, dst_key_t **keys,
+ unsigned int *nkeys);
+isc_result_t
+dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
+ dns_dbnode_t *node, dns_name_t *name,
+ const char *directory, isc_mem_t *mctx,
+ unsigned int maxkeys, dst_key_t **keys,
+ unsigned int *nkeys);
+/*%<
+ * Finds a set of zone keys.
+ * XXX temporary - this should be handled in dns_zone_t.
+ */
+/*@}*/
+
+isc_result_t
+dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key);
+/*%<
+ * Signs a message with a SIG(0) record. This is implicitly called by
+ * dns_message_renderend() if msg->sig0key is not NULL.
+ *
+ * Requires:
+ *\li 'msg' is a valid message
+ *\li 'key' is a valid key that can be used for signing
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li DST_R_*
+ */
+
+isc_result_t
+dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
+ dst_key_t *key);
+/*%<
+ * Verifies a message signed by a SIG(0) record. This is not
+ * called implicitly by dns_message_parse(). If dns_message_signer()
+ * is called before dns_dnssec_verifymessage(), it will return
+ * #DNS_R_NOTVERIFIEDYET. dns_dnssec_verifymessage() will set
+ * the verified_sig0 flag in msg if the verify succeeds, and
+ * the sig0status field otherwise.
+ *
+ * Requires:
+ *\li 'source' is a valid buffer containing the unparsed message
+ *\li 'msg' is a valid message
+ *\li 'key' is a valid key
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_NOTFOUND - no SIG(0) was found
+ *\li #DNS_R_SIGINVALID - the SIG record is not well-formed or
+ * was not generated by the key.
+ *\li DST_R_*
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_DNSSEC_H */
diff --git a/lib/dns/include/dns/ds.h b/lib/dns/include/dns/ds.h
new file mode 100644
index 0000000..5e4cc40
--- /dev/null
+++ b/lib/dns/include/dns/ds.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: ds.h,v 1.3.20.5 2006/02/22 23:50:09 marka Exp $ */
+
+#ifndef DNS_DS_H
+#define DNS_DS_H 1
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+#define DNS_DSDIGEST_SHA1 (1)
+#define DNS_DSDIGEST_SHA256 (2)
+
+/*
+ * Assuming SHA-256 digest type.
+ */
+#define DNS_DS_BUFFERSIZE (36)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key,
+ unsigned int digest_type, unsigned char *buffer,
+ dns_rdata_t *rdata);
+/*%<
+ * Build the rdata of a DS record.
+ *
+ * Requires:
+ *\li key Points to a valid DNS KEY record.
+ *\li buffer Points to a temporary buffer of at least
+ * #DNS_DS_BUFFERSIZE bytes.
+ *\li rdata Points to an initialized dns_rdata_t.
+ *
+ * Ensures:
+ * \li *rdata Contains a valid DS rdata. The 'data' member refers
+ * to 'buffer'.
+ */
+
+isc_boolean_t
+dns_ds_digest_supported(unsigned int digest_type);
+/*%<
+ * Is this digest algorithm supported by dns_ds_buildrdata()?
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_DS_H */
diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h
new file mode 100644
index 0000000..d1ebef3
--- /dev/null
+++ b/lib/dns/include/dns/events.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2004, 2005 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: events.h,v 1.42.18.3 2005/04/29 00:16:13 marka Exp $ */
+
+#ifndef DNS_EVENTS_H
+#define DNS_EVENTS_H 1
+
+#include <isc/eventclass.h>
+
+/*! \file
+ * \brief
+ * Registry of DNS event numbers.
+ */
+
+#define DNS_EVENT_FETCHCONTROL (ISC_EVENTCLASS_DNS + 0)
+#define DNS_EVENT_FETCHDONE (ISC_EVENTCLASS_DNS + 1)
+#define DNS_EVENT_VIEWRESSHUTDOWN (ISC_EVENTCLASS_DNS + 2)
+#define DNS_EVENT_VIEWADBSHUTDOWN (ISC_EVENTCLASS_DNS + 3)
+#define DNS_EVENT_UPDATE (ISC_EVENTCLASS_DNS + 4)
+#define DNS_EVENT_UPDATEDONE (ISC_EVENTCLASS_DNS + 5)
+#define DNS_EVENT_DISPATCH (ISC_EVENTCLASS_DNS + 6)
+#define DNS_EVENT_TCPMSG (ISC_EVENTCLASS_DNS + 7)
+#define DNS_EVENT_ADBMOREADDRESSES (ISC_EVENTCLASS_DNS + 8)
+#define DNS_EVENT_ADBNOMOREADDRESSES (ISC_EVENTCLASS_DNS + 9)
+#define DNS_EVENT_ADBCANCELED (ISC_EVENTCLASS_DNS + 10)
+#define DNS_EVENT_ADBNAMEDELETED (ISC_EVENTCLASS_DNS + 11)
+#define DNS_EVENT_ADBSHUTDOWN (ISC_EVENTCLASS_DNS + 12)
+#define DNS_EVENT_ADBEXPIRED (ISC_EVENTCLASS_DNS + 13)
+#define DNS_EVENT_ADBCONTROL (ISC_EVENTCLASS_DNS + 14)
+#define DNS_EVENT_CACHECLEAN (ISC_EVENTCLASS_DNS + 15)
+#define DNS_EVENT_BYADDRDONE (ISC_EVENTCLASS_DNS + 16)
+#define DNS_EVENT_ZONECONTROL (ISC_EVENTCLASS_DNS + 17)
+#define DNS_EVENT_DBDESTROYED (ISC_EVENTCLASS_DNS + 18)
+#define DNS_EVENT_VALIDATORDONE (ISC_EVENTCLASS_DNS + 19)
+#define DNS_EVENT_REQUESTDONE (ISC_EVENTCLASS_DNS + 20)
+#define DNS_EVENT_VALIDATORSTART (ISC_EVENTCLASS_DNS + 21)
+#define DNS_EVENT_VIEWREQSHUTDOWN (ISC_EVENTCLASS_DNS + 22)
+#define DNS_EVENT_NOTIFYSENDTOADDR (ISC_EVENTCLASS_DNS + 23)
+#define DNS_EVENT_ZONE (ISC_EVENTCLASS_DNS + 24)
+#define DNS_EVENT_ZONESTARTXFRIN (ISC_EVENTCLASS_DNS + 25)
+#define DNS_EVENT_MASTERQUANTUM (ISC_EVENTCLASS_DNS + 26)
+#define DNS_EVENT_CACHEOVERMEM (ISC_EVENTCLASS_DNS + 27)
+#define DNS_EVENT_MASTERNEXTZONE (ISC_EVENTCLASS_DNS + 28)
+#define DNS_EVENT_IOREADY (ISC_EVENTCLASS_DNS + 29)
+#define DNS_EVENT_LOOKUPDONE (ISC_EVENTCLASS_DNS + 30)
+/* #define DNS_EVENT_unused (ISC_EVENTCLASS_DNS + 31) */
+#define DNS_EVENT_DISPATCHCONTROL (ISC_EVENTCLASS_DNS + 32)
+#define DNS_EVENT_REQUESTCONTROL (ISC_EVENTCLASS_DNS + 33)
+#define DNS_EVENT_DUMPQUANTUM (ISC_EVENTCLASS_DNS + 34)
+#define DNS_EVENT_IMPORTRECVDONE (ISC_EVENTCLASS_DNS + 35)
+#define DNS_EVENT_FREESTORAGE (ISC_EVENTCLASS_DNS + 36)
+#define DNS_EVENT_VIEWACACHESHUTDOWN (ISC_EVENTCLASS_DNS + 37)
+#define DNS_EVENT_ACACHECONTROL (ISC_EVENTCLASS_DNS + 38)
+#define DNS_EVENT_ACACHECLEAN (ISC_EVENTCLASS_DNS + 39)
+#define DNS_EVENT_ACACHEOVERMEM (ISC_EVENTCLASS_DNS + 40)
+
+#define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0)
+#define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535)
+
+#endif /* DNS_EVENTS_H */
diff --git a/lib/dns/include/dns/fixedname.h b/lib/dns/include/dns/fixedname.h
new file mode 100644
index 0000000..8380de6
--- /dev/null
+++ b/lib/dns/include/dns/fixedname.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2004, 2005 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: fixedname.h,v 1.13.18.2 2005/04/29 00:16:13 marka Exp $ */
+
+#ifndef DNS_FIXEDNAME_H
+#define DNS_FIXEDNAME_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Fixed-size Names
+ *
+ * dns_fixedname_t is a convenience type containing a name, an offsets table,
+ * and a dedicated buffer big enough for the longest possible name.
+ *
+ * MP:
+ *\li The caller must ensure any required synchronization.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li Per dns_fixedname_t:
+ *\code
+ * sizeof(dns_name_t) + sizeof(dns_offsets_t) +
+ * sizeof(isc_buffer_t) + 255 bytes + structure padding
+ *\endcode
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li None.
+ */
+
+/*****
+ ***** Imports
+ *****/
+
+#include <isc/buffer.h>
+
+#include <dns/name.h>
+
+/*****
+ ***** Types
+ *****/
+
+struct dns_fixedname {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_buffer_t buffer;
+ unsigned char data[DNS_NAME_MAXWIRE];
+};
+
+#define dns_fixedname_init(fn) \
+ do { \
+ dns_name_init(&((fn)->name), (fn)->offsets); \
+ isc_buffer_init(&((fn)->buffer), (fn)->data, \
+ DNS_NAME_MAXWIRE); \
+ dns_name_setbuffer(&((fn)->name), &((fn)->buffer)); \
+ } while (0)
+
+#define dns_fixedname_invalidate(fn) \
+ dns_name_invalidate(&((fn)->name))
+
+#define dns_fixedname_name(fn) (&((fn)->name))
+
+#endif /* DNS_FIXEDNAME_H */
diff --git a/lib/dns/include/dns/forward.h b/lib/dns/include/dns/forward.h
new file mode 100644
index 0000000..ddf6d7f
--- /dev/null
+++ b/lib/dns/include/dns/forward.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2004, 2005 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: forward.h,v 1.3.18.3 2005/04/27 05:01:33 sra Exp $ */
+
+#ifndef DNS_FORWARD_H
+#define DNS_FORWARD_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+struct dns_forwarders {
+ isc_sockaddrlist_t addrs;
+ dns_fwdpolicy_t fwdpolicy;
+};
+
+isc_result_t
+dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep);
+/*%<
+ * Creates a new forwarding table.
+ *
+ * Requires:
+ * \li mctx is a valid memory context.
+ * \li fwdtablep != NULL && *fwdtablep == NULL
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name,
+ isc_sockaddrlist_t *addrs, dns_fwdpolicy_t policy);
+/*%<
+ * Adds an entry to the forwarding table. The entry associates
+ * a domain with a list of forwarders and a forwarding policy. The
+ * addrs list is copied if not empty, so the caller should free its copy.
+ *
+ * Requires:
+ * \li fwdtable is a valid forwarding table.
+ * \li name is a valid name
+ * \li addrs is a valid list of sockaddrs, which may be empty.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_fwdtable_find(dns_fwdtable_t *fwdtable, dns_name_t *name,
+ dns_forwarders_t **forwardersp);
+/*%<
+ * Finds a domain in the forwarding table. The closest matching parent
+ * domain is returned.
+ *
+ * Requires:
+ * \li fwdtable is a valid forwarding table.
+ * \li name is a valid name
+ * \li forwardersp != NULL && *forwardersp == NULL
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND
+ */
+
+isc_result_t
+dns_fwdtable_find2(dns_fwdtable_t *fwdtable, dns_name_t *name,
+ dns_name_t *foundname, dns_forwarders_t **forwardersp);
+/*%<
+ * Finds a domain in the forwarding table. The closest matching parent
+ * domain is returned.
+ *
+ * Requires:
+ * \li fwdtable is a valid forwarding table.
+ * \li name is a valid name
+ * \li forwardersp != NULL && *forwardersp == NULL
+ * \li foundname to be NULL or a valid name with buffer.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND
+ */
+
+void
+dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep);
+/*%<
+ * Destroys a forwarding table.
+ *
+ * Requires:
+ * \li fwtablep != NULL && *fwtablep != NULL
+ *
+ * Ensures:
+ * \li all memory associated with the forwarding table is freed.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_FORWARD_H */
diff --git a/lib/dns/include/dns/journal.h b/lib/dns/include/dns/journal.h
new file mode 100644
index 0000000..b776a30
--- /dev/null
+++ b/lib/dns/include/dns/journal.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2004, 2005 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: journal.h,v 1.25.18.2 2005/04/29 00:16:13 marka Exp $ */
+
+#ifndef DNS_JOURNAL_H
+#define DNS_JOURNAL_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Database journalling.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+
+#include <dns/name.h>
+#include <dns/diff.h>
+#include <dns/rdata.h>
+#include <dns/types.h>
+
+/***
+ *** Types
+ ***/
+
+/*%
+ * A dns_journal_t represents an open journal file. This is an opaque type.
+ *
+ * A particular dns_journal_t object may be opened for writing, in which case
+ * it can be used for writing transactions to a journal file, or it can be
+ * opened for reading, in which case it can be used for reading transactions
+ * from (iterating over) a journal file. A single dns_journal_t object may
+ * not be used for both purposes.
+ */
+typedef struct dns_journal dns_journal_t;
+
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+/**************************************************************************/
+
+isc_result_t
+dns_db_createsoatuple(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx,
+ dns_diffop_t op, dns_difftuple_t **tp);
+/*!< brief
+ * Create a diff tuple for the current database SOA.
+ * XXX this probably belongs somewhere else.
+ */
+
+
+/*@{*/
+#define DNS_SERIAL_GT(a, b) ((int)(((a) - (b)) & 0xFFFFFFFF) > 0)
+#define DNS_SERIAL_GE(a, b) ((int)(((a) - (b)) & 0xFFFFFFFF) >= 0)
+/*!< brief
+ * Compare SOA serial numbers. DNS_SERIAL_GT(a, b) returns true iff
+ * a is "greater than" b where "greater than" is as defined in RFC1982.
+ * DNS_SERIAL_GE(a, b) returns true iff a is "greater than or equal to" b.
+ */
+/*@}*/
+
+/**************************************************************************/
+/*
+ * Journal object creation and destruction.
+ */
+
+isc_result_t
+dns_journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
+ dns_journal_t **journalp);
+/*%<
+ * Open the journal file 'filename' and create a dns_journal_t object for it.
+ *
+ * If 'write' is ISC_TRUE, the journal is open for writing. If it does
+ * not exist, it is created.
+ *
+ * If 'write' is ISC_FALSE, the journal is open for reading. If it does
+ * not exist, ISC_R_NOTFOUND is returned.
+ */
+
+void
+dns_journal_destroy(dns_journal_t **journalp);
+/*%<
+ * Destroy a dns_journal_t, closing any open files and freeing its memory.
+ */
+
+/**************************************************************************/
+/*
+ * Writing transactions to journals.
+ */
+
+isc_result_t
+dns_journal_begin_transaction(dns_journal_t *j);
+/*%<
+ * Prepare to write a new transaction to the open journal file 'j'.
+ *
+ * Requires:
+ * \li 'j' is open for writing.
+ */
+
+isc_result_t
+dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff);
+/*%<
+ * Write 'diff' to the current transaction of journal file 'j'.
+ *
+ * Requires:
+ * \li 'j' is open for writing and dns_journal_begin_transaction()
+ * has been called.
+ *
+ *\li 'diff' is a full or partial, correctly ordered IXFR
+ * difference sequence.
+ */
+
+isc_result_t
+dns_journal_commit(dns_journal_t *j);
+/*%<
+ * Commit the current transaction of journal file 'j'.
+ *
+ * Requires:
+ * \li 'j' is open for writing and dns_journal_begin_transaction()
+ * has been called.
+ *
+ * \li dns_journal_writediff() has been called one or more times
+ * to form a complete, correctly ordered IXFR difference
+ * sequence.
+ */
+
+isc_result_t
+dns_journal_write_transaction(dns_journal_t *j, dns_diff_t *diff);
+/*%
+ * Write a complete transaction at once to a journal file,
+ * sorting it if necessary, and commit it. Equivalent to calling
+ * dns_diff_sort(), dns_journal_begin_transaction(),
+ * dns_journal_writediff(), and dns_journal_commit().
+ *
+ * Requires:
+ *\li 'j' is open for writing.
+ *
+ * \li 'diff' contains exactly one SOA deletion, one SOA addition
+ * with a greater serial number, and possibly other changes,
+ * in arbitrary order.
+ */
+
+/**************************************************************************/
+/*
+ * Reading transactions from journals.
+ */
+
+isc_uint32_t
+dns_journal_first_serial(dns_journal_t *j);
+isc_uint32_t
+dns_journal_last_serial(dns_journal_t *j);
+/*%<
+ * Get the first and last addressable serial number in the journal.
+ */
+
+isc_result_t
+dns_journal_iter_init(dns_journal_t *j,
+ isc_uint32_t begin_serial, isc_uint32_t end_serial);
+/*%<
+ * Prepare to iterate over the transactions that will bring the database
+ * from SOA serial number 'begin_serial' to 'end_serial'.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_RANGE begin_serial is outside the addressable range.
+ *\li ISC_R_NOTFOUND begin_serial is within the range of adressable
+ * serial numbers covered by the journal, but
+ * this particular serial number does not exist.
+ */
+
+/*@{*/
+isc_result_t
+dns_journal_first_rr(dns_journal_t *j);
+isc_result_t
+dns_journal_next_rr(dns_journal_t *j);
+/*%<
+ * Position the iterator at the first/next RR in a journal
+ * transaction sequence established using dns_journal_iter_init().
+ *
+ * Requires:
+ * \li dns_journal_iter_init() has been called.
+ *
+ */
+/*@}*/
+
+void
+dns_journal_current_rr(dns_journal_t *j, dns_name_t **name, isc_uint32_t *ttl,
+ dns_rdata_t **rdata);
+/*%<
+ * Get the name, ttl, and rdata of the current journal RR.
+ *
+ * Requires:
+ * \li The last call to dns_journal_first_rr() or dns_journal_next_rr()
+ * returned ISC_R_SUCCESS.
+ */
+
+/**************************************************************************/
+/*
+ * Database roll-forward.
+ */
+
+isc_result_t
+dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, const char *filename);
+/*%<
+ * Roll forward (play back) the journal file "filename" into the
+ * database "db". This should be called when the server starts
+ * after a shutdown or crash.
+ *
+ * Requires:
+ *\li 'mctx' is a valid memory context.
+ *\li 'db' is a valid database which does not have a version
+ * open for writing.
+ * \li 'filename' is the name of the journal file belonging to 'db'.
+ *
+ * Returns:
+ *\li DNS_R_NOJOURNAL when journal does not exist.
+ *\li ISC_R_NOTFOUND when current serial in not in journal.
+ *\li ISC_R_RANGE when current serial in not in journals range.
+ *\li ISC_R_SUCCESS journal has been applied successfully to database.
+ * others
+ */
+
+isc_result_t
+dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file);
+/* For debugging not general use */
+
+isc_result_t
+dns_db_diff(isc_mem_t *mctx,
+ dns_db_t *dba, dns_dbversion_t *dbvera,
+ dns_db_t *dbb, dns_dbversion_t *dbverb,
+ const char *journal_filename);
+/*%<
+ * Compare the databases 'dba' and 'dbb' and generate a journal
+ * entry containing the changes to make 'dba' from 'dbb' (note
+ * the order). This journal entry will consist of a single,
+ * possibly very large transaction. Append the journal
+ * entry to the journal file specified by 'journal_filename'.
+ */
+
+isc_result_t
+dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
+ isc_uint32_t target_size);
+/*%<
+ * Attempt to compact the journal if it is greater that 'target_size'.
+ * Changes from 'serial' onwards will be preserved. If the journal
+ * exists and is non-empty 'serial' must exist in the journal.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_JOURNAL_H */
diff --git a/lib/dns/include/dns/keyflags.h b/lib/dns/include/dns/keyflags.h
new file mode 100644
index 0000000..665b517
--- /dev/null
+++ b/lib/dns/include/dns/keyflags.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2004, 2005 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: keyflags.h,v 1.10.18.2 2005/04/29 00:16:13 marka Exp $ */
+
+#ifndef DNS_KEYFLAGS_H
+#define DNS_KEYFLAGS_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_keyflags_fromtext(dns_keyflags_t *flagsp, isc_textregion_t *source);
+/*%<
+ * Convert the text 'source' refers to into a DNSSEC KEY flags value.
+ * The text may contain either a set of flag mnemonics separated by
+ * vertical bars or a decimal flags value. For compatibility with
+ * older versions of BIND and the DNSSEC signer, octal values
+ * prefixed with a zero and hexadecimal values prefixed with "0x"
+ * are also accepted.
+ *
+ * Requires:
+ *\li 'flagsp' is a valid pointer.
+ *
+ *\li 'source' is a valid text region.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS on success
+ *\li ISC_R_RANGE numeric flag value is out of range
+ *\li DNS_R_UNKNOWN mnemonic flag is unknown
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_KEYFLAGS_H */
diff --git a/lib/dns/include/dns/keytable.h b/lib/dns/include/dns/keytable.h
new file mode 100644
index 0000000..b8bfcc1
--- /dev/null
+++ b/lib/dns/include/dns/keytable.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2004, 2005 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: keytable.h,v 1.11.18.3 2005/12/05 00:00:03 marka Exp $ */
+
+#ifndef DNS_KEYTABLE_H
+#define DNS_KEYTABLE_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * The keytable module provides services for storing and retrieving DNSSEC
+ * trusted keys, as well as the ability to find the deepest matching key
+ * for a given domain name.
+ *
+ * MP:
+ *\li The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+#include <dst/dst.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep);
+/*%<
+ * Create a keytable.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li keytablep != NULL && *keytablep == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, *keytablep is a valid, empty key table.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *
+ *\li Any other result indicates failure.
+ */
+
+
+void
+dns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp);
+/*%<
+ * Attach *targetp to source.
+ *
+ * Requires:
+ *
+ *\li 'source' is a valid keytable.
+ *
+ *\li 'targetp' points to a NULL dns_keytable_t *.
+ *
+ * Ensures:
+ *
+ *\li *targetp is attached to source.
+ */
+
+void
+dns_keytable_detach(dns_keytable_t **keytablep);
+/*%<
+ * Detach *keytablep from its keytable.
+ *
+ * Requires:
+ *
+ *\li 'keytablep' points to a valid keytable.
+ *
+ * Ensures:
+ *
+ *\li *keytablep is NULL.
+ *
+ *\li If '*keytablep' is the last reference to the keytable,
+ * all resources used by the keytable will be freed
+ */
+
+isc_result_t
+dns_keytable_add(dns_keytable_t *keytable, dst_key_t **keyp);
+/*%<
+ * Add '*keyp' to 'keytable'.
+ *
+ * Notes:
+ *
+ *\li Ownership of *keyp is transferred to the keytable.
+ *
+ * Requires:
+ *
+ *\li keyp != NULL && *keyp is a valid dst_key_t *.
+ *
+ * Ensures:
+ *
+ *\li On success, *keyp == NULL
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *
+ *\li Any other result indicates failure.
+ */
+
+isc_result_t
+dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name,
+ dns_secalg_t algorithm, dns_keytag_t tag,
+ dns_keynode_t **keynodep);
+/*%<
+ * Search for a key named 'name', matching 'algorithm' and 'tag' in
+ * 'keytable'. This finds the first instance which matches. Use
+ * dns_keytable_findnextkeynode() to find other instances.
+ *
+ * Requires:
+ *
+ *\li 'keytable' is a valid keytable.
+ *
+ *\li 'name' is a valid absolute name.
+ *
+ *\li keynodep != NULL && *keynodep == NULL
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *\li DNS_R_PARTIALMATCH the name existed in the keytable.
+ *\li ISC_R_NOTFOUND
+ *
+ *\li Any other result indicates an error.
+ */
+
+isc_result_t
+dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
+ dns_keynode_t **nextnodep);
+/*%<
+ * Search for the next key with the same properties as 'keynode' in
+ * 'keytable' as found by dns_keytable_findkeynode().
+ *
+ * Requires:
+ *
+ *\li 'keytable' is a valid keytable.
+ *
+ *\li 'keynode' is a valid keynode.
+ *
+ *\li nextnodep != NULL && *nextnodep == NULL
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOTFOUND
+ *
+ *\li Any other result indicates an error.
+ */
+
+isc_result_t
+dns_keytable_finddeepestmatch(dns_keytable_t *keytable, dns_name_t *name,
+ dns_name_t *foundname);
+/*%<
+ * Search for the deepest match of 'name' in 'keytable'.
+ *
+ * Requires:
+ *
+ *\li 'keytable' is a valid keytable.
+ *
+ *\li 'name' is a valid absolute name.
+ *
+ *\li 'foundname' is a name with a dedicated buffer.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOTFOUND
+ *
+ *\li Any other result indicates an error.
+ */
+
+void
+dns_keytable_detachkeynode(dns_keytable_t *keytable,
+ dns_keynode_t **keynodep);
+/*%<
+ * Give back a keynode found via dns_keytable_findkeynode().
+ *
+ * Requires:
+ *
+ *\li 'keytable' is a valid keytable.
+ *
+ *\li *keynodep is a valid keynode returned by a call to
+ * dns_keytable_findkeynode().
+ *
+ * Ensures:
+ *
+ *\li *keynodep == NULL
+ */
+
+isc_result_t
+dns_keytable_issecuredomain(dns_keytable_t *keytable, dns_name_t *name,
+ isc_boolean_t *wantdnssecp);
+/*%<
+ * Is 'name' at or beneath a trusted key?
+ *
+ * Requires:
+ *
+ *\li 'keytable' is a valid keytable.
+ *
+ *\li 'name' is a valid absolute name.
+ *
+ *\li '*wantsdnssecp' is a valid isc_boolean_t.
+ *
+ * Ensures:
+ *
+ *\li On success, *wantsdnssecp will be ISC_TRUE if and only if 'name'
+ * is at or beneath a trusted key.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *
+ *\li Any other result is an error.
+ */
+
+dst_key_t *
+dns_keynode_key(dns_keynode_t *keynode);
+/*%<
+ * Get the DST key associated with keynode.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_KEYTABLE_H */
diff --git a/lib/dns/include/dns/keyvalues.h b/lib/dns/include/dns/keyvalues.h
new file mode 100644
index 0000000..df17ace
--- /dev/null
+++ b/lib/dns/include/dns/keyvalues.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2004, 2005 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: keyvalues.h,v 1.15.18.2 2005/04/29 00:16:14 marka Exp $ */
+
+#ifndef DNS_KEYVALUES_H
+#define DNS_KEYVALUES_H 1
+
+/*! \file */
+
+/*
+ * Flags field of the KEY RR rdata
+ */
+#define DNS_KEYFLAG_TYPEMASK 0xC000 /*%< Mask for "type" bits */
+#define DNS_KEYTYPE_AUTHCONF 0x0000 /*%< Key usable for both */
+#define DNS_KEYTYPE_CONFONLY 0x8000 /*%< Key usable for confidentiality */
+#define DNS_KEYTYPE_AUTHONLY 0x4000 /*%< Key usable for authentication */
+#define DNS_KEYTYPE_NOKEY 0xC000 /*%< No key usable for either; no key */
+#define DNS_KEYTYPE_NOAUTH DNS_KEYTYPE_CONFONLY
+#define DNS_KEYTYPE_NOCONF DNS_KEYTYPE_AUTHONLY
+
+#define DNS_KEYFLAG_RESERVED2 0x2000 /*%< reserved - must be zero */
+#define DNS_KEYFLAG_EXTENDED 0x1000 /*%< key has extended flags */
+#define DNS_KEYFLAG_RESERVED4 0x0800 /*%< reserved - must be zero */
+#define DNS_KEYFLAG_RESERVED5 0x0400 /*%< reserved - must be zero */
+#define DNS_KEYFLAG_OWNERMASK 0x0300 /*%< these bits determine the type */
+#define DNS_KEYOWNER_USER 0x0000 /*%< key is assoc. with user */
+#define DNS_KEYOWNER_ENTITY 0x0200 /*%< key is assoc. with entity eg host */
+#define DNS_KEYOWNER_ZONE 0x0100 /*%< key is zone key */
+#define DNS_KEYOWNER_RESERVED 0x0300 /*%< reserved meaning */
+#define DNS_KEYFLAG_RESERVED8 0x0080 /*%< reserved - must be zero */
+#define DNS_KEYFLAG_RESERVED9 0x0040 /*%< reserved - must be zero */
+#define DNS_KEYFLAG_RESERVED10 0x0020 /*%< reserved - must be zero */
+#define DNS_KEYFLAG_RESERVED11 0x0010 /*%< reserved - must be zero */
+#define DNS_KEYFLAG_SIGNATORYMASK 0x000F /*%< key can sign RR's of same name */
+
+#define DNS_KEYFLAG_RESERVEDMASK (DNS_KEYFLAG_RESERVED2 | \
+ DNS_KEYFLAG_RESERVED4 | \
+ DNS_KEYFLAG_RESERVED5 | \
+ DNS_KEYFLAG_RESERVED8 | \
+ DNS_KEYFLAG_RESERVED9 | \
+ DNS_KEYFLAG_RESERVED10 | \
+ DNS_KEYFLAG_RESERVED11 )
+#define DNS_KEYFLAG_KSK 0x0001 /*%< key signing key */
+
+#define DNS_KEYFLAG_RESERVEDMASK2 0xFFFF /*%< no bits defined here */
+
+/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */
+#define DNS_KEYALG_RSAMD5 1 /*%< RSA with MD5 */
+#define DNS_KEYALG_RSA DNS_KEYALG_RSAMD5
+#define DNS_KEYALG_DH 2 /*%< Diffie Hellman KEY */
+#define DNS_KEYALG_DSA 3 /*%< DSA KEY */
+#define DNS_KEYALG_DSS NS_ALG_DSA
+#define DNS_KEYALG_ECC 4
+#define DNS_KEYALG_RSASHA1 5
+#define DNS_KEYALG_INDIRECT 252
+#define DNS_KEYALG_PRIVATEDNS 253
+#define DNS_KEYALG_PRIVATEOID 254 /*%< Key begins with OID giving alg */
+
+/* Protocol values */
+#define DNS_KEYPROTO_RESERVED 0
+#define DNS_KEYPROTO_TLS 1
+#define DNS_KEYPROTO_EMAIL 2
+#define DNS_KEYPROTO_DNSSEC 3
+#define DNS_KEYPROTO_IPSEC 4
+#define DNS_KEYPROTO_ANY 255
+
+/* Signatures */
+#define DNS_SIG_RSAMINBITS 512 /*%< Size of a mod or exp in bits */
+#define DNS_SIG_RSAMAXBITS 2552
+ /* Total of binary mod and exp */
+#define DNS_SIG_RSAMAXBYTES ((DNS_SIG_RSAMAXBITS+7/8)*2+3)
+ /*%< Max length of text sig block */
+#define DNS_SIG_RSAMAXBASE64 (((DNS_SIG_RSAMAXBYTES+2)/3)*4)
+#define DNS_SIG_RSAMINSIZE ((DNS_SIG_RSAMINBITS+7)/8)
+#define DNS_SIG_RSAMAXSIZE ((DNS_SIG_RSAMAXBITS+7)/8)
+
+#define DNS_SIG_DSASIGSIZE 41
+#define DNS_SIG_DSAMINBITS 512
+#define DNS_SIG_DSAMAXBITS 1024
+#define DNS_SIG_DSAMINBYTES 213
+#define DNS_SIG_DSAMAXBYTES 405
+
+#endif /* DNS_KEYVALUES_H */
diff --git a/lib/dns/include/dns/lib.h b/lib/dns/include/dns/lib.h
new file mode 100644
index 0000000..d59dde3
--- /dev/null
+++ b/lib/dns/include/dns/lib.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2005 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: lib.h,v 1.8.18.4 2005/09/20 04:33:48 marka Exp $ */
+
+#ifndef DNS_LIB_H
+#define DNS_LIB_H 1
+
+/*! \file */
+
+#include <isc/types.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * Tuning: external query load in packets per seconds.
+ */
+LIBDNS_EXTERNAL_DATA extern unsigned int dns_pps;
+LIBDNS_EXTERNAL_DATA extern isc_msgcat_t *dns_msgcat;
+
+void
+dns_lib_initmsgcat(void);
+/*%<
+ * Initialize the DNS library's message catalog, dns_msgcat, if it
+ * has not already been initialized.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_LIB_H */
diff --git a/lib/dns/include/dns/log.h b/lib/dns/include/dns/log.h
new file mode 100644
index 0000000..7bee174
--- /dev/null
+++ b/lib/dns/include/dns/log.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2004, 2005 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: log.h,v 1.33.18.4 2005/09/05 00:18:27 marka Exp $ */
+
+/*! \file
+ * \author Principal Authors: DCL */
+
+#ifndef DNS_LOG_H
+#define DNS_LOG_H 1
+
+#include <isc/lang.h>
+#include <isc/log.h>
+
+LIBDNS_EXTERNAL_DATA extern isc_log_t *dns_lctx;
+LIBDNS_EXTERNAL_DATA extern isc_logcategory_t dns_categories[];
+LIBDNS_EXTERNAL_DATA extern isc_logmodule_t dns_modules[];
+
+#define DNS_LOGCATEGORY_NOTIFY (&dns_categories[0])
+#define DNS_LOGCATEGORY_DATABASE (&dns_categories[1])
+#define DNS_LOGCATEGORY_SECURITY (&dns_categories[2])
+/* DNS_LOGCATEGORY_CONFIG superseded by CFG_LOGCATEGORY_CONFIG */
+#define DNS_LOGCATEGORY_DNSSEC (&dns_categories[4])
+#define DNS_LOGCATEGORY_RESOLVER (&dns_categories[5])
+#define DNS_LOGCATEGORY_XFER_IN (&dns_categories[6])
+#define DNS_LOGCATEGORY_XFER_OUT (&dns_categories[7])
+#define DNS_LOGCATEGORY_DISPATCH (&dns_categories[8])
+#define DNS_LOGCATEGORY_LAME_SERVERS (&dns_categories[9])
+#define DNS_LOGCATEGORY_DELEGATION_ONLY (&dns_categories[10])
+
+/* Backwards compatibility. */
+#define DNS_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL
+
+#define DNS_LOGMODULE_DB (&dns_modules[0])
+#define DNS_LOGMODULE_RBTDB (&dns_modules[1])
+#define DNS_LOGMODULE_RBTDB64 (&dns_modules[2])
+#define DNS_LOGMODULE_RBT (&dns_modules[3])
+#define DNS_LOGMODULE_RDATA (&dns_modules[4])
+#define DNS_LOGMODULE_MASTER (&dns_modules[5])
+#define DNS_LOGMODULE_MESSAGE (&dns_modules[6])
+#define DNS_LOGMODULE_CACHE (&dns_modules[7])
+#define DNS_LOGMODULE_CONFIG (&dns_modules[8])
+#define DNS_LOGMODULE_RESOLVER (&dns_modules[9])
+#define DNS_LOGMODULE_ZONE (&dns_modules[10])
+#define DNS_LOGMODULE_JOURNAL (&dns_modules[11])
+#define DNS_LOGMODULE_ADB (&dns_modules[12])
+#define DNS_LOGMODULE_XFER_IN (&dns_modules[13])
+#define DNS_LOGMODULE_XFER_OUT (&dns_modules[14])
+#define DNS_LOGMODULE_ACL (&dns_modules[15])
+#define DNS_LOGMODULE_VALIDATOR (&dns_modules[16])
+#define DNS_LOGMODULE_DISPATCH (&dns_modules[17])
+#define DNS_LOGMODULE_REQUEST (&dns_modules[18])
+#define DNS_LOGMODULE_MASTERDUMP (&dns_modules[19])
+#define DNS_LOGMODULE_TSIG (&dns_modules[20])
+#define DNS_LOGMODULE_TKEY (&dns_modules[21])
+#define DNS_LOGMODULE_SDB (&dns_modules[22])
+#define DNS_LOGMODULE_DIFF (&dns_modules[23])
+#define DNS_LOGMODULE_HINTS (&dns_modules[24])
+#define DNS_LOGMODULE_ACACHE (&dns_modules[25])
+#define DNS_LOGMODULE_DLZ (&dns_modules[26])
+
+ISC_LANG_BEGINDECLS
+
+void
+dns_log_init(isc_log_t *lctx);
+/*%
+ * Make the libdns categories and modules available for use with the
+ * ISC logging library.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ *\li dns_log_init() is called only once.
+ *
+ * Ensures:
+ * \li The catgories and modules defined above are available for
+ * use by isc_log_usechannnel() and isc_log_write().
+ */
+
+void
+dns_log_setcontext(isc_log_t *lctx);
+/*%
+ * Make the libdns library use the provided context for logging internal
+ * messages.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_LOG_H */
diff --git a/lib/dns/include/dns/lookup.h b/lib/dns/include/dns/lookup.h
new file mode 100644
index 0000000..aea6f84
--- /dev/null
+++ b/lib/dns/include/dns/lookup.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2004, 2005 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: lookup.h,v 1.6.18.2 2005/04/29 00:16:15 marka Exp $ */
+
+#ifndef DNS_LOOKUP_H
+#define DNS_LOOKUP_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * The lookup module performs simple DNS lookups. It implements
+ * the full resolver algorithm, both looking for local data and
+ * resoving external names as necessary.
+ *
+ * MP:
+ *\li The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li RFCs: 1034, 1035, 2181, TBS
+ *\li Drafts: TBS
+ */
+
+#include <isc/lang.h>
+#include <isc/event.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * A 'dns_lookupevent_t' is returned when a lookup completes.
+ * The sender field will be set to the lookup that completed. If 'result'
+ * is ISC_R_SUCCESS, then 'names' will contain a list of names associated
+ * with the address. The recipient of the event must not change the list
+ * and must not refer to any of the name data after the event is freed.
+ */
+typedef struct dns_lookupevent {
+ ISC_EVENT_COMMON(struct dns_lookupevent);
+ isc_result_t result;
+ dns_name_t *name;
+ dns_rdataset_t *rdataset;
+ dns_rdataset_t *sigrdataset;
+ dns_db_t *db;
+ dns_dbnode_t *node;
+} dns_lookupevent_t;
+
+isc_result_t
+dns_lookup_create(isc_mem_t *mctx, dns_name_t *name, dns_rdatatype_t type,
+ dns_view_t *view, unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg, dns_lookup_t **lookupp);
+/*%<
+ * Finds the rrsets matching 'name' and 'type'.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid mctx.
+ *
+ *\li 'name' is a valid name.
+ *
+ *\li 'view' is a valid view which has a resolver.
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li lookupp != NULL && *lookupp == NULL
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOMEMORY
+ *
+ *\li Any resolver-related error (e.g. ISC_R_SHUTTINGDOWN) may also be
+ * returned.
+ */
+
+void
+dns_lookup_cancel(dns_lookup_t *lookup);
+/*%<
+ * Cancel 'lookup'.
+ *
+ * Notes:
+ *
+ *\li If 'lookup' has not completed, post its LOOKUPDONE event with a
+ * result code of ISC_R_CANCELED.
+ *
+ * Requires:
+ *
+ *\li 'lookup' is a valid lookup.
+ */
+
+void
+dns_lookup_destroy(dns_lookup_t **lookupp);
+/*%<
+ * Destroy 'lookup'.
+ *
+ * Requires:
+ *
+ *\li '*lookupp' is a valid lookup.
+ *
+ *\li The caller has received the LOOKUPDONE event (either because the
+ * lookup completed or because dns_lookup_cancel() was called).
+ *
+ * Ensures:
+ *
+ *\li *lookupp == NULL.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_LOOKUP_H */
diff --git a/lib/dns/include/dns/master.h b/lib/dns/include/dns/master.h
new file mode 100644
index 0000000..1f94c8c
--- /dev/null
+++ b/lib/dns/include/dns/master.h
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2004, 2005 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: master.h,v 1.38.18.6 2005/06/20 01:19:43 marka Exp $ */
+
+#ifndef DNS_MASTER_H
+#define DNS_MASTER_H 1
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+/*
+ * Flags to be passed in the 'options' argument in the functions below.
+ */
+#define DNS_MASTER_AGETTL 0x00000001 /*%< Age the ttl based on $DATE. */
+#define DNS_MASTER_MANYERRORS 0x00000002 /*%< Continue processing on errors. */
+#define DNS_MASTER_NOINCLUDE 0x00000004 /*%< Disallow $INCLUDE directives. */
+#define DNS_MASTER_ZONE 0x00000008 /*%< Loading a zone master file. */
+#define DNS_MASTER_HINT 0x00000010 /*%< Loading a hint master file. */
+#define DNS_MASTER_SLAVE 0x00000020 /*%< Loading a slave master file. */
+#define DNS_MASTER_CHECKNS 0x00000040 /*%<
+ * Check NS records to see
+ * if they are an address
+ */
+#define DNS_MASTER_FATALNS 0x00000080 /*%<
+ * Treat DNS_MASTER_CHECKNS
+ * matches as fatal
+ */
+#define DNS_MASTER_CHECKNAMES 0x00000100
+#define DNS_MASTER_CHECKNAMESFAIL 0x00000200
+#define DNS_MASTER_CHECKWILDCARD 0x00000400 /* Check for internal wildcards. */
+#define DNS_MASTER_CHECKMX 0x00000800
+#define DNS_MASTER_CHECKMXFAIL 0x00001000
+
+ISC_LANG_BEGINDECLS
+
+/*
+ * Structures that implement the "raw" format for master dump.
+ * These are provided for a reference purpose only; in the actual
+ * encoding, we directly read/write each field so that the encoded data
+ * is always "packed", regardless of the hardware architecture.
+ */
+#define DNS_RAWFORMAT_VERSION 0
+
+/* Common header */
+typedef struct {
+ isc_uint32_t format; /* must be
+ * dns_masterformat_raw */
+ isc_uint32_t version; /* compatibility for future
+ * extensions */
+ isc_uint32_t dumptime; /* timestamp on creation
+ * (currently unused)
+ */
+} dns_masterrawheader_t;
+
+/* The structure for each RRset */
+typedef struct {
+ isc_uint32_t totallen; /* length of the data for this
+ * RRset, including the
+ * "header" part */
+ dns_rdataclass_t rdclass; /* 16-bit class */
+ dns_rdatatype_t type; /* 16-bit type */
+ dns_rdatatype_t covers; /* same as type */
+ dns_ttl_t ttl; /* 32-bit TTL */
+ isc_uint32_t nrdata; /* number of RRs in this set */
+ /* followed by encoded owner name, and then rdata */
+} dns_masterrawrdataset_t;
+
+/***
+ *** Function
+ ***/
+
+isc_result_t
+dns_master_loadfile(const char *master_file,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks,
+ isc_mem_t *mctx);
+
+isc_result_t
+dns_master_loadfile2(const char *master_file,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks,
+ isc_mem_t *mctx,
+ dns_masterformat_t format);
+
+isc_result_t
+dns_master_loadstream(FILE *stream,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks,
+ isc_mem_t *mctx);
+
+isc_result_t
+dns_master_loadbuffer(isc_buffer_t *buffer,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks,
+ isc_mem_t *mctx);
+
+isc_result_t
+dns_master_loadlexer(isc_lex_t *lex,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks,
+ isc_mem_t *mctx);
+
+isc_result_t
+dns_master_loadfileinc(const char *master_file,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks,
+ isc_task_t *task,
+ dns_loaddonefunc_t done, void *done_arg,
+ dns_loadctx_t **ctxp, isc_mem_t *mctx);
+
+isc_result_t
+dns_master_loadfileinc2(const char *master_file,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks,
+ isc_task_t *task,
+ dns_loaddonefunc_t done, void *done_arg,
+ dns_loadctx_t **ctxp, isc_mem_t *mctx,
+ dns_masterformat_t format);
+
+isc_result_t
+dns_master_loadstreaminc(FILE *stream,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks,
+ isc_task_t *task,
+ dns_loaddonefunc_t done, void *done_arg,
+ dns_loadctx_t **ctxp, isc_mem_t *mctx);
+
+isc_result_t
+dns_master_loadbufferinc(isc_buffer_t *buffer,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks,
+ isc_task_t *task,
+ dns_loaddonefunc_t done, void *done_arg,
+ dns_loadctx_t **ctxp, isc_mem_t *mctx);
+
+isc_result_t
+dns_master_loadlexerinc(isc_lex_t *lex,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks,
+ isc_task_t *task,
+ dns_loaddonefunc_t done, void *done_arg,
+ dns_loadctx_t **ctxp, isc_mem_t *mctx);
+
+/*%<
+ * Loads a RFC1305 master file from a file, stream, buffer, or existing
+ * lexer into rdatasets and then calls 'callbacks->commit' to commit the
+ * rdatasets. Rdata memory belongs to dns_master_load and will be
+ * reused / released when the callback completes. dns_load_master will
+ * abort if callbacks->commit returns any value other than ISC_R_SUCCESS.
+ *
+ * If 'DNS_MASTER_AGETTL' is set and the master file contains one or more
+ * $DATE directives, the TTLs of the data will be aged accordingly.
+ *
+ * 'callbacks->commit' is assumed to call 'callbacks->error' or
+ * 'callbacks->warn' to generate any error messages required.
+ *
+ * 'done' is called with 'done_arg' and a result code when the loading
+ * is completed or has failed. If the initial setup fails 'done' is
+ * not called.
+ *
+ * Requires:
+ *\li 'master_file' points to a valid string.
+ *\li 'lexer' points to a valid lexer.
+ *\li 'top' points to a valid name.
+ *\li 'origin' points to a valid name.
+ *\li 'callbacks->commit' points to a valid function.
+ *\li 'callbacks->error' points to a valid function.
+ *\li 'callbacks->warn' points to a valid function.
+ *\li 'mctx' points to a valid memory context.
+ *\li 'task' and 'done' to be valid.
+ *\li 'lmgr' to be valid.
+ *\li 'ctxp != NULL && ctxp == NULL'.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS upon successfully loading the master file.
+ *\li ISC_R_SEENINCLUDE upon successfully loading the master file with
+ * a $INCLUDE statement.
+ *\li ISC_R_NOMEMORY out of memory.
+ *\li ISC_R_UNEXPECTEDEND expected to be able to read a input token and
+ * there was not one.
+ *\li ISC_R_UNEXPECTED
+ *\li DNS_R_NOOWNER failed to specify a ownername.
+ *\li DNS_R_NOTTL failed to specify a ttl.
+ *\li DNS_R_BADCLASS record class did not match zone class.
+ *\li DNS_R_CONTINUE load still in progress (dns_master_load*inc() only).
+ *\li Any dns_rdata_fromtext() error code.
+ *\li Any error code from callbacks->commit().
+ */
+
+void
+dns_loadctx_detach(dns_loadctx_t **ctxp);
+/*%<
+ * Detach from the load context.
+ *
+ * Requires:
+ *\li '*ctxp' to be valid.
+ *
+ * Ensures:
+ *\li '*ctxp == NULL'
+ */
+
+void
+dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target);
+/*%<
+ * Attach to the load context.
+ *
+ * Requires:
+ *\li 'source' to be valid.
+ *\li 'target != NULL && *target == NULL'.
+ */
+
+void
+dns_loadctx_cancel(dns_loadctx_t *ctx);
+/*%<
+ * Cancel loading the zone file associated with this load context.
+ *
+ * Requires:
+ *\li 'ctx' to be valid
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_MASTER_H */
diff --git a/lib/dns/include/dns/masterdump.h b/lib/dns/include/dns/masterdump.h
new file mode 100644
index 0000000..8cf5c13
--- /dev/null
+++ b/lib/dns/include/dns/masterdump.h
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2004, 2005 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: masterdump.h,v 1.31.14.4 2005/09/01 03:04:28 marka Exp $ */
+
+#ifndef DNS_MASTERDUMP_H
+#define DNS_MASTERDUMP_H 1
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+/***
+ *** Types
+ ***/
+
+typedef struct dns_master_style dns_master_style_t;
+
+/***
+ *** Definitions
+ ***/
+
+/*
+ * Flags affecting master file formatting. Flags 0x0000FFFF
+ * define the formatting of the rdata part and are defined in
+ * rdata.h.
+ */
+
+/*% Omit the owner name when possible. */
+#define DNS_STYLEFLAG_OMIT_OWNER 0x00010000U
+
+/*%
+ * Omit the TTL when possible. If DNS_STYLEFLAG_TTL is
+ * also set, this means no TTLs are ever printed
+ * because $TTL directives are generated before every
+ * change in the TTL. In this case, no columns need to
+ * be reserved for the TTL. Master files generated with
+ * these options will be rejected by BIND 4.x because it
+ * does not recognize the $TTL directive.
+ *
+ * If DNS_STYLEFLAG_TTL is not also set, the TTL will be
+ * omitted when it is equal to the previous TTL.
+ * This is correct according to RFC1035, but the
+ * TTLs may be silently misinterpreted by older
+ * versions of BIND which use the SOA MINTTL as a
+ * default TTL value.
+ */
+#define DNS_STYLEFLAG_OMIT_TTL 0x00020000U
+
+/*% Omit the class when possible. */
+#define DNS_STYLEFLAG_OMIT_CLASS 0x00040000U
+
+/*% Output $TTL directives. */
+#define DNS_STYLEFLAG_TTL 0x00080000U
+
+/*%
+ * Output $ORIGIN directives and print owner names relative to
+ * the origin when possible.
+ */
+#define DNS_STYLEFLAG_REL_OWNER 0x00100000U
+
+/*% Print domain names in RR data in relative form when possible.
+ For this to take effect, DNS_STYLEFLAG_REL_OWNER must also be set. */
+#define DNS_STYLEFLAG_REL_DATA 0x00200000U
+
+/*% Print the trust level of each rdataset. */
+#define DNS_STYLEFLAG_TRUST 0x00400000U
+
+/*% Print negative caching entries. */
+#define DNS_STYLEFLAG_NCACHE 0x00800000U
+
+/*% Never print the TTL */
+#define DNS_STYLEFLAG_NO_TTL 0x01000000U
+
+/*% Never print the CLASS */
+#define DNS_STYLEFLAG_NO_CLASS 0x02000000U
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Constants
+ ***/
+
+/*%
+ * The default master file style.
+ *
+ * This uses $TTL directives to avoid the need to dedicate a
+ * tab stop for the TTL. The class is only printed for the first
+ * rrset in the file and shares a tab stop with the RR type.
+ */
+LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_default;
+
+/*%
+ * A master file style that dumps zones to a very generic format easily
+ * imported/checked with external tools.
+ */
+LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_full;
+
+/*%
+ * A master file style that prints explicit TTL values on each
+ * record line, never using $TTL statements. The TTL has a tab
+ * stop of its own, but the class and type share one.
+ */
+LIBDNS_EXTERNAL_DATA extern const dns_master_style_t
+ dns_master_style_explicitttl;
+
+/*%
+ * A master style format designed for cache files. It prints explicit TTL
+ * values on each record line and never uses $ORIGIN or relative names.
+ */
+LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_cache;
+
+/*%
+ * A master style that prints name, ttl, class, type, and value on
+ * every line. Similar to explicitttl above, but more verbose.
+ * Intended for generating master files which can be easily parsed
+ * by perl scripts and similar applications.
+ */
+LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_simple;
+
+/*%
+ * The style used for debugging, "dig" output, etc.
+ */
+LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_debug;
+
+/***
+ *** Functions
+ ***/
+
+void
+dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target);
+/*%<
+ * Attach to a dump context.
+ *
+ * Require:
+ *\li 'source' to be valid.
+ *\li 'target' to be non NULL and '*target' to be NULL.
+ */
+
+void
+dns_dumpctx_detach(dns_dumpctx_t **dctxp);
+/*%<
+ * Detach from a dump context.
+ *
+ * Require:
+ *\li 'dctxp' to point to a valid dump context.
+ *
+ * Ensures:
+ *\li '*dctxp' is NULL.
+ */
+
+void
+dns_dumpctx_cancel(dns_dumpctx_t *dctx);
+/*%<
+ * Cancel a in progress dump.
+ *
+ * Require:
+ *\li 'dctx' to be valid.
+ */
+
+dns_dbversion_t *
+dns_dumpctx_version(dns_dumpctx_t *dctx);
+/*%<
+ * Return the version handle (if any) of the database being dumped.
+ *
+ * Require:
+ *\li 'dctx' to be valid.
+ */
+
+dns_db_t *
+dns_dumpctx_db(dns_dumpctx_t *dctx);
+/*%<
+ * Return the database being dumped.
+ *
+ * Require:
+ *\li 'dctx' to be valid.
+ */
+
+
+/*@{*/
+isc_result_t
+dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db,
+ dns_dbversion_t *version,
+ const dns_master_style_t *style, FILE *f,
+ isc_task_t *task, dns_dumpdonefunc_t done,
+ void *done_arg, dns_dumpctx_t **dctxp);
+
+isc_result_t
+dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db,
+ dns_dbversion_t *version,
+ const dns_master_style_t *style, FILE *f);
+
+isc_result_t
+dns_master_dumptostream2(isc_mem_t *mctx, dns_db_t *db,
+ dns_dbversion_t *version,
+ const dns_master_style_t *style,
+ dns_masterformat_t format, FILE *f);
+/*%<
+ * Dump the database 'db' to the steam 'f' in the specified format by
+ * 'format'. If the format is dns_masterformat_text (the RFC1035 format),
+ * 'style' specifies the file style (e.g., &dns_master_style_default).
+ *
+ * dns_master_dumptostream() is an old form of dns_master_dumptostream2(),
+ * which always specifies the dns_masterformat_text format.
+ *
+ * Temporary dynamic memory may be allocated from 'mctx'.
+ *
+ * Require:
+ *\li 'task' to be valid.
+ *\li 'done' to be non NULL.
+ *\li 'dctxp' to be non NULL && '*dctxp' to be NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_CONTINUE dns_master_dumptostreaminc() only.
+ *\li ISC_R_NOMEMORY
+ *\li Any database or rrset iterator error.
+ *\li Any dns_rdata_totext() error code.
+ */
+/*@}*/
+
+/*@{*/
+isc_result_t
+dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
+ const dns_master_style_t *style, const char *filename,
+ isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
+ dns_dumpctx_t **dctxp);
+
+isc_result_t
+dns_master_dumpinc2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
+ const dns_master_style_t *style, const char *filename,
+ isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, dns_dumpctx_t **dctxp, dns_masterformat_t format);
+
+isc_result_t
+dns_master_dump(isc_mem_t *mctx, dns_db_t *db,
+ dns_dbversion_t *version,
+ const dns_master_style_t *style, const char *filename);
+
+isc_result_t
+dns_master_dump2(isc_mem_t *mctx, dns_db_t *db,
+ dns_dbversion_t *version,
+ const dns_master_style_t *style, const char *filename,
+ dns_masterformat_t format);
+
+/*%<
+ * Dump the database 'db' to the file 'filename' in the specified format by
+ * 'format'. If the format is dns_masterformat_text (the RFC1035 format),
+ * 'style' specifies the file style (e.g., &dns_master_style_default).
+ *
+ * dns_master_dumpinc() and dns_master_dump() are old forms of _dumpinc2()
+ * and _dump2(), respectively, which always specify the dns_masterformat_text
+ * format.
+ *
+ * Temporary dynamic memory may be allocated from 'mctx'.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_CONTINUE dns_master_dumpinc() only.
+ *\li ISC_R_NOMEMORY
+ *\li Any database or rrset iterator error.
+ *\li Any dns_rdata_totext() error code.
+ */
+/*@}*/
+
+isc_result_t
+dns_master_rdatasettotext(dns_name_t *owner_name,
+ dns_rdataset_t *rdataset,
+ const dns_master_style_t *style,
+ isc_buffer_t *target);
+/*%<
+ * Convert 'rdataset' to text format, storing the result in 'target'.
+ *
+ * Notes:
+ *\li The rdata cursor position will be changed.
+ *
+ * Requires:
+ *\li 'rdataset' is a valid non-question rdataset.
+ *
+ *\li 'rdataset' is not empty.
+ */
+
+isc_result_t
+dns_master_questiontotext(dns_name_t *owner_name,
+ dns_rdataset_t *rdataset,
+ const dns_master_style_t *style,
+ isc_buffer_t *target);
+
+isc_result_t
+dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db,
+ dns_dbversion_t *version,
+ dns_dbnode_t *node, dns_name_t *name,
+ const dns_master_style_t *style,
+ FILE *f);
+
+isc_result_t
+dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
+ dns_dbnode_t *node, dns_name_t *name,
+ const dns_master_style_t *style, const char *filename);
+
+isc_result_t
+dns_master_stylecreate(dns_master_style_t **style, unsigned int flags,
+ unsigned int ttl_column, unsigned int class_column,
+ unsigned int type_column, unsigned int rdata_column,
+ unsigned int line_length, unsigned int tab_width,
+ isc_mem_t *mctx);
+
+void
+dns_master_styledestroy(dns_master_style_t **style, isc_mem_t *mctx);
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_MASTERDUMP_H */
diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h
new file mode 100644
index 0000000..9002b83
--- /dev/null
+++ b/lib/dns/include/dns/message.h
@@ -0,0 +1,1339 @@
+/*
+ * Copyright (C) 2004-2006 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: message.h,v 1.114.18.6 2006/03/02 23:19:20 marka Exp $ */
+
+#ifndef DNS_MESSAGE_H
+#define DNS_MESSAGE_H 1
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+
+#include <dns/compress.h>
+#include <dns/masterdump.h>
+#include <dns/types.h>
+
+#include <dst/dst.h>
+
+/*! \file
+ * \brief Message Handling Module
+ *
+ * How this beast works:
+ *
+ * When a dns message is received in a buffer, dns_message_fromwire() is called
+ * on the memory region. Various items are checked including the format
+ * of the message (if counts are right, if counts consume the entire sections,
+ * and if sections consume the entire message) and known pseudo-RRs in the
+ * additional data section are analyzed and removed.
+ *
+ * TSIG checking is also done at this layer, and any DNSSEC transaction
+ * signatures should also be checked here.
+ *
+ * Notes on using the gettemp*() and puttemp*() functions:
+ *
+ * These functions return items (names, rdatasets, etc) allocated from some
+ * internal state of the dns_message_t.
+ *
+ * Names and rdatasets must be put back into the dns_message_t in
+ * one of two ways. Assume a name was allocated via
+ * dns_message_gettempname():
+ *
+ *\li (1) insert it into a section, using dns_message_addname().
+ *
+ *\li (2) return it to the message using dns_message_puttempname().
+ *
+ * The same applies to rdatasets.
+ *
+ * On the other hand, offsets, rdatalists and rdatas allocated using
+ * dns_message_gettemp*() will always be freed automatically
+ * when the message is reset or destroyed; calling dns_message_puttemp*()
+ * on rdatalists and rdatas is optional and serves only to enable the item
+ * to be reused multiple times during the lifetime of the message; offsets
+ * cannot be reused.
+ *
+ * Buffers allocated using isc_buffer_allocate() can be automatically freed
+ * as well by giving the buffer to the message using dns_message_takebuffer().
+ * Doing this will cause the buffer to be freed using isc_buffer_free()
+ * when the section lists are cleared, such as in a reset or in a destroy.
+ * Since the buffer itself exists until the message is destroyed, this sort
+ * of code can be written:
+ *
+ * \code
+ * buffer = isc_buffer_allocate(mctx, 512);
+ * name = NULL;
+ * name = dns_message_gettempname(message, &name);
+ * dns_name_init(name, NULL);
+ * result = dns_name_fromtext(name, &source, dns_rootname, ISC_FALSE,
+ * buffer);
+ * dns_message_takebuffer(message, &buffer);
+ * \endcode
+ *
+ *
+ * TODO:
+ *
+ * XXX Needed: ways to set and retrieve EDNS information, add rdata to a
+ * section, move rdata from one section to another, remove rdata, etc.
+ */
+
+#define DNS_MESSAGEFLAG_QR 0x8000U
+#define DNS_MESSAGEFLAG_AA 0x0400U
+#define DNS_MESSAGEFLAG_TC 0x0200U
+#define DNS_MESSAGEFLAG_RD 0x0100U
+#define DNS_MESSAGEFLAG_RA 0x0080U
+#define DNS_MESSAGEFLAG_AD 0x0020U
+#define DNS_MESSAGEFLAG_CD 0x0010U
+
+#define DNS_MESSAGEEXTFLAG_DO 0x8000U
+
+#define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD|DNS_MESSAGEFLAG_CD)
+#define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO)
+
+#define DNS_MESSAGE_HEADERLEN 12 /*%< 6 isc_uint16_t's */
+
+#define DNS_MESSAGE_MAGIC ISC_MAGIC('M','S','G','@')
+#define DNS_MESSAGE_VALID(msg) ISC_MAGIC_VALID(msg, DNS_MESSAGE_MAGIC)
+
+/*
+ * Ordering here matters. DNS_SECTION_ANY must be the lowest and negative,
+ * and DNS_SECTION_MAX must be one greater than the last used section.
+ */
+typedef int dns_section_t;
+#define DNS_SECTION_ANY (-1)
+#define DNS_SECTION_QUESTION 0
+#define DNS_SECTION_ANSWER 1
+#define DNS_SECTION_AUTHORITY 2
+#define DNS_SECTION_ADDITIONAL 3
+#define DNS_SECTION_MAX 4
+
+typedef int dns_pseudosection_t;
+#define DNS_PSEUDOSECTION_ANY (-1)
+#define DNS_PSEUDOSECTION_OPT 0
+#define DNS_PSEUDOSECTION_TSIG 1
+#define DNS_PSEUDOSECTION_SIG0 2
+#define DNS_PSEUDOSECTION_MAX 3
+
+typedef int dns_messagetextflag_t;
+#define DNS_MESSAGETEXTFLAG_NOCOMMENTS 0x0001
+#define DNS_MESSAGETEXTFLAG_NOHEADERS 0x0002
+
+/*
+ * Dynamic update names for these sections.
+ */
+#define DNS_SECTION_ZONE DNS_SECTION_QUESTION
+#define DNS_SECTION_PREREQUISITE DNS_SECTION_ANSWER
+#define DNS_SECTION_UPDATE DNS_SECTION_AUTHORITY
+
+/*
+ * These tell the message library how the created dns_message_t will be used.
+ */
+#define DNS_MESSAGE_INTENTUNKNOWN 0 /*%< internal use only */
+#define DNS_MESSAGE_INTENTPARSE 1 /*%< parsing messages */
+#define DNS_MESSAGE_INTENTRENDER 2 /*%< rendering */
+
+/*
+ * Control behavior of parsing
+ */
+#define DNS_MESSAGEPARSE_PRESERVEORDER 0x0001 /*%< preserve rdata order */
+#define DNS_MESSAGEPARSE_BESTEFFORT 0x0002 /*%< return a message if a
+ recoverable parse error
+ occurs */
+#define DNS_MESSAGEPARSE_CLONEBUFFER 0x0004 /*%< save a copy of the
+ source buffer */
+#define DNS_MESSAGEPARSE_IGNORETRUNCATION 0x0008 /*%< trucation errors are
+ * not fatal. */
+
+/*
+ * Control behavior of rendering
+ */
+#define DNS_MESSAGERENDER_ORDERED 0x0001 /*%< don't change order */
+#define DNS_MESSAGERENDER_PARTIAL 0x0002 /*%< allow a partial rdataset */
+#define DNS_MESSAGERENDER_OMITDNSSEC 0x0004 /*%< omit DNSSEC records */
+#define DNS_MESSAGERENDER_PREFER_A 0x0008 /*%< prefer A records in
+ additional section. */
+#define DNS_MESSAGERENDER_PREFER_AAAA 0x0010 /*%< prefer AAAA records in
+ additional section. */
+
+typedef struct dns_msgblock dns_msgblock_t;
+
+struct dns_message {
+ /* public from here down */
+ unsigned int magic;
+
+ dns_messageid_t id;
+ unsigned int flags;
+ dns_rcode_t rcode;
+ unsigned int opcode;
+ dns_rdataclass_t rdclass;
+
+ /* 4 real, 1 pseudo */
+ unsigned int counts[DNS_SECTION_MAX];
+
+ /* private from here down */
+ dns_namelist_t sections[DNS_SECTION_MAX];
+ dns_name_t *cursors[DNS_SECTION_MAX];
+ dns_rdataset_t *opt;
+ dns_rdataset_t *sig0;
+ dns_rdataset_t *tsig;
+
+ int state;
+ unsigned int from_to_wire : 2;
+ unsigned int header_ok : 1;
+ unsigned int question_ok : 1;
+ unsigned int tcp_continuation : 1;
+ unsigned int verified_sig : 1;
+ unsigned int verify_attempted : 1;
+ unsigned int free_query : 1;
+ unsigned int free_saved : 1;
+
+ unsigned int opt_reserved;
+ unsigned int sig_reserved;
+ unsigned int reserved; /* reserved space (render) */
+
+ isc_buffer_t *buffer;
+ dns_compress_t *cctx;
+
+ isc_mem_t *mctx;
+ isc_mempool_t *namepool;
+ isc_mempool_t *rdspool;
+
+ isc_bufferlist_t scratchpad;
+ isc_bufferlist_t cleanup;
+
+ ISC_LIST(dns_msgblock_t) rdatas;
+ ISC_LIST(dns_msgblock_t) rdatalists;
+ ISC_LIST(dns_msgblock_t) offsets;
+
+ ISC_LIST(dns_rdata_t) freerdata;
+ ISC_LIST(dns_rdatalist_t) freerdatalist;
+
+ dns_rcode_t tsigstatus;
+ dns_rcode_t querytsigstatus;
+ dns_name_t *tsigname; /* Owner name of TSIG, if any */
+ dns_rdataset_t *querytsig;
+ dns_tsigkey_t *tsigkey;
+ dst_context_t *tsigctx;
+ int sigstart;
+ int timeadjust;
+
+ dns_name_t *sig0name; /* Owner name of SIG0, if any */
+ dst_key_t *sig0key;
+ dns_rcode_t sig0status;
+ isc_region_t query;
+ isc_region_t saved;
+
+ dns_rdatasetorderfunc_t order;
+ const void * order_arg;
+};
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp);
+
+/*%<
+ * Create msg structure.
+ *
+ * This function will allocate some internal blocks of memory that are
+ * expected to be needed for parsing or rendering nearly any type of message.
+ *
+ * Requires:
+ *\li 'mctx' be a valid memory context.
+ *
+ *\li 'msgp' be non-null and '*msg' be NULL.
+ *
+ *\li 'intent' must be one of DNS_MESSAGE_INTENTPARSE or
+ * #DNS_MESSAGE_INTENTRENDER.
+ *
+ * Ensures:
+ *\li The data in "*msg" is set to indicate an unused and empty msg
+ * structure.
+ *
+ * Returns:
+ *\li #ISC_R_NOMEMORY -- out of memory
+ *\li #ISC_R_SUCCESS -- success
+ */
+
+void
+dns_message_reset(dns_message_t *msg, unsigned int intent);
+/*%<
+ * Reset a message structure to default state. All internal lists are freed
+ * or reset to a default state as well. This is simply a more efficient
+ * way to call dns_message_destroy() followed by dns_message_allocate(),
+ * since it avoid many memory allocations.
+ *
+ * If any data loanouts (buffers, names, rdatas, etc) were requested,
+ * the caller must no longer use them after this call.
+ *
+ * The intended next use of the message will be 'intent'.
+ *
+ * Requires:
+ *
+ *\li 'msg' be valid.
+ *
+ *\li 'intent' is DNS_MESSAGE_INTENTPARSE or DNS_MESSAGE_INTENTRENDER
+ */
+
+void
+dns_message_destroy(dns_message_t **msgp);
+/*%<
+ * Destroy all state in the message.
+ *
+ * Requires:
+ *
+ *\li 'msgp' be valid.
+ *
+ * Ensures:
+ *\li '*msgp' == NULL
+ */
+
+isc_result_t
+dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
+ const dns_master_style_t *style,
+ dns_messagetextflag_t flags,
+ isc_buffer_t *target);
+
+isc_result_t
+dns_message_pseudosectiontotext(dns_message_t *msg,
+ dns_pseudosection_t section,
+ const dns_master_style_t *style,
+ dns_messagetextflag_t flags,
+ isc_buffer_t *target);
+/*%<
+ * Convert section 'section' or 'pseudosection' of message 'msg' to
+ * a cleartext representation
+ *
+ * Notes:
+ * \li See dns_message_totext for meanings of flags.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message.
+ *
+ *\li 'style' is a valid master dump style.
+ *
+ *\li 'target' is a valid buffer.
+ *
+ *\li 'section' is a valid section label.
+ *
+ * Ensures:
+ *
+ *\li If the result is success:
+ * The used space in 'target' is updated.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE
+ *\li #ISC_R_NOMORE
+ *
+ *\li Note: On error return, *target may be partially filled with data.
+*/
+
+isc_result_t
+dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
+ dns_messagetextflag_t flags, isc_buffer_t *target);
+/*%<
+ * Convert all sections of message 'msg' to a cleartext representation
+ *
+ * Notes:
+ * \li In flags, If #DNS_MESSAGETEXTFLAG_OMITDOT is set, then the
+ * final '.' in absolute names will not be emitted. If
+ * #DNS_MESSAGETEXTFLAG_NOCOMMENTS is cleared, lines beginning
+ * with ";;" will be emitted indicating section name. If
+ * #DNS_MESSAGETEXTFLAG_NOHEADERS is cleared, header lines will
+ * be emitted.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message.
+ *
+ *\li 'style' is a valid master dump style.
+ *
+ *\li 'target' is a valid buffer.
+ *
+ * Ensures:
+ *
+ *\li If the result is success:
+ * The used space in 'target' is updated.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE
+ *\li #ISC_R_NOMORE
+ *
+ *\li Note: On error return, *target may be partially filled with data.
+ */
+
+isc_result_t
+dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
+ unsigned int options);
+/*%<
+ * Parse raw wire data in 'source' as a DNS message.
+ *
+ * OPT records are detected and stored in the pseudo-section "opt".
+ * TSIGs are detected and stored in the pseudo-section "tsig".
+ *
+ * If #DNS_MESSAGEPARSE_PRESERVEORDER is set, or if the opcode of the message
+ * is UPDATE, a separate dns_name_t object will be created for each RR in the
+ * message. Each such dns_name_t will have a single rdataset containing the
+ * single RR, and the order of the RRs in the message is preserved.
+ * Otherwise, only one dns_name_t object will be created for each unique
+ * owner name in the section, and each such dns_name_t will have a list
+ * of rdatasets. To access the names and their data, use
+ * dns_message_firstname() and dns_message_nextname().
+ *
+ * If #DNS_MESSAGEPARSE_BESTEFFORT is set, errors in message content will
+ * not be considered FORMERRs. If the entire message can be parsed, it
+ * will be returned and DNS_R_RECOVERABLE will be returned.
+ *
+ * If #DNS_MESSAGEPARSE_IGNORETRUNCATION is set then return as many complete
+ * RR's as possible, DNS_R_RECOVERABLE will be returned.
+ *
+ * OPT and TSIG records are always handled specially, regardless of the
+ * 'preserve_order' setting.
+ *
+ * Requires:
+ *\li "msg" be valid.
+ *
+ *\li "buffer" be a wire format buffer.
+ *
+ * Ensures:
+ *\li The buffer's data format is correct.
+ *
+ *\li The buffer's contents verify as correct regarding header bits, buffer
+ * and rdata sizes, etc.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- all is well
+ *\li #ISC_R_NOMEMORY -- no memory
+ *\li #DNS_R_RECOVERABLE -- the message parsed properly, but contained
+ * errors.
+ *\li Many other errors possible XXXMLG
+ */
+
+isc_result_t
+dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
+ isc_buffer_t *buffer);
+/*%<
+ * Begin rendering on a message. Only one call can be made to this function
+ * per message.
+ *
+ * The compression context is "owned" by the message library until
+ * dns_message_renderend() is called. It must be invalidated by the caller.
+ *
+ * The buffer is "owned" by the message library until dns_message_renderend()
+ * is called.
+ *
+ * Requires:
+ *
+ *\li 'msg' be valid.
+ *
+ *\li 'cctx' be valid.
+ *
+ *\li 'buffer' is a valid buffer.
+ *
+ * Side Effects:
+ *
+ *\li The buffer is cleared before it is used.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- all is well
+ *\li #ISC_R_NOSPACE -- output buffer is too small
+ */
+
+isc_result_t
+dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer);
+/*%<
+ * Reset the buffer. This can be used after growing the old buffer
+ * on a ISC_R_NOSPACE return from most of the render functions.
+ *
+ * On successful completion, the old buffer is no longer used by the
+ * library. The new buffer is owned by the library until
+ * dns_message_renderend() is called.
+ *
+ * Requires:
+ *
+ *\li 'msg' be valid.
+ *
+ *\li dns_message_renderbegin() was called.
+ *
+ *\li buffer != NULL.
+ *
+ * Returns:
+ *\li #ISC_R_NOSPACE -- new buffer is too small
+ *\li #ISC_R_SUCCESS -- all is well.
+ */
+
+isc_result_t
+dns_message_renderreserve(dns_message_t *msg, unsigned int space);
+/*%<
+ * XXXMLG should use size_t rather than unsigned int once the buffer
+ * API is cleaned up
+ *
+ * Reserve "space" bytes in the given buffer.
+ *
+ * Requires:
+ *
+ *\li 'msg' be valid.
+ *
+ *\li dns_message_renderbegin() was called.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- all is well.
+ *\li #ISC_R_NOSPACE -- not enough free space in the buffer.
+ */
+
+void
+dns_message_renderrelease(dns_message_t *msg, unsigned int space);
+/*%<
+ * XXXMLG should use size_t rather than unsigned int once the buffer
+ * API is cleaned up
+ *
+ * Release "space" bytes in the given buffer that was previously reserved.
+ *
+ * Requires:
+ *
+ *\li 'msg' be valid.
+ *
+ *\li 'space' is less than or equal to the total amount of space reserved
+ * via prior calls to dns_message_renderreserve().
+ *
+ *\li dns_message_renderbegin() was called.
+ */
+
+isc_result_t
+dns_message_rendersection(dns_message_t *msg, dns_section_t section,
+ unsigned int options);
+/*%<
+ * Render all names, rdatalists, etc from the given section at the
+ * specified priority or higher.
+ *
+ * Requires:
+ *\li 'msg' be valid.
+ *
+ *\li 'section' be a valid section.
+ *
+ *\li dns_message_renderbegin() was called.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- all records were written, and there are
+ * no more records for this section.
+ *\li #ISC_R_NOSPACE -- Not enough room in the buffer to write
+ * all records requested.
+ *\li #DNS_R_MOREDATA -- All requested records written, and there
+ * are records remaining for this section.
+ */
+
+void
+dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target);
+/*%<
+ * Render the message header. This is implicitly called by
+ * dns_message_renderend().
+ *
+ * Requires:
+ *
+ *\li 'msg' be a valid message.
+ *
+ *\li dns_message_renderbegin() was called.
+ *
+ *\li 'target' is a valid buffer with enough space to hold a message header
+ */
+
+isc_result_t
+dns_message_renderend(dns_message_t *msg);
+/*%<
+ * Finish rendering to the buffer. Note that more data can be in the
+ * 'msg' structure. Destroying the structure will free this, or in a multi-
+ * part EDNS1 message this data can be rendered to another buffer later.
+ *
+ * Requires:
+ *
+ *\li 'msg' be a valid message.
+ *
+ *\li dns_message_renderbegin() was called.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- all is well.
+ */
+
+void
+dns_message_renderreset(dns_message_t *msg);
+/*%<
+ * Reset the message so that it may be rendered again.
+ *
+ * Notes:
+ *
+ *\li If dns_message_renderbegin() has been called, dns_message_renderend()
+ * must be called before calling this function.
+ *
+ * Requires:
+ *
+ *\li 'msg' be a valid message with rendering intent.
+ */
+
+isc_result_t
+dns_message_firstname(dns_message_t *msg, dns_section_t section);
+/*%<
+ * Set internal per-section name pointer to the beginning of the section.
+ *
+ * The functions dns_message_firstname() and dns_message_nextname() may
+ * be used for iterating over the owner names in a section.
+ *
+ * Requires:
+ *
+ *\li 'msg' be valid.
+ *
+ *\li 'section' be a valid section.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- All is well.
+ *\li #ISC_R_NOMORE -- No names on given section.
+ */
+
+isc_result_t
+dns_message_nextname(dns_message_t *msg, dns_section_t section);
+/*%<
+ * Sets the internal per-section name pointer to point to the next name
+ * in that section.
+ *
+ * Requires:
+ *
+ * \li 'msg' be valid.
+ *
+ *\li 'section' be a valid section.
+ *
+ *\li dns_message_firstname() must have been called on this section,
+ * and the result was ISC_R_SUCCESS.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- All is well.
+ *\li #ISC_R_NOMORE -- No more names in given section.
+ */
+
+void
+dns_message_currentname(dns_message_t *msg, dns_section_t section,
+ dns_name_t **name);
+/*%<
+ * Sets 'name' to point to the name where the per-section internal name
+ * pointer is currently set.
+ *
+ * This function returns the name in the database, so any data associated
+ * with it (via the name's "list" member) contains the actual rdatasets.
+ *
+ * Requires:
+ *
+ *\li 'msg' be valid.
+ *
+ *\li 'name' be non-NULL, and *name be NULL.
+ *
+ *\li 'section' be a valid section.
+ *
+ *\li dns_message_firstname() must have been called on this section,
+ * and the result of it and any dns_message_nextname() calls was
+ * #ISC_R_SUCCESS.
+ */
+
+isc_result_t
+dns_message_findname(dns_message_t *msg, dns_section_t section,
+ dns_name_t *target, dns_rdatatype_t type,
+ dns_rdatatype_t covers, dns_name_t **foundname,
+ dns_rdataset_t **rdataset);
+/*%<
+ * Search for a name in the specified section. If it is found, *name is
+ * set to point to the name, and *rdataset is set to point to the found
+ * rdataset (if type is specified as other than dns_rdatatype_any).
+ *
+ * Requires:
+ *\li 'msg' be valid.
+ *
+ *\li 'section' be a valid section.
+ *
+ *\li If a pointer to the name is desired, 'foundname' should be non-NULL.
+ * If it is non-NULL, '*foundname' MUST be NULL.
+ *
+ *\li If a type other than dns_datatype_any is searched for, 'rdataset'
+ * may be non-NULL, '*rdataset' be NULL, and will point at the found
+ * rdataset. If the type is dns_datatype_any, 'rdataset' must be NULL.
+ *
+ *\li 'target' be a valid name.
+ *
+ *\li 'type' be a valid type.
+ *
+ *\li If 'type' is dns_rdatatype_rrsig, 'covers' must be a valid type.
+ * Otherwise it should be 0.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- all is well.
+ *\li #DNS_R_NXDOMAIN -- name does not exist in that section.
+ *\li #DNS_R_NXRRSET -- The name does exist, but the desired
+ * type does not.
+ */
+
+isc_result_t
+dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
+ dns_rdatatype_t covers, dns_rdataset_t **rdataset);
+/*%<
+ * Search the name for the specified type. If it is found, *rdataset is
+ * filled in with a pointer to that rdataset.
+ *
+ * Requires:
+ *\li if '**rdataset' is non-NULL, *rdataset needs to be NULL.
+ *
+ *\li 'type' be a valid type, and NOT dns_rdatatype_any.
+ *
+ *\li If 'type' is dns_rdatatype_rrsig, 'covers' must be a valid type.
+ * Otherwise it should be 0.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- all is well.
+ *\li #ISC_R_NOTFOUND -- the desired type does not exist.
+ */
+
+isc_result_t
+dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, dns_rdatatype_t covers,
+ dns_rdataset_t **rdataset);
+/*%<
+ * Search the name for the specified rdclass and type. If it is found,
+ * *rdataset is filled in with a pointer to that rdataset.
+ *
+ * Requires:
+ *\li if '**rdataset' is non-NULL, *rdataset needs to be NULL.
+ *
+ *\li 'type' be a valid type, and NOT dns_rdatatype_any.
+ *
+ *\li If 'type' is dns_rdatatype_rrsig, 'covers' must be a valid type.
+ * Otherwise it should be 0.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- all is well.
+ *\li #ISC_R_NOTFOUND -- the desired type does not exist.
+ */
+
+void
+dns_message_movename(dns_message_t *msg, dns_name_t *name,
+ dns_section_t fromsection,
+ dns_section_t tosection);
+/*%<
+ * Move a name from one section to another.
+ *
+ * Requires:
+ *
+ *\li 'msg' be valid.
+ *
+ *\li 'name' must be a name already in 'fromsection'.
+ *
+ *\li 'fromsection' must be a valid section.
+ *
+ *\li 'tosection' must be a valid section.
+ */
+
+void
+dns_message_addname(dns_message_t *msg, dns_name_t *name,
+ dns_section_t section);
+/*%<
+ * Adds the name to the given section.
+ *
+ * It is the caller's responsibility to enforce any unique name requirements
+ * in a section.
+ *
+ * Requires:
+ *
+ *\li 'msg' be valid, and be a renderable message.
+ *
+ *\li 'name' be a valid absolute name.
+ *
+ *\li 'section' be a named section.
+ */
+
+void
+dns_message_removename(dns_message_t *msg, dns_name_t *name,
+ dns_section_t section);
+/*%<
+ * Remove a existing name from a given section.
+ *
+ * It is the caller's responsibility to ensure the name is part of the
+ * given section.
+ *
+ * Requires:
+ *
+ *\li 'msg' be valid, and be a renderable message.
+ *
+ *\li 'name' be a valid absolute name.
+ *
+ *\li 'section' be a named section.
+ */
+
+
+/*
+ * LOANOUT FUNCTIONS
+ *
+ * Each of these functions loan a particular type of data to the caller.
+ * The storage for these will vanish when the message is destroyed or
+ * reset, and must NOT be used after these operations.
+ */
+
+isc_result_t
+dns_message_gettempname(dns_message_t *msg, dns_name_t **item);
+/*%<
+ * Return a name that can be used for any temporary purpose, including
+ * inserting into the message's linked lists. The name must be returned
+ * to the message code using dns_message_puttempname() or inserted into
+ * one of the message's sections before the message is destroyed.
+ *
+ * It is the caller's responsibility to initialize this name.
+ *
+ * Requires:
+ *\li msg be a valid message
+ *
+ *\li item != NULL && *item == NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- All is well.
+ *\li #ISC_R_NOMEMORY -- No item can be allocated.
+ */
+
+isc_result_t
+dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item);
+/*%<
+ * Return an offsets array that can be used for any temporary purpose,
+ * such as attaching to a temporary name. The offsets will be freed
+ * when the message is destroyed or reset.
+ *
+ * Requires:
+ *\li msg be a valid message
+ *
+ *\li item != NULL && *item == NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- All is well.
+ *\li #ISC_R_NOMEMORY -- No item can be allocated.
+ */
+
+isc_result_t
+dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item);
+/*%<
+ * Return a rdata that can be used for any temporary purpose, including
+ * inserting into the message's linked lists. The rdata will be freed
+ * when the message is destroyed or reset.
+ *
+ * Requires:
+ *\li msg be a valid message
+ *
+ *\li item != NULL && *item == NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- All is well.
+ *\li #ISC_R_NOMEMORY -- No item can be allocated.
+ */
+
+isc_result_t
+dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item);
+/*%<
+ * Return a rdataset that can be used for any temporary purpose, including
+ * inserting into the message's linked lists. The name must be returned
+ * to the message code using dns_message_puttempname() or inserted into
+ * one of the message's sections before the message is destroyed.
+ *
+ * Requires:
+ *\li msg be a valid message
+ *
+ *\li item != NULL && *item == NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- All is well.
+ *\li #ISC_R_NOMEMORY -- No item can be allocated.
+ */
+
+isc_result_t
+dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item);
+/*%<
+ * Return a rdatalist that can be used for any temporary purpose, including
+ * inserting into the message's linked lists. The rdatalist will be
+ * destroyed when the message is destroyed or reset.
+ *
+ * Requires:
+ *\li msg be a valid message
+ *
+ *\li item != NULL && *item == NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- All is well.
+ *\li #ISC_R_NOMEMORY -- No item can be allocated.
+ */
+
+void
+dns_message_puttempname(dns_message_t *msg, dns_name_t **item);
+/*%<
+ * Return a borrowed name to the message's name free list.
+ *
+ * Requires:
+ *\li msg be a valid message
+ *
+ *\li item != NULL && *item point to a name returned by
+ * dns_message_gettempname()
+ *
+ * Ensures:
+ *\li *item == NULL
+ */
+
+void
+dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item);
+/*%<
+ * Return a borrowed rdata to the message's rdata free list.
+ *
+ * Requires:
+ *\li msg be a valid message
+ *
+ *\li item != NULL && *item point to a rdata returned by
+ * dns_message_gettemprdata()
+ *
+ * Ensures:
+ *\li *item == NULL
+ */
+
+void
+dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item);
+/*%<
+ * Return a borrowed rdataset to the message's rdataset free list.
+ *
+ * Requires:
+ *\li msg be a valid message
+ *
+ *\li item != NULL && *item point to a rdataset returned by
+ * dns_message_gettemprdataset()
+ *
+ * Ensures:
+ *\li *item == NULL
+ */
+
+void
+dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item);
+/*%<
+ * Return a borrowed rdatalist to the message's rdatalist free list.
+ *
+ * Requires:
+ *\li msg be a valid message
+ *
+ *\li item != NULL && *item point to a rdatalist returned by
+ * dns_message_gettemprdatalist()
+ *
+ * Ensures:
+ *\li *item == NULL
+ */
+
+isc_result_t
+dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
+ unsigned int *flagsp);
+/*%<
+ * Assume the remaining region of "source" is a DNS message. Peek into
+ * it and fill in "*idp" with the message id, and "*flagsp" with the flags.
+ *
+ * Requires:
+ *
+ *\li source != NULL
+ *
+ * Ensures:
+ *
+ *\li if (idp != NULL) *idp == message id.
+ *
+ *\li if (flagsp != NULL) *flagsp == message flags.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS -- all is well.
+ *
+ *\li #ISC_R_UNEXPECTEDEND -- buffer doesn't contain enough for a header.
+ */
+
+isc_result_t
+dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section);
+/*%<
+ * Start formatting a reply to the query in 'msg'.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message with parsing intent, and contains a query.
+ *
+ * Ensures:
+ *
+ *\li The message will have a rendering intent. If 'want_question_section'
+ * is true, the message opcode is query or notify, and the question
+ * section is present and properly formatted, then the question section
+ * will be included in the reply. All other sections will be cleared.
+ * The QR flag will be set, the RD flag will be preserved, and all other
+ * flags will be cleared.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS -- all is well.
+ *
+ *\li #DNS_R_FORMERR -- the header or question section of the
+ * message is invalid, replying is impossible.
+ * If DNS_R_FORMERR is returned when
+ * want_question_section is ISC_FALSE, then
+ * it's the header section that's bad;
+ * otherwise either of the header or question
+ * sections may be bad.
+ */
+
+dns_rdataset_t *
+dns_message_getopt(dns_message_t *msg);
+/*%<
+ * Get the OPT record for 'msg'.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message.
+ *
+ * Returns:
+ *
+ *\li The OPT rdataset of 'msg', or NULL if there isn't one.
+ */
+
+isc_result_t
+dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt);
+/*%<
+ * Set the OPT record for 'msg'.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message with rendering intent
+ * and no sections have been rendered.
+ *
+ *\li 'opt' is a valid OPT record.
+ *
+ * Ensures:
+ *
+ *\li The OPT record has either been freed or ownership of it has
+ * been transferred to the message.
+ *
+ *\li If ISC_R_SUCCESS was returned, the OPT record will be rendered
+ * when dns_message_renderend() is called.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS -- all is well.
+ *
+ *\li #ISC_R_NOSPACE -- there is no space for the OPT record.
+ */
+
+dns_rdataset_t *
+dns_message_gettsig(dns_message_t *msg, dns_name_t **owner);
+/*%<
+ * Get the TSIG record and owner for 'msg'.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message.
+ *\li 'owner' is NULL or *owner is NULL.
+ *
+ * Returns:
+ *
+ *\li The TSIG rdataset of 'msg', or NULL if there isn't one.
+ *
+ * Ensures:
+ *
+ * \li If 'owner' is not NULL, it will point to the owner name.
+ */
+
+isc_result_t
+dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key);
+/*%<
+ * Set the tsig key for 'msg'. This is only necessary for when rendering a
+ * query or parsing a response. The key (if non-NULL) is attached to, and
+ * will be detached when the message is destroyed.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message with rendering intent,
+ * dns_message_renderbegin() has been called, and no sections have been
+ * rendered.
+ *\li 'key' is a valid tsig key or NULL.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS -- all is well.
+ *
+ *\li #ISC_R_NOSPACE -- there is no space for the TSIG record.
+ */
+
+dns_tsigkey_t *
+dns_message_gettsigkey(dns_message_t *msg);
+/*%<
+ * Gets the tsig key for 'msg'.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message
+ */
+
+isc_result_t
+dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig);
+/*%<
+ * Indicates that 'querytsig' is the TSIG from the signed query for which
+ * 'msg' is the response. This is also used for chained TSIGs in TCP
+ * responses.
+ *
+ * Requires:
+ *
+ *\li 'querytsig' is a valid buffer as returned by dns_message_getquerytsig()
+ * or NULL
+ *
+ *\li 'msg' is a valid message
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
+ isc_buffer_t **querytsig);
+/*%<
+ * Gets the tsig from the TSIG from the signed query 'msg'. This is also used
+ * for chained TSIGs in TCP responses. Unlike dns_message_gettsig, this makes
+ * a copy of the data, so can be used if the message is destroyed.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid signed message
+ *\li 'mctx' is a valid memory context
+ *\li querytsig != NULL && *querytsig == NULL
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *
+ * Ensures:
+ *\li 'tsig' points to NULL or an allocated buffer which must be freed
+ * by the caller.
+ */
+
+dns_rdataset_t *
+dns_message_getsig0(dns_message_t *msg, dns_name_t **owner);
+/*%<
+ * Get the SIG(0) record and owner for 'msg'.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message.
+ *\li 'owner' is NULL or *owner is NULL.
+ *
+ * Returns:
+ *
+ *\li The SIG(0) rdataset of 'msg', or NULL if there isn't one.
+ *
+ * Ensures:
+ *
+ * \li If 'owner' is not NULL, it will point to the owner name.
+ */
+
+isc_result_t
+dns_message_setsig0key(dns_message_t *msg, dst_key_t *key);
+/*%<
+ * Set the SIG(0) key for 'msg'.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message with rendering intent,
+ * dns_message_renderbegin() has been called, and no sections have been
+ * rendered.
+ *\li 'key' is a valid sig key or NULL.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS -- all is well.
+ *
+ *\li #ISC_R_NOSPACE -- there is no space for the SIG(0) record.
+ */
+
+dst_key_t *
+dns_message_getsig0key(dns_message_t *msg);
+/*%<
+ * Gets the SIG(0) key for 'msg'.
+ *
+ * Requires:
+ *
+ *\li 'msg' is a valid message
+ */
+
+void
+dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer);
+/*%<
+ * Give the *buffer to the message code to clean up when it is no
+ * longer needed. This is usually when the message is reset or
+ * destroyed.
+ *
+ * Requires:
+ *
+ *\li msg be a valid message.
+ *
+ *\li buffer != NULL && *buffer is a valid isc_buffer_t, which was
+ * dynamincally allocated via isc_buffer_allocate().
+ */
+
+isc_result_t
+dns_message_signer(dns_message_t *msg, dns_name_t *signer);
+/*%<
+ * If this message was signed, return the identity of the signer.
+ * Unless ISC_R_NOTFOUND is returned, signer will reflect the name of the
+ * key that signed the message.
+ *
+ * Requires:
+ *
+ *\li msg is a valid parsed message.
+ *\li signer is a valid name
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS - the message was signed, and *signer
+ * contains the signing identity
+ *
+ *\li #ISC_R_NOTFOUND - no TSIG or SIG(0) record is present in the
+ * message
+ *
+ *\li #DNS_R_TSIGVERIFYFAILURE - the message was signed by a TSIG, but the
+ * signature failed to verify
+ *
+ *\li #DNS_R_TSIGERRORSET - the message was signed by a TSIG and
+ * verified, but the query was rejected by
+ * the server
+ *
+ *\li #DNS_R_NOIDENTITY - the message was signed by a TSIG and
+ * verified, but the key has no identity since
+ * it was generated by an unsigned TKEY process
+ *
+ *\li #DNS_R_SIGINVALID - the message was signed by a SIG(0), but
+ * the signature failed to verify
+ *
+ *\li #DNS_R_NOTVERIFIEDYET - the message was signed by a TSIG or SIG(0),
+ * but the signature has not been verified yet
+ */
+
+isc_result_t
+dns_message_checksig(dns_message_t *msg, dns_view_t *view);
+/*%<
+ * If this message was signed, verify the signature.
+ *
+ * Requires:
+ *
+ *\li msg is a valid parsed message.
+ *\li view is a valid view or NULL
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS - the message was unsigned, or the message
+ * was signed correctly.
+ *
+ *\li #DNS_R_EXPECTEDTSIG - A TSIG was expected, but not seen
+ *\li #DNS_R_UNEXPECTEDTSIG - A TSIG was seen but not expected
+ *\li #DNS_R_TSIGVERIFYFAILURE - The TSIG failed to verify
+ */
+
+isc_result_t
+dns_message_rechecksig(dns_message_t *msg, dns_view_t *view);
+/*%<
+ * Reset the signature state and then if the message was signed,
+ * verify the message.
+ *
+ * Requires:
+ *
+ *\li msg is a valid parsed message.
+ *\li view is a valid view or NULL
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS - the message was unsigned, or the message
+ * was signed correctly.
+ *
+ *\li #DNS_R_EXPECTEDTSIG - A TSIG was expected, but not seen
+ *\li #DNS_R_UNEXPECTEDTSIG - A TSIG was seen but not expected
+ *\li #DNS_R_TSIGVERIFYFAILURE - The TSIG failed to verify
+ */
+
+void
+dns_message_resetsig(dns_message_t *msg);
+/*%<
+ * Reset the signature state.
+ *
+ * Requires:
+ *\li 'msg' is a valid parsed message.
+ */
+
+isc_region_t *
+dns_message_getrawmessage(dns_message_t *msg);
+/*%<
+ * Retrieve the raw message in compressed wire format. The message must
+ * have been successfully parsed for it to have been saved.
+ *
+ * Requires:
+ *\li msg is a valid parsed message.
+ *
+ * Returns:
+ *\li NULL if there is no saved message.
+ * a pointer to a region which refers the dns message.
+ */
+
+void
+dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
+ const void *order_arg);
+/*%<
+ * Define the order in which RR sets get rendered by
+ * dns_message_rendersection() to be the ascending order
+ * defined by the integer value returned by 'order' when
+ * given each RR and 'arg' as arguments. If 'order' and
+ * 'order_arg' are NULL, a default order is used.
+ *
+ * Requires:
+ *\li msg be a valid message.
+ *\li order_arg is NULL if and only if order is NULL.
+ */
+
+void
+dns_message_settimeadjust(dns_message_t *msg, int timeadjust);
+/*%<
+ * Adjust the time used to sign/verify a message by timeadjust.
+ * Currently only TSIG.
+ *
+ * Requires:
+ *\li msg be a valid message.
+ */
+
+int
+dns_message_gettimeadjust(dns_message_t *msg);
+/*%<
+ * Return the current time adjustment.
+ *
+ * Requires:
+ *\li msg be a valid message.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_MESSAGE_H */
diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h
new file mode 100644
index 0000000..038ae05
--- /dev/null
+++ b/lib/dns/include/dns/name.h
@@ -0,0 +1,1296 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: name.h,v 1.107.18.15 2006/03/02 00:37:21 marka Exp $ */
+
+#ifndef DNS_NAME_H
+#define DNS_NAME_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Provides facilities for manipulating DNS names and labels, including
+ * conversions to and from wire format and text format.
+ *
+ * Given the large number of names possible in a nameserver, and because
+ * names occur in rdata, it was important to come up with a very efficient
+ * way of storing name data, but at the same time allow names to be
+ * manipulated. The decision was to store names in uncompressed wire format,
+ * and not to make them fully abstracted objects; i.e. certain parts of the
+ * server know names are stored that way. This saves a lot of memory, and
+ * makes adding names to messages easy. Having much of the server know
+ * the representation would be perilous, and we certainly don't want each
+ * user of names to be manipulating such a low-level structure. This is
+ * where the Names and Labels module comes in. The module allows name or
+ * label handles to be created and attached to uncompressed wire format
+ * regions. All name operations and conversions are done through these
+ * handles.
+ *
+ * MP:
+ *\li Clients of this module must impose any required synchronization.
+ *
+ * Reliability:
+ *\li This module deals with low-level byte streams. Errors in any of
+ * the functions are likely to crash the server or corrupt memory.
+ *
+ * Resources:
+ *\li None.
+ *
+ * Security:
+ *
+ *\li *** WARNING ***
+ *
+ *\li dns_name_fromwire() deals with raw network data. An error in
+ * this routine could result in the failure or hijacking of the server.
+ *
+ * Standards:
+ *\li RFC1035
+ *\li Draft EDNS0 (0)
+ *\li Draft Binary Labels (2)
+ *
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdio.h>
+
+#include <isc/boolean.h>
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/region.h> /* Required for storage size of dns_label_t. */
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Labels
+ *****
+ ***** A 'label' is basically a region. It contains one DNS wire format
+ ***** label of type 00 (ordinary).
+ *****/
+
+/*****
+ ***** Names
+ *****
+ ***** A 'name' is a handle to a binary region. It contains a sequence of one
+ ***** or more DNS wire format labels of type 00 (ordinary).
+ ***** Note that all names are not required to end with the root label,
+ ***** as they are in the actual DNS wire protocol.
+ *****/
+
+/***
+ *** Compression pointer chaining limit
+ ***/
+
+#define DNS_POINTER_MAXHOPS 16
+
+/***
+ *** Types
+ ***/
+
+/*%
+ * Clients are strongly discouraged from using this type directly, with
+ * the exception of the 'link' and 'list' fields which may be used directly
+ * for whatever purpose the client desires.
+ */
+struct dns_name {
+ unsigned int magic;
+ unsigned char * ndata;
+ unsigned int length;
+ unsigned int labels;
+ unsigned int attributes;
+ unsigned char * offsets;
+ isc_buffer_t * buffer;
+ ISC_LINK(dns_name_t) link;
+ ISC_LIST(dns_rdataset_t) list;
+};
+
+#define DNS_NAME_MAGIC ISC_MAGIC('D','N','S','n')
+
+#define DNS_NAMEATTR_ABSOLUTE 0x0001
+#define DNS_NAMEATTR_READONLY 0x0002
+#define DNS_NAMEATTR_DYNAMIC 0x0004
+#define DNS_NAMEATTR_DYNOFFSETS 0x0008
+/*
+ * Attributes below 0x0100 reserved for name.c usage.
+ */
+#define DNS_NAMEATTR_CACHE 0x0100 /*%< Used by resolver. */
+#define DNS_NAMEATTR_ANSWER 0x0200 /*%< Used by resolver. */
+#define DNS_NAMEATTR_NCACHE 0x0400 /*%< Used by resolver. */
+#define DNS_NAMEATTR_CHAINING 0x0800 /*%< Used by resolver. */
+#define DNS_NAMEATTR_CHASE 0x1000 /*%< Used by resolver. */
+#define DNS_NAMEATTR_WILDCARD 0x2000 /*%< Used by server. */
+
+#define DNS_NAME_DOWNCASE 0x0001
+#define DNS_NAME_CHECKNAMES 0x0002 /*%< Used by rdata. */
+#define DNS_NAME_CHECKNAMESFAIL 0x0004 /*%< Used by rdata. */
+#define DNS_NAME_CHECKREVERSE 0x0008 /*%< Used by rdata. */
+#define DNS_NAME_CHECKMX 0x0010 /*%< Used by rdata. */
+#define DNS_NAME_CHECKMXFAIL 0x0020 /*%< Used by rdata. */
+
+LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_rootname;
+LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_wildcardname;
+
+/*%
+ * Standard size of a wire format name
+ */
+#define DNS_NAME_MAXWIRE 255
+
+/*
+ * Text output filter procedure.
+ * 'target' is the buffer to be converted. The region to be converted
+ * is from 'buffer'->base + 'used_org' to the end of the used region.
+ */
+typedef isc_result_t (*dns_name_totextfilter_t)(isc_buffer_t *target,
+ unsigned int used_org,
+ isc_boolean_t absolute);
+
+/***
+ *** Initialization
+ ***/
+
+void
+dns_name_init(dns_name_t *name, unsigned char *offsets);
+/*%<
+ * Initialize 'name'.
+ *
+ * Notes:
+ * \li 'offsets' is never required to be non-NULL, but specifying a
+ * dns_offsets_t for 'offsets' will improve the performance of most
+ * name operations if the name is used more than once.
+ *
+ * Requires:
+ * \li 'name' is not NULL and points to a struct dns_name.
+ *
+ * \li offsets == NULL or offsets is a dns_offsets_t.
+ *
+ * Ensures:
+ * \li 'name' is a valid name.
+ * \li dns_name_countlabels(name) == 0
+ * \li dns_name_isabsolute(name) == ISC_FALSE
+ */
+
+void
+dns_name_reset(dns_name_t *name);
+/*%<
+ * Reinitialize 'name'.
+ *
+ * Notes:
+ * \li This function distinguishes itself from dns_name_init() in two
+ * key ways:
+ *
+ * \li + If any buffer is associated with 'name' (via dns_name_setbuffer()
+ * or by being part of a dns_fixedname_t) the link to the buffer
+ * is retained but the buffer itself is cleared.
+ *
+ * \li + Of the attributes associated with 'name', all are retained except
+ * DNS_NAMEATTR_ABSOLUTE.
+ *
+ * Requires:
+ * \li 'name' is a valid name.
+ *
+ * Ensures:
+ * \li 'name' is a valid name.
+ * \li dns_name_countlabels(name) == 0
+ * \li dns_name_isabsolute(name) == ISC_FALSE
+ */
+
+void
+dns_name_invalidate(dns_name_t *name);
+/*%<
+ * Make 'name' invalid.
+ *
+ * Requires:
+ * \li 'name' is a valid name.
+ *
+ * Ensures:
+ * \li If assertion checking is enabled, future attempts to use 'name'
+ * without initializing it will cause an assertion failure.
+ *
+ * \li If the name had a dedicated buffer, that association is ended.
+ */
+
+
+/***
+ *** Dedicated Buffers
+ ***/
+
+void
+dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer);
+/*%<
+ * Dedicate a buffer for use with 'name'.
+ *
+ * Notes:
+ * \li Specification of a target buffer in dns_name_fromwire(),
+ * dns_name_fromtext(), and dns_name_concatentate() is optional if
+ * 'name' has a dedicated buffer.
+ *
+ * \li The caller must not write to buffer until the name has been
+ * invalidated or is otherwise known not to be in use.
+ *
+ * \li If buffer is NULL and the name previously had a dedicated buffer,
+ * than that buffer is no longer dedicated to use with this name.
+ * The caller is responsible for ensuring that the storage used by
+ * the name remains valid.
+ *
+ * Requires:
+ * \li 'name' is a valid name.
+ *
+ * \li 'buffer' is a valid binary buffer and 'name' doesn't have a
+ * dedicated buffer already, or 'buffer' is NULL.
+ */
+
+isc_boolean_t
+dns_name_hasbuffer(const dns_name_t *name);
+/*%<
+ * Does 'name' have a dedicated buffer?
+ *
+ * Requires:
+ * \li 'name' is a valid name.
+ *
+ * Returns:
+ * \li ISC_TRUE 'name' has a dedicated buffer.
+ * \li ISC_FALSE 'name' does not have a dedicated buffer.
+ */
+
+/***
+ *** Properties
+ ***/
+
+isc_boolean_t
+dns_name_isabsolute(const dns_name_t *name);
+/*%<
+ * Does 'name' end in the root label?
+ *
+ * Requires:
+ * \li 'name' is a valid name
+ *
+ * Returns:
+ * \li TRUE The last label in 'name' is the root label.
+ * \li FALSE The last label in 'name' is not the root label.
+ */
+
+isc_boolean_t
+dns_name_iswildcard(const dns_name_t *name);
+/*%<
+ * Is 'name' a wildcard name?
+ *
+ * Requires:
+ * \li 'name' is a valid name
+ *
+ * \li dns_name_countlabels(name) > 0
+ *
+ * Returns:
+ * \li TRUE The least significant label of 'name' is '*'.
+ * \li FALSE The least significant label of 'name' is not '*'.
+ */
+
+unsigned int
+dns_name_hash(dns_name_t *name, isc_boolean_t case_sensitive);
+/*%<
+ * Provide a hash value for 'name'.
+ *
+ * Note: if 'case_sensitive' is ISC_FALSE, then names which differ only in
+ * case will have the same hash value.
+ *
+ * Requires:
+ * \li 'name' is a valid name
+ *
+ * Returns:
+ * \li A hash value
+ */
+
+unsigned int
+dns_name_fullhash(dns_name_t *name, isc_boolean_t case_sensitive);
+/*%<
+ * Provide a hash value for 'name'. Unlike dns_name_hash(), this function
+ * always takes into account of the entire name to calculate the hash value.
+ *
+ * Note: if 'case_sensitive' is ISC_FALSE, then names which differ only in
+ * case will have the same hash value.
+ *
+ * Requires:
+ *\li 'name' is a valid name
+ *
+ * Returns:
+ *\li A hash value
+ */
+
+unsigned int
+dns_name_hashbylabel(dns_name_t *name, isc_boolean_t case_sensitive);
+/*%<
+ * Provide a hash value for 'name', where the hash value is the sum
+ * of the hash values of each label.
+ *
+ * Note: if 'case_sensitive' is ISC_FALSE, then names which differ only in
+ * case will have the same hash value.
+ *
+ * Requires:
+ *\li 'name' is a valid name
+ *
+ * Returns:
+ *\li A hash value
+ */
+
+/*
+ *** Comparisons
+ ***/
+
+dns_namereln_t
+dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
+ int *orderp, unsigned int *nlabelsp);
+/*%<
+ * Determine the relative ordering under the DNSSEC order relation of
+ * 'name1' and 'name2', and also determine the hierarchical
+ * relationship of the names.
+ *
+ * Note: It makes no sense for one of the names to be relative and the
+ * other absolute. If both names are relative, then to be meaningfully
+ * compared the caller must ensure that they are both relative to the
+ * same domain.
+ *
+ * Requires:
+ *\li 'name1' is a valid name
+ *
+ *\li dns_name_countlabels(name1) > 0
+ *
+ *\li 'name2' is a valid name
+ *
+ *\li dns_name_countlabels(name2) > 0
+ *
+ *\li orderp and nlabelsp are valid pointers.
+ *
+ *\li Either name1 is absolute and name2 is absolute, or neither is.
+ *
+ * Ensures:
+ *
+ *\li *orderp is < 0 if name1 < name2, 0 if name1 = name2, > 0 if
+ * name1 > name2.
+ *
+ *\li *nlabelsp is the number of common significant labels.
+ *
+ * Returns:
+ *\li dns_namereln_none There's no hierarchical relationship
+ * between name1 and name2.
+ *\li dns_namereln_contains name1 properly contains name2; i.e.
+ * name2 is a proper subdomain of name1.
+ *\li dns_namereln_subdomain name1 is a proper subdomain of name2.
+ *\li dns_namereln_equal name1 and name2 are equal.
+ *\li dns_namereln_commonancestor name1 and name2 share a common
+ * ancestor.
+ */
+
+int
+dns_name_compare(const dns_name_t *name1, const dns_name_t *name2);
+/*%<
+ * Determine the relative ordering under the DNSSEC order relation of
+ * 'name1' and 'name2'.
+ *
+ * Note: It makes no sense for one of the names to be relative and the
+ * other absolute. If both names are relative, then to be meaningfully
+ * compared the caller must ensure that they are both relative to the
+ * same domain.
+ *
+ * Requires:
+ * \li 'name1' is a valid name
+ *
+ * \li 'name2' is a valid name
+ *
+ * \li Either name1 is absolute and name2 is absolute, or neither is.
+ *
+ * Returns:
+ * \li < 0 'name1' is less than 'name2'
+ * \li 0 'name1' is equal to 'name2'
+ * \li > 0 'name1' is greater than 'name2'
+ */
+
+isc_boolean_t
+dns_name_equal(const dns_name_t *name1, const dns_name_t *name2);
+/*%<
+ * Are 'name1' and 'name2' equal?
+ *
+ * Notes:
+ * \li Because it only needs to test for equality, dns_name_equal() can be
+ * significantly faster than dns_name_fullcompare() or dns_name_compare().
+ *
+ * \li Offsets tables are not used in the comparision.
+ *
+ * \li It makes no sense for one of the names to be relative and the
+ * other absolute. If both names are relative, then to be meaningfully
+ * compared the caller must ensure that they are both relative to the
+ * same domain.
+ *
+ * Requires:
+ * \li 'name1' is a valid name
+ *
+ * \li 'name2' is a valid name
+ *
+ * \li Either name1 is absolute and name2 is absolute, or neither is.
+ *
+ * Returns:
+ * \li ISC_TRUE 'name1' and 'name2' are equal
+ * \li ISC_FALSE 'name1' and 'name2' are not equal
+ */
+
+isc_boolean_t
+dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2);
+/*%<
+ * Case sensitive version of dns_name_equal().
+ */
+
+int
+dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2);
+/*%<
+ * Compare two names as if they are part of rdata in DNSSEC canonical
+ * form.
+ *
+ * Requires:
+ * \li 'name1' is a valid absolute name
+ *
+ * \li dns_name_countlabels(name1) > 0
+ *
+ * \li 'name2' is a valid absolute name
+ *
+ * \li dns_name_countlabels(name2) > 0
+ *
+ * Returns:
+ * \li < 0 'name1' is less than 'name2'
+ * \li 0 'name1' is equal to 'name2'
+ * \li > 0 'name1' is greater than 'name2'
+ */
+
+isc_boolean_t
+dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2);
+/*%<
+ * Is 'name1' a subdomain of 'name2'?
+ *
+ * Notes:
+ * \li name1 is a subdomain of name2 if name1 is contained in name2, or
+ * name1 equals name2.
+ *
+ * \li It makes no sense for one of the names to be relative and the
+ * other absolute. If both names are relative, then to be meaningfully
+ * compared the caller must ensure that they are both relative to the
+ * same domain.
+ *
+ * Requires:
+ * \li 'name1' is a valid name
+ *
+ * \li 'name2' is a valid name
+ *
+ * \li Either name1 is absolute and name2 is absolute, or neither is.
+ *
+ * Returns:
+ * \li TRUE 'name1' is a subdomain of 'name2'
+ * \li FALSE 'name1' is not a subdomain of 'name2'
+ */
+
+isc_boolean_t
+dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname);
+/*%<
+ * Does 'name' match the wildcard specified in 'wname'?
+ *
+ * Notes:
+ * \li name matches the wildcard specified in wname if all labels
+ * following the wildcard in wname are identical to the same number
+ * of labels at the end of name.
+ *
+ * \li It makes no sense for one of the names to be relative and the
+ * other absolute. If both names are relative, then to be meaningfully
+ * compared the caller must ensure that they are both relative to the
+ * same domain.
+ *
+ * Requires:
+ * \li 'name' is a valid name
+ *
+ * \li dns_name_countlabels(name) > 0
+ *
+ * \li 'wname' is a valid name
+ *
+ * \li dns_name_countlabels(wname) > 0
+ *
+ * \li dns_name_iswildcard(wname) is true
+ *
+ * \li Either name is absolute and wname is absolute, or neither is.
+ *
+ * Returns:
+ * \li TRUE 'name' matches the wildcard specified in 'wname'
+ * \li FALSE 'name' does not match the wildcard specified in 'wname'
+ */
+
+/***
+ *** Labels
+ ***/
+
+unsigned int
+dns_name_countlabels(const dns_name_t *name);
+/*%<
+ * How many labels does 'name' have?
+ *
+ * Notes:
+ * \li In this case, as in other places, a 'label' is an ordinary label.
+ *
+ * Requires:
+ * \li 'name' is a valid name
+ *
+ * Ensures:
+ * \li The result is <= 128.
+ *
+ * Returns:
+ * \li The number of labels in 'name'.
+ */
+
+void
+dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label);
+/*%<
+ * Make 'label' refer to the 'n'th least significant label of 'name'.
+ *
+ * Notes:
+ * \li Numbering starts at 0.
+ *
+ * \li Given "rc.vix.com.", the label 0 is "rc", and label 3 is the
+ * root label.
+ *
+ * \li 'label' refers to the same memory as 'name', so 'name' must not
+ * be changed while 'label' is still in use.
+ *
+ * Requires:
+ * \li n < dns_name_countlabels(name)
+ */
+
+void
+dns_name_getlabelsequence(const dns_name_t *source, unsigned int first,
+ unsigned int n, dns_name_t *target);
+/*%<
+ * Make 'target' refer to the 'n' labels including and following 'first'
+ * in 'source'.
+ *
+ * Notes:
+ * \li Numbering starts at 0.
+ *
+ * \li Given "rc.vix.com.", the label 0 is "rc", and label 3 is the
+ * root label.
+ *
+ * \li 'target' refers to the same memory as 'source', so 'source'
+ * must not be changed while 'target' is still in use.
+ *
+ * Requires:
+ * \li 'source' and 'target' are valid names.
+ *
+ * \li first < dns_name_countlabels(name)
+ *
+ * \li first + n <= dns_name_countlabels(name)
+ */
+
+
+void
+dns_name_clone(const dns_name_t *source, dns_name_t *target);
+/*%<
+ * Make 'target' refer to the same name as 'source'.
+ *
+ * Notes:
+ *
+ * \li 'target' refers to the same memory as 'source', so 'source'
+ * must not be changed while 'target' is still in use.
+ *
+ * \li This call is functionally equivalent to:
+ *
+ * \code
+ * dns_name_getlabelsequence(source, 0,
+ * dns_name_countlabels(source),
+ * target);
+ * \endcode
+ *
+ * but is more efficient. Also, dns_name_clone() works even if 'source'
+ * is empty.
+ *
+ * Requires:
+ *
+ * \li 'source' is a valid name.
+ *
+ * \li 'target' is a valid name that is not read-only.
+ */
+
+/***
+ *** Conversions
+ ***/
+
+void
+dns_name_fromregion(dns_name_t *name, const isc_region_t *r);
+/*%<
+ * Make 'name' refer to region 'r'.
+ *
+ * Note:
+ * \li If the conversion encounters a root label before the end of the
+ * region the conversion stops and the length is set to the length
+ * so far converted. A maximum of 255 bytes is converted.
+ *
+ * Requires:
+ * \li The data in 'r' is a sequence of one or more type 00 or type 01000001
+ * labels.
+ */
+
+void
+dns_name_toregion(dns_name_t *name, isc_region_t *r);
+/*%<
+ * Make 'r' refer to 'name'.
+ *
+ * Requires:
+ *
+ * \li 'name' is a valid name.
+ *
+ * \li 'r' is a valid region.
+ */
+
+isc_result_t
+dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
+ dns_decompress_t *dctx, unsigned int options,
+ isc_buffer_t *target);
+/*%<
+ * Copy the possibly-compressed name at source (active region) into target,
+ * decompressing it.
+ *
+ * Notes:
+ * \li Decompression policy is controlled by 'dctx'.
+ *
+ * \li If DNS_NAME_DOWNCASE is set, any uppercase letters in 'source' will be
+ * downcased when they are copied into 'target'.
+ *
+ * Security:
+ *
+ * \li *** WARNING ***
+ *
+ * \li This routine will often be used when 'source' contains raw network
+ * data. A programming error in this routine could result in a denial
+ * of service, or in the hijacking of the server.
+ *
+ * Requires:
+ *
+ * \li 'name' is a valid name.
+ *
+ * \li 'source' is a valid buffer and the first byte of the active
+ * region should be the first byte of a DNS wire format domain name.
+ *
+ * \li 'target' is a valid buffer or 'target' is NULL and 'name' has
+ * a dedicated buffer.
+ *
+ * \li 'dctx' is a valid decompression context.
+ *
+ * Ensures:
+ *
+ * If result is success:
+ * \li If 'target' is not NULL, 'name' is attached to it.
+ *
+ * \li Uppercase letters are downcased in the copy iff
+ * DNS_NAME_DOWNCASE is set in options.
+ *
+ * \li The current location in source is advanced, and the used space
+ * in target is updated.
+ *
+ * Result:
+ * \li Success
+ * \li Bad Form: Label Length
+ * \li Bad Form: Unknown Label Type
+ * \li Bad Form: Name Length
+ * \li Bad Form: Compression type not allowed
+ * \li Bad Form: Bad compression pointer
+ * \li Bad Form: Input too short
+ * \li Resource Limit: Too many compression pointers
+ * \li Resource Limit: Not enough space in buffer
+ */
+
+isc_result_t
+dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
+ isc_buffer_t *target);
+/*%<
+ * Convert 'name' into wire format, compressing it as specified by the
+ * compression context 'cctx', and storing the result in 'target'.
+ *
+ * Notes:
+ * \li If the compression context allows global compression, then the
+ * global compression table may be updated.
+ *
+ * Requires:
+ * \li 'name' is a valid name
+ *
+ * \li dns_name_countlabels(name) > 0
+ *
+ * \li dns_name_isabsolute(name) == TRUE
+ *
+ * \li target is a valid buffer.
+ *
+ * \li Any offsets specified in a global compression table are valid
+ * for buffer.
+ *
+ * Ensures:
+ *
+ * If the result is success:
+ *
+ * \li The used space in target is updated.
+ *
+ * Returns:
+ * \li Success
+ * \li Resource Limit: Not enough space in buffer
+ */
+
+isc_result_t
+dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
+ dns_name_t *origin, unsigned int options,
+ isc_buffer_t *target);
+/*%<
+ * Convert the textual representation of a DNS name at source
+ * into uncompressed wire form stored in target.
+ *
+ * Notes:
+ * \li Relative domain names will have 'origin' appended to them
+ * unless 'origin' is NULL, in which case relative domain names
+ * will remain relative.
+ *
+ * \li If DNS_NAME_DOWNCASE is set in 'options', any uppercase letters
+ * in 'source' will be downcased when they are copied into 'target'.
+ *
+ * Requires:
+ *
+ * \li 'name' is a valid name.
+ *
+ * \li 'source' is a valid buffer.
+ *
+ * \li 'target' is a valid buffer or 'target' is NULL and 'name' has
+ * a dedicated buffer.
+ *
+ * Ensures:
+ *
+ * If result is success:
+ * \li If 'target' is not NULL, 'name' is attached to it.
+ *
+ * \li Uppercase letters are downcased in the copy iff
+ * DNS_NAME_DOWNCASE is set in 'options'.
+ *
+ * \li The current location in source is advanced, and the used space
+ * in target is updated.
+ *
+ * Result:
+ *\li #ISC_R_SUCCESS
+ *\li #DNS_R_EMPTYLABEL
+ *\li #DNS_R_LABELTOOLONG
+ *\li #DNS_R_BADESCAPE
+ *\li (#DNS_R_BADBITSTRING: should not be returned)
+ *\li (#DNS_R_BITSTRINGTOOLONG: should not be returned)
+ *\li #DNS_R_BADDOTTEDQUAD
+ *\li #ISC_R_NOSPACE
+ *\li #ISC_R_UNEXPECTEDEND
+ */
+
+isc_result_t
+dns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot,
+ isc_buffer_t *target);
+/*%<
+ * Convert 'name' into text format, storing the result in 'target'.
+ *
+ * Notes:
+ *\li If 'omit_final_dot' is true, then the final '.' in absolute
+ * names other than the root name will be omitted.
+ *
+ *\li If dns_name_countlabels == 0, the name will be "@", representing the
+ * current origin as described by RFC1035.
+ *
+ *\li The name is not NUL terminated.
+ *
+ * Requires:
+ *
+ *\li 'name' is a valid name
+ *
+ *\li 'target' is a valid buffer.
+ *
+ *\li if dns_name_isabsolute == FALSE, then omit_final_dot == FALSE
+ *
+ * Ensures:
+ *
+ *\li If the result is success:
+ * the used space in target is updated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE
+ */
+
+#define DNS_NAME_MAXTEXT 1023
+/*%<
+ * The maximum length of the text representation of a domain
+ * name as generated by dns_name_totext(). This does not
+ * include space for a terminating NULL.
+ *
+ * This definition is conservative - the actual maximum
+ * is 1004, derived as follows:
+ *
+ * A backslash-decimal escaped character takes 4 bytes.
+ * A wire-encoded name can be up to 255 bytes and each
+ * label is one length byte + at most 63 bytes of data.
+ * Maximizing the label lengths gives us a name of
+ * three 63-octet labels, one 61-octet label, and the
+ * root label:
+ *
+ * 1 + 63 + 1 + 63 + 1 + 63 + 1 + 61 + 1 = 255
+ *
+ * When printed, this is (3 * 63 + 61) * 4
+ * bytes for the escaped label data + 4 bytes for the
+ * dot terminating each label = 1004 bytes total.
+ */
+
+isc_result_t
+dns_name_tofilenametext(dns_name_t *name, isc_boolean_t omit_final_dot,
+ isc_buffer_t *target);
+/*%<
+ * Convert 'name' into an alternate text format appropriate for filenames,
+ * storing the result in 'target'. The name data is downcased, guaranteeing
+ * that the filename does not depend on the case of the converted name.
+ *
+ * Notes:
+ *\li If 'omit_final_dot' is true, then the final '.' in absolute
+ * names other than the root name will be omitted.
+ *
+ *\li The name is not NUL terminated.
+ *
+ * Requires:
+ *
+ *\li 'name' is a valid absolute name
+ *
+ *\li 'target' is a valid buffer.
+ *
+ * Ensures:
+ *
+ *\li If the result is success:
+ * the used space in target is updated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE
+ */
+
+isc_result_t
+dns_name_downcase(dns_name_t *source, dns_name_t *name,
+ isc_buffer_t *target);
+/*%<
+ * Downcase 'source'.
+ *
+ * Requires:
+ *
+ *\li 'source' and 'name' are valid names.
+ *
+ *\li If source == name, then
+ * 'source' must not be read-only
+ *
+ *\li Otherwise,
+ * 'target' is a valid buffer or 'target' is NULL and
+ * 'name' has a dedicated buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE
+ *
+ * Note: if source == name, then the result will always be ISC_R_SUCCESS.
+ */
+
+isc_result_t
+dns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix,
+ dns_name_t *name, isc_buffer_t *target);
+/*%<
+ * Concatenate 'prefix' and 'suffix'.
+ *
+ * Requires:
+ *
+ *\li 'prefix' is a valid name or NULL.
+ *
+ *\li 'suffix' is a valid name or NULL.
+ *
+ *\li 'name' is a valid name or NULL.
+ *
+ *\li 'target' is a valid buffer or 'target' is NULL and 'name' has
+ * a dedicated buffer.
+ *
+ *\li If 'prefix' is absolute, 'suffix' must be NULL or the empty name.
+ *
+ * Ensures:
+ *
+ *\li On success,
+ * If 'target' is not NULL and 'name' is not NULL, then 'name'
+ * is attached to it.
+ * The used space in target is updated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE
+ *\li #DNS_R_NAMETOOLONG
+ */
+
+void
+dns_name_split(dns_name_t *name, unsigned int suffixlabels,
+ dns_name_t *prefix, dns_name_t *suffix);
+/*%<
+ *
+ * Split 'name' into two pieces on a label boundary.
+ *
+ * Notes:
+ * \li 'name' is split such that 'suffix' holds the most significant
+ * 'suffixlabels' labels. All other labels are stored in 'prefix'.
+ *
+ *\li Copying name data is avoided as much as possible, so 'prefix'
+ * and 'suffix' will end up pointing at the data for 'name'.
+ *
+ *\li It is legitimate to pass a 'prefix' or 'suffix' that has
+ * its name data stored someplace other than the dedicated buffer.
+ * This is useful to avoid name copying in the calling function.
+ *
+ *\li It is also legitimate to pass a 'prefix' or 'suffix' that is
+ * the same dns_name_t as 'name'.
+ *
+ * Requires:
+ *\li 'name' is a valid name.
+ *
+ *\li 'suffixlabels' cannot exceed the number of labels in 'name'.
+ *
+ * \li 'prefix' is a valid name or NULL, and cannot be read-only.
+ *
+ *\li 'suffix' is a valid name or NULL, and cannot be read-only.
+ *
+ *\li If non-NULL, 'prefix' and 'suffix' must have dedicated buffers.
+ *
+ *\li 'prefix' and 'suffix' cannot point to the same buffer.
+ *
+ * Ensures:
+ *
+ *\li On success:
+ * If 'prefix' is not NULL it will contain the least significant
+ * labels.
+ * If 'suffix' is not NULL it will contain the most significant
+ * labels. dns_name_countlabels(suffix) will be equal to
+ * suffixlabels.
+ *
+ *\li On failure:
+ * Either 'prefix' or 'suffix' is invalidated (depending
+ * on which one the problem was encountered with).
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS No worries. (This function should always success).
+ */
+
+isc_result_t
+dns_name_dup(const dns_name_t *source, isc_mem_t *mctx,
+ dns_name_t *target);
+/*%<
+ * Make 'target' a dynamically allocated copy of 'source'.
+ *
+ * Requires:
+ *
+ *\li 'source' is a valid non-empty name.
+ *
+ *\li 'target' is a valid name that is not read-only.
+ *
+ *\li 'mctx' is a valid memory context.
+ */
+
+isc_result_t
+dns_name_dupwithoffsets(dns_name_t *source, isc_mem_t *mctx,
+ dns_name_t *target);
+/*%<
+ * Make 'target' a read-only dynamically allocated copy of 'source'.
+ * 'target' will also have a dynamically allocated offsets table.
+ *
+ * Requires:
+ *
+ *\li 'source' is a valid non-empty name.
+ *
+ *\li 'target' is a valid name that is not read-only.
+ *
+ *\li 'target' has no offsets table.
+ *
+ *\li 'mctx' is a valid memory context.
+ */
+
+void
+dns_name_free(dns_name_t *name, isc_mem_t *mctx);
+/*%<
+ * Free 'name'.
+ *
+ * Requires:
+ *
+ *\li 'name' is a valid name created previously in 'mctx' by dns_name_dup().
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ * Ensures:
+ *
+ *\li All dynamic resources used by 'name' are freed and the name is
+ * invalidated.
+ */
+
+isc_result_t
+dns_name_digest(dns_name_t *name, dns_digestfunc_t digest, void *arg);
+/*%<
+ * Send 'name' in DNSSEC canonical form to 'digest'.
+ *
+ * Requires:
+ *
+ *\li 'name' is a valid name.
+ *
+ *\li 'digest' is a valid dns_digestfunc_t.
+ *
+ * Ensures:
+ *
+ *\li If successful, the DNSSEC canonical form of 'name' will have been
+ * sent to 'digest'.
+ *
+ *\li If digest() returns something other than ISC_R_SUCCESS, that result
+ * will be returned as the result of dns_name_digest().
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *
+ *\li Many other results are possible if not successful.
+ *
+ */
+
+isc_boolean_t
+dns_name_dynamic(dns_name_t *name);
+/*%<
+ * Returns whether there is dynamic memory associated with this name.
+ *
+ * Requires:
+ *
+ *\li 'name' is a valid name.
+ *
+ * Returns:
+ *
+ *\li 'ISC_TRUE' if the name is dynamic othewise 'ISC_FALSE'.
+ */
+
+isc_result_t
+dns_name_print(dns_name_t *name, FILE *stream);
+/*%<
+ * Print 'name' on 'stream'.
+ *
+ * Requires:
+ *
+ *\li 'name' is a valid name.
+ *
+ *\li 'stream' is a valid stream.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *
+ *\li Any error that dns_name_totext() can return.
+ */
+
+void
+dns_name_format(dns_name_t *name, char *cp, unsigned int size);
+/*%<
+ * Format 'name' as text appropriate for use in log messages.
+ *
+ * Store the formatted name at 'cp', writing no more than
+ * 'size' bytes. The resulting string is guaranteed to be
+ * null terminated.
+ *
+ * The formatted name will have a terminating dot only if it is
+ * the root.
+ *
+ * This function cannot fail, instead any errors are indicated
+ * in the returned text.
+ *
+ * Requires:
+ *
+ *\li 'name' is a valid name.
+ *
+ *\li 'cp' points a valid character array of size 'size'.
+ *
+ *\li 'size' > 0.
+ *
+ */
+
+isc_result_t
+dns_name_settotextfilter(dns_name_totextfilter_t proc);
+/*%<
+ * Set / clear a thread specific function 'proc' to be called at the
+ * end of dns_name_totext().
+ *
+ * Note: Under Windows you need to call "dns_name_settotextfilter(NULL);"
+ * prior to exiting the thread otherwise memory will be leaked.
+ * For other platforms, which are pthreads based, this is still a good
+ * idea but not required.
+ *
+ * Returns
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_UNEXPECTED
+ */
+
+#define DNS_NAME_FORMATSIZE (DNS_NAME_MAXTEXT + 1)
+/*%<
+ * Suggested size of buffer passed to dns_name_format().
+ * Includes space for the terminating NULL.
+ */
+
+isc_result_t
+dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target);
+/*%<
+ * Makes 'dest' refer to a copy of the name in 'source'. The data are
+ * either copied to 'target' or the dedicated buffer in 'dest'.
+ *
+ * Requires:
+ * \li 'source' is a valid name.
+ *
+ * \li 'dest' is an initialized name with a dedicated buffer.
+ *
+ * \li 'target' is NULL or an initialized buffer.
+ *
+ * \li Either dest has a dedicated buffer or target != NULL.
+ *
+ * Ensures:
+ *
+ *\li On success, the used space in target is updated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE
+ */
+
+isc_boolean_t
+dns_name_ishostname(const dns_name_t *name, isc_boolean_t wildcard);
+/*%<
+ * Return if 'name' is a valid hostname. RFC 952 / RFC 1123.
+ * If 'wildcard' is ISC_TRUE then allow the first label of name to
+ * be a wildcard.
+ * The root is also accepted.
+ *
+ * Requires:
+ * 'name' to be valid.
+ */
+
+
+isc_boolean_t
+dns_name_ismailbox(const dns_name_t *name);
+/*%<
+ * Return if 'name' is a valid mailbox. RFC 821.
+ *
+ * Requires:
+ * \li 'name' to be valid.
+ */
+
+isc_boolean_t
+dns_name_internalwildcard(const dns_name_t *name);
+/*%<
+ * Return if 'name' contains a internal wildcard name.
+ *
+ * Requires:
+ * \li 'name' to be valid.
+ */
+
+void
+dns_name_destroy(void);
+/*%<
+ * Cleanup dns_name_settotextfilter() / dns_name_totext() state.
+ *
+ * This should be called as part of the final cleanup process.
+ *
+ * Note: dns_name_settotextfilter(NULL); should be called for all
+ * threads which have called dns_name_settotextfilter() with a
+ * non-NULL argument prior to calling dns_name_destroy();
+ */
+
+ISC_LANG_ENDDECLS
+
+/*
+ *** High Peformance Macros
+ ***/
+
+/*
+ * WARNING: Use of these macros by applications may require recompilation
+ * of the application in some situations where calling the function
+ * would not.
+ *
+ * WARNING: No assertion checking is done for these macros.
+ */
+
+#define DNS_NAME_INIT(n, o) \
+do { \
+ (n)->magic = DNS_NAME_MAGIC; \
+ (n)->ndata = NULL; \
+ (n)->length = 0; \
+ (n)->labels = 0; \
+ (n)->attributes = 0; \
+ (n)->offsets = (o); \
+ (n)->buffer = NULL; \
+ ISC_LINK_INIT((n), link); \
+ ISC_LIST_INIT((n)->list); \
+} while (0)
+
+#define DNS_NAME_RESET(n) \
+do { \
+ (n)->ndata = NULL; \
+ (n)->length = 0; \
+ (n)->labels = 0; \
+ (n)->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \
+ if ((n)->buffer != NULL) \
+ isc_buffer_clear((n)->buffer); \
+} while (0)
+
+#define DNS_NAME_SETBUFFER(n, b) \
+ (n)->buffer = (b)
+
+#define DNS_NAME_ISABSOLUTE(n) \
+ (((n)->attributes & DNS_NAMEATTR_ABSOLUTE) != 0 ? ISC_TRUE : ISC_FALSE)
+
+#define DNS_NAME_COUNTLABELS(n) \
+ ((n)->labels)
+
+#define DNS_NAME_TOREGION(n, r) \
+do { \
+ (r)->base = (n)->ndata; \
+ (r)->length = (n)->length; \
+} while (0)
+
+#define DNS_NAME_SPLIT(n, l, p, s) \
+do { \
+ dns_name_t *_n = (n); \
+ dns_name_t *_p = (p); \
+ dns_name_t *_s = (s); \
+ unsigned int _l = (l); \
+ if (_p != NULL) \
+ dns_name_getlabelsequence(_n, 0, _n->labels - _l, _p); \
+ if (_s != NULL) \
+ dns_name_getlabelsequence(_n, _n->labels - _l, _l, _s); \
+} while (0)
+
+#ifdef DNS_NAME_USEINLINE
+
+#define dns_name_init(n, o) DNS_NAME_INIT(n, o)
+#define dns_name_reset(n) DNS_NAME_RESET(n)
+#define dns_name_setbuffer(n, b) DNS_NAME_SETBUFFER(n, b)
+#define dns_name_countlabels(n) DNS_NAME_COUNTLABELS(n)
+#define dns_name_isabsolute(n) DNS_NAME_ISABSOLUTE(n)
+#define dns_name_toregion(n, r) DNS_NAME_TOREGION(n, r)
+#define dns_name_split(n, l, p, s) DNS_NAME_SPLIT(n, l, p, s)
+
+#endif /* DNS_NAME_USEINLINE */
+
+#endif /* DNS_NAME_H */
diff --git a/lib/dns/include/dns/ncache.h b/lib/dns/include/dns/ncache.h
new file mode 100644
index 0000000..459effb
--- /dev/null
+++ b/lib/dns/include/dns/ncache.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2004, 2005 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: ncache.h,v 1.17.18.2 2005/04/29 00:16:16 marka Exp $ */
+
+#ifndef DNS_NCACHE_H
+#define DNS_NCACHE_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ *\brief
+ * DNS Ncache
+ *
+ * XXX TBS XXX
+ *
+ * MP:
+ *\li The caller must ensure any required synchronization.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li RFC2308
+ */
+
+#include <isc/lang.h>
+#include <isc/stdtime.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * _OMITDNSSEC:
+ * Omit DNSSEC records when rendering.
+ */
+#define DNS_NCACHETOWIRE_OMITDNSSEC 0x0001
+
+isc_result_t
+dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
+ dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
+ dns_rdataset_t *addedrdataset);
+/*%<
+ * Convert the authority data from 'message' into a negative cache
+ * rdataset, and store it in 'cache' at 'node' with a TTL limited to
+ * 'maxttl'.
+ *
+ * The 'covers' argument is the RR type whose nonexistence we are caching,
+ * or dns_rdatatype_any when caching a NXDOMAIN response.
+ *
+ * Note:
+ *\li If 'addedrdataset' is not NULL, then it will be attached to the added
+ * rdataset. See dns_db_addrdataset() for more details.
+ *
+ * Requires:
+ *\li 'message' is a valid message with a properly formatting negative cache
+ * authority section.
+ *
+ *\li The requirements of dns_db_addrdataset() apply to 'cache', 'node',
+ * 'now', and 'addedrdataset'.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE
+ *
+ *\li Any result code of dns_db_addrdataset() is a possible result code
+ * of dns_ncache_add().
+ */
+
+isc_result_t
+dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
+ isc_buffer_t *target, unsigned int options,
+ unsigned int *countp);
+/*%<
+ * Convert the negative caching rdataset 'rdataset' to wire format,
+ * compressing names as specified in 'cctx', and storing the result in
+ * 'target'. If 'omit_dnssec' is set, DNSSEC records will not
+ * be added to 'target'.
+ *
+ * Notes:
+ *\li The number of RRs added to target will be added to *countp.
+ *
+ * Requires:
+ *\li 'rdataset' is a valid negative caching rdataset.
+ *
+ *\li 'rdataset' is not empty.
+ *
+ *\li 'countp' is a valid pointer.
+ *
+ * Ensures:
+ *\li On a return of ISC_R_SUCCESS, 'target' contains a wire format
+ * for the data contained in 'rdataset'. Any error return leaves
+ * the buffer unchanged.
+ *
+ *\li *countp has been incremented by the number of RRs added to
+ * target.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS - all ok
+ *\li #ISC_R_NOSPACE - 'target' doesn't have enough room
+ *
+ *\li Any error returned by dns_rdata_towire(), dns_rdataset_next(),
+ * dns_name_towire().
+ */
+
+isc_result_t
+dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
+ dns_rdatatype_t type, dns_rdataset_t *rdataset);
+/*%<
+ * Search the negative caching rdataset for an rdataset with the
+ * specified name and type.
+ *
+ * Requires:
+ *\li 'ncacherdataset' is a valid negative caching rdataset.
+ *
+ *\li 'ncacherdataset' is not empty.
+ *
+ *\li 'name' is a valid name.
+ *
+ *\li 'type' is not SIG, or a meta-RR type.
+ *
+ *\li 'rdataset' is a valid disassociated rdataset.
+ *
+ * Ensures:
+ *\li On a return of ISC_R_SUCCESS, 'rdataset' is bound to the found
+ * rdataset.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS - the rdataset was found.
+ *\li #ISC_R_NOTFOUND - the rdataset was not found.
+ *
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_NCACHE_H */
diff --git a/lib/dns/include/dns/nsec.h b/lib/dns/include/dns/nsec.h
new file mode 100644
index 0000000..46b75fa
--- /dev/null
+++ b/lib/dns/include/dns/nsec.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2004, 2005 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: nsec.h,v 1.4.20.2 2005/04/29 00:16:16 marka Exp $ */
+
+#ifndef DNS_NSEC_H
+#define DNS_NSEC_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+#include <dns/name.h>
+
+#define DNS_NSEC_BUFFERSIZE (DNS_NAME_MAXWIRE + 8192 + 512)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_nsec_buildrdata(dns_db_t *db, dns_dbversion_t *version,
+ dns_dbnode_t *node, dns_name_t *target,
+ unsigned char *buffer, dns_rdata_t *rdata);
+/*%<
+ * Build the rdata of a NSEC record.
+ *
+ * Requires:
+ *\li buffer Points to a temporary buffer of at least
+ * DNS_NSEC_BUFFERSIZE bytes.
+ *\li rdata Points to an initialized dns_rdata_t.
+ *
+ * Ensures:
+ * \li *rdata Contains a valid NSEC rdata. The 'data' member refers
+ * to 'buffer'.
+ */
+
+isc_result_t
+dns_nsec_build(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
+ dns_name_t *target, dns_ttl_t ttl);
+/*%<
+ * Build a NSEC record and add it to a database.
+ */
+
+isc_boolean_t
+dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type);
+/*%<
+ * Determine if a type is marked as present in an NSEC record.
+ *
+ * Requires:
+ *\li 'nsec' points to a valid rdataset of type NSEC
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_NSEC_H */
diff --git a/lib/dns/include/dns/opcode.h b/lib/dns/include/dns/opcode.h
new file mode 100644
index 0000000..4796dba
--- /dev/null
+++ b/lib/dns/include/dns/opcode.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: opcode.h,v 1.2.18.2 2005/04/29 00:16:16 marka Exp $ */
+
+#ifndef DNS_OPCODE_H
+#define DNS_OPCODE_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target);
+/*%<
+ * Put a textual representation of error 'opcode' into 'target'.
+ *
+ * Requires:
+ *\li 'opcode' is a valid opcode.
+ *
+ *\li 'target' is a valid text buffer.
+ *
+ * Ensures:
+ *\li If the result is success:
+ * The used space in 'target' is updated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS on success
+ *\li #ISC_R_NOSPACE target buffer is too small
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_OPCODE_H */
diff --git a/lib/dns/include/dns/order.h b/lib/dns/include/dns/order.h
new file mode 100644
index 0000000..6458db0
--- /dev/null
+++ b/lib/dns/include/dns/order.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: order.h,v 1.3.18.2 2005/04/29 00:16:17 marka Exp $ */
+
+#ifndef DNS_ORDER_H
+#define DNS_ORDER_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_order_create(isc_mem_t *mctx, dns_order_t **orderp);
+/*%<
+ * Create a order object.
+ *
+ * Requires:
+ * \li 'orderp' to be non NULL and '*orderp == NULL'.
+ *\li 'mctx' to be valid.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_order_add(dns_order_t *order, dns_name_t *name,
+ dns_rdatatype_t rdtype, dns_rdataclass_t rdclass,
+ unsigned int mode);
+/*%<
+ * Add a entry to the end of the order list.
+ *
+ * Requires:
+ * \li 'order' to be valid.
+ *\li 'name' to be valid.
+ *\li 'mode' to be one of #DNS_RDATASERATTR_RANDOMIZE,
+ * #DNS_RDATASERATTR_RANDOMIZE or zero (#DNS_RDATASERATTR_CYCLIC).
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+unsigned int
+dns_order_find(dns_order_t *order, dns_name_t *name,
+ dns_rdatatype_t rdtype, dns_rdataclass_t rdclass);
+/*%<
+ * Find the first matching entry on the list.
+ *
+ * Requires:
+ *\li 'order' to be valid.
+ *\li 'name' to be valid.
+ *
+ * Returns the mode set by dns_order_add() or zero.
+ */
+
+void
+dns_order_attach(dns_order_t *source, dns_order_t **target);
+/*%<
+ * Attach to the 'source' object.
+ *
+ * Requires:
+ * \li 'source' to be valid.
+ *\li 'target' to be non NULL and '*target == NULL'.
+ */
+
+void
+dns_order_detach(dns_order_t **orderp);
+/*%<
+ * Detach from the object. Clean up if last this was the last
+ * reference.
+ *
+ * Requires:
+ *\li '*orderp' to be valid.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_ORDER_H */
diff --git a/lib/dns/include/dns/peer.h b/lib/dns/include/dns/peer.h
new file mode 100644
index 0000000..be5a8c3
--- /dev/null
+++ b/lib/dns/include/dns/peer.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2004-2006 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: peer.h,v 1.20.18.8 2006/02/28 03:10:48 marka Exp $ */
+
+#ifndef DNS_PEER_H
+#define DNS_PEER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Data structures for peers (e.g. a 'server' config file statement)
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/netaddr.h>
+
+#include <dns/types.h>
+
+#define DNS_PEERLIST_MAGIC ISC_MAGIC('s','e','R','L')
+#define DNS_PEER_MAGIC ISC_MAGIC('S','E','r','v')
+
+#define DNS_PEERLIST_VALID(ptr) ISC_MAGIC_VALID(ptr, DNS_PEERLIST_MAGIC)
+#define DNS_PEER_VALID(ptr) ISC_MAGIC_VALID(ptr, DNS_PEER_MAGIC)
+
+/***
+ *** Types
+ ***/
+
+struct dns_peerlist {
+ unsigned int magic;
+ isc_uint32_t refs;
+
+ isc_mem_t *mem;
+
+ ISC_LIST(dns_peer_t) elements;
+};
+
+struct dns_peer {
+ unsigned int magic;
+ isc_uint32_t refs;
+
+ isc_mem_t *mem;
+
+ isc_netaddr_t address;
+ unsigned int prefixlen;
+ isc_boolean_t bogus;
+ dns_transfer_format_t transfer_format;
+ isc_uint32_t transfers;
+ isc_boolean_t support_ixfr;
+ isc_boolean_t provide_ixfr;
+ isc_boolean_t request_ixfr;
+ isc_boolean_t support_edns;
+ dns_name_t *key;
+ isc_sockaddr_t *transfer_source;
+ isc_sockaddr_t *notify_source;
+ isc_sockaddr_t *query_source;
+ isc_uint16_t udpsize; /* recieve size */
+ isc_uint16_t maxudp; /* transmit size */
+
+ isc_uint32_t bitflags;
+
+ ISC_LINK(dns_peer_t) next;
+};
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_peerlist_new(isc_mem_t *mem, dns_peerlist_t **list);
+
+void
+dns_peerlist_attach(dns_peerlist_t *source, dns_peerlist_t **target);
+
+void
+dns_peerlist_detach(dns_peerlist_t **list);
+
+/*
+ * After return caller still holds a reference to peer.
+ */
+void
+dns_peerlist_addpeer(dns_peerlist_t *peers, dns_peer_t *peer);
+
+/*
+ * Ditto. */
+isc_result_t
+dns_peerlist_peerbyaddr(dns_peerlist_t *peers, isc_netaddr_t *addr,
+ dns_peer_t **retval);
+
+/*
+ * What he said.
+ */
+isc_result_t
+dns_peerlist_currpeer(dns_peerlist_t *peers, dns_peer_t **retval);
+
+isc_result_t
+dns_peer_new(isc_mem_t *mem, isc_netaddr_t *ipaddr, dns_peer_t **peer);
+
+isc_result_t
+dns_peer_newprefix(isc_mem_t *mem, isc_netaddr_t *ipaddr,
+ unsigned int prefixlen, dns_peer_t **peer);
+
+void
+dns_peer_attach(dns_peer_t *source, dns_peer_t **target);
+
+void
+dns_peer_detach(dns_peer_t **list);
+
+isc_result_t
+dns_peer_setbogus(dns_peer_t *peer, isc_boolean_t newval);
+
+isc_result_t
+dns_peer_getbogus(dns_peer_t *peer, isc_boolean_t *retval);
+
+isc_result_t
+dns_peer_setrequestixfr(dns_peer_t *peer, isc_boolean_t newval);
+
+isc_result_t
+dns_peer_getrequestixfr(dns_peer_t *peer, isc_boolean_t *retval);
+
+isc_result_t
+dns_peer_setprovideixfr(dns_peer_t *peer, isc_boolean_t newval);
+
+isc_result_t
+dns_peer_getprovideixfr(dns_peer_t *peer, isc_boolean_t *retval);
+
+isc_result_t
+dns_peer_setsupportedns(dns_peer_t *peer, isc_boolean_t newval);
+
+isc_result_t
+dns_peer_getsupportedns(dns_peer_t *peer, isc_boolean_t *retval);
+
+isc_result_t
+dns_peer_settransfers(dns_peer_t *peer, isc_uint32_t newval);
+
+isc_result_t
+dns_peer_gettransfers(dns_peer_t *peer, isc_uint32_t *retval);
+
+isc_result_t
+dns_peer_settransferformat(dns_peer_t *peer, dns_transfer_format_t newval);
+
+isc_result_t
+dns_peer_gettransferformat(dns_peer_t *peer, dns_transfer_format_t *retval);
+
+isc_result_t
+dns_peer_setkeybycharp(dns_peer_t *peer, const char *keyval);
+
+isc_result_t
+dns_peer_getkey(dns_peer_t *peer, dns_name_t **retval);
+
+isc_result_t
+dns_peer_setkey(dns_peer_t *peer, dns_name_t **keyval);
+
+isc_result_t
+dns_peer_settransfersource(dns_peer_t *peer,
+ const isc_sockaddr_t *transfer_source);
+
+isc_result_t
+dns_peer_gettransfersource(dns_peer_t *peer, isc_sockaddr_t *transfer_source);
+
+isc_result_t
+dns_peer_setudpsize(dns_peer_t *peer, isc_uint16_t udpsize);
+
+isc_result_t
+dns_peer_getudpsize(dns_peer_t *peer, isc_uint16_t *udpsize);
+
+isc_result_t
+dns_peer_setmaxudp(dns_peer_t *peer, isc_uint16_t maxudp);
+
+isc_result_t
+dns_peer_getmaxudp(dns_peer_t *peer, isc_uint16_t *maxudp);
+
+isc_result_t
+dns_peer_setnotifysource(dns_peer_t *peer, const isc_sockaddr_t *notify_source);
+
+isc_result_t
+dns_peer_getnotifysource(dns_peer_t *peer, isc_sockaddr_t *notify_source);
+
+isc_result_t
+dns_peer_setquerysource(dns_peer_t *peer, const isc_sockaddr_t *query_source);
+
+isc_result_t
+dns_peer_getquerysource(dns_peer_t *peer, isc_sockaddr_t *query_source);
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_PEER_H */
diff --git a/lib/dns/include/dns/portlist.h b/lib/dns/include/dns/portlist.h
new file mode 100644
index 0000000..2d400d4
--- /dev/null
+++ b/lib/dns/include/dns/portlist.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: portlist.h,v 1.3.18.2 2005/04/29 00:16:17 marka Exp $ */
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/net.h>
+#include <isc/types.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp);
+/*%<
+ * Create a port list.
+ *
+ * Requires:
+ *\li 'mctx' to be valid.
+ *\li 'portlistp' to be non NULL and '*portlistp' to be NULL;
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port);
+/*%<
+ * Add the given <port,af> tuple to the portlist.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ *\li 'af' to be AF_INET or AF_INET6
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+void
+dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port);
+/*%<
+ * Remove the given <port,af> tuple to the portlist.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ *\li 'af' to be AF_INET or AF_INET6
+ */
+
+isc_boolean_t
+dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port);
+/*%<
+ * Find the given <port,af> tuple to the portlist.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ *\li 'af' to be AF_INET or AF_INET6
+ *
+ * Returns
+ * \li #ISC_TRUE if the tuple is found, ISC_FALSE otherwise.
+ */
+
+void
+dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp);
+/*%<
+ * Attach to a port list.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ *\li 'portlistp' to be non NULL and '*portlistp' to be NULL;
+ */
+
+void
+dns_portlist_detach(dns_portlist_t **portlistp);
+/*%<
+ * Detach from a port list.
+ *
+ * Requires:
+ *\li '*portlistp' to be valid.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/dns/include/dns/rbt.h b/lib/dns/include/dns/rbt.h
new file mode 100644
index 0000000..a1edf0c
--- /dev/null
+++ b/lib/dns/include/dns/rbt.h
@@ -0,0 +1,916 @@
+/*
+ * Copyright (C) 2004, 2005 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: rbt.h,v 1.59.18.5 2005/10/13 01:26:07 marka Exp $ */
+
+#ifndef DNS_RBT_H
+#define DNS_RBT_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/refcount.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+#define DNS_RBT_USEHASH 1
+
+/*@{*/
+/*%
+ * Option values for dns_rbt_findnode() and dns_rbt_findname().
+ * These are used to form a bitmask.
+ */
+#define DNS_RBTFIND_NOOPTIONS 0x00
+#define DNS_RBTFIND_EMPTYDATA 0x01
+#define DNS_RBTFIND_NOEXACT 0x02
+#define DNS_RBTFIND_NOPREDECESSOR 0x04
+/*@}*/
+
+#ifndef DNS_RBT_USEISCREFCOUNT
+#ifdef ISC_REFCOUNT_HAVEATOMIC
+#define DNS_RBT_USEISCREFCOUNT 1
+#endif
+#endif
+
+/*
+ * These should add up to 30.
+ */
+#define DNS_RBT_LOCKLENGTH 10
+#define DNS_RBT_REFLENGTH 20
+
+#define DNS_RBTNODE_MAGIC ISC_MAGIC('R','B','N','O')
+#if DNS_RBT_USEMAGIC
+#define DNS_RBTNODE_VALID(n) ISC_MAGIC_VALID(n, DNS_RBTNODE_MAGIC)
+#else
+#define DNS_RBTNODE_VALID(n) ISC_TRUE
+#endif
+
+/*%
+ * This is the structure that is used for each node in the red/black
+ * tree of trees. NOTE WELL: the implementation manages this as a variable
+ * length structure, with the actual wire-format name and other data
+ * appended to this structure. Allocating a contiguous block of memory for
+ * multiple dns_rbtnode structures will not work.
+ */
+typedef struct dns_rbtnode {
+#if DNS_RBT_USEMAGIC
+ unsigned int magic;
+#endif
+ struct dns_rbtnode *parent;
+ struct dns_rbtnode *left;
+ struct dns_rbtnode *right;
+ struct dns_rbtnode *down;
+#ifdef DNS_RBT_USEHASH
+ struct dns_rbtnode *hashnext;
+#endif
+ /*@{*/
+ /*!
+ * The following bitfields add up to a total bitwidth of 32.
+ * The range of values necessary for each item is indicated,
+ * but in the case of "attributes" the field is wider to accomodate
+ * possible future expansion. "offsetlen" could be one bit
+ * narrower by always adjusting its value by 1 to find the real
+ * offsetlen, but doing so does not gain anything (except perhaps
+ * another bit for "attributes", which doesn't yet need any more).
+ *
+ * In each case below the "range" indicated is what's _necessary_ for
+ * the bitfield to hold, not what it actually _can_ hold.
+ */
+ unsigned int is_root : 1; /*%< range is 0..1 */
+ unsigned int color : 1; /*%< range is 0..1 */
+ unsigned int find_callback : 1; /*%< range is 0..1 */
+ unsigned int attributes : 4; /*%< range is 0..2 */
+ unsigned int namelen : 8; /*%< range is 1..255 */
+ unsigned int offsetlen : 8; /*%< range is 1..128 */
+ unsigned int padbytes : 9; /*%< range is 0..380 */
+ /*@}*/
+
+#ifdef DNS_RBT_USEHASH
+ unsigned int hashval;
+#endif
+
+ /*@{*/
+ /*!
+ * These values are used in the RBT DB implementation. The appropriate
+ * node lock must be held before accessing them.
+ */
+ void *data;
+ unsigned int dirty:1;
+ unsigned int wild:1;
+ unsigned int locknum:DNS_RBT_LOCKLENGTH;
+#ifndef DNS_RBT_USEISCREFCOUNT
+ unsigned int references:DNS_RBT_REFLENGTH;
+#else
+ isc_refcount_t references; /* note that this is not in the bitfield */
+#endif
+ /*@}*/
+} dns_rbtnode_t;
+
+typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node,
+ dns_name_t *name,
+ void *callback_arg);
+
+/*****
+ ***** Chain Info
+ *****/
+
+/*!
+ * A chain is used to keep track of the sequence of nodes to reach any given
+ * node from the root of the tree. Originally nodes did not have parent
+ * pointers in them (for memory usage reasons) so there was no way to find
+ * the path back to the root from any given node. Now that nodes have parent
+ * pointers, chains might be going away in a future release, though the
+ * movement functionality would remain.
+ *
+ * In any event, parent information, whether via parent pointers or chains, is
+ * necessary information for iterating through the tree or for basic internal
+ * tree maintenance issues (ie, the rotations that are done to rebalance the
+ * tree when a node is added). The obvious implication of this is that for a
+ * chain to remain valid, the tree has to be locked down against writes for the
+ * duration of the useful life of the chain, because additions or removals can
+ * change the path from the root to the node the chain has targetted.
+ *
+ * The dns_rbtnodechain_ functions _first, _last, _prev and _next all take
+ * dns_name_t parameters for the name and the origin, which can be NULL. If
+ * non-NULL, 'name' will end up pointing to the name data and offsets that are
+ * stored at the node (and thus it will be read-only), so it should be a
+ * regular dns_name_t that has been initialized with dns_name_init. When
+ * 'origin' is non-NULL, it will get the name of the origin stored in it, so it
+ * needs to have its own buffer space and offsets, which is most easily
+ * accomplished with a dns_fixedname_t. It is _not_ necessary to reinitialize
+ * either 'name' or 'origin' between calls to the chain functions.
+ *
+ * NOTE WELL: even though the name data at the root of the tree of trees will
+ * be absolute (typically just "."), it will will be made into a relative name
+ * with an origin of "." -- an empty name when the node is ".". This is
+ * because a common on operation on 'name' and 'origin' is to use
+ * dns_name_concatenate() on them to generate the complete name. An empty name
+ * can be detected when dns_name_countlabels == 0, and is printed by
+ * dns_name_totext()/dns_name_format() as "@", consistent with RFC1035's
+ * definition of "@" as the current origin.
+ *
+ * dns_rbtnodechain_current is similar to the _first, _last, _prev and _next
+ * functions but additionally can provide the node to which the chain points.
+ */
+
+/*%
+ * The number of level blocks to allocate at a time. Currently the maximum
+ * number of levels is allocated directly in the structure, but future
+ * revisions of this code might have a static initial block with dynamic
+ * growth. Allocating space for 256 levels when the tree is almost never that
+ * deep is wasteful, but it's not clear that it matters, since the waste is
+ * only 2MB for 1000 concurrently active chains on a system with 64-bit
+ * pointers.
+ */
+#define DNS_RBT_LEVELBLOCK 254
+
+typedef struct dns_rbtnodechain {
+ unsigned int magic;
+ isc_mem_t * mctx;
+ /*%
+ * The terminal node of the chain. It is not in levels[].
+ * This is ostensibly private ... but in a pinch it could be
+ * used tell that the chain points nowhere without needing to
+ * call dns_rbtnodechain_current().
+ */
+ dns_rbtnode_t * end;
+ /*%
+ * The maximum number of labels in a name is 128; bitstrings mean
+ * a conceptually very large number (which I have not bothered to
+ * compute) of logical levels because splitting can potentially occur
+ * at each bit. However, DNSSEC restricts the number of "logical"
+ * labels in a name to 255, meaning only 254 pointers are needed
+ * in the worst case.
+ */
+ dns_rbtnode_t * levels[DNS_RBT_LEVELBLOCK];
+ /*%
+ * level_count indicates how deep the chain points into the
+ * tree of trees, and is the index into the levels[] array.
+ * Thus, levels[level_count - 1] is the last level node stored.
+ * A chain that points to the top level of the tree of trees has
+ * a level_count of 0, the first level has a level_count of 1, and
+ * so on.
+ */
+ unsigned int level_count;
+ /*%
+ * level_matches tells how many levels matched above the node
+ * returned by dns_rbt_findnode(). A match (partial or exact) found
+ * in the first level thus results in level_matches being set to 1.
+ * This is used by the rbtdb to set the start point for a recursive
+ * search of superdomains until the RR it is looking for is found.
+ */
+ unsigned int level_matches;
+} dns_rbtnodechain_t;
+
+/*****
+ ***** Public interfaces.
+ *****/
+isc_result_t
+dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
+ void *deleter_arg, dns_rbt_t **rbtp);
+/*%<
+ * Initialize a red-black tree of trees.
+ *
+ * Notes:
+ *\li The deleter argument, if non-null, points to a function that is
+ * responsible for cleaning up any memory associated with the data
+ * pointer of a node when the node is deleted. It is passed the
+ * deleted node's data pointer as its first argument and deleter_arg
+ * as its second argument.
+ *
+ * Requires:
+ * \li mctx is a pointer to a valid memory context.
+ *\li rbtp != NULL && *rbtp == NULL
+ *\li arg == NULL iff deleter == NULL
+ *
+ * Ensures:
+ *\li If result is ISC_R_SUCCESS:
+ * *rbtp points to a valid red-black tree manager
+ *
+ *\li If result is failure:
+ * *rbtp does not point to a valid red-black tree manager.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of Memory
+ */
+
+isc_result_t
+dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data);
+/*%<
+ * Add 'name' to the tree of trees, associated with 'data'.
+ *
+ * Notes:
+ *\li 'data' is never required to be non-NULL, but specifying it
+ * when the name is added is faster than searching for 'name'
+ * again and then setting the data pointer. The lack of a data pointer
+ * for a node also has other ramifications regarding whether
+ * dns_rbt_findname considers a node to exist, or dns_rbt_deletename
+ * joins nodes.
+ *
+ * Requires:
+ *\li rbt is a valid rbt manager.
+ *\li dns_name_isabsolute(name) == TRUE
+ *
+ * Ensures:
+ *\li 'name' is not altered in any way.
+ *
+ *\li Any external references to nodes in the tree are unaffected by
+ * node splits that are necessary to insert the new name.
+ *
+ *\li If result is #ISC_R_SUCCESS:
+ * 'name' is findable in the red/black tree of trees in O(log N).
+ * The data pointer of the node for 'name' is set to 'data'.
+ *
+ *\li If result is #ISC_R_EXISTS or #ISC_R_NOSPACE:
+ * The tree of trees is unaltered.
+ *
+ *\li If result is #ISC_R_NOMEMORY:
+ * No guarantees.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_EXISTS The name already exists with associated data.
+ *\li #ISC_R_NOSPACE The name had more logical labels than are allowed.
+ *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory
+ */
+
+isc_result_t
+dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep);
+
+/*%<
+ * Just like dns_rbt_addname, but returns the address of the node.
+ *
+ * Requires:
+ *\li rbt is a valid rbt structure.
+ *\li dns_name_isabsolute(name) == TRUE
+ *\li nodep != NULL && *nodep == NULL
+ *
+ * Ensures:
+ *\li 'name' is not altered in any way.
+ *
+ *\li Any external references to nodes in the tree are unaffected by
+ * node splits that are necessary to insert the new name.
+ *
+ *\li If result is ISC_R_SUCCESS:
+ * 'name' is findable in the red/black tree of trees in O(log N).
+ * *nodep is the node that was added for 'name'.
+ *
+ *\li If result is ISC_R_EXISTS:
+ * The tree of trees is unaltered.
+ * *nodep is the existing node for 'name'.
+ *
+ *\li If result is ISC_R_NOMEMORY:
+ * No guarantees.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_EXISTS The name already exists, possibly without data.
+ *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory
+ */
+
+isc_result_t
+dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
+ dns_name_t *foundname, void **data);
+/*%<
+ * Get the data pointer associated with 'name'.
+ *
+ * Notes:
+ *\li When #DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
+ * returned (also subject to #DNS_RBTFIND_EMPTYDATA), even when there is
+ * an exact match in the tree.
+ *
+ *\li A node that has no data is considered not to exist for this function,
+ * unless the #DNS_RBTFIND_EMPTYDATA option is set.
+ *
+ * Requires:
+ *\li rbt is a valid rbt manager.
+ *\li dns_name_isabsolute(name) == TRUE
+ *\li data != NULL && *data == NULL
+ *
+ * Ensures:
+ *\li 'name' and the tree are not altered in any way.
+ *
+ *\li If result is ISC_R_SUCCESS:
+ * *data is the data associated with 'name'.
+ *
+ *\li If result is DNS_R_PARTIALMATCH:
+ * *data is the data associated with the deepest superdomain
+ * of 'name' which has data.
+ *
+ *\li If result is ISC_R_NOTFOUND:
+ * Neither the name nor a superdomain was found with data.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #DNS_R_PARTIALMATCH Superdomain found with data
+ *\li #ISC_R_NOTFOUND No match
+ *\li #ISC_R_NOSPACE Concatenating nodes to form foundname failed
+ */
+
+isc_result_t
+dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
+ dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
+ unsigned int options, dns_rbtfindcallback_t callback,
+ void *callback_arg);
+/*%<
+ * Find the node for 'name'.
+ *
+ * Notes:
+ *\li A node that has no data is considered not to exist for this function,
+ * unless the DNS_RBTFIND_EMPTYDATA option is set. This applies to both
+ * exact matches and partial matches.
+ *
+ *\li If the chain parameter is non-NULL, then the path through the tree
+ * to the DNSSEC predecessor of the searched for name is maintained,
+ * unless the DNS_RBTFIND_NOPREDECESSOR or DNS_RBTFIND_NOEXACT option
+ * is used. (For more details on those options, see below.)
+ *
+ *\li If there is no predecessor, then the chain will point to nowhere, as
+ * indicated by chain->end being NULL or dns_rbtnodechain_current
+ * returning ISC_R_NOTFOUND. Note that in a normal Internet DNS RBT
+ * there will always be a predecessor for all names except the root
+ * name, because '.' will exist and '.' is the predecessor of
+ * everything. But you can certainly construct a trivial tree and a
+ * search for it that has no predecessor.
+ *
+ *\li Within the chain structure, the 'levels' member of the structure holds
+ * the root node of each level except the first.
+ *
+ *\li The 'level_count' of the chain indicates how deep the chain to the
+ * predecessor name is, as an index into the 'levels[]' array. It does
+ * not count name elements, per se, but only levels of the tree of trees,
+ * the distinction arrising because multiple labels from a name can be
+ * stored on only one level. It is also does not include the level
+ * that has the node, since that level is not stored in levels[].
+ *
+ *\li The chain's 'level_matches' is not directly related to the predecessor.
+ * It is the number of levels above the level of the found 'node',
+ * regardless of whether it was a partial match or exact match. When
+ * the node is found in the top level tree, or no node is found at all,
+ * level_matches is 0.
+ *
+ *\li When DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
+ * returned (also subject to DNS_RBTFIND_EMPTYDATA), even when
+ * there is an exact match in the tree. In this case, the chain
+ * will not point to the DNSSEC predecessor, but will instead point
+ * to the exact match, if there was any. Thus the preceding paragraphs
+ * should have "exact match" substituted for "predecessor" to describe
+ * how the various elements of the chain are set. This was done to
+ * ensure that the chain's state was sane, and to prevent problems that
+ * occurred when running the predecessor location code under conditions
+ * it was not designed for. It is not clear *where* the chain should
+ * point when DNS_RBTFIND_NOEXACT is set, so if you end up using a chain
+ * with this option because you want a particular node, let us know
+ * where you want the chain pointed, so this can be made more firm.
+ *
+ * Requires:
+ *\li rbt is a valid rbt manager.
+ *\li dns_name_isabsolute(name) == TRUE.
+ *\li node != NULL && *node == NULL.
+ *\li #DNS_RBTFIND_NOEXACT and DNS_RBTFIND_NOPREDECESSOR are mutally
+ * exclusive.
+ *
+ * Ensures:
+ *\li 'name' and the tree are not altered in any way.
+ *
+ *\li If result is ISC_R_SUCCESS:
+ *\verbatim
+ * *node is the terminal node for 'name'.
+
+ * 'foundname' and 'name' represent the same name (though not
+ * the same memory).
+
+ * 'chain' points to the DNSSEC predecessor, if any, of 'name'.
+ *
+ * chain->level_matches and chain->level_count are equal.
+ *\endverbatim
+ *
+ * If result is DNS_R_PARTIALMATCH:
+ *\verbatim
+ * *node is the data associated with the deepest superdomain
+ * of 'name' which has data.
+ *
+ * 'foundname' is the name of deepest superdomain (which has
+ * data, unless the DNS_RBTFIND_EMPTYDATA option is set).
+ *
+ * 'chain' points to the DNSSEC predecessor, if any, of 'name'.
+ *\endverbatim
+ *
+ *\li If result is ISC_R_NOTFOUND:
+ *\verbatim
+ * Neither the name nor a superdomain was found. *node is NULL.
+ *
+ * 'chain' points to the DNSSEC predecessor, if any, of 'name'.
+ *
+ * chain->level_matches is 0.
+ *\endverbatim
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #DNS_R_PARTIALMATCH Superdomain found with data
+ *\li #ISC_R_NOTFOUND No match, or superdomain with no data
+ *\li #ISC_R_NOSPACE Concatenating nodes to form foundname failed
+ */
+
+isc_result_t
+dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse);
+/*%<
+ * Delete 'name' from the tree of trees.
+ *
+ * Notes:
+ *\li When 'name' is removed, if recurse is ISC_TRUE then all of its
+ * subnames are removed too.
+ *
+ * Requires:
+ *\li rbt is a valid rbt manager.
+ *\li dns_name_isabsolute(name) == TRUE
+ *
+ * Ensures:
+ *\li 'name' is not altered in any way.
+ *
+ *\li Does NOT ensure that any external references to nodes in the tree
+ * are unaffected by node joins.
+ *
+ *\li If result is ISC_R_SUCCESS:
+ * 'name' does not appear in the tree with data; however,
+ * the node for the name might still exist which can be
+ * found with dns_rbt_findnode (but not dns_rbt_findname).
+ *
+ *\li If result is ISC_R_NOTFOUND:
+ * 'name' does not appear in the tree with data, because
+ * it did not appear in the tree before the function was called.
+ *
+ *\li If result is something else:
+ * See result codes for dns_rbt_findnode (if it fails, the
+ * node is not deleted) or dns_rbt_deletenode (if it fails,
+ * the node is deleted, but the tree is not optimized when
+ * it could have been).
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOTFOUND No match
+ *\li something_else Any return code from dns_rbt_findnode except
+ * DNS_R_PARTIALMATCH (which causes ISC_R_NOTFOUND
+ * to be returned instead), and any code from
+ * dns_rbt_deletenode.
+ */
+
+isc_result_t
+dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse);
+/*%<
+ * Delete 'node' from the tree of trees.
+ *
+ * Notes:
+ *\li When 'node' is removed, if recurse is ISC_TRUE then all nodes
+ * in levels down from it are removed too.
+ *
+ * Requires:
+ *\li rbt is a valid rbt manager.
+ *\li node != NULL.
+ *
+ * Ensures:
+ *\li Does NOT ensure that any external references to nodes in the tree
+ * are unaffected by node joins.
+ *
+ *\li If result is ISC_R_SUCCESS:
+ * 'node' does not appear in the tree with data; however,
+ * the node might still exist if it serves as a pointer to
+ * a lower tree level as long as 'recurse' was false, hence
+ * the node could can be found with dns_rbt_findnode whem
+ * that function's empty_data_ok parameter is true.
+ *
+ *\li If result is ISC_R_NOMEMORY or ISC_R_NOSPACE:
+ * The node was deleted, but the tree structure was not
+ * optimized.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory when joining nodes.
+ *\li #ISC_R_NOSPACE dns_name_concatenate failed when joining nodes.
+ */
+
+void
+dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name);
+/*%<
+ * Convert the sequence of labels stored at 'node' into a 'name'.
+ *
+ * Notes:
+ *\li This function does not return the full name, from the root, but
+ * just the labels at the indicated node.
+ *
+ *\li The name data pointed to by 'name' is the information stored
+ * in the node, not a copy. Altering the data at this pointer
+ * will likely cause grief.
+ *
+ * Requires:
+ * \li name->offsets == NULL
+ *
+ * Ensures:
+ * \li 'name' is DNS_NAMEATTR_READONLY.
+ *
+ * \li 'name' will point directly to the labels stored after the
+ * dns_rbtnode_t struct.
+ *
+ * \li 'name' will have offsets that also point to the information stored
+ * as part of the node.
+ */
+
+isc_result_t
+dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name);
+/*%<
+ * Like dns_rbt_namefromnode, but returns the full name from the root.
+ *
+ * Notes:
+ * \li Unlike dns_rbt_namefromnode, the name will not point directly
+ * to node data. Rather, dns_name_concatenate will be used to copy
+ * the name data from each node into the 'name' argument.
+ *
+ * Requires:
+ * \li name != NULL
+ * \li name has a dedicated buffer.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOSPACE (possible via dns_name_concatenate)
+ * \li DNS_R_NAMETOOLONG (possible via dns_name_concatenate)
+ */
+
+char *
+dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname,
+ unsigned int size);
+/*%<
+ * Format the full name of a node for printing, using dns_name_format().
+ *
+ * Notes:
+ * \li 'size' is the length of the printname buffer. This should be
+ * DNS_NAME_FORMATSIZE or larger.
+ *
+ * Requires:
+ * \li node and printname are not NULL.
+ *
+ * Returns:
+ * \li The 'printname' pointer.
+ */
+
+unsigned int
+dns_rbt_nodecount(dns_rbt_t *rbt);
+/*%<
+ * Obtain the number of nodes in the tree of trees.
+ *
+ * Requires:
+ * \li rbt is a valid rbt manager.
+ */
+
+void
+dns_rbt_destroy(dns_rbt_t **rbtp);
+isc_result_t
+dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum);
+/*%<
+ * Stop working with a red-black tree of trees.
+ * If 'quantum' is zero then the entire tree will be destroyed.
+ * If 'quantum' is non zero then up to 'quantum' nodes will be destroyed
+ * allowing the rbt to be incrementally destroyed by repeated calls to
+ * dns_rbt_destroy2(). Once dns_rbt_destroy2() has been called no other
+ * operations than dns_rbt_destroy()/dns_rbt_destroy2() should be
+ * performed on the tree of trees.
+ *
+ * Requires:
+ * \li *rbt is a valid rbt manager.
+ *
+ * Ensures on ISC_R_SUCCESS:
+ * \li All space allocated by the RBT library has been returned.
+ *
+ * \li *rbt is invalidated as an rbt manager.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_QUOTA if 'quantum' nodes have been destroyed.
+ */
+
+void
+dns_rbt_printall(dns_rbt_t *rbt);
+/*%<
+ * Print an ASCII representation of the internal structure of the red-black
+ * tree of trees.
+ *
+ * Notes:
+ * \li The name stored at each node, along with the node's color, is printed.
+ * Then the down pointer, left and right pointers are displayed
+ * recursively in turn. NULL down pointers are silently omitted;
+ * NULL left and right pointers are printed.
+ */
+
+/*****
+ ***** Chain Functions
+ *****/
+
+void
+dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx);
+/*%<
+ * Initialize 'chain'.
+ *
+ * Requires:
+ *\li 'chain' is a valid pointer.
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ * Ensures:
+ *\li 'chain' is suitable for use.
+ */
+
+void
+dns_rbtnodechain_reset(dns_rbtnodechain_t *chain);
+/*%<
+ * Free any dynamic storage associated with 'chain', and then reinitialize
+ * 'chain'.
+ *
+ * Requires:
+ *\li 'chain' is a valid pointer.
+ *
+ * Ensures:
+ *\li 'chain' is suitable for use, and uses no dynamic storage.
+ */
+
+void
+dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain);
+/*%<
+ * Free any dynamic storage associated with 'chain', and then invalidates it.
+ *
+ * Notes:
+ *\li Future calls to any dns_rbtnodechain_ function will need to call
+ * dns_rbtnodechain_init on the chain first (except, of course,
+ * dns_rbtnodechain_init itself).
+ *
+ * Requires:
+ *\li 'chain' is a valid chain.
+ *
+ * Ensures:
+ *\li 'chain' is no longer suitable for use, and uses no dynamic storage.
+ */
+
+isc_result_t
+dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
+ dns_name_t *origin, dns_rbtnode_t **node);
+/*%<
+ * Provide the name, origin and node to which the chain is currently pointed.
+ *
+ * Notes:
+ *\li The tree need not have be locked against additions for the chain
+ * to remain valid, however there are no guarantees if any deletion
+ * has been made since the chain was established.
+ *
+ * Requires:
+ *\li 'chain' is a valid chain.
+ *
+ * Ensures:
+ *\li 'node', if non-NULL, is the node to which the chain was pointed
+ * by dns_rbt_findnode, dns_rbtnodechain_first or dns_rbtnodechain_last.
+ * If none were called for the chain since it was initialized or reset,
+ * or if the was no predecessor to the name searched for with
+ * dns_rbt_findnode, then '*node' is NULL and ISC_R_NOTFOUND is returned.
+ *
+ *\li 'name', if non-NULL, is the name stored at the terminal level of
+ * the chain. This is typically a single label, like the "www" of
+ * "www.isc.org", but need not be so. At the root of the tree of trees,
+ * if the node is "." then 'name' is ".", otherwise it is relative to ".".
+ * (Minimalist and atypical case: if the tree has just the name
+ * "isc.org." then the root node's stored name is "isc.org." but 'name'
+ * will be "isc.org".)
+ *
+ *\li 'origin', if non-NULL, is the sequence of labels in the levels
+ * above the terminal level, such as "isc.org." in the above example.
+ * 'origin' is always "." for the root node.
+ *
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS name, origin & node were successfully set.
+ *\li #ISC_R_NOTFOUND The chain does not point to any node.
+ *\li &lt;something_else> Any error return from dns_name_concatenate.
+ */
+
+isc_result_t
+dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
+ dns_name_t *name, dns_name_t *origin);
+/*%<
+ * Set the chain to the lexically first node in the tree of trees.
+ *
+ * Notes:
+ *\li By the definition of ordering for DNS names, the root of the tree of
+ * trees is the very first node, since everything else in the megatree
+ * uses it as a common suffix.
+ *
+ * Requires:
+ *\li 'chain' is a valid chain.
+ *\li 'rbt' is a valid rbt manager.
+ *
+ * Ensures:
+ *\li The chain points to the very first node of the tree.
+ *
+ *\li 'name' and 'origin', if non-NULL, are set as described for
+ * dns_rbtnodechain_current. Thus 'origin' will always be ".".
+ *
+ * Returns:
+ *\li #DNS_R_NEWORIGIN The name & origin were successfully set.
+ *\li &lt;something_else> Any error result from dns_rbtnodechain_current.
+ */
+
+isc_result_t
+dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
+ dns_name_t *name, dns_name_t *origin);
+/*%<
+ * Set the chain to the lexically last node in the tree of trees.
+ *
+ * Requires:
+ *\li 'chain' is a valid chain.
+ *\li 'rbt' is a valid rbt manager.
+ *
+ * Ensures:
+ *\li The chain points to the very last node of the tree.
+ *
+ *\li 'name' and 'origin', if non-NULL, are set as described for
+ * dns_rbtnodechain_current.
+ *
+ * Returns:
+ *\li #DNS_R_NEWORIGIN The name & origin were successfully set.
+ *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory building chain.
+ *\li &lt;something_else> Any error result from dns_name_concatenate.
+ */
+
+isc_result_t
+dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
+ dns_name_t *origin);
+/*%<
+ * Adjusts chain to point the DNSSEC predecessor of the name to which it
+ * is currently pointed.
+ *
+ * Requires:
+ *\li 'chain' is a valid chain.
+ *\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
+ * dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
+ * dns_rbt_findnode is not guaranteed to point the chain somewhere,
+ * since there may have been no predecessor to the searched for name.
+ *
+ * Ensures:
+ *\li The chain is pointed to the predecessor of its current target.
+ *
+ *\li 'name' and 'origin', if non-NULL, are set as described for
+ * dns_rbtnodechain_current.
+ *
+ *\li 'origin' is only if a new origin was found.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS The predecessor was found and 'name' was set.
+ *\li #DNS_R_NEWORIGIN The predecessor was found with a different
+ * origin and 'name' and 'origin' were set.
+ *\li #ISC_R_NOMORE There was no predecessor.
+ *\li &lt;something_else> Any error result from dns_rbtnodechain_current.
+ */
+
+isc_result_t
+dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
+ dns_name_t *origin);
+/*%<
+ * Adjusts chain to point the DNSSEC successor of the name to which it
+ * is currently pointed.
+ *
+ * Requires:
+ *\li 'chain' is a valid chain.
+ *\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
+ * dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
+ * dns_rbt_findnode is not guaranteed to point the chain somewhere,
+ * since there may have been no predecessor to the searched for name.
+ *
+ * Ensures:
+ *\li The chain is pointed to the successor of its current target.
+ *
+ *\li 'name' and 'origin', if non-NULL, are set as described for
+ * dns_rbtnodechain_current.
+ *
+ *\li 'origin' is only if a new origin was found.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS The successor was found and 'name' was set.
+ *\li #DNS_R_NEWORIGIN The successor was found with a different
+ * origin and 'name' and 'origin' were set.
+ *\li #ISC_R_NOMORE There was no successor.
+ *\li &lt;something_else> Any error result from dns_name_concatenate.
+ */
+
+/*
+ * Wrapper macros for manipulating the rbtnode reference counter:
+ * Since we selectively use isc_refcount_t for the reference counter of
+ * a rbtnode, operations on the counter depend on the actual type of it.
+ * The following macros provide a common interface to these operations,
+ * hiding the back-end. The usage is the same as that of isc_refcount_xxx().
+ */
+#ifdef DNS_RBT_USEISCREFCOUNT
+#define dns_rbtnode_refinit(node, n) \
+ do { \
+ isc_refcount_init(&(node)->references, (n)); \
+ } while (0)
+#define dns_rbtnode_refdestroy(node) \
+ do { \
+ isc_refcount_destroy(&(node)->references); \
+ } while (0)
+#define dns_rbtnode_refcurrent(node) \
+ isc_refcount_current(&(node)->references)
+#define dns_rbtnode_refincrement0(node, refs) \
+ do { \
+ isc_refcount_increment0(&(node)->references, (refs)); \
+ } while (0)
+#define dns_rbtnode_refincrement(node, refs) \
+ do { \
+ isc_refcount_increment(&(node)->references, (refs)); \
+ } while (0)
+#define dns_rbtnode_refdecrement(node, refs) \
+ do { \
+ isc_refcount_decrement(&(node)->references, (refs)); \
+ } while (0)
+#else /* DNS_RBT_USEISCREFCOUNT */
+#define dns_rbtnode_refinit(node, n) ((node)->references = (n))
+#define dns_rbtnode_refdestroy(node) (REQUIRE((node)->references == 0))
+#define dns_rbtnode_refcurrent(node) ((node)->references)
+#define dns_rbtnode_refincrement0(node, refs) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(refs); \
+ (node)->references++; \
+ if ((_tmp) != NULL) \
+ (*_tmp) = (node)->references; \
+ } while (0)
+#define dns_rbtnode_refincrement(node, refs) \
+ do { \
+ REQUIRE((node)->references > 0); \
+ (node)->references++; \
+ if ((refs) != NULL) \
+ (*refs) = (node)->references; \
+ } while (0)
+#define dns_rbtnode_refdecrement(node, refs) \
+ do { \
+ REQUIRE((node)->references > 0); \
+ (node)->references--; \
+ if ((refs) != NULL) \
+ (*refs) = (node)->references; \
+ } while (0)
+#endif /* DNS_RBT_USEISCREFCOUNT */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RBT_H */
diff --git a/lib/dns/include/dns/rcode.h b/lib/dns/include/dns/rcode.h
new file mode 100644
index 0000000..03c145b
--- /dev/null
+++ b/lib/dns/include/dns/rcode.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2004, 2005 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: rcode.h,v 1.13.18.2 2005/04/29 00:16:18 marka Exp $ */
+
+#ifndef DNS_RCODE_H
+#define DNS_RCODE_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t dns_rcode_fromtext(dns_rcode_t *rcodep, isc_textregion_t *source);
+/*%<
+ * Convert the text 'source' refers to into a DNS error value.
+ *
+ * Requires:
+ *\li 'rcodep' is a valid pointer.
+ *
+ *\li 'source' is a valid text region.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS on success
+ *\li #DNS_R_UNKNOWN type is unknown
+ */
+
+isc_result_t dns_rcode_totext(dns_rcode_t rcode, isc_buffer_t *target);
+/*%<
+ * Put a textual representation of error 'rcode' into 'target'.
+ *
+ * Requires:
+ *\li 'rcode' is a valid rcode.
+ *
+ *\li 'target' is a valid text buffer.
+ *
+ * Ensures:
+ *\li If the result is success:
+ * The used space in 'target' is updated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS on success
+ *\li #ISC_R_NOSPACE target buffer is too small
+ */
+
+isc_result_t dns_tsigrcode_fromtext(dns_rcode_t *rcodep,
+ isc_textregion_t *source);
+/*%<
+ * Convert the text 'source' refers to into a TSIG/TKEY error value.
+ *
+ * Requires:
+ *\li 'rcodep' is a valid pointer.
+ *
+ *\li 'source' is a valid text region.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS on success
+ *\li #DNS_R_UNKNOWN type is unknown
+ */
+
+isc_result_t dns_tsigrcode_totext(dns_rcode_t rcode, isc_buffer_t *target);
+/*%<
+ * Put a textual representation of TSIG/TKEY error 'rcode' into 'target'.
+ *
+ * Requires:
+ *\li 'rcode' is a valid TSIG/TKEY error code.
+ *
+ *\li 'target' is a valid text buffer.
+ *
+ * Ensures:
+ *\li If the result is success:
+ * The used space in 'target' is updated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS on success
+ *\li #ISC_R_NOSPACE target buffer is too small
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RCODE_H */
diff --git a/lib/dns/include/dns/rdata.h b/lib/dns/include/dns/rdata.h
new file mode 100644
index 0000000..a14bde7
--- /dev/null
+++ b/lib/dns/include/dns/rdata.h
@@ -0,0 +1,701 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: rdata.h,v 1.60.18.3 2005/05/19 04:59:56 marka Exp $ */
+
+#ifndef DNS_RDATA_H
+#define DNS_RDATA_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Provides facilities for manipulating DNS rdata, including conversions to
+ * and from wire format and text format.
+ *
+ * Given the large amount of rdata possible in a nameserver, it was important
+ * to come up with a very efficient way of storing rdata, but at the same
+ * time allow it to be manipulated.
+ *
+ * The decision was to store rdata in uncompressed wire format,
+ * and not to make it a fully abstracted object; i.e. certain parts of the
+ * server know rdata is stored that way. This saves a lot of memory, and
+ * makes adding rdata to messages easy. Having much of the server know
+ * the representation would be perilous, and we certainly don't want each
+ * user of rdata to be manipulating such a low-level structure. This is
+ * where the rdata module comes in. The module allows rdata handles to be
+ * created and attached to uncompressed wire format regions. All rdata
+ * operations and conversions are done through these handles.
+ *
+ * Implementation Notes:
+ *
+ *\li The routines in this module are expected to be synthesized by the
+ * build process from a set of source files, one per rdata type. For
+ * portability, it's probably best that the building be done by a C
+ * program. Adding a new rdata type will be a simple matter of adding
+ * a file to a directory and rebuilding the server. *All* knowlege of
+ * the format of a particular rdata type is in this file.
+ *
+ * MP:
+ *\li Clients of this module must impose any required synchronization.
+ *
+ * Reliability:
+ *\li This module deals with low-level byte streams. Errors in any of
+ * the functions are likely to crash the server or corrupt memory.
+ *
+ *\li Rdata is typed, and the caller must know what type of rdata it has.
+ * A caller that gets this wrong could crash the server.
+ *
+ *\li The fromstruct() and tostruct() routines use a void * pointer to
+ * represent the structure. The caller must ensure that it passes a
+ * pointer to the appropriate type, or the server could crash or memory
+ * could be corrupted.
+ *
+ * Resources:
+ *\li None.
+ *
+ * Security:
+ *
+ *\li *** WARNING ***
+ * dns_rdata_fromwire() deals with raw network data. An error in
+ * this routine could result in the failure or hijacking of the server.
+ *
+ * Standards:
+ *\li RFC1035
+ *\li Draft EDNS0 (0)
+ *\li Draft EDNS1 (0)
+ *\li Draft Binary Labels (2)
+ *\li Draft Local Compression (1)
+ *\li Various RFCs for particular types; these will be documented in the
+ * sources files of the types.
+ *
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+#include <dns/name.h>
+
+ISC_LANG_BEGINDECLS
+
+
+/***
+ *** Types
+ ***/
+
+/*%
+ ***** An 'rdata' is a handle to a binary region. The handle has an RR
+ ***** class and type, and the data in the binary region is in the format
+ ***** of the given class and type.
+ *****/
+/*%
+ * Clients are strongly discouraged from using this type directly, with
+ * the exception of the 'link' field which may be used directly for whatever
+ * purpose the client desires.
+ */
+struct dns_rdata {
+ unsigned char * data;
+ unsigned int length;
+ dns_rdataclass_t rdclass;
+ dns_rdatatype_t type;
+ unsigned int flags;
+ ISC_LINK(dns_rdata_t) link;
+};
+
+#define DNS_RDATA_INIT { NULL, 0, 0, 0, 0, {(void*)(-1), (void *)(-1)}}
+
+#define DNS_RDATA_UPDATE 0x0001 /*%< update pseudo record */
+
+/*
+ * Flags affecting rdata formatting style. Flags 0xFFFF0000
+ * are used by masterfile-level formatting and defined elsewhere.
+ * See additional comments at dns_rdata_tofmttext().
+ */
+
+/*% Split the rdata into multiple lines to try to keep it
+ within the "width". */
+#define DNS_STYLEFLAG_MULTILINE 0x00000001U
+
+/*% Output explanatory comments. */
+#define DNS_STYLEFLAG_COMMENT 0x00000002U
+
+#define DNS_RDATA_DOWNCASE DNS_NAME_DOWNCASE
+#define DNS_RDATA_CHECKNAMES DNS_NAME_CHECKNAMES
+#define DNS_RDATA_CHECKNAMESFAIL DNS_NAME_CHECKNAMESFAIL
+#define DNS_RDATA_CHECKREVERSE DNS_NAME_CHECKREVERSE
+#define DNS_RDATA_CHECKMX DNS_NAME_CHECKMX
+#define DNS_RDATA_CHECKMXFAIL DNS_NAME_CHECKMXFAIL
+
+/***
+ *** Initialization
+ ***/
+
+void
+dns_rdata_init(dns_rdata_t *rdata);
+/*%<
+ * Make 'rdata' empty.
+ *
+ * Requires:
+ * 'rdata' is a valid rdata (i.e. not NULL, points to a struct dns_rdata)
+ */
+
+void
+dns_rdata_reset(dns_rdata_t *rdata);
+/*%<
+ * Make 'rdata' empty.
+ *
+ * Requires:
+ *\li 'rdata' is a previously initialized rdata and is not linked.
+ */
+
+void
+dns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target);
+/*%<
+ * Clone 'target' from 'src'.
+ *
+ * Requires:
+ *\li 'src' to be initialized.
+ *\li 'target' to be initialized.
+ */
+
+/***
+ *** Comparisons
+ ***/
+
+int
+dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2);
+/*%<
+ * Determine the relative ordering under the DNSSEC order relation of
+ * 'rdata1' and 'rdata2'.
+ *
+ * Requires:
+ *
+ *\li 'rdata1' is a valid, non-empty rdata
+ *
+ *\li 'rdata2' is a valid, non-empty rdata
+ *
+ * Returns:
+ *\li < 0 'rdata1' is less than 'rdata2'
+ *\li 0 'rdata1' is equal to 'rdata2'
+ *\li > 0 'rdata1' is greater than 'rdata2'
+ */
+
+/***
+ *** Conversions
+ ***/
+
+void
+dns_rdata_fromregion(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, isc_region_t *r);
+/*%<
+ * Make 'rdata' refer to region 'r'.
+ *
+ * Requires:
+ *
+ *\li The data in 'r' is properly formatted for whatever type it is.
+ */
+
+void
+dns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r);
+/*%<
+ * Make 'r' refer to 'rdata'.
+ */
+
+isc_result_t
+dns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, isc_buffer_t *source,
+ dns_decompress_t *dctx, unsigned int options,
+ isc_buffer_t *target);
+/*%<
+ * Copy the possibly-compressed rdata at source into the target region.
+ *
+ * Notes:
+ *\li Name decompression policy is controlled by 'dctx'.
+ *
+ * 'options'
+ *\li DNS_RDATA_DOWNCASE downcase domain names when they are copied
+ * into target.
+ *
+ * Requires:
+ *
+ *\li 'rdclass' and 'type' are valid.
+ *
+ *\li 'source' is a valid buffer, and the active region of 'source'
+ * references the rdata to be processed.
+ *
+ *\li 'target' is a valid buffer.
+ *
+ *\li 'dctx' is a valid decompression context.
+ *
+ * Ensures,
+ * if result is success:
+ * \li If 'rdata' is not NULL, it is attached to the target.
+ * \li The conditions dns_name_fromwire() ensures for names hold
+ * for all names in the rdata.
+ * \li The current location in source is advanced, and the used space
+ * in target is updated.
+ *
+ * Result:
+ *\li Success
+ *\li Any non-success status from dns_name_fromwire()
+ *\li Various 'Bad Form' class failures depending on class and type
+ *\li Bad Form: Input too short
+ *\li Resource Limit: Not enough space
+ */
+
+isc_result_t
+dns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx,
+ isc_buffer_t *target);
+/*%<
+ * Convert 'rdata' into wire format, compressing it as specified by the
+ * compression context 'cctx', and storing the result in 'target'.
+ *
+ * Notes:
+ *\li If the compression context allows global compression, then the
+ * global compression table may be updated.
+ *
+ * Requires:
+ *\li 'rdata' is a valid, non-empty rdata
+ *
+ *\li target is a valid buffer
+ *
+ *\li Any offsets specified in a global compression table are valid
+ * for target.
+ *
+ * Ensures,
+ * if the result is success:
+ * \li The used space in target is updated.
+ *
+ * Returns:
+ *\li Success
+ *\li Any non-success status from dns_name_towire()
+ *\li Resource Limit: Not enough space
+ */
+
+isc_result_t
+dns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, isc_lex_t *lexer, dns_name_t *origin,
+ unsigned int options, isc_mem_t *mctx,
+ isc_buffer_t *target, dns_rdatacallbacks_t *callbacks);
+/*%<
+ * Convert the textual representation of a DNS rdata into uncompressed wire
+ * form stored in the target region. Tokens constituting the text of the rdata
+ * are taken from 'lexer'.
+ *
+ * Notes:
+ *\li Relative domain names in the rdata will have 'origin' appended to them.
+ * A NULL origin implies "origin == dns_rootname".
+ *
+ *
+ * 'options'
+ *\li DNS_RDATA_DOWNCASE downcase domain names when they are copied
+ * into target.
+ *\li DNS_RDATA_CHECKNAMES perform checknames checks.
+ *\li DNS_RDATA_CHECKNAMESFAIL fail if the checknames check fail. If
+ * not set a warning will be issued.
+ *\li DNS_RDATA_CHECKREVERSE this should set if the owner name ends
+ * in IP6.ARPA, IP6.INT or IN-ADDR.ARPA.
+ *
+ * Requires:
+ *
+ *\li 'rdclass' and 'type' are valid.
+ *
+ *\li 'lexer' is a valid isc_lex_t.
+ *
+ *\li 'mctx' is a valid isc_mem_t.
+ *
+ *\li 'target' is a valid region.
+ *
+ *\li 'origin' if non NULL it must be absolute.
+ *
+ *\li 'callbacks' to be NULL or callbacks->warn and callbacks->error be
+ * initialized.
+ *
+ * Ensures,
+ * if result is success:
+ *\li If 'rdata' is not NULL, it is attached to the target.
+
+ *\li The conditions dns_name_fromtext() ensures for names hold
+ * for all names in the rdata.
+
+ *\li The used space in target is updated.
+ *
+ * Result:
+ *\li Success
+ *\li Translated result codes from isc_lex_gettoken
+ *\li Various 'Bad Form' class failures depending on class and type
+ *\li Bad Form: Input too short
+ *\li Resource Limit: Not enough space
+ *\li Resource Limit: Not enough memory
+ */
+
+isc_result_t
+dns_rdata_totext(dns_rdata_t *rdata, dns_name_t *origin, isc_buffer_t *target);
+/*%<
+ * Convert 'rdata' into text format, storing the result in 'target'.
+ * The text will consist of a single line, with fields separated by
+ * single spaces.
+ *
+ * Notes:
+ *\li If 'origin' is not NULL, then any names in the rdata that are
+ * subdomains of 'origin' will be made relative it.
+ *
+ *\li XXX Do we *really* want to support 'origin'? I'm inclined towards "no"
+ * at the moment.
+ *
+ * Requires:
+ *
+ *\li 'rdata' is a valid, non-empty rdata
+ *
+ *\li 'origin' is NULL, or is a valid name
+ *
+ *\li 'target' is a valid text buffer
+ *
+ * Ensures,
+ * if the result is success:
+ *
+ * \li The used space in target is updated.
+ *
+ * Returns:
+ *\li Success
+ *\li Any non-success status from dns_name_totext()
+ *\li Resource Limit: Not enough space
+ */
+
+isc_result_t
+dns_rdata_tofmttext(dns_rdata_t *rdata, dns_name_t *origin, unsigned int flags,
+ unsigned int width, char *linebreak, isc_buffer_t *target);
+/*%<
+ * Like dns_rdata_totext, but do formatted output suitable for
+ * database dumps. This is intended for use by dns_db_dump();
+ * library users are discouraged from calling it directly.
+ *
+ * If (flags & #DNS_STYLEFLAG_MULTILINE) != 0, attempt to stay
+ * within 'width' by breaking the text into multiple lines.
+ * The string 'linebreak' is inserted between lines, and parentheses
+ * are added when necessary. Because RRs contain unbreakable elements
+ * such as domain names whose length is variable, unpredictable, and
+ * potentially large, there is no guarantee that the lines will
+ * not exceed 'width' anyway.
+ *
+ * If (flags & #DNS_STYLEFLAG_MULTILINE) == 0, the rdata is always
+ * printed as a single line, and no parentheses are used.
+ * The 'width' and 'linebreak' arguments are ignored.
+ *
+ * If (flags & #DNS_STYLEFLAG_COMMENT) != 0, output explanatory
+ * comments next to things like the SOA timer fields. Some
+ * comments (e.g., the SOA ones) are only printed when multiline
+ * output is selected.
+ */
+
+isc_result_t
+dns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, void *source, isc_buffer_t *target);
+/*%<
+ * Convert the C structure representation of an rdata into uncompressed wire
+ * format in 'target'.
+ *
+ * XXX Should we have a 'size' parameter as a sanity check on target?
+ *
+ * Requires:
+ *
+ *\li 'rdclass' and 'type' are valid.
+ *
+ *\li 'source' points to a valid C struct for the class and type.
+ *
+ *\li 'target' is a valid buffer.
+ *
+ *\li All structure pointers to memory blocks should be NULL if their
+ * corresponding length values are zero.
+ *
+ * Ensures,
+ * if result is success:
+ * \li If 'rdata' is not NULL, it is attached to the target.
+ *
+ * \li The used space in 'target' is updated.
+ *
+ * Result:
+ *\li Success
+ *\li Various 'Bad Form' class failures depending on class and type
+ *\li Resource Limit: Not enough space
+ */
+
+isc_result_t
+dns_rdata_tostruct(dns_rdata_t *rdata, void *target, isc_mem_t *mctx);
+/*%<
+ * Convert an rdata into its C structure representation.
+ *
+ * If 'mctx' is NULL then 'rdata' must persist while 'target' is being used.
+ *
+ * If 'mctx' is non NULL then memory will be allocated if required.
+ *
+ * Requires:
+ *
+ *\li 'rdata' is a valid, non-empty rdata.
+ *
+ *\li 'target' to point to a valid pointer for the type and class.
+ *
+ * Result:
+ *\li Success
+ *\li Resource Limit: Not enough memory
+ */
+
+void
+dns_rdata_freestruct(void *source);
+/*%<
+ * Free dynamic memory attached to 'source' (if any).
+ *
+ * Requires:
+ *
+ *\li 'source' to point to the structure previously filled in by
+ * dns_rdata_tostruct().
+ */
+
+isc_boolean_t
+dns_rdatatype_ismeta(dns_rdatatype_t type);
+/*%<
+ * Return true iff the rdata type 'type' is a meta-type
+ * like ANY or AXFR.
+ */
+
+isc_boolean_t
+dns_rdatatype_issingleton(dns_rdatatype_t type);
+/*%<
+ * Return true iff the rdata type 'type' is a singleton type,
+ * like CNAME or SOA.
+ *
+ * Requires:
+ * \li 'type' is a valid rdata type.
+ *
+ */
+
+isc_boolean_t
+dns_rdataclass_ismeta(dns_rdataclass_t rdclass);
+/*%<
+ * Return true iff the rdata class 'rdclass' is a meta-class
+ * like ANY or NONE.
+ */
+
+isc_boolean_t
+dns_rdatatype_isdnssec(dns_rdatatype_t type);
+/*%<
+ * Return true iff 'type' is one of the DNSSEC
+ * rdata types that may exist alongside a CNAME record.
+ *
+ * Requires:
+ * \li 'type' is a valid rdata type.
+ */
+
+isc_boolean_t
+dns_rdatatype_iszonecutauth(dns_rdatatype_t type);
+/*%<
+ * Return true iff rdata of type 'type' is considered authoritative
+ * data (not glue) in the NSEC chain when it occurs in the parent zone
+ * at a zone cut.
+ *
+ * Requires:
+ * \li 'type' is a valid rdata type.
+ *
+ */
+
+isc_boolean_t
+dns_rdatatype_isknown(dns_rdatatype_t type);
+/*%<
+ * Return true iff the rdata type 'type' is known.
+ *
+ * Requires:
+ * \li 'type' is a valid rdata type.
+ *
+ */
+
+
+isc_result_t
+dns_rdata_additionaldata(dns_rdata_t *rdata, dns_additionaldatafunc_t add,
+ void *arg);
+/*%<
+ * Call 'add' for each name and type from 'rdata' which is subject to
+ * additional section processing.
+ *
+ * Requires:
+ *
+ *\li 'rdata' is a valid, non-empty rdata.
+ *
+ *\li 'add' is a valid dns_additionalfunc_t.
+ *
+ * Ensures:
+ *
+ *\li If successful, then add() will have been called for each name
+ * and type subject to additional section processing.
+ *
+ *\li If add() returns something other than #ISC_R_SUCCESS, that result
+ * will be returned as the result of dns_rdata_additionaldata().
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *
+ *\li Many other results are possible if not successful.
+ */
+
+isc_result_t
+dns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg);
+/*%<
+ * Send 'rdata' in DNSSEC canonical form to 'digest'.
+ *
+ * Note:
+ *\li 'digest' may be called more than once by dns_rdata_digest(). The
+ * concatenation of all the regions, in the order they were given
+ * to 'digest', will be the DNSSEC canonical form of 'rdata'.
+ *
+ * Requires:
+ *
+ *\li 'rdata' is a valid, non-empty rdata.
+ *
+ *\li 'digest' is a valid dns_digestfunc_t.
+ *
+ * Ensures:
+ *
+ *\li If successful, then all of the rdata's data has been sent, in
+ * DNSSEC canonical form, to 'digest'.
+ *
+ *\li If digest() returns something other than ISC_R_SUCCESS, that result
+ * will be returned as the result of dns_rdata_digest().
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *
+ *\li Many other results are possible if not successful.
+ */
+
+isc_boolean_t
+dns_rdatatype_questiononly(dns_rdatatype_t type);
+/*%<
+ * Return true iff rdata of type 'type' can only appear in the question
+ * section of a properly formatted message.
+ *
+ * Requires:
+ * \li 'type' is a valid rdata type.
+ *
+ */
+
+isc_boolean_t
+dns_rdatatype_notquestion(dns_rdatatype_t type);
+/*%<
+ * Return true iff rdata of type 'type' can not appear in the question
+ * section of a properly formatted message.
+ *
+ * Requires:
+ * \li 'type' is a valid rdata type.
+ *
+ */
+
+isc_boolean_t
+dns_rdatatype_atparent(dns_rdatatype_t type);
+/*%<
+ * Return true iff rdata of type 'type' should appear at the parent of
+ * a zone cut.
+ *
+ * Requires:
+ * \li 'type' is a valid rdata type.
+ *
+ */
+
+unsigned int
+dns_rdatatype_attributes(dns_rdatatype_t rdtype);
+/*%<
+ * Return attributes for the given type.
+ *
+ * Requires:
+ *\li 'rdtype' are known.
+ *
+ * Returns:
+ *\li a bitmask consisting of the following flags.
+ */
+
+/*% only one may exist for a name */
+#define DNS_RDATATYPEATTR_SINGLETON 0x00000001U
+/*% requires no other data be present */
+#define DNS_RDATATYPEATTR_EXCLUSIVE 0x00000002U
+/*% Is a meta type */
+#define DNS_RDATATYPEATTR_META 0x00000004U
+/*% Is a DNSSEC type, like RRSIG or NSEC */
+#define DNS_RDATATYPEATTR_DNSSEC 0x00000008U
+/*% Is a zone cut authority type */
+#define DNS_RDATATYPEATTR_ZONECUTAUTH 0x00000010U
+/*% Is reserved (unusable) */
+#define DNS_RDATATYPEATTR_RESERVED 0x00000020U
+/*% Is an unknown type */
+#define DNS_RDATATYPEATTR_UNKNOWN 0x00000040U
+/*% Is META, and can only be in a question section */
+#define DNS_RDATATYPEATTR_QUESTIONONLY 0x00000080U
+/*% is META, and can NOT be in a question section */
+#define DNS_RDATATYPEATTR_NOTQUESTION 0x00000100U
+/*% Is present at zone cuts in the parent, not the child */
+#define DNS_RDATATYPEATTR_ATPARENT 0x00000200U
+
+dns_rdatatype_t
+dns_rdata_covers(dns_rdata_t *rdata);
+/*%<
+ * Return the rdatatype that this type covers.
+ *
+ * Requires:
+ *\li 'rdata' is a valid, non-empty rdata.
+ *
+ *\li 'rdata' is a type that covers other rdata types.
+ *
+ * Returns:
+ *\li The type covered.
+ */
+
+isc_boolean_t
+dns_rdata_checkowner(dns_name_t* name, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, isc_boolean_t wildcard);
+/*
+ * Returns whether this is a valid ownername for this <type,class>.
+ * If wildcard is true allow the first label to be a wildcard if
+ * appropriate.
+ *
+ * Requires:
+ * 'name' is a valid name.
+ */
+
+isc_boolean_t
+dns_rdata_checknames(dns_rdata_t *rdata, dns_name_t *owner, dns_name_t *bad);
+/*
+ * Returns whether 'rdata' contains valid domain names. The checks are
+ * sensitive to the owner name.
+ *
+ * If 'bad' is non-NULL and a domain name fails the check the
+ * the offending name will be return in 'bad' by cloning from
+ * the 'rdata' contents.
+ *
+ * Requires:
+ * 'rdata' to be valid.
+ * 'owner' to be valid.
+ * 'bad' to be NULL or valid.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RDATA_H */
diff --git a/lib/dns/include/dns/rdataclass.h b/lib/dns/include/dns/rdataclass.h
new file mode 100644
index 0000000..fc622bf
--- /dev/null
+++ b/lib/dns/include/dns/rdataclass.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: rdataclass.h,v 1.18.18.2 2005/04/29 00:16:18 marka Exp $ */
+
+#ifndef DNS_RDATACLASS_H
+#define DNS_RDATACLASS_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_rdataclass_fromtext(dns_rdataclass_t *classp, isc_textregion_t *source);
+/*%<
+ * Convert the text 'source' refers to into a DNS class.
+ *
+ * Requires:
+ *\li 'classp' is a valid pointer.
+ *
+ *\li 'source' is a valid text region.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS on success
+ *\li #DNS_R_UNKNOWN class is unknown
+ */
+
+isc_result_t
+dns_rdataclass_totext(dns_rdataclass_t rdclass, isc_buffer_t *target);
+/*%<
+ * Put a textual representation of class 'rdclass' into 'target'.
+ *
+ * Requires:
+ *\li 'rdclass' is a valid class.
+ *
+ *\li 'target' is a valid text buffer.
+ *
+ * Ensures,
+ * if the result is success:
+ *\li The used space in 'target' is updated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS on success
+ *\li #ISC_R_NOSPACE target buffer is too small
+ */
+
+void
+dns_rdataclass_format(dns_rdataclass_t rdclass,
+ char *array, unsigned int size);
+/*%<
+ * Format a human-readable representation of the class 'rdclass'
+ * into the character array 'array', which is of size 'size'.
+ * The resulting string is guaranteed to be null-terminated.
+ */
+
+#define DNS_RDATACLASS_FORMATSIZE sizeof("CLASS65535")
+/*%<
+ * Minimum size of array to pass to dns_rdataclass_format().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RDATACLASS_H */
diff --git a/lib/dns/include/dns/rdatalist.h b/lib/dns/include/dns/rdatalist.h
new file mode 100644
index 0000000..697386f
--- /dev/null
+++ b/lib/dns/include/dns/rdatalist.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2004, 2005 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: rdatalist.h,v 1.14.18.2 2005/04/29 00:16:19 marka Exp $ */
+
+#ifndef DNS_RDATALIST_H
+#define DNS_RDATALIST_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * A DNS rdatalist is a list of rdata of a common type and class.
+ *
+ * MP:
+ *\li Clients of this module must impose any required synchronization.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li None.
+ */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+/*%
+ * Clients may use this type directly.
+ */
+struct dns_rdatalist {
+ dns_rdataclass_t rdclass;
+ dns_rdatatype_t type;
+ dns_rdatatype_t covers;
+ dns_ttl_t ttl;
+ ISC_LIST(dns_rdata_t) rdata;
+ ISC_LINK(dns_rdatalist_t) link;
+};
+
+ISC_LANG_BEGINDECLS
+
+void
+dns_rdatalist_init(dns_rdatalist_t *rdatalist);
+/*%<
+ * Initialize rdatalist.
+ *
+ * Ensures:
+ *\li All fields of rdatalist have been initialized to their default
+ * values.
+ */
+
+isc_result_t
+dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist,
+ dns_rdataset_t *rdataset);
+/*%<
+ * Make 'rdataset' refer to the rdata in 'rdatalist'.
+ *
+ * Note:
+ *\li The caller must ensure that 'rdatalist' remains valid and unchanged
+ * while 'rdataset' is associated with it.
+ *
+ * Requires:
+ *
+ *\li 'rdatalist' is a valid rdatalist.
+ *
+ *\li 'rdataset' is a valid rdataset that is not currently associated with
+ * any rdata.
+ *
+ * Ensures,
+ * on success,
+ *
+ *\li 'rdataset' is associated with the rdata in rdatalist.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RDATALIST_H */
diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h
new file mode 100644
index 0000000..5597591
--- /dev/null
+++ b/lib/dns/include/dns/rdataset.h
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2004-2006 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: rdataset.h,v 1.51.18.7 2006/03/03 00:56:53 marka Exp $ */
+
+#ifndef DNS_RDATASET_H
+#define DNS_RDATASET_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * A DNS rdataset is a handle that can be associated with a collection of
+ * rdata all having a common owner name, class, and type.
+ *
+ * The dns_rdataset_t type is like a "virtual class". To actually use
+ * rdatasets, an implementation of the method suite (e.g. "slabbed rdata") is
+ * required.
+ *
+ * XXX &lt;more&gt; XXX
+ *
+ * MP:
+ *\li Clients of this module must impose any required synchronization.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li None.
+ */
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/stdtime.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef enum {
+ dns_rdatasetadditional_fromauth,
+ dns_rdatasetadditional_fromcache,
+ dns_rdatasetadditional_fromglue
+} dns_rdatasetadditional_t;
+
+typedef struct dns_rdatasetmethods {
+ void (*disassociate)(dns_rdataset_t *rdataset);
+ isc_result_t (*first)(dns_rdataset_t *rdataset);
+ isc_result_t (*next)(dns_rdataset_t *rdataset);
+ void (*current)(dns_rdataset_t *rdataset,
+ dns_rdata_t *rdata);
+ void (*clone)(dns_rdataset_t *source,
+ dns_rdataset_t *target);
+ unsigned int (*count)(dns_rdataset_t *rdataset);
+ isc_result_t (*addnoqname)(dns_rdataset_t *rdataset,
+ dns_name_t *name);
+ isc_result_t (*getnoqname)(dns_rdataset_t *rdataset,
+ dns_name_t *name,
+ dns_rdataset_t *nsec,
+ dns_rdataset_t *nsecsig);
+ isc_result_t (*getadditional)(dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype,
+ dns_acache_t *acache,
+ dns_zone_t **zonep,
+ dns_db_t **dbp,
+ dns_dbversion_t **versionp,
+ dns_dbnode_t **nodep,
+ dns_name_t *fname,
+ dns_message_t *msg,
+ isc_stdtime_t now);
+ isc_result_t (*setadditional)(dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype,
+ dns_acache_t *acache,
+ dns_zone_t *zone,
+ dns_db_t *db,
+ dns_dbversion_t *version,
+ dns_dbnode_t *node,
+ dns_name_t *fname);
+ isc_result_t (*putadditional)(dns_acache_t *acache,
+ dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype);
+} dns_rdatasetmethods_t;
+
+#define DNS_RDATASET_MAGIC ISC_MAGIC('D','N','S','R')
+#define DNS_RDATASET_VALID(set) ISC_MAGIC_VALID(set, DNS_RDATASET_MAGIC)
+
+/*%
+ * Direct use of this structure by clients is strongly discouraged, except
+ * for the 'link' field which may be used however the client wishes. The
+ * 'private', 'current', and 'index' fields MUST NOT be changed by clients.
+ * rdataset implementations may change any of the fields.
+ */
+struct dns_rdataset {
+ unsigned int magic; /* XXX ? */
+ dns_rdatasetmethods_t * methods;
+ ISC_LINK(dns_rdataset_t) link;
+ /*
+ * XXX do we need these, or should they be retrieved by methods?
+ * Leaning towards the latter, since they are not frequently required
+ * once you have the rdataset.
+ */
+ dns_rdataclass_t rdclass;
+ dns_rdatatype_t type;
+ dns_ttl_t ttl;
+ dns_trust_t trust;
+ dns_rdatatype_t covers;
+ /*
+ * attributes
+ */
+ unsigned int attributes;
+ /*%
+ * the counter provides the starting point in the "cyclic" order.
+ * The value ISC_UINT32_MAX has a special meaning of "picking up a
+ * random value." in order to take care of databases that do not
+ * increment the counter.
+ */
+ isc_uint32_t count;
+ /*@{*/
+ /*%
+ * These are for use by the rdataset implementation, and MUST NOT
+ * be changed by clients.
+ */
+ void * private1;
+ void * private2;
+ void * private3;
+ unsigned int privateuint4;
+ void * private5;
+ void * private6;
+ /*@}*/
+};
+
+/*!
+ * \def DNS_RDATASETATTR_RENDERED
+ * Used by message.c to indicate that the rdataset was rendered.
+ *
+ * \def DNS_RDATASETATTR_TTLADJUSTED
+ * Used by message.c to indicate that the rdataset's rdata had differing
+ * TTL values, and the rdataset->ttl holds the smallest.
+ *
+ * \def DNS_RDATASETATTR_LOADORDER
+ * Output the RRset in load order.
+ */
+
+#define DNS_RDATASETATTR_QUESTION 0x00000001
+#define DNS_RDATASETATTR_RENDERED 0x00000002 /*%< Used by message.c */
+#define DNS_RDATASETATTR_ANSWERED 0x00000004 /*%< Used by server. */
+#define DNS_RDATASETATTR_CACHE 0x00000008 /*%< Used by resolver. */
+#define DNS_RDATASETATTR_ANSWER 0x00000010 /*%< Used by resolver. */
+#define DNS_RDATASETATTR_ANSWERSIG 0x00000020 /*%< Used by resolver. */
+#define DNS_RDATASETATTR_EXTERNAL 0x00000040 /*%< Used by resolver. */
+#define DNS_RDATASETATTR_NCACHE 0x00000080 /*%< Used by resolver. */
+#define DNS_RDATASETATTR_CHAINING 0x00000100 /*%< Used by resolver. */
+#define DNS_RDATASETATTR_TTLADJUSTED 0x00000200 /*%< Used by message.c */
+#define DNS_RDATASETATTR_FIXEDORDER 0x00000400
+#define DNS_RDATASETATTR_RANDOMIZE 0x00000800
+#define DNS_RDATASETATTR_CHASE 0x00001000 /*%< Used by resolver. */
+#define DNS_RDATASETATTR_NXDOMAIN 0x00002000
+#define DNS_RDATASETATTR_NOQNAME 0x00004000
+#define DNS_RDATASETATTR_CHECKNAMES 0x00008000 /*%< Used by resolver. */
+#define DNS_RDATASETATTR_REQUIREDGLUE 0x00010000
+#define DNS_RDATASETATTR_LOADORDER 0x00020000
+
+/*%
+ * _OMITDNSSEC:
+ * Omit DNSSEC records when rendering ncache records.
+ */
+#define DNS_RDATASETTOWIRE_OMITDNSSEC 0x0001
+
+void
+dns_rdataset_init(dns_rdataset_t *rdataset);
+/*%<
+ * Make 'rdataset' a valid, disassociated rdataset.
+ *
+ * Requires:
+ *\li 'rdataset' is not NULL.
+ *
+ * Ensures:
+ *\li 'rdataset' is a valid, disassociated rdataset.
+ */
+
+void
+dns_rdataset_invalidate(dns_rdataset_t *rdataset);
+/*%<
+ * Invalidate 'rdataset'.
+ *
+ * Requires:
+ *\li 'rdataset' is a valid, disassociated rdataset.
+ *
+ * Ensures:
+ *\li If assertion checking is enabled, future attempts to use 'rdataset'
+ * without initializing it will cause an assertion failure.
+ */
+
+void
+dns_rdataset_disassociate(dns_rdataset_t *rdataset);
+/*%<
+ * Disassociate 'rdataset' from its rdata, allowing it to be reused.
+ *
+ * Notes:
+ *\li The client must ensure it has no references to rdata in the rdataset
+ * before disassociating.
+ *
+ * Requires:
+ *\li 'rdataset' is a valid, associated rdataset.
+ *
+ * Ensures:
+ *\li 'rdataset' is a valid, disassociated rdataset.
+ */
+
+isc_boolean_t
+dns_rdataset_isassociated(dns_rdataset_t *rdataset);
+/*%<
+ * Is 'rdataset' associated?
+ *
+ * Requires:
+ *\li 'rdataset' is a valid rdataset.
+ *
+ * Returns:
+ *\li #ISC_TRUE 'rdataset' is associated.
+ *\li #ISC_FALSE 'rdataset' is not associated.
+ */
+
+void
+dns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type);
+/*%<
+ * Make 'rdataset' a valid, associated, question rdataset, with a
+ * question class of 'rdclass' and type 'type'.
+ *
+ * Notes:
+ *\li Question rdatasets have a class and type, but no rdata.
+ *
+ * Requires:
+ *\li 'rdataset' is a valid, disassociated rdataset.
+ *
+ * Ensures:
+ *\li 'rdataset' is a valid, associated, question rdataset.
+ */
+
+void
+dns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
+/*%<
+ * Make 'target' refer to the same rdataset as 'source'.
+ *
+ * Requires:
+ *\li 'source' is a valid, associated rdataset.
+ *
+ *\li 'target' is a valid, dissociated rdataset.
+ *
+ * Ensures:
+ *\li 'target' references the same rdataset as 'source'.
+ */
+
+unsigned int
+dns_rdataset_count(dns_rdataset_t *rdataset);
+/*%<
+ * Return the number of records in 'rdataset'.
+ *
+ * Requires:
+ *\li 'rdataset' is a valid, associated rdataset.
+ *
+ * Returns:
+ *\li The number of records in 'rdataset'.
+ */
+
+isc_result_t
+dns_rdataset_first(dns_rdataset_t *rdataset);
+/*%<
+ * Move the rdata cursor to the first rdata in the rdataset (if any).
+ *
+ * Requires:
+ *\li 'rdataset' is a valid, associated rdataset.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMORE There are no rdata in the set.
+ */
+
+isc_result_t
+dns_rdataset_next(dns_rdataset_t *rdataset);
+/*%<
+ * Move the rdata cursor to the next rdata in the rdataset (if any).
+ *
+ * Requires:
+ *\li 'rdataset' is a valid, associated rdataset.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMORE There are no more rdata in the set.
+ */
+
+void
+dns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
+/*%<
+ * Make 'rdata' refer to the current rdata.
+ *
+ * Notes:
+ *
+ *\li The data returned in 'rdata' is valid for the life of the
+ * rdataset; in particular, subsequent changes in the cursor position
+ * do not invalidate 'rdata'.
+ *
+ * Requires:
+ *\li 'rdataset' is a valid, associated rdataset.
+ *
+ *\li The rdata cursor of 'rdataset' is at a valid location (i.e. the
+ * result of last call to a cursor movement command was ISC_R_SUCCESS).
+ *
+ * Ensures:
+ *\li 'rdata' refers to the rdata at the rdata cursor location of
+ *\li 'rdataset'.
+ */
+
+isc_result_t
+dns_rdataset_totext(dns_rdataset_t *rdataset,
+ dns_name_t *owner_name,
+ isc_boolean_t omit_final_dot,
+ isc_boolean_t question,
+ isc_buffer_t *target);
+/*%<
+ * Convert 'rdataset' to text format, storing the result in 'target'.
+ *
+ * Notes:
+ *\li The rdata cursor position will be changed.
+ *
+ *\li The 'question' flag should normally be #ISC_FALSE. If it is
+ * #ISC_TRUE, the TTL and rdata fields are not printed. This is
+ * for use when printing an rdata representing a question section.
+ *
+ *\li This interface is deprecated; use dns_master_rdatasettottext()
+ * and/or dns_master_questiontotext() instead.
+ *
+ * Requires:
+ *\li 'rdataset' is a valid rdataset.
+ *
+ *\li 'rdataset' is not empty.
+ */
+
+isc_result_t
+dns_rdataset_towire(dns_rdataset_t *rdataset,
+ dns_name_t *owner_name,
+ dns_compress_t *cctx,
+ isc_buffer_t *target,
+ unsigned int options,
+ unsigned int *countp);
+/*%<
+ * Convert 'rdataset' to wire format, compressing names as specified
+ * in 'cctx', and storing the result in 'target'.
+ *
+ * Notes:
+ *\li The rdata cursor position will be changed.
+ *
+ *\li The number of RRs added to target will be added to *countp.
+ *
+ * Requires:
+ *\li 'rdataset' is a valid rdataset.
+ *
+ *\li 'rdataset' is not empty.
+ *
+ *\li 'countp' is a valid pointer.
+ *
+ * Ensures:
+ *\li On a return of ISC_R_SUCCESS, 'target' contains a wire format
+ * for the data contained in 'rdataset'. Any error return leaves
+ * the buffer unchanged.
+ *
+ *\li *countp has been incremented by the number of RRs added to
+ * target.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS - all ok
+ *\li #ISC_R_NOSPACE - 'target' doesn't have enough room
+ *
+ *\li Any error returned by dns_rdata_towire(), dns_rdataset_next(),
+ * dns_name_towire().
+ */
+
+isc_result_t
+dns_rdataset_towiresorted(dns_rdataset_t *rdataset,
+ const dns_name_t *owner_name,
+ dns_compress_t *cctx,
+ isc_buffer_t *target,
+ dns_rdatasetorderfunc_t order,
+ const void *order_arg,
+ unsigned int options,
+ unsigned int *countp);
+/*%<
+ * Like dns_rdataset_towire(), but sorting the rdatasets according to
+ * the integer value returned by 'order' when called witih the rdataset
+ * and 'order_arg' as arguments.
+ *
+ * Requires:
+ *\li All the requirements of dns_rdataset_towire(), and
+ * that order_arg is NULL if and only if order is NULL.
+ */
+
+isc_result_t
+dns_rdataset_towirepartial(dns_rdataset_t *rdataset,
+ const dns_name_t *owner_name,
+ dns_compress_t *cctx,
+ isc_buffer_t *target,
+ dns_rdatasetorderfunc_t order,
+ const void *order_arg,
+ unsigned int options,
+ unsigned int *countp,
+ void **state);
+/*%<
+ * Like dns_rdataset_towiresorted() except that a partial rdataset
+ * may be written.
+ *
+ * Requires:
+ *\li All the requirements of dns_rdataset_towiresorted().
+ * If 'state' is non NULL then the current position in the
+ * rdataset will be remembered if the rdataset in not
+ * completely written and should be passed on on subsequent
+ * calls (NOT CURRENTLY IMPLEMENTED).
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS if all of the records were written.
+ *\li #ISC_R_NOSPACE if unable to fit in all of the records. *countp
+ * will be updated to reflect the number of records
+ * written.
+ */
+
+isc_result_t
+dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
+ dns_additionaldatafunc_t add, void *arg);
+/*%<
+ * For each rdata in rdataset, call 'add' for each name and type in the
+ * rdata which is subject to additional section processing.
+ *
+ * Requires:
+ *
+ *\li 'rdataset' is a valid, non-question rdataset.
+ *
+ *\li 'add' is a valid dns_additionaldatafunc_t
+ *
+ * Ensures:
+ *
+ *\li If successful, dns_rdata_additionaldata() will have been called for
+ * each rdata in 'rdataset'.
+ *
+ *\li If a call to dns_rdata_additionaldata() is not successful, the
+ * result returned will be the result of dns_rdataset_additionaldata().
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *
+ *\li Any error that dns_rdata_additionaldata() can return.
+ */
+
+isc_result_t
+dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
+ dns_rdataset_t *nsec, dns_rdataset_t *nsecsig);
+/*%<
+ * Return the noqname proof for this record.
+ *
+ * Requires:
+ *\li 'rdataset' to be valid and #DNS_RDATASETATTR_NOQNAME to be set.
+ *\li 'name' to be valid.
+ *\li 'nsec' and 'nsecsig' to be valid and not associated.
+ */
+
+isc_result_t
+dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name);
+/*%<
+ * Associate a noqname proof with this record.
+ * Sets #DNS_RDATASETATTR_NOQNAME if successful.
+ * Adjusts the 'rdataset->ttl' to minimum of the 'rdataset->ttl' and
+ * the 'nsec' and 'rrsig(nsec)' ttl.
+ *
+ * Requires:
+ *\li 'rdataset' to be valid and #DNS_RDATASETATTR_NOQNAME to be set.
+ *\li 'name' to be valid and have NSEC and RRSIG(NSEC) rdatasets.
+ */
+
+isc_result_t
+dns_rdataset_getadditional(dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype,
+ dns_acache_t *acache,
+ dns_zone_t **zonep,
+ dns_db_t **dbp,
+ dns_dbversion_t **versionp,
+ dns_dbnode_t **nodep,
+ dns_name_t *fname,
+ dns_message_t *msg,
+ isc_stdtime_t now);
+/*%<
+ * Get cached additional information from the DB node for a particular
+ * 'rdataset.' 'type' is one of dns_rdatasetadditional_fromauth,
+ * dns_rdatasetadditional_fromcache, and dns_rdatasetadditional_fromglue,
+ * which specifies the origin of the information. 'qtype' is intended to
+ * be used for specifying a particular rdata type in the cached information.
+ *
+ * Requires:
+ * \li 'rdataset' is a valid rdataset.
+ * \li 'acache' can be NULL, in which case this function will simply return
+ * ISC_R_FAILURE.
+ * \li For the other pointers, see dns_acache_getentry().
+ *
+ * Ensures:
+ * \li See dns_acache_getentry().
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_FAILURE - additional information caching is not supported.
+ * \li #ISC_R_NOTFOUND - the corresponding DB node has not cached additional
+ * information for 'rdataset.'
+ * \li Any error that dns_acache_getentry() can return.
+ */
+
+isc_result_t
+dns_rdataset_setadditional(dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype,
+ dns_acache_t *acache,
+ dns_zone_t *zone,
+ dns_db_t *db,
+ dns_dbversion_t *version,
+ dns_dbnode_t *node,
+ dns_name_t *fname);
+/*%<
+ * Set cached additional information to the DB node for a particular
+ * 'rdataset.' See dns_rdataset_getadditional for the semantics of 'type'
+ * and 'qtype'.
+ *
+ * Requires:
+ * \li 'rdataset' is a valid rdataset.
+ * \li 'acache' can be NULL, in which case this function will simply return
+ * ISC_R_FAILURE.
+ * \li For the other pointers, see dns_acache_setentry().
+ *
+ * Ensures:
+ * \li See dns_acache_setentry().
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_FAILURE - additional information caching is not supported.
+ * \li #ISC_R_NOMEMORY
+ * \li Any error that dns_acache_setentry() can return.
+ */
+
+isc_result_t
+dns_rdataset_putadditional(dns_acache_t *acache,
+ dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype);
+/*%<
+ * Discard cached additional information stored in the DB node for a particular
+ * 'rdataset.' See dns_rdataset_getadditional for the semantics of 'type'
+ * and 'qtype'.
+ *
+ * Requires:
+ * \li 'rdataset' is a valid rdataset.
+ * \li 'acache' can be NULL, in which case this function will simply return
+ * ISC_R_FAILURE.
+ *
+ * Ensures:
+ * \li See dns_acache_cancelentry().
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_FAILURE - additional information caching is not supported.
+ * \li #ISC_R_NOTFOUND - the corresponding DB node has not cached additional
+ * information for 'rdataset.'
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RDATASET_H */
diff --git a/lib/dns/include/dns/rdatasetiter.h b/lib/dns/include/dns/rdatasetiter.h
new file mode 100644
index 0000000..b2e13f8
--- /dev/null
+++ b/lib/dns/include/dns/rdatasetiter.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2004, 2005 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: rdatasetiter.h,v 1.15.18.2 2005/04/29 00:16:19 marka Exp $ */
+
+#ifndef DNS_RDATASETITER_H
+#define DNS_RDATASETITER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * The DNS Rdataset Iterator interface allows iteration of all of the
+ * rdatasets at a node.
+ *
+ * The dns_rdatasetiter_t type is like a "virtual class". To actually use
+ * it, an implementation of the class is required. This implementation is
+ * supplied by the database.
+ *
+ * It is the client's responsibility to call dns_rdataset_disassociate()
+ * on all rdatasets returned.
+ *
+ * XXX more XXX
+ *
+ * MP:
+ *\li The iterator itself is not locked. The caller must ensure
+ * synchronization.
+ *
+ *\li The iterator methods ensure appropriate database locking.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li None.
+ */
+
+/*****
+ ***** Imports
+ *****/
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/stdtime.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Types
+ *****/
+
+typedef struct dns_rdatasetitermethods {
+ void (*destroy)(dns_rdatasetiter_t **iteratorp);
+ isc_result_t (*first)(dns_rdatasetiter_t *iterator);
+ isc_result_t (*next)(dns_rdatasetiter_t *iterator);
+ void (*current)(dns_rdatasetiter_t *iterator,
+ dns_rdataset_t *rdataset);
+} dns_rdatasetitermethods_t;
+
+#define DNS_RDATASETITER_MAGIC ISC_MAGIC('D','N','S','i')
+#define DNS_RDATASETITER_VALID(i) ISC_MAGIC_VALID(i, DNS_RDATASETITER_MAGIC)
+
+/*%
+ * This structure is actually just the common prefix of a DNS db
+ * implementation's version of a dns_rdatasetiter_t.
+ * \brief
+ * Direct use of this structure by clients is forbidden. DB implementations
+ * may change the structure. 'magic' must be #DNS_RDATASETITER_MAGIC for
+ * any of the dns_rdatasetiter routines to work. DB implementations must
+ * maintain all DB rdataset iterator invariants.
+ */
+struct dns_rdatasetiter {
+ /* Unlocked. */
+ unsigned int magic;
+ dns_rdatasetitermethods_t * methods;
+ dns_db_t * db;
+ dns_dbnode_t * node;
+ dns_dbversion_t * version;
+ isc_stdtime_t now;
+};
+
+void
+dns_rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
+/*%<
+ * Destroy '*iteratorp'.
+ *
+ * Requires:
+ *
+ *\li '*iteratorp' is a valid iterator.
+ *
+ * Ensures:
+ *
+ *\li All resources used by the iterator are freed.
+ *
+ *\li *iteratorp == NULL.
+ */
+
+isc_result_t
+dns_rdatasetiter_first(dns_rdatasetiter_t *iterator);
+/*%<
+ * Move the rdataset cursor to the first rdataset at the node (if any).
+ *
+ * Requires:
+ *\li 'iterator' is a valid iterator.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOMORE There are no rdatasets at the node.
+ *
+ *\li Other results are possible, depending on the DB implementation.
+ */
+
+isc_result_t
+dns_rdatasetiter_next(dns_rdatasetiter_t *iterator);
+/*%<
+ * Move the rdataset cursor to the next rdataset at the node (if any).
+ *
+ * Requires:
+ *\li 'iterator' is a valid iterator.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOMORE There are no more rdatasets at the
+ * node.
+ *
+ *\li Other results are possible, depending on the DB implementation.
+ */
+
+void
+dns_rdatasetiter_current(dns_rdatasetiter_t *iterator,
+ dns_rdataset_t *rdataset);
+/*%<
+ * Return the current rdataset.
+ *
+ * Requires:
+ *\li 'iterator' is a valid iterator.
+ *
+ *\li 'rdataset' is a valid, disassociated rdataset.
+ *
+ *\li The rdataset cursor of 'iterator' is at a valid location (i.e. the
+ * result of last call to a cursor movement command was #ISC_R_SUCCESS).
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RDATASETITER_H */
diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h
new file mode 100644
index 0000000..b693a71
--- /dev/null
+++ b/lib/dns/include/dns/rdataslab.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2004, 2005 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: rdataslab.h,v 1.25.18.2 2005/04/29 00:16:19 marka Exp $ */
+
+#ifndef DNS_RDATASLAB_H
+#define DNS_RDATASLAB_H 1
+
+/*! \file
+ * \brief
+ * Implements storage of rdatasets into slabs of memory.
+ *
+ * MP:
+ *\li Clients of this module must impose any required synchronization.
+ *
+ * Reliability:
+ *\li This module deals with low-level byte streams. Errors in any of
+ * the functions are likely to crash the server or corrupt memory.
+ *
+ *\li If the caller passes invalid memory references, these functions are
+ * likely to crash the server or corrupt memory.
+ *
+ * Resources:
+ *\li None.
+ *
+ * Security:
+ *\li None.
+ *
+ * Standards:
+ *\li None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+#define DNS_RDATASLAB_FORCE 0x1
+#define DNS_RDATASLAB_EXACT 0x2
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
+ isc_region_t *region, unsigned int reservelen);
+/*%<
+ * Slabify a rdataset. The slab area will be allocated and returned
+ * in 'region'.
+ *
+ * Requires:
+ *\li 'rdataset' is valid.
+ *
+ * Ensures:
+ *\li 'region' will have base pointing to the start of allocated memory,
+ * with the slabified region beginning at region->base + reservelen.
+ * region->length contains the total length allocated.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS - successful completion
+ *\li ISC_R_NOMEMORY - no memory.
+ *\li XXX others
+ */
+
+void
+dns_rdataslab_tordataset(unsigned char *slab, unsigned int reservelen,
+ dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
+ dns_rdatatype_t covers, dns_ttl_t ttl,
+ dns_rdataset_t *rdataset);
+/*%<
+ * Construct an rdataset from a slab.
+ *
+ * Requires:
+ *\li 'slab' points to a slab.
+ *\li 'rdataset' is disassociated.
+ *
+ * Ensures:
+ *\li 'rdataset' is associated and points to a valid rdataest.
+ */
+unsigned int
+dns_rdataslab_size(unsigned char *slab, unsigned int reservelen);
+/*%<
+ * Return the total size of an rdataslab.
+ *
+ * Requires:
+ *\li 'slab' points to a slab.
+ *
+ * Returns:
+ *\li The number of bytes in the slab, including the reservelen.
+ */
+
+isc_result_t
+dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
+ unsigned int reservelen, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_rdatatype_t type,
+ unsigned int flags, unsigned char **tslabp);
+/*%<
+ * Merge 'oslab' and 'nslab'.
+ */
+
+isc_result_t
+dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab,
+ unsigned int reservelen, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_rdatatype_t type,
+ unsigned int flags, unsigned char **tslabp);
+/*%<
+ * Subtract 'sslab' from 'mslab'. If 'exact' is true then all elements
+ * of 'sslab' must exist in 'mslab'.
+ *
+ * XXX
+ * valid flags are DNS_RDATASLAB_EXACT
+ */
+
+isc_boolean_t
+dns_rdataslab_equal(unsigned char *slab1, unsigned char *slab2,
+ unsigned int reservelen);
+/*%<
+ * Compare two rdataslabs for equality. This does _not_ do a full
+ * DNSSEC comparison.
+ *
+ * Requires:
+ *\li 'slab1' and 'slab2' point to slabs.
+ *
+ * Returns:
+ *\li ISC_TRUE if the slabs are equal, ISC_FALSE otherwise.
+ */
+isc_boolean_t
+dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2,
+ unsigned int reservelen, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type);
+/*%<
+ * Compare two rdataslabs for DNSSEC equality.
+ *
+ * Requires:
+ *\li 'slab1' and 'slab2' point to slabs.
+ *
+ * Returns:
+ *\li ISC_TRUE if the slabs are equal, #ISC_FALSE otherwise.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RDATASLAB_H */
diff --git a/lib/dns/include/dns/rdatatype.h b/lib/dns/include/dns/rdatatype.h
new file mode 100644
index 0000000..40a884d
--- /dev/null
+++ b/lib/dns/include/dns/rdatatype.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: rdatatype.h,v 1.18.18.2 2005/04/29 00:16:20 marka Exp $ */
+
+#ifndef DNS_RDATATYPE_H
+#define DNS_RDATATYPE_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source);
+/*%<
+ * Convert the text 'source' refers to into a DNS rdata type.
+ *
+ * Requires:
+ *\li 'typep' is a valid pointer.
+ *
+ *\li 'source' is a valid text region.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS on success
+ *\li DNS_R_UNKNOWN type is unknown
+ */
+
+isc_result_t
+dns_rdatatype_totext(dns_rdatatype_t type, isc_buffer_t *target);
+/*%<
+ * Put a textual representation of type 'type' into 'target'.
+ *
+ * Requires:
+ *\li 'type' is a valid type.
+ *
+ *\li 'target' is a valid text buffer.
+ *
+ * Ensures,
+ * if the result is success:
+ *\li The used space in 'target' is updated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS on success
+ *\li #ISC_R_NOSPACE target buffer is too small
+ */
+
+void
+dns_rdatatype_format(dns_rdatatype_t rdtype,
+ char *array, unsigned int size);
+/*%<
+ * Format a human-readable representation of the type 'rdtype'
+ * into the character array 'array', which is of size 'size'.
+ * The resulting string is guaranteed to be null-terminated.
+ */
+
+#define DNS_RDATATYPE_FORMATSIZE sizeof("TYPE65535")
+/*%<
+ * Minimum size of array to pass to dns_rdatatype_format().
+ * May need to be adjusted if a new RR type with a very long
+ * name is defined.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RDATATYPE_H */
diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h
new file mode 100644
index 0000000..b858a9e
--- /dev/null
+++ b/lib/dns/include/dns/request.h
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2004, 2005 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: request.h,v 1.21.18.2 2005/04/29 00:16:20 marka Exp $ */
+
+#ifndef DNS_REQUEST_H
+#define DNS_REQUEST_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ *
+ * \brief
+ * The request module provides simple request/response services useful for
+ * sending SOA queries, DNS Notify messages, and dynamic update requests.
+ *
+ * MP:
+ *\li The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ */
+
+#include <isc/lang.h>
+#include <isc/event.h>
+
+#include <dns/types.h>
+
+#define DNS_REQUESTOPT_TCP 0x00000001U
+
+typedef struct dns_requestevent {
+ ISC_EVENT_COMMON(struct dns_requestevent);
+ isc_result_t result;
+ dns_request_t *request;
+} dns_requestevent_t;
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
+ isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
+ dns_dispatchmgr_t *dispatchmgr,
+ dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
+ dns_requestmgr_t **requestmgrp);
+/*%<
+ * Create a request manager.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li 'timermgr' is a valid timer manager.
+ *
+ *\li 'socketmgr' is a valid socket manager.
+ *
+ *\li 'taskmgr' is a valid task manager.
+ *
+ *\li 'dispatchv4' is a valid dispatcher with an IPv4 UDP socket, or is NULL.
+ *
+ *\li 'dispatchv6' is a valid dispatcher with an IPv6 UDP socket, or is NULL.
+ *
+ *\li requestmgrp != NULL && *requestmgrp == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, *requestmgrp is a valid request manager.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *
+ *\li Any other result indicates failure.
+ */
+
+void
+dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task,
+ isc_event_t **eventp);
+/*%<
+ * Send '*eventp' to 'task' when 'requestmgr' has completed shutdown.
+ *
+ * Notes:
+ *
+ *\li It is not safe to detach the last reference to 'requestmgr' until
+ * shutdown is complete.
+ *
+ * Requires:
+ *
+ *\li 'requestmgr' is a valid request manager.
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li *eventp is a valid event.
+ *
+ * Ensures:
+ *
+ *\li *eventp == NULL.
+ */
+
+void
+dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr);
+/*%<
+ * Start the shutdown process for 'requestmgr'.
+ *
+ * Notes:
+ *
+ *\li This call has no effect if the request manager is already shutting
+ * down.
+ *
+ * Requires:
+ *
+ *\li 'requestmgr' is a valid requestmgr.
+ */
+
+void
+dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp);
+/*%<
+ * Attach to the request manager. dns_requestmgr_shutdown() must not
+ * have been called on 'source' prior to calling dns_requestmgr_attach().
+ *
+ * Requires:
+ *
+ *\li 'source' is a valid requestmgr.
+ *
+ *\li 'targetp' to be non NULL and '*targetp' to be NULL.
+ */
+
+void
+dns_requestmgr_detach(dns_requestmgr_t **requestmgrp);
+/*%<
+ * Detach from the given requestmgr. If this is the final detach
+ * requestmgr will be destroyed. dns_requestmgr_shutdown() must
+ * be called before the final detach.
+ *
+ * Requires:
+ *
+ *\li '*requestmgrp' is a valid requestmgr.
+ *
+ * Ensures:
+ *\li '*requestmgrp' is NULL.
+ */
+
+isc_result_t
+dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
+ isc_sockaddr_t *address, unsigned int options,
+ dns_tsigkey_t *key,
+ unsigned int timeout, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_request_t **requestp);
+/*%<
+ * Create and send a request.
+ *
+ * Notes:
+ *
+ *\li 'message' will be rendered and sent to 'address'. If the
+ * #DNS_REQUESTOPT_TCP option is set, TCP will be used. The request
+ * will timeout after 'timeout' seconds.
+ *
+ *\li When the request completes, successfully, due to a timeout, or
+ * because it was canceled, a completion event will be sent to 'task'.
+ *
+ * Requires:
+ *
+ *\li 'message' is a valid DNS message.
+ *
+ *\li 'address' is a valid sockaddr.
+ *
+ *\li 'timeout' > 0
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li requestp != NULL && *requestp == NULL
+ */
+
+/*% See dns_request_createvia3() */
+isc_result_t
+dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, dns_tsigkey_t *key,
+ unsigned int timeout, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_request_t **requestp);
+
+/*% See dns_request_createvia3() */
+isc_result_t
+dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, dns_tsigkey_t *key,
+ unsigned int timeout, unsigned int udptimeout,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_request_t **requestp);
+
+isc_result_t
+dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, dns_tsigkey_t *key,
+ unsigned int timeout, unsigned int udptimeout,
+ unsigned int udpretries, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_request_t **requestp);
+/*%<
+ * Create and send a request.
+ *
+ * Notes:
+ *
+ *\li 'message' will be rendered and sent to 'address'. If the
+ * #DNS_REQUESTOPT_TCP option is set, TCP will be used. The request
+ * will timeout after 'timeout' seconds. UDP requests will be resent
+ * at 'udptimeout' intervals if non-zero or 'udpretries' is non-zero.
+ *
+ *\li When the request completes, successfully, due to a timeout, or
+ * because it was canceled, a completion event will be sent to 'task'.
+ *
+ * Requires:
+ *
+ *\li 'message' is a valid DNS message.
+ *
+ *\li 'dstaddr' is a valid sockaddr.
+ *
+ *\li 'srcaddr' is a valid sockaddr or NULL.
+ *
+ *\li 'srcaddr' and 'dstaddr' are the same protocol family.
+ *
+ *\li 'timeout' > 0
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li requestp != NULL && *requestp == NULL
+ */
+
+/*% See dns_request_createraw3() */
+isc_result_t
+dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, unsigned int timeout,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_request_t **requestp);
+
+/*% See dns_request_createraw3() */
+isc_result_t
+dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, unsigned int timeout,
+ unsigned int udptimeout, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_request_t **requestp);
+
+isc_result_t
+dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, unsigned int timeout,
+ unsigned int udptimeout, unsigned int udpretries,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_request_t **requestp);
+/*!<
+ * \brief Create and send a request.
+ *
+ * Notes:
+ *
+ *\li 'msgbuf' will be sent to 'destaddr' after setting the id. If the
+ * #DNS_REQUESTOPT_TCP option is set, TCP will be used. The request
+ * will timeout after 'timeout' seconds. UDP requests will be resent
+ * at 'udptimeout' intervals if non-zero or if 'udpretries' is not zero.
+ *
+ *\li When the request completes, successfully, due to a timeout, or
+ * because it was canceled, a completion event will be sent to 'task'.
+ *
+ * Requires:
+ *
+ *\li 'msgbuf' is a valid DNS message in compressed wire format.
+ *
+ *\li 'destaddr' is a valid sockaddr.
+ *
+ *\li 'srcaddr' is a valid sockaddr or NULL.
+ *
+ *\li 'srcaddr' and 'dstaddr' are the same protocol family.
+ *
+ *\li 'timeout' > 0
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li requestp != NULL && *requestp == NULL
+ */
+
+void
+dns_request_cancel(dns_request_t *request);
+/*%<
+ * Cancel 'request'.
+ *
+ * Requires:
+ *
+ *\li 'request' is a valid request.
+ *
+ * Ensures:
+ *
+ *\li If the completion event for 'request' has not yet been sent, it
+ * will be sent, and the result code will be ISC_R_CANCELED.
+ */
+
+isc_result_t
+dns_request_getresponse(dns_request_t *request, dns_message_t *message,
+ unsigned int options);
+/*%<
+ * Get the response to 'request' by filling in 'message'.
+ *
+ * 'options' is passed to dns_message_parse(). See dns_message_parse()
+ * for more details.
+ *
+ * Requires:
+ *
+ *\li 'request' is a valid request for which the caller has received the
+ * completion event.
+ *
+ *\li The result code of the completion event was #ISC_R_SUCCESS.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *
+ *\li Any result that dns_message_parse() can return.
+ */
+
+isc_boolean_t
+dns_request_usedtcp(dns_request_t *request);
+/*%<
+ * Return whether this query used TCP or not. Setting #DNS_REQUESTOPT_TCP
+ * in the call to dns_request_create() will cause the function to return
+ * #ISC_TRUE, othewise the result is based on the query message size.
+ *
+ * Requires:
+ *\li 'request' is a valid request.
+ *
+ * Returns:
+ *\li ISC_TRUE if TCP was used.
+ *\li ISC_FALSE if UDP was used.
+ */
+
+void
+dns_request_destroy(dns_request_t **requestp);
+/*%<
+ * Destroy 'request'.
+ *
+ * Requires:
+ *
+ *\li 'request' is a valid request for which the caller has received the
+ * completion event.
+ *
+ * Ensures:
+ *
+ *\li *requestp == NULL
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_REQUEST_H */
diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h
new file mode 100644
index 0000000..4e0e6a0
--- /dev/null
+++ b/lib/dns/include/dns/resolver.h
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2004-2006 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: resolver.h,v 1.40.18.11 2006/02/01 22:39:17 marka Exp $ */
+
+#ifndef DNS_RESOLVER_H
+#define DNS_RESOLVER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ *
+ * \brief
+ * This is the BIND 9 resolver, the module responsible for resolving DNS
+ * requests by iteratively querying authoritative servers and following
+ * referrals. This is a "full resolver", not to be confused with
+ * the stub resolvers most people associate with the word "resolver".
+ * The full resolver is part of the caching name server or resolver
+ * daemon the stub resolver talks to.
+ *
+ * MP:
+ *\li The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li RFCs: 1034, 1035, 2181, TBS
+ *\li Drafts: TBS
+ */
+
+#include <isc/lang.h>
+#include <isc/socket.h>
+
+#include <dns/types.h>
+#include <dns/fixedname.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * A dns_fetchevent_t is sent when a 'fetch' completes. Any of 'db',
+ * 'node', 'rdataset', and 'sigrdataset' may be bound. It is the
+ * receiver's responsibility to detach before freeing the event.
+ * \brief
+ * 'rdataset', 'sigrdataset', 'client' and 'id' are the values that were
+ * supplied when dns_resolver_createfetch() was called. They are returned
+ * to the caller so that they may be freed.
+ */
+typedef struct dns_fetchevent {
+ ISC_EVENT_COMMON(struct dns_fetchevent);
+ dns_fetch_t * fetch;
+ isc_result_t result;
+ dns_rdatatype_t qtype;
+ dns_db_t * db;
+ dns_dbnode_t * node;
+ dns_rdataset_t * rdataset;
+ dns_rdataset_t * sigrdataset;
+ dns_fixedname_t foundname;
+ isc_sockaddr_t * client;
+ dns_messageid_t id;
+} dns_fetchevent_t;
+
+/*
+ * Options that modify how a 'fetch' is done.
+ */
+#define DNS_FETCHOPT_TCP 0x01 /*%< Use TCP. */
+#define DNS_FETCHOPT_UNSHARED 0x02 /*%< See below. */
+#define DNS_FETCHOPT_RECURSIVE 0x04 /*%< Set RD? */
+#define DNS_FETCHOPT_NOEDNS0 0x08 /*%< Do not use EDNS. */
+#define DNS_FETCHOPT_FORWARDONLY 0x10 /*%< Only use forwarders. */
+#define DNS_FETCHOPT_NOVALIDATE 0x20 /*%< Disable validation. */
+#define DNS_FETCHOPT_EDNS512 0x40 /*%< Advertise a 512 byte
+ UDP buffer. */
+
+#define DNS_FETCHOPT_EDNSVERSIONSET 0x00800000
+#define DNS_FETCHOPT_EDNSVERSIONMASK 0xff000000
+#define DNS_FETCHOPT_EDNSVERSIONSHIFT 24
+
+/*
+ * XXXRTH Should this API be made semi-private? (I.e.
+ * _dns_resolver_create()).
+ */
+
+#define DNS_RESOLVER_CHECKNAMES 0x01
+#define DNS_RESOLVER_CHECKNAMESFAIL 0x02
+
+isc_result_t
+dns_resolver_create(dns_view_t *view,
+ isc_taskmgr_t *taskmgr, unsigned int ntasks,
+ isc_socketmgr_t *socketmgr,
+ isc_timermgr_t *timermgr,
+ unsigned int options,
+ dns_dispatchmgr_t *dispatchmgr,
+ dns_dispatch_t *dispatchv4,
+ dns_dispatch_t *dispatchv6,
+ dns_resolver_t **resp);
+
+/*%<
+ * Create a resolver.
+ *
+ * Notes:
+ *
+ *\li Generally, applications should not create a resolver directly, but
+ * should instead call dns_view_createresolver().
+ *
+ *\li No options are currently defined.
+ *
+ * Requires:
+ *
+ *\li 'view' is a valid view.
+ *
+ *\li 'taskmgr' is a valid task manager.
+ *
+ *\li 'ntasks' > 0.
+ *
+ *\li 'socketmgr' is a valid socket manager.
+ *
+ *\li 'timermgr' is a valid timer manager.
+ *
+ *\li 'dispatchv4' is a valid dispatcher with an IPv4 UDP socket, or is NULL.
+ *
+ *\li 'dispatchv6' is a valid dispatcher with an IPv6 UDP socket, or is NULL.
+ *
+ *\li resp != NULL && *resp == NULL.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS On success.
+ *
+ *\li Anything else Failure.
+ */
+
+void
+dns_resolver_freeze(dns_resolver_t *res);
+/*%<
+ * Freeze resolver.
+ *
+ * Notes:
+ *
+ *\li Certain configuration changes cannot be made after the resolver
+ * is frozen. Fetches cannot be created until the resolver is frozen.
+ *
+ * Requires:
+ *
+ *\li 'res' is a valid, unfrozen resolver.
+ *
+ * Ensures:
+ *
+ *\li 'res' is frozen.
+ */
+
+void
+dns_resolver_prime(dns_resolver_t *res);
+/*%<
+ * Prime resolver.
+ *
+ * Notes:
+ *
+ *\li Resolvers which have a forwarding policy other than dns_fwdpolicy_only
+ * need to be primed with the root nameservers, otherwise the root
+ * nameserver hints data may be used indefinitely. This function requests
+ * that the resolver start a priming fetch, if it isn't already priming.
+ *
+ * Requires:
+ *
+ *\li 'res' is a valid, frozen resolver.
+ */
+
+
+void
+dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task,
+ isc_event_t **eventp);
+/*%<
+ * Send '*eventp' to 'task' when 'res' has completed shutdown.
+ *
+ * Notes:
+ *
+ *\li It is not safe to detach the last reference to 'res' until
+ * shutdown is complete.
+ *
+ * Requires:
+ *
+ *\li 'res' is a valid resolver.
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li *eventp is a valid event.
+ *
+ * Ensures:
+ *
+ *\li *eventp == NULL.
+ */
+
+void
+dns_resolver_shutdown(dns_resolver_t *res);
+/*%<
+ * Start the shutdown process for 'res'.
+ *
+ * Notes:
+ *
+ *\li This call has no effect if the resolver is already shutting down.
+ *
+ * Requires:
+ *
+ *\li 'res' is a valid resolver.
+ */
+
+void
+dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp);
+
+void
+dns_resolver_detach(dns_resolver_t **resp);
+
+isc_result_t
+dns_resolver_createfetch(dns_resolver_t *res, dns_name_t *name,
+ dns_rdatatype_t type,
+ dns_name_t *domain, dns_rdataset_t *nameservers,
+ dns_forwarders_t *forwarders,
+ unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset,
+ dns_fetch_t **fetchp);
+
+isc_result_t
+dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
+ dns_rdatatype_t type,
+ dns_name_t *domain, dns_rdataset_t *nameservers,
+ dns_forwarders_t *forwarders,
+ isc_sockaddr_t *client, isc_uint16_t id,
+ unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset,
+ dns_fetch_t **fetchp);
+/*%<
+ * Recurse to answer a question.
+ *
+ * Notes:
+ *
+ *\li This call starts a query for 'name', type 'type'.
+ *
+ *\li The 'domain' is a parent domain of 'name' for which
+ * a set of name servers 'nameservers' is known. If no
+ * such name server information is available, set
+ * 'domain' and 'nameservers' to NULL.
+ *
+ *\li 'forwarders' is unimplemented, and subject to change when
+ * we figure out how selective forwarding will work.
+ *
+ *\li When the fetch completes (successfully or otherwise), a
+ * #DNS_EVENT_FETCHDONE event with action 'action' and arg 'arg' will be
+ * posted to 'task'.
+ *
+ *\li The values of 'rdataset' and 'sigrdataset' will be returned in
+ * the FETCHDONE event.
+ *
+ *\li 'client' and 'id' are used for duplicate query detection. '*client'
+ * must remain stable until after 'action' has been called or
+ * dns_resolver_cancelfetch() is called.
+ *
+ * Requires:
+ *
+ *\li 'res' is a valid resolver that has been frozen.
+ *
+ *\li 'name' is a valid name.
+ *
+ *\li 'type' is not a meta type other than ANY.
+ *
+ *\li 'domain' is a valid name or NULL.
+ *
+ *\li 'nameservers' is a valid NS rdataset (whose owner name is 'domain')
+ * iff. 'domain' is not NULL.
+ *
+ *\li 'forwarders' is NULL.
+ *
+ *\li 'client' is a valid sockaddr or NULL.
+ *
+ *\li 'options' contains valid options.
+ *
+ *\li 'rdataset' is a valid, disassociated rdataset.
+ *
+ *\li 'sigrdataset' is NULL, or is a valid, disassociated rdataset.
+ *
+ *\li fetchp != NULL && *fetchp == NULL.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS Success
+ *\li #DNS_R_DUPLICATE
+ *\li #DNS_R_DROP
+ *
+ *\li Many other values are possible, all of which indicate failure.
+ */
+
+void
+dns_resolver_cancelfetch(dns_fetch_t *fetch);
+/*%<
+ * Cancel 'fetch'.
+ *
+ * Notes:
+ *
+ *\li If 'fetch' has not completed, post its FETCHDONE event with a
+ * result code of #ISC_R_CANCELED.
+ *
+ * Requires:
+ *
+ *\li 'fetch' is a valid fetch.
+ */
+
+void
+dns_resolver_destroyfetch(dns_fetch_t **fetchp);
+/*%<
+ * Destroy 'fetch'.
+ *
+ * Requires:
+ *
+ *\li '*fetchp' is a valid fetch.
+ *
+ *\li The caller has received the FETCHDONE event (either because the
+ * fetch completed or because dns_resolver_cancelfetch() was called).
+ *
+ * Ensures:
+ *
+ *\li *fetchp == NULL.
+ */
+
+dns_dispatchmgr_t *
+dns_resolver_dispatchmgr(dns_resolver_t *resolver);
+
+dns_dispatch_t *
+dns_resolver_dispatchv4(dns_resolver_t *resolver);
+
+dns_dispatch_t *
+dns_resolver_dispatchv6(dns_resolver_t *resolver);
+
+isc_socketmgr_t *
+dns_resolver_socketmgr(dns_resolver_t *resolver);
+
+isc_taskmgr_t *
+dns_resolver_taskmgr(dns_resolver_t *resolver);
+
+isc_uint32_t
+dns_resolver_getlamettl(dns_resolver_t *resolver);
+/*%<
+ * Get the resolver's lame-ttl. zero => no lame processing.
+ *
+ * Requires:
+ *\li 'resolver' to be valid.
+ */
+
+void
+dns_resolver_setlamettl(dns_resolver_t *resolver, isc_uint32_t lame_ttl);
+/*%<
+ * Set the resolver's lame-ttl. zero => no lame processing.
+ *
+ * Requires:
+ *\li 'resolver' to be valid.
+ */
+
+unsigned int
+dns_resolver_nrunning(dns_resolver_t *resolver);
+/*%<
+ * Return the number of currently running resolutions in this
+ * resolver. This is may be less than the number of outstanding
+ * fetches due to multiple identical fetches, or more than the
+ * number of of outstanding fetches due to the fact that resolution
+ * can continue even though a fetch has been canceled.
+ */
+
+isc_result_t
+dns_resolver_addalternate(dns_resolver_t *resolver, isc_sockaddr_t *alt,
+ dns_name_t *name, in_port_t port);
+/*%<
+ * Add alternate addresses to be tried in the event that the nameservers
+ * for a zone are not available in the address families supported by the
+ * operating system.
+ *
+ * Require:
+ * \li only one of 'name' or 'alt' to be valid.
+ */
+
+void
+dns_resolver_setudpsize(dns_resolver_t *resolver, isc_uint16_t udpsize);
+/*%<
+ * Set the EDNS UDP buffer size advertised by the server.
+ */
+
+isc_uint16_t
+dns_resolver_getudpsize(dns_resolver_t *resolver);
+/*%<
+ * Get the current EDNS UDP buffer size.
+ */
+
+void
+dns_resolver_reset_algorithms(dns_resolver_t *resolver);
+/*%<
+ * Clear the disabled DNSSEC algorithms.
+ */
+
+isc_result_t
+dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name,
+ unsigned int alg);
+/*%<
+ * Mark the give DNSSEC algorithm as disabled and below 'name'.
+ * Valid algorithms are less than 256.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_RANGE
+ *\li #ISC_R_NOMEMORY
+ */
+
+isc_boolean_t
+dns_resolver_algorithm_supported(dns_resolver_t *resolver, dns_name_t *name,
+ unsigned int alg);
+/*%<
+ * Check if the given algorithm is supported by this resolver.
+ * This checks if the algorithm has been disabled via
+ * dns_resolver_disable_algorithm() then the underlying
+ * crypto libraries if not specifically disabled.
+ */
+
+isc_boolean_t
+dns_resolver_digest_supported(dns_resolver_t *resolver, unsigned int digest_type);
+/*%<
+ * Is this digest type supported.
+ */
+
+void
+dns_resolver_resetmustbesecure(dns_resolver_t *resolver);
+
+isc_result_t
+dns_resolver_setmustbesecure(dns_resolver_t *resolver, dns_name_t *name,
+ isc_boolean_t value);
+
+isc_boolean_t
+dns_resolver_getmustbesecure(dns_resolver_t *resolver, dns_name_t *name);
+
+void
+dns_resolver_setclientsperquery(dns_resolver_t *resolver,
+ isc_uint32_t min, isc_uint32_t max);
+
+void
+dns_resolver_getclientsperquery(dns_resolver_t *resolver, isc_uint32_t *cur,
+ isc_uint32_t *min, isc_uint32_t *max);
+
+isc_boolean_t
+dns_resolver_getzeronosoattl(dns_resolver_t *resolver);
+
+void
+dns_resolver_setzeronosoattl(dns_resolver_t *resolver, isc_boolean_t state);
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RESOLVER_H */
diff --git a/lib/dns/include/dns/result.h b/lib/dns/include/dns/result.h
new file mode 100644
index 0000000..db5481b
--- /dev/null
+++ b/lib/dns/include/dns/result.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: result.h,v 1.104.10.6 2005/06/17 02:04:32 marka Exp $ */
+
+#ifndef DNS_RESULT_H
+#define DNS_RESULT_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/resultclass.h>
+
+#include <dns/types.h>
+
+/*
+ * Nothing in this file truly depends on <isc/result.h>, but the
+ * DNS result codes are considered to be publicly derived from
+ * the ISC result codes, so including this file buys you the ISC_R_
+ * namespace too.
+ */
+#include <isc/result.h> /* Contractual promise. */
+
+/*
+ * DNS library result codes
+ */
+#define DNS_R_LABELTOOLONG (ISC_RESULTCLASS_DNS + 0)
+#define DNS_R_BADESCAPE (ISC_RESULTCLASS_DNS + 1)
+/*
+ * Since we dropped the support of bitstring labels, deprecate the related
+ * result codes too.
+
+#define DNS_R_BADBITSTRING (ISC_RESULTCLASS_DNS + 2)
+#define DNS_R_BITSTRINGTOOLONG (ISC_RESULTCLASS_DNS + 3)
+*/
+#define DNS_R_EMPTYLABEL (ISC_RESULTCLASS_DNS + 4)
+#define DNS_R_BADDOTTEDQUAD (ISC_RESULTCLASS_DNS + 5)
+#define DNS_R_INVALIDNS (ISC_RESULTCLASS_DNS + 6)
+#define DNS_R_UNKNOWN (ISC_RESULTCLASS_DNS + 7)
+#define DNS_R_BADLABELTYPE (ISC_RESULTCLASS_DNS + 8)
+#define DNS_R_BADPOINTER (ISC_RESULTCLASS_DNS + 9)
+#define DNS_R_TOOMANYHOPS (ISC_RESULTCLASS_DNS + 10)
+#define DNS_R_DISALLOWED (ISC_RESULTCLASS_DNS + 11)
+#define DNS_R_EXTRATOKEN (ISC_RESULTCLASS_DNS + 12)
+#define DNS_R_EXTRADATA (ISC_RESULTCLASS_DNS + 13)
+#define DNS_R_TEXTTOOLONG (ISC_RESULTCLASS_DNS + 14)
+#define DNS_R_NOTZONETOP (ISC_RESULTCLASS_DNS + 15)
+#define DNS_R_SYNTAX (ISC_RESULTCLASS_DNS + 16)
+#define DNS_R_BADCKSUM (ISC_RESULTCLASS_DNS + 17)
+#define DNS_R_BADAAAA (ISC_RESULTCLASS_DNS + 18)
+#define DNS_R_NOOWNER (ISC_RESULTCLASS_DNS + 19)
+#define DNS_R_NOTTL (ISC_RESULTCLASS_DNS + 20)
+#define DNS_R_BADCLASS (ISC_RESULTCLASS_DNS + 21)
+#define DNS_R_NAMETOOLONG (ISC_RESULTCLASS_DNS + 22)
+#define DNS_R_PARTIALMATCH (ISC_RESULTCLASS_DNS + 23)
+#define DNS_R_NEWORIGIN (ISC_RESULTCLASS_DNS + 24)
+#define DNS_R_UNCHANGED (ISC_RESULTCLASS_DNS + 25)
+#define DNS_R_BADTTL (ISC_RESULTCLASS_DNS + 26)
+#define DNS_R_NOREDATA (ISC_RESULTCLASS_DNS + 27)
+#define DNS_R_CONTINUE (ISC_RESULTCLASS_DNS + 28)
+#define DNS_R_DELEGATION (ISC_RESULTCLASS_DNS + 29)
+#define DNS_R_GLUE (ISC_RESULTCLASS_DNS + 30)
+#define DNS_R_DNAME (ISC_RESULTCLASS_DNS + 31)
+#define DNS_R_CNAME (ISC_RESULTCLASS_DNS + 32)
+#define DNS_R_BADDB (ISC_RESULTCLASS_DNS + 33)
+#define DNS_R_ZONECUT (ISC_RESULTCLASS_DNS + 34)
+#define DNS_R_BADZONE (ISC_RESULTCLASS_DNS + 35)
+#define DNS_R_MOREDATA (ISC_RESULTCLASS_DNS + 36)
+#define DNS_R_UPTODATE (ISC_RESULTCLASS_DNS + 37)
+#define DNS_R_TSIGVERIFYFAILURE (ISC_RESULTCLASS_DNS + 38)
+#define DNS_R_TSIGERRORSET (ISC_RESULTCLASS_DNS + 39)
+#define DNS_R_SIGINVALID (ISC_RESULTCLASS_DNS + 40)
+#define DNS_R_SIGEXPIRED (ISC_RESULTCLASS_DNS + 41)
+#define DNS_R_SIGFUTURE (ISC_RESULTCLASS_DNS + 42)
+#define DNS_R_KEYUNAUTHORIZED (ISC_RESULTCLASS_DNS + 43)
+#define DNS_R_INVALIDTIME (ISC_RESULTCLASS_DNS + 44)
+#define DNS_R_EXPECTEDTSIG (ISC_RESULTCLASS_DNS + 45)
+#define DNS_R_UNEXPECTEDTSIG (ISC_RESULTCLASS_DNS + 46)
+#define DNS_R_INVALIDTKEY (ISC_RESULTCLASS_DNS + 47)
+#define DNS_R_HINT (ISC_RESULTCLASS_DNS + 48)
+#define DNS_R_DROP (ISC_RESULTCLASS_DNS + 49)
+#define DNS_R_NOTLOADED (ISC_RESULTCLASS_DNS + 50)
+#define DNS_R_NCACHENXDOMAIN (ISC_RESULTCLASS_DNS + 51)
+#define DNS_R_NCACHENXRRSET (ISC_RESULTCLASS_DNS + 52)
+#define DNS_R_WAIT (ISC_RESULTCLASS_DNS + 53)
+#define DNS_R_NOTVERIFIEDYET (ISC_RESULTCLASS_DNS + 54)
+#define DNS_R_NOIDENTITY (ISC_RESULTCLASS_DNS + 55)
+#define DNS_R_NOJOURNAL (ISC_RESULTCLASS_DNS + 56)
+#define DNS_R_ALIAS (ISC_RESULTCLASS_DNS + 57)
+#define DNS_R_USETCP (ISC_RESULTCLASS_DNS + 58)
+#define DNS_R_NOVALIDSIG (ISC_RESULTCLASS_DNS + 59)
+#define DNS_R_NOVALIDNSEC (ISC_RESULTCLASS_DNS + 60)
+#define DNS_R_NOTINSECURE (ISC_RESULTCLASS_DNS + 61)
+#define DNS_R_UNKNOWNSERVICE (ISC_RESULTCLASS_DNS + 62)
+#define DNS_R_RECOVERABLE (ISC_RESULTCLASS_DNS + 63)
+#define DNS_R_UNKNOWNOPT (ISC_RESULTCLASS_DNS + 64)
+#define DNS_R_UNEXPECTEDID (ISC_RESULTCLASS_DNS + 65)
+#define DNS_R_SEENINCLUDE (ISC_RESULTCLASS_DNS + 66)
+#define DNS_R_NOTEXACT (ISC_RESULTCLASS_DNS + 67)
+#define DNS_R_BLACKHOLED (ISC_RESULTCLASS_DNS + 68)
+#define DNS_R_BADALG (ISC_RESULTCLASS_DNS + 69)
+#define DNS_R_METATYPE (ISC_RESULTCLASS_DNS + 70)
+#define DNS_R_CNAMEANDOTHER (ISC_RESULTCLASS_DNS + 71)
+#define DNS_R_SINGLETON (ISC_RESULTCLASS_DNS + 72)
+#define DNS_R_HINTNXRRSET (ISC_RESULTCLASS_DNS + 73)
+#define DNS_R_NOMASTERFILE (ISC_RESULTCLASS_DNS + 74)
+#define DNS_R_UNKNOWNPROTO (ISC_RESULTCLASS_DNS + 75)
+#define DNS_R_CLOCKSKEW (ISC_RESULTCLASS_DNS + 76)
+#define DNS_R_BADIXFR (ISC_RESULTCLASS_DNS + 77)
+#define DNS_R_NOTAUTHORITATIVE (ISC_RESULTCLASS_DNS + 78)
+#define DNS_R_NOVALIDKEY (ISC_RESULTCLASS_DNS + 79)
+#define DNS_R_OBSOLETE (ISC_RESULTCLASS_DNS + 80)
+#define DNS_R_FROZEN (ISC_RESULTCLASS_DNS + 81)
+#define DNS_R_UNKNOWNFLAG (ISC_RESULTCLASS_DNS + 82)
+#define DNS_R_EXPECTEDRESPONSE (ISC_RESULTCLASS_DNS + 83)
+#define DNS_R_NOVALIDDS (ISC_RESULTCLASS_DNS + 84)
+#define DNS_R_NSISADDRESS (ISC_RESULTCLASS_DNS + 85)
+#define DNS_R_REMOTEFORMERR (ISC_RESULTCLASS_DNS + 86)
+#define DNS_R_TRUNCATEDTCP (ISC_RESULTCLASS_DNS + 87)
+#define DNS_R_LAME (ISC_RESULTCLASS_DNS + 88)
+#define DNS_R_UNEXPECTEDRCODE (ISC_RESULTCLASS_DNS + 89)
+#define DNS_R_UNEXPECTEDOPCODE (ISC_RESULTCLASS_DNS + 90)
+#define DNS_R_CHASEDSSERVERS (ISC_RESULTCLASS_DNS + 91)
+#define DNS_R_EMPTYNAME (ISC_RESULTCLASS_DNS + 92)
+#define DNS_R_EMPTYWILD (ISC_RESULTCLASS_DNS + 93)
+#define DNS_R_BADBITMAP (ISC_RESULTCLASS_DNS + 94)
+#define DNS_R_FROMWILDCARD (ISC_RESULTCLASS_DNS + 95)
+#define DNS_R_BADOWNERNAME (ISC_RESULTCLASS_DNS + 96)
+#define DNS_R_BADNAME (ISC_RESULTCLASS_DNS + 97)
+#define DNS_R_DYNAMIC (ISC_RESULTCLASS_DNS + 98)
+#define DNS_R_UNKNOWNCOMMAND (ISC_RESULTCLASS_DNS + 99)
+#define DNS_R_MUSTBESECURE (ISC_RESULTCLASS_DNS + 100)
+#define DNS_R_COVERINGNSEC (ISC_RESULTCLASS_DNS + 101)
+#define DNS_R_MXISADDRESS (ISC_RESULTCLASS_DNS + 102)
+#define DNS_R_DUPLICATE (ISC_RESULTCLASS_DNS + 103)
+
+#define DNS_R_NRESULTS 104 /*%< Number of results */
+
+/*
+ * DNS wire format rcodes.
+ *
+ * By making these their own class we can easily convert them into the
+ * wire-format rcode value simply by masking off the resultclass.
+ */
+#define DNS_R_NOERROR (ISC_RESULTCLASS_DNSRCODE + 0)
+#define DNS_R_FORMERR (ISC_RESULTCLASS_DNSRCODE + 1)
+#define DNS_R_SERVFAIL (ISC_RESULTCLASS_DNSRCODE + 2)
+#define DNS_R_NXDOMAIN (ISC_RESULTCLASS_DNSRCODE + 3)
+#define DNS_R_NOTIMP (ISC_RESULTCLASS_DNSRCODE + 4)
+#define DNS_R_REFUSED (ISC_RESULTCLASS_DNSRCODE + 5)
+#define DNS_R_YXDOMAIN (ISC_RESULTCLASS_DNSRCODE + 6)
+#define DNS_R_YXRRSET (ISC_RESULTCLASS_DNSRCODE + 7)
+#define DNS_R_NXRRSET (ISC_RESULTCLASS_DNSRCODE + 8)
+#define DNS_R_NOTAUTH (ISC_RESULTCLASS_DNSRCODE + 9)
+#define DNS_R_NOTZONE (ISC_RESULTCLASS_DNSRCODE + 10)
+#define DNS_R_BADVERS (ISC_RESULTCLASS_DNSRCODE + 16)
+
+#define DNS_R_NRCODERESULTS 17 /*%< Number of rcode results */
+
+#define DNS_RESULT_ISRCODE(result) \
+ (ISC_RESULTCLASS_INCLASS(ISC_RESULTCLASS_DNSRCODE, (result)))
+
+ISC_LANG_BEGINDECLS
+
+const char *
+dns_result_totext(isc_result_t);
+
+void
+dns_result_register(void);
+
+dns_rcode_t
+dns_result_torcode(isc_result_t result);
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RESULT_H */
diff --git a/lib/dns/include/dns/rootns.h b/lib/dns/include/dns/rootns.h
new file mode 100644
index 0000000..a3ddc48
--- /dev/null
+++ b/lib/dns/include/dns/rootns.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2005 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: rootns.h,v 1.9.18.3 2005/04/27 05:01:38 sra Exp $ */
+
+#ifndef DNS_ROOTNS_H
+#define DNS_ROOTNS_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_rootns_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
+ const char *filename, dns_db_t **target);
+
+void
+dns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db);
+/*
+ * Reports differences between hints and the real roots.
+ *
+ * Requires view, hints and (cache) db to be valid.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_ROOTNS_H */
diff --git a/lib/dns/include/dns/sdb.h b/lib/dns/include/dns/sdb.h
new file mode 100644
index 0000000..de849f9
--- /dev/null
+++ b/lib/dns/include/dns/sdb.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2004, 2005 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: sdb.h,v 1.15.18.2 2005/04/29 00:16:21 marka Exp $ */
+
+#ifndef DNS_SDB_H
+#define DNS_SDB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Simple database API.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+/***
+ *** Types
+ ***/
+
+/*%
+ * A simple database. This is an opaque type.
+ */
+typedef struct dns_sdb dns_sdb_t;
+
+/*%
+ * A simple database lookup in progress. This is an opaque type.
+ */
+typedef struct dns_sdblookup dns_sdblookup_t;
+
+/*%
+ * A simple database traversal in progress. This is an opaque type.
+ */
+typedef struct dns_sdballnodes dns_sdballnodes_t;
+
+typedef isc_result_t
+(*dns_sdblookupfunc_t)(const char *zone, const char *name, void *dbdata,
+ dns_sdblookup_t *);
+
+typedef isc_result_t
+(*dns_sdbauthorityfunc_t)(const char *zone, void *dbdata, dns_sdblookup_t *);
+
+typedef isc_result_t
+(*dns_sdballnodesfunc_t)(const char *zone, void *dbdata,
+ dns_sdballnodes_t *allnodes);
+
+typedef isc_result_t
+(*dns_sdbcreatefunc_t)(const char *zone, int argc, char **argv,
+ void *driverdata, void **dbdata);
+
+typedef void
+(*dns_sdbdestroyfunc_t)(const char *zone, void *driverdata, void **dbdata);
+
+
+typedef struct dns_sdbmethods {
+ dns_sdblookupfunc_t lookup;
+ dns_sdbauthorityfunc_t authority;
+ dns_sdballnodesfunc_t allnodes;
+ dns_sdbcreatefunc_t create;
+ dns_sdbdestroyfunc_t destroy;
+} dns_sdbmethods_t;
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+#define DNS_SDBFLAG_RELATIVEOWNER 0x00000001U
+#define DNS_SDBFLAG_RELATIVERDATA 0x00000002U
+#define DNS_SDBFLAG_THREADSAFE 0x00000004U
+
+isc_result_t
+dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
+ void *driverdata, unsigned int flags, isc_mem_t *mctx,
+ dns_sdbimplementation_t **sdbimp);
+/*%<
+ * Register a simple database driver for the database type 'drivername',
+ * implemented by the functions in '*methods'.
+ *
+ * sdbimp must point to a NULL dns_sdbimplementation_t pointer. That is,
+ * sdbimp != NULL && *sdbimp == NULL. It will be assigned a value that
+ * will later be used to identify the driver when deregistering it.
+ *
+ * The name server will perform lookups in the database by calling the
+ * function 'lookup', passing it a printable zone name 'zone', a printable
+ * domain name 'name', and a copy of the argument 'dbdata' that
+ * was potentially returned by the create function. The 'dns_sdblookup_t'
+ * argument to 'lookup' and 'authority' is an opaque pointer to be passed to
+ * ns_sdb_putrr().
+ *
+ * The lookup function returns the lookup results to the name server
+ * by calling ns_sdb_putrr() once for each record found. On success,
+ * the return value of the lookup function should be ISC_R_SUCCESS.
+ * If the domain name 'name' does not exist, the lookup function should
+ * ISC_R_NOTFOUND. Any other return value is treated as an error.
+ *
+ * Lookups at the zone apex will cause the server to also call the
+ * function 'authority' (if non-NULL), which must provide an SOA record
+ * and NS records for the zone by calling ns_sdb_putrr() once for each of
+ * these records. The 'authority' function may be NULL if invoking
+ * the 'lookup' function on the zone apex will return SOA and NS records.
+ *
+ * The allnodes function, if non-NULL, fills in an opaque structure to be
+ * used by a database iterator. This allows the zone to be transferred.
+ * This may use a considerable amount of memory for large zones, and the
+ * zone transfer may not be fully RFC1035 compliant if the zone is
+ * frequently changed.
+ *
+ * The create function will be called for each zone configured
+ * into the name server using this database type. It can be used
+ * to create a "database object" containg zone specific data,
+ * which can make use of the database arguments specified in the
+ * name server configuration.
+ *
+ * The destroy function will be called to free the database object
+ * when its zone is destroyed.
+ *
+ * The create and destroy functions may be NULL.
+ *
+ * If flags includes DNS_SDBFLAG_RELATIVEOWNER, the lookup and authority
+ * functions will be called with relative names rather than absolute names.
+ * The string "@" represents the zone apex in this case.
+ *
+ * If flags includes DNS_SDBFLAG_RELATIVERDATA, the rdata strings may
+ * include relative names. Otherwise, all names in the rdata string must
+ * be absolute. Be aware that if relative names are allowed, any
+ * absolute names must contain a trailing dot.
+ *
+ * If flags includes DNS_SDBFLAG_THREADSAFE, the driver must be able to
+ * handle multiple lookups in parallel. Otherwise, calls into the driver
+ * are serialized.
+ */
+
+void
+dns_sdb_unregister(dns_sdbimplementation_t **sdbimp);
+/*%<
+ * Removes the simple database driver from the list of registered database
+ * types. There must be no active databases of this type when this function
+ * is called.
+ */
+
+/*% See dns_sdb_putradata() */
+isc_result_t
+dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
+ const char *data);
+isc_result_t
+dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t type, dns_ttl_t ttl,
+ const unsigned char *rdata, unsigned int rdlen);
+/*%<
+ * Add a single resource record to the lookup structure to be
+ * returned in the query response. dns_sdb_putrr() takes the
+ * resource record in master file text format as a null-terminated
+ * string, and dns_sdb_putrdata() takes the raw RDATA in
+ * uncompressed wire format.
+ */
+
+/*% See dns_sdb_putnamerdata() */
+isc_result_t
+dns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
+ const char *type, dns_ttl_t ttl, const char *data);
+isc_result_t
+dns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
+ dns_rdatatype_t type, dns_ttl_t ttl,
+ const void *rdata, unsigned int rdlen);
+/*%<
+ * Add a single resource record to the allnodes structure to be
+ * included in a zone transfer response, in text or wire
+ * format as above.
+ */
+
+isc_result_t
+dns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
+ isc_uint32_t serial);
+/*%<
+ * This function may optionally be called from the 'authority' callback
+ * to simplify construction of the SOA record for 'zone'. It will
+ * provide a SOA listing 'mname' as as the master server and 'rname' as
+ * the responsible person mailbox. It is the responsibility of the
+ * driver to increment the serial number between responses if necessary.
+ * All other SOA fields will have reasonable default values.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_SDB_H */
diff --git a/lib/dns/include/dns/sdlz.h b/lib/dns/include/dns/sdlz.h
new file mode 100644
index 0000000..13ba14a
--- /dev/null
+++ b/lib/dns/include/dns/sdlz.h
@@ -0,0 +1,266 @@
+/*
+ * Portions Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions 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.
+ */
+
+/*
+ * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER 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 development of Dynamically Loadable Zones (DLZ) for Bind 9 was
+ * conceived and contributed by Rob Butler.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: sdlz.h,v 1.2.2.2 2005/09/06 03:47:19 marka Exp $ */
+
+/*! \file */
+
+#ifndef SDLZ_H
+#define SDLZ_H 1
+
+#include <dns/dlz.h>
+
+ISC_LANG_BEGINDECLS
+
+#define DNS_SDLZFLAG_THREADSAFE 0x00000001U
+#define DNS_SDLZFLAG_RELATIVEOWNER 0x00000002U
+#define DNS_SDLZFLAG_RELATIVERDATA 0x00000004U
+
+ /* A simple DLZ database. */
+typedef struct dns_sdlz_db dns_sdlz_db_t;
+
+ /* A simple DLZ database lookup in progress. */
+typedef struct dns_sdlzlookup dns_sdlzlookup_t;
+
+ /* A simple DLZ database traversal in progress. */
+typedef struct dns_sdlzallnodes dns_sdlzallnodes_t;
+
+
+typedef isc_result_t
+(*dns_sdlzallnodesfunc_t)(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzallnodes_t *allnodes);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface may
+ * supply an all nodes method. This method is called when the DNS
+ * server is performing a zone transfer query, after the allow zone
+ * transfer method has been called. This method is only called if the
+ * allow zone transfer method returned ISC_R_SUCCESS. This method and
+ * the allow zone transfer method are both required for zone transfers
+ * to be supported. If the driver generates data dynamically (instead
+ * of searching in a database for it) it should not implement this
+ * function as a zone transfer would be meaningless. A SDLZ driver
+ * does not have to implement an all nodes method.
+ */
+
+typedef isc_result_t
+(*dns_sdlzallowzonexfr_t)(void *driverarg, void *dbdata, const char *name,
+ const char *client);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface may
+ * supply an allow zone transfer method. This method is called when
+ * the DNS server is performing a zone transfer query, before the all
+ * nodes method can be called. This method and the all node method
+ * are both required for zone transfers to be supported. If the
+ * driver generates data dynamically (instead of searching in a
+ * database for it) it should not implement this function as a zone
+ * transfer would be meaningless. A SDLZ driver does not have to
+ * implement an allow zone transfer method.
+ *
+ * This method should return ISC_R_SUCCESS if the zone is supported by
+ * the database and a zone transfer is allowed for the specified
+ * client. If the zone is supported by the database, but zone
+ * transfers are not allowed for the specified client this method
+ * should return ISC_R_NOPERM.. Lastly the method should return
+ * ISC_R_NOTFOUND if the zone is not supported by the database. If an
+ * error occurs it should return a result code indicating the type of
+ * error.
+ */
+
+typedef isc_result_t
+(*dns_sdlzauthorityfunc_t)(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzlookup_t *lookup);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface may
+ * supply an authority method. This method is called when the DNS
+ * server is performing a query, after both the find zone and lookup
+ * methods have been called. This method is required if the lookup
+ * function does not supply authority information for the dns
+ * record. A SDLZ driver does not have to implement an authority
+ * method.
+ */
+
+typedef isc_result_t
+(*dns_sdlzcreate_t)(const char *dlzname, unsigned int argc, char *argv[],
+ void *driverarg, void **dbdata);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface may
+ * supply a create method. This method is called when the DNS server
+ * is starting up and creating drivers for use later. A SDLZ driver
+ * does not have to implement a create method.
+ */
+
+typedef void
+(*dns_sdlzdestroy_t)(void *driverarg, void *dbdata);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface may
+ * supply a destroy method. This method is called when the DNS server
+ * is shuting down and no longer needs the driver. A SDLZ driver does
+ * not have to implement a destroy method.
+ */
+
+typedef isc_result_t
+(*dns_sdlzfindzone_t)(void *driverarg, void *dbdata, const char *name);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface MUST
+ * supply a find zone method. This method is called when the DNS
+ * server is performing a query to to determine if 'name' is a
+ * supported dns zone. The find zone method will be called with the
+ * longest possible name first, and continue to be called with
+ * successively shorter domain names, until any of the following
+ * occur:
+ *
+ * \li 1) the function returns (ISC_R_SUCCESS) indicating a zone name
+ * match.
+ *
+ * \li 2) a problem occurs, and the functions returns anything other than
+ * (ISC_R_NOTFOUND)
+ *
+ * \li 3) we run out of domain name labels. I.E. we have tried the
+ * shortest domain name
+ *
+ * \li 4) the number of labels in the domain name is less than min_lables
+ * for dns_dlzfindzone
+ *
+ * The driver's find zone method should return ISC_R_SUCCESS if the
+ * zone is supported by the database. Otherwise it should return
+ * ISC_R_NOTFOUND, if the zone is not supported. If an error occurs
+ * it should return a result code indicating the type of error.
+ */
+
+typedef isc_result_t
+(*dns_sdlzlookupfunc_t)(const char *zone, const char *name, void *driverarg,
+ void *dbdata, dns_sdlzlookup_t *lookup);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface MUST
+ * supply a lookup method. This method is called when the DNS server
+ * is performing a query, after the find zone and before any other
+ * methods have been called. This function returns record DNS record
+ * information using the dns_sdlz_putrr and dns_sdlz_putsoa functions.
+ * If this function supplies authority information for the DNS record
+ * the authority method is not required. If it does not, the
+ * authority function is required. A SDLZ driver must implement a
+ * lookup method.
+ */
+
+typedef struct dns_sdlzmethods {
+ dns_sdlzcreate_t create;
+ dns_sdlzdestroy_t destroy;
+ dns_sdlzfindzone_t findzone;
+ dns_sdlzlookupfunc_t lookup;
+ dns_sdlzauthorityfunc_t authority;
+ dns_sdlzallnodesfunc_t allnodes;
+ dns_sdlzallowzonexfr_t allowzonexfr;
+} dns_sdlzmethods_t;
+
+isc_result_t
+dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
+ void *driverarg, unsigned int flags, isc_mem_t *mctx,
+ dns_sdlzimplementation_t **sdlzimp);
+/*%<
+ * Register a dynamically loadable zones (dlz) driver for the database
+ * type 'drivername', implemented by the functions in '*methods'.
+ *
+ * sdlzimp must point to a NULL dns_sdlzimplementation_t pointer.
+ * That is, sdlzimp != NULL && *sdlzimp == NULL. It will be assigned
+ * a value that will later be used to identify the driver when
+ * deregistering it.
+ */
+
+void
+dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp);
+
+/*%<
+ * Removes the sdlz driver from the list of registered sdlz drivers.
+ * There must be no active sdlz drivers of this type when this
+ * function is called.
+ */
+
+isc_result_t
+dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
+ const char *type, dns_ttl_t ttl, const char *data);
+/*%<
+ * Add a single resource record to the allnodes structure to be later
+ * parsed into a zone transfer response.
+ */
+
+isc_result_t
+dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
+ const char *data);
+/*%<
+ * Add a single resource record to the lookup structure to be later
+ * parsed into a query response.
+ */
+
+isc_result_t
+dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
+ isc_uint32_t serial);
+/*%<
+ * This function may optionally be called from the 'authority'
+ * callback to simplify construction of the SOA record for 'zone'. It
+ * will provide a SOA listing 'mname' as as the master server and
+ * 'rname' as the responsible person mailbox. It is the
+ * responsibility of the driver to increment the serial number between
+ * responses if necessary. All other SOA fields will have reasonable
+ * default values.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* SDLZ_H */
diff --git a/lib/dns/include/dns/secalg.h b/lib/dns/include/dns/secalg.h
new file mode 100644
index 0000000..0466d91
--- /dev/null
+++ b/lib/dns/include/dns/secalg.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2004, 2005 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: secalg.h,v 1.13.18.2 2005/04/29 00:16:21 marka Exp $ */
+
+#ifndef DNS_SECALG_H
+#define DNS_SECALG_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_secalg_fromtext(dns_secalg_t *secalgp, isc_textregion_t *source);
+/*%<
+ * Convert the text 'source' refers to into a DNSSEC security algorithm value.
+ * The text may contain either a mnemonic algorithm name or a decimal algorithm
+ * number.
+ *
+ * Requires:
+ *\li 'secalgp' is a valid pointer.
+ *
+ *\li 'source' is a valid text region.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS on success
+ *\li ISC_R_RANGE numeric type is out of range
+ *\li DNS_R_UNKNOWN mnemonic type is unknown
+ */
+
+isc_result_t
+dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target);
+/*%<
+ * Put a textual representation of the DNSSEC security algorithm 'secalg'
+ * into 'target'.
+ *
+ * Requires:
+ *\li 'secalg' is a valid secalg.
+ *
+ *\li 'target' is a valid text buffer.
+ *
+ * Ensures,
+ * if the result is success:
+ *\li The used space in 'target' is updated.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS on success
+ *\li ISC_R_NOSPACE target buffer is too small
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_SECALG_H */
diff --git a/lib/dns/include/dns/secproto.h b/lib/dns/include/dns/secproto.h
new file mode 100644
index 0000000..a6cfd5c
--- /dev/null
+++ b/lib/dns/include/dns/secproto.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2004, 2005 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: secproto.h,v 1.10.18.2 2005/04/29 00:16:21 marka Exp $ */
+
+#ifndef DNS_SECPROTO_H
+#define DNS_SECPROTO_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_secproto_fromtext(dns_secproto_t *secprotop, isc_textregion_t *source);
+/*%<
+ * Convert the text 'source' refers to into a DNSSEC security protocol value.
+ * The text may contain either a mnemonic protocol name or a decimal protocol
+ * number.
+ *
+ * Requires:
+ *\li 'secprotop' is a valid pointer.
+ *
+ *\li 'source' is a valid text region.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS on success
+ *\li ISC_R_RANGE numeric type is out of range
+ *\li DNS_R_UNKNOWN mnemonic type is unknown
+ */
+
+isc_result_t
+dns_secproto_totext(dns_secproto_t secproto, isc_buffer_t *target);
+/*%<
+ * Put a textual representation of the DNSSEC security protocol 'secproto'
+ * into 'target'.
+ *
+ * Requires:
+ *\li 'secproto' is a valid secproto.
+ *
+ *\li 'target' is a valid text buffer.
+ *
+ * Ensures,
+ * if the result is success:
+ * \li The used space in 'target' is updated.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS on success
+ *\li ISC_R_NOSPACE target buffer is too small
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_SECPROTO_H */
diff --git a/lib/dns/include/dns/soa.h b/lib/dns/include/dns/soa.h
new file mode 100644
index 0000000..70c6725
--- /dev/null
+++ b/lib/dns/include/dns/soa.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2004, 2005 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: soa.h,v 1.3.18.2 2005/04/29 00:16:22 marka Exp $ */
+
+#ifndef DNS_SOA_H
+#define DNS_SOA_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * SOA utilities.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_uint32_t
+dns_soa_getserial(dns_rdata_t *rdata);
+isc_uint32_t
+dns_soa_getrefresh(dns_rdata_t *rdata);
+isc_uint32_t
+dns_soa_getretry(dns_rdata_t *rdata);
+isc_uint32_t
+dns_soa_getexpire(dns_rdata_t *rdata);
+isc_uint32_t
+dns_soa_getminimum(dns_rdata_t *rdata);
+/*
+ * Extract an integer field from the rdata of a SOA record.
+ *
+ * Requires:
+ * rdata refers to the rdata of a well-formed SOA record.
+ */
+
+void
+dns_soa_setserial(isc_uint32_t val, dns_rdata_t *rdata);
+void
+dns_soa_setrefresh(isc_uint32_t val, dns_rdata_t *rdata);
+void
+dns_soa_setretry(isc_uint32_t val, dns_rdata_t *rdata);
+void
+dns_soa_setexpire(isc_uint32_t val, dns_rdata_t *rdata);
+void
+dns_soa_setminimum(isc_uint32_t val, dns_rdata_t *rdata);
+/*
+ * Change an integer field of a SOA record by modifying the
+ * rdata in-place.
+ *
+ * Requires:
+ * rdata refers to the rdata of a well-formed SOA record.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_SOA_H */
diff --git a/lib/dns/include/dns/ssu.h b/lib/dns/include/dns/ssu.h
new file mode 100644
index 0000000..b709030
--- /dev/null
+++ b/lib/dns/include/dns/ssu.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2004-2006 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: ssu.h,v 1.13.18.4 2006/02/16 23:51:32 marka Exp $ */
+
+#ifndef DNS_SSU_H
+#define DNS_SSU_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+#define DNS_SSUMATCHTYPE_NAME 0
+#define DNS_SSUMATCHTYPE_SUBDOMAIN 1
+#define DNS_SSUMATCHTYPE_WILDCARD 2
+#define DNS_SSUMATCHTYPE_SELF 3
+#define DNS_SSUMATCHTYPE_SELFSUB 4
+#define DNS_SSUMATCHTYPE_SELFWILD 5
+#define DNS_SSUMATCHTYPE_MAX 5 /* maximum defined value */
+
+
+isc_result_t
+dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **table);
+/*%<
+ * Creates a table that will be used to store simple-secure-update rules.
+ * Note: all locking must be provided by the client.
+ *
+ * Requires:
+ *\li 'mctx' is a valid memory context
+ *\li 'table' is not NULL, and '*table' is NULL
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOMEMORY
+ */
+
+void
+dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp);
+/*%<
+ * Attach '*targetp' to 'source'.
+ *
+ * Requires:
+ *\li 'source' is a valid SSU table
+ *\li 'targetp' points to a NULL dns_ssutable_t *.
+ *
+ * Ensures:
+ *\li *targetp is attached to source.
+ */
+
+void
+dns_ssutable_detach(dns_ssutable_t **tablep);
+/*%<
+ * Detach '*tablep' from its simple-secure-update rule table.
+ *
+ * Requires:
+ *\li 'tablep' points to a valid dns_ssutable_t
+ *
+ * Ensures:
+ *\li *tablep is NULL
+ *\li If '*tablep' is the last reference to the SSU table, all
+ * resources used by the table will be freed.
+ */
+
+isc_result_t
+dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant,
+ dns_name_t *identity, unsigned int matchtype,
+ dns_name_t *name, unsigned int ntypes,
+ dns_rdatatype_t *types);
+/*%<
+ * Adds a new rule to a simple-secure-update rule table. The rule
+ * either grants or denies update privileges of an identity (or set of
+ * identities) to modify a name (or set of names) or certain types present
+ * at that name.
+ *
+ * Notes:
+ *\li If 'matchtype' is SELF, this rule only matches if the name
+ * to be updated matches the signing identity.
+ *
+ *\li If 'ntypes' is 0, this rule applies to all types except
+ * NS, SOA, RRSIG, and NSEC.
+ *
+ *\li If 'types' includes ANY, this rule applies to all types
+ * except NSEC.
+ *
+ * Requires:
+ *\li 'table' is a valid SSU table
+ *\li 'identity' is a valid absolute name
+ *\li 'matchtype' must be one of the defined constants.
+ *\li 'name' is a valid absolute name
+ *\li If 'ntypes' > 0, 'types' must not be NULL
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOMEMORY
+ */
+
+isc_boolean_t
+dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
+ dns_name_t *name, dns_rdatatype_t type);
+/*%<
+ * Checks that the attempted update of (name, type) is allowed according
+ * to the rules specified in the simple-secure-update rule table. If
+ * no rules are matched, access is denied. If signer is NULL, access
+ * is denied.
+ *
+ * Requires:
+ *\li 'table' is a valid SSU table
+ *\li 'signer' is NULL or a valid absolute name
+ *\li 'name' is a valid absolute name
+ */
+
+
+/*% Accessor functions to extract rule components */
+isc_boolean_t dns_ssurule_isgrant(const dns_ssurule_t *rule);
+/*% Accessor functions to extract rule components */
+dns_name_t * dns_ssurule_identity(const dns_ssurule_t *rule);
+/*% Accessor functions to extract rule components */
+unsigned int dns_ssurule_matchtype(const dns_ssurule_t *rule);
+/*% Accessor functions to extract rule components */
+dns_name_t * dns_ssurule_name(const dns_ssurule_t *rule);
+/*% Accessor functions to extract rule components */
+unsigned int dns_ssurule_types(const dns_ssurule_t *rule,
+ dns_rdatatype_t **types);
+
+isc_result_t dns_ssutable_firstrule(const dns_ssutable_t *table,
+ dns_ssurule_t **rule);
+/*%<
+ * Initiates a rule iterator. There is no need to maintain any state.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMORE
+ */
+
+isc_result_t dns_ssutable_nextrule(dns_ssurule_t *rule,
+ dns_ssurule_t **nextrule);
+/*%<
+ * Returns the next rule in the table.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMORE
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_SSU_H */
diff --git a/lib/dns/include/dns/stats.h b/lib/dns/include/dns/stats.h
new file mode 100644
index 0000000..6cd95ac
--- /dev/null
+++ b/lib/dns/include/dns/stats.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2004, 2005 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: stats.h,v 1.5.18.4 2005/06/27 00:20:03 marka Exp $ */
+
+#ifndef DNS_STATS_H
+#define DNS_STATS_H 1
+
+/*! \file */
+
+#include <dns/types.h>
+
+/*%
+ * Query statistics counter types.
+ */
+typedef enum {
+ dns_statscounter_success = 0, /*%< Successful lookup */
+ dns_statscounter_referral = 1, /*%< Referral result */
+ dns_statscounter_nxrrset = 2, /*%< NXRRSET result */
+ dns_statscounter_nxdomain = 3, /*%< NXDOMAIN result */
+ dns_statscounter_recursion = 4, /*%< Recursion was used */
+ dns_statscounter_failure = 5, /*%< Some other failure */
+ dns_statscounter_duplicate = 6, /*%< Duplicate query */
+ dns_statscounter_dropped = 7 /*%< Duplicate query */
+} dns_statscounter_t;
+
+#define DNS_STATS_NCOUNTERS 8
+
+LIBDNS_EXTERNAL_DATA extern const char *dns_statscounter_names[];
+
+isc_result_t
+dns_stats_alloccounters(isc_mem_t *mctx, isc_uint64_t **ctrp);
+/*%<
+ * Allocate an array of query statistics counters from the memory
+ * context 'mctx'.
+ */
+
+void
+dns_stats_freecounters(isc_mem_t *mctx, isc_uint64_t **ctrp);
+/*%<
+ * Free an array of query statistics counters allocated from the memory
+ * context 'mctx'.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_STATS_H */
diff --git a/lib/dns/include/dns/tcpmsg.h b/lib/dns/include/dns/tcpmsg.h
new file mode 100644
index 0000000..075f463
--- /dev/null
+++ b/lib/dns/include/dns/tcpmsg.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2004, 2005 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: tcpmsg.h,v 1.16.18.2 2005/04/29 00:16:22 marka Exp $ */
+
+#ifndef DNS_TCPMSG_H
+#define DNS_TCPMSG_H 1
+
+/*! \file */
+
+#include <isc/buffer.h>
+#include <isc/lang.h>
+#include <isc/socket.h>
+
+typedef struct dns_tcpmsg {
+ /* private (don't touch!) */
+ unsigned int magic;
+ isc_uint16_t size;
+ isc_buffer_t buffer;
+ unsigned int maxsize;
+ isc_mem_t *mctx;
+ isc_socket_t *sock;
+ isc_task_t *task;
+ isc_taskaction_t action;
+ void *arg;
+ isc_event_t event;
+ /* public (read-only) */
+ isc_result_t result;
+ isc_sockaddr_t address;
+} dns_tcpmsg_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg);
+/*%<
+ * Associate a tcp message state with a given memory context and
+ * TCP socket.
+ *
+ * Requires:
+ *
+ *\li "mctx" and "sock" be non-NULL and valid types.
+ *
+ *\li "sock" be a read/write TCP socket.
+ *
+ *\li "tcpmsg" be non-NULL and an uninitialized or invalidated structure.
+ *
+ * Ensures:
+ *
+ *\li "tcpmsg" is a valid structure.
+ */
+
+void
+dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize);
+/*%<
+ * Set the maximum packet size to "maxsize"
+ *
+ * Requires:
+ *
+ *\li "tcpmsg" be valid.
+ *
+ *\li 512 <= "maxsize" <= 65536
+ */
+
+isc_result_t
+dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg,
+ isc_task_t *task, isc_taskaction_t action, void *arg);
+/*%<
+ * Schedule an event to be delivered when a DNS message is readable, or
+ * when an error occurs on the socket.
+ *
+ * Requires:
+ *
+ *\li "tcpmsg" be valid.
+ *
+ *\li "task", "taskaction", and "arg" be valid.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS -- no error
+ *\li Anything that the isc_socket_recv() call can return. XXXMLG
+ *
+ * Notes:
+ *
+ *\li The event delivered is a fully generic event. It will contain no
+ * actual data. The sender will be a pointer to the dns_tcpmsg_t.
+ * The result code inside that structure should be checked to see
+ * what the final result was.
+ */
+
+void
+dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg);
+/*%<
+ * Cancel a readmessage() call. The event will still be posted with a
+ * CANCELED result code.
+ *
+ * Requires:
+ *
+ *\li "tcpmsg" be valid.
+ */
+
+void
+dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer);
+/*%<
+ * If a dns buffer is to be kept between calls, this function marks the
+ * internal state-machine buffer as invalid, and copies all the contents
+ * of the state into "buffer".
+ *
+ * Requires:
+ *
+ *\li "tcpmsg" be valid.
+ *
+ *\li "buffer" be non-NULL.
+ */
+
+void
+dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg);
+/*%<
+ * Clean up all allocated state, and invalidate the structure.
+ *
+ * Requires:
+ *
+ *\li "tcpmsg" be valid.
+ *
+ * Ensures:
+ *
+ *\li "tcpmsg" is invalidated and disassociated with all memory contexts,
+ * sockets, etc.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_TCPMSG_H */
diff --git a/lib/dns/include/dns/time.h b/lib/dns/include/dns/time.h
new file mode 100644
index 0000000..9e8f5cc
--- /dev/null
+++ b/lib/dns/include/dns/time.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2004, 2005 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: time.h,v 1.11.18.2 2005/04/29 00:16:23 marka Exp $ */
+
+#ifndef DNS_TIME_H
+#define DNS_TIME_H 1
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/buffer.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+dns_time64_fromtext(const char *source, isc_int64_t *target);
+/*%<
+ * Convert a date and time in YYYYMMDDHHMMSS text format at 'source'
+ * into to a 64-bit count of seconds since Jan 1 1970 0:00 GMT.
+ * Store the count at 'target'.
+ */
+
+isc_result_t
+dns_time32_fromtext(const char *source, isc_uint32_t *target);
+/*%<
+ * Like dns_time64_fromtext, but returns the second count modulo 2^32
+ * as per RFC2535.
+ */
+
+
+isc_result_t
+dns_time64_totext(isc_int64_t value, isc_buffer_t *target);
+/*%<
+ * Convert a 64-bit count of seconds since Jan 1 1970 0:00 GMT into
+ * a YYYYMMDDHHMMSS text representation and append it to 'target'.
+ */
+
+isc_result_t
+dns_time32_totext(isc_uint32_t value, isc_buffer_t *target);
+/*%<
+ * Like dns_time64_totext, but for a 32-bit cyclic time value.
+ * Of those dates whose counts of seconds since Jan 1 1970 0:00 GMT
+ * are congruent with 'value' modulo 2^32, the one closest to the
+ * current date is chosen.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_TIME_H */
diff --git a/lib/dns/include/dns/timer.h b/lib/dns/include/dns/timer.h
new file mode 100644
index 0000000..cd936a0
--- /dev/null
+++ b/lib/dns/include/dns/timer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2004, 2005 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: timer.h,v 1.3.18.2 2005/04/29 00:16:23 marka Exp $ */
+
+#ifndef DNS_TIMER_H
+#define DNS_TIMER_H 1
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/buffer.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+dns_timer_setidle(isc_timer_t *timer, unsigned int maxtime,
+ unsigned int idletime, isc_boolean_t purge);
+/*%<
+ * Convenience function for setting up simple, one-second-granularity
+ * idle timers as used by zone transfers.
+ * \brief
+ * Set the timer 'timer' to go off after 'idletime' seconds of inactivity,
+ * or after 'maxtime' at the very latest. Events are purged iff
+ * 'purge' is ISC_TRUE.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_TIMER_H */
diff --git a/lib/dns/include/dns/tkey.h b/lib/dns/include/dns/tkey.h
new file mode 100644
index 0000000..4e3e80a
--- /dev/null
+++ b/lib/dns/include/dns/tkey.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2004, 2005 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: tkey.h,v 1.19.18.2 2005/04/29 00:16:23 marka Exp $ */
+
+#ifndef DNS_TKEY_H
+#define DNS_TKEY_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+#include <dst/dst.h>
+
+ISC_LANG_BEGINDECLS
+
+/* Key agreement modes */
+#define DNS_TKEYMODE_SERVERASSIGNED 1
+#define DNS_TKEYMODE_DIFFIEHELLMAN 2
+#define DNS_TKEYMODE_GSSAPI 3
+#define DNS_TKEYMODE_RESOLVERASSIGNED 4
+#define DNS_TKEYMODE_DELETE 5
+
+struct dns_tkeyctx {
+ dst_key_t *dhkey;
+ dns_name_t *domain;
+ void *gsscred;
+ isc_mem_t *mctx;
+ isc_entropy_t *ectx;
+};
+
+isc_result_t
+dns_tkeyctx_create(isc_mem_t *mctx, isc_entropy_t *ectx, dns_tkeyctx_t **tctxp);
+/*%<
+ * Create an empty TKEY context.
+ *
+ * Requires:
+ *\li 'mctx' is not NULL
+ *\li 'tctx' is not NULL
+ *\li '*tctx' is NULL
+ *
+ * Returns
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li return codes from dns_name_fromtext()
+ */
+
+void
+dns_tkeyctx_destroy(dns_tkeyctx_t **tctxp);
+/*%<
+ * Frees all data associated with the TKEY context
+ *
+ * Requires:
+ *\li 'tctx' is not NULL
+ *\li '*tctx' is not NULL
+ */
+
+isc_result_t
+dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx,
+ dns_tsig_keyring_t *ring);
+/*%<
+ * Processes a query containing a TKEY record, adding or deleting TSIG
+ * keys if necessary, and modifies the message to contain the response.
+ *
+ * Requires:
+ *\li 'msg' is a valid message
+ *\li 'tctx' is a valid TKEY context
+ *\li 'ring' is a valid TSIG keyring
+ *
+ * Returns
+ *\li #ISC_R_SUCCESS msg was updated (the TKEY operation succeeded,
+ * or msg now includes a TKEY with an error set)
+ * DNS_R_FORMERR the packet was malformed (missing a TKEY
+ * or KEY).
+ *\li other An error occurred while processing the message
+ */
+
+isc_result_t
+dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name,
+ dns_name_t *algorithm, isc_buffer_t *nonce,
+ isc_uint32_t lifetime);
+/*%<
+ * Builds a query containing a TKEY that will generate a shared
+ * secret using a Diffie-Hellman key exchange. The shared key
+ * will be of the specified algorithm (only DNS_TSIG_HMACMD5_NAME
+ * is supported), and will be named either 'name',
+ * 'name' + server chosen domain, or random data + server chosen domain
+ * if 'name' == dns_rootname. If nonce is not NULL, it supplies
+ * random data used in the shared secret computation. The key is
+ * requested to have the specified lifetime (in seconds)
+ *
+ *
+ * Requires:
+ *\li 'msg' is a valid message
+ *\li 'key' is a valid Diffie Hellman dst key
+ *\li 'name' is a valid name
+ *\li 'algorithm' is a valid name
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS msg was successfully updated to include the
+ * query to be sent
+ *\li other an error occurred while building the message
+ */
+
+isc_result_t
+dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name,
+ dns_name_t *gname, void *cred,
+ isc_uint32_t lifetime, void **context);
+/*%<
+ * XXX
+ */
+
+isc_result_t
+dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key);
+/*%<
+ * Builds a query containing a TKEY record that will delete the
+ * specified shared secret from the server.
+ *
+ * Requires:
+ *\li 'msg' is a valid message
+ *\li 'key' is a valid TSIG key
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS msg was successfully updated to include the
+ * query to be sent
+ *\li other an error occurred while building the message
+ */
+
+isc_result_t
+dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+ dst_key_t *key, isc_buffer_t *nonce,
+ dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring);
+/*%<
+ * Processes a response to a query containing a TKEY that was
+ * designed to generate a shared secret using a Diffie-Hellman key
+ * exchange. If the query was successful, a new shared key
+ * is created and added to the list of shared keys.
+ *
+ * Requires:
+ *\li 'qmsg' is a valid message (the query)
+ *\li 'rmsg' is a valid message (the response)
+ *\li 'key' is a valid Diffie Hellman dst key
+ *\li 'outkey' is either NULL or a pointer to NULL
+ *\li 'ring' is a valid keyring or NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS the shared key was successfully added
+ *\li #ISC_R_NOTFOUND an error occurred while looking for a
+ * component of the query or response
+ */
+
+isc_result_t
+dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+ dns_name_t *gname, void *cred, void **context,
+ dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring);
+/*%<
+ * XXX
+ */
+
+isc_result_t
+dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+ dns_tsig_keyring_t *ring);
+/*%<
+ * Processes a response to a query containing a TKEY that was
+ * designed to delete a shared secret. If the query was successful,
+ * the shared key is deleted from the list of shared keys.
+ *
+ * Requires:
+ *\li 'qmsg' is a valid message (the query)
+ *\li 'rmsg' is a valid message (the response)
+ *\li 'ring' is not NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS the shared key was successfully deleted
+ *\li #ISC_R_NOTFOUND an error occurred while looking for a
+ * component of the query or response
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_TKEY_H */
diff --git a/lib/dns/include/dns/tsig.h b/lib/dns/include/dns/tsig.h
new file mode 100644
index 0000000..b3fd6cc
--- /dev/null
+++ b/lib/dns/include/dns/tsig.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2004-2006 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: tsig.h,v 1.43.18.4 2006/01/27 23:57:44 marka Exp $ */
+
+#ifndef DNS_TSIG_H
+#define DNS_TSIG_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/refcount.h>
+#include <isc/rwlock.h>
+#include <isc/stdtime.h>
+
+#include <dns/types.h>
+#include <dns/name.h>
+
+#include <dst/dst.h>
+
+/*
+ * Algorithms.
+ */
+LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacmd5_name;
+#define DNS_TSIG_HMACMD5_NAME dns_tsig_hmacmd5_name
+LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_gssapi_name;
+#define DNS_TSIG_GSSAPI_NAME dns_tsig_gssapi_name
+LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_gssapims_name;
+#define DNS_TSIG_GSSAPIMS_NAME dns_tsig_gssapims_name
+LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha1_name;
+#define DNS_TSIG_HMACSHA1_NAME dns_tsig_hmacsha1_name
+LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha224_name;
+#define DNS_TSIG_HMACSHA224_NAME dns_tsig_hmacsha224_name
+LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha256_name;
+#define DNS_TSIG_HMACSHA256_NAME dns_tsig_hmacsha256_name
+LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha384_name;
+#define DNS_TSIG_HMACSHA384_NAME dns_tsig_hmacsha384_name
+LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha512_name;
+#define DNS_TSIG_HMACSHA512_NAME dns_tsig_hmacsha512_name
+
+/*%
+ * Default fudge value.
+ */
+#define DNS_TSIG_FUDGE 300
+
+struct dns_tsig_keyring {
+ dns_rbt_t *keys;
+ isc_rwlock_t lock;
+ isc_mem_t *mctx;
+};
+
+struct dns_tsigkey {
+ /* Unlocked */
+ unsigned int magic; /*%< Magic number. */
+ isc_mem_t *mctx;
+ dst_key_t *key; /*%< Key */
+ dns_name_t name; /*%< Key name */
+ dns_name_t *algorithm; /*%< Algorithm name */
+ dns_name_t *creator; /*%< name that created secret */
+ isc_boolean_t generated; /*%< was this generated? */
+ isc_stdtime_t inception; /*%< start of validity period */
+ isc_stdtime_t expire; /*%< end of validity period */
+ dns_tsig_keyring_t *ring; /*%< the enclosing keyring */
+ isc_refcount_t refs; /*%< reference counter */
+};
+
+#define dns_tsigkey_identity(tsigkey) \
+ ((tsigkey)->generated ? ((tsigkey)->creator) : (&((tsigkey)->name)))
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
+ unsigned char *secret, int length, isc_boolean_t generated,
+ dns_name_t *creator, isc_stdtime_t inception,
+ isc_stdtime_t expire, isc_mem_t *mctx,
+ dns_tsig_keyring_t *ring, dns_tsigkey_t **key);
+
+isc_result_t
+dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
+ dst_key_t *dstkey, isc_boolean_t generated,
+ dns_name_t *creator, isc_stdtime_t inception,
+ isc_stdtime_t expire, isc_mem_t *mctx,
+ dns_tsig_keyring_t *ring, dns_tsigkey_t **key);
+/*%<
+ * Creates a tsig key structure and saves it in the keyring. If key is
+ * not NULL, *key will contain a copy of the key. The keys validity
+ * period is specified by (inception, expire), and will not expire if
+ * inception == expire. If the key was generated, the creating identity,
+ * if there is one, should be in the creator parameter. Specifying an
+ * unimplemented algorithm will cause failure only if dstkey != NULL; this
+ * allows a transient key with an invalid algorithm to exist long enough
+ * to generate a BADKEY response.
+ *
+ * Requires:
+ *\li 'name' is a valid dns_name_t
+ *\li 'algorithm' is a valid dns_name_t
+ *\li 'secret' is a valid pointer
+ *\li 'length' is an integer >= 0
+ *\li 'key' is a valid dst key or NULL
+ *\li 'creator' points to a valid dns_name_t or is NULL
+ *\li 'mctx' is a valid memory context
+ *\li 'ring' is a valid TSIG keyring or NULL
+ *\li 'key' or '*key' must be NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_EXISTS - a key with this name already exists
+ *\li #ISC_R_NOTIMPLEMENTED - algorithm is not implemented
+ *\li #ISC_R_NOMEMORY
+ */
+
+void
+dns_tsigkey_attach(dns_tsigkey_t *source, dns_tsigkey_t **targetp);
+/*%<
+ * Attach '*targetp' to 'source'.
+ *
+ * Requires:
+ *\li 'key' is a valid TSIG key
+ *
+ * Ensures:
+ *\li *targetp is attached to source.
+ */
+
+void
+dns_tsigkey_detach(dns_tsigkey_t **keyp);
+/*%<
+ * Detaches from the tsig key structure pointed to by '*key'.
+ *
+ * Requires:
+ *\li 'keyp' is not NULL and '*keyp' is a valid TSIG key
+ *
+ * Ensures:
+ *\li 'keyp' points to NULL
+ */
+
+void
+dns_tsigkey_setdeleted(dns_tsigkey_t *key);
+/*%<
+ * Prevents this key from being used again. It will be deleted when
+ * no references exist.
+ *
+ * Requires:
+ *\li 'key' is a valid TSIG key on a keyring
+ */
+
+isc_result_t
+dns_tsig_sign(dns_message_t *msg);
+/*%<
+ * Generates a TSIG record for this message
+ *
+ * Requires:
+ *\li 'msg' is a valid message
+ *\li 'msg->tsigkey' is a valid TSIG key
+ *\li 'msg->tsig' is NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_NOSPACE
+ *\li #DNS_R_EXPECTEDTSIG
+ * - this is a response & msg->querytsig is NULL
+ */
+
+isc_result_t
+dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
+ dns_tsig_keyring_t *ring1, dns_tsig_keyring_t *ring2);
+/*%<
+ * Verifies the TSIG record in this message
+ *
+ * Requires:
+ *\li 'source' is a valid buffer containing the unparsed message
+ *\li 'msg' is a valid message
+ *\li 'msg->tsigkey' is a valid TSIG key if this is a response
+ *\li 'msg->tsig' is NULL
+ *\li 'msg->querytsig' is not NULL if this is a response
+ *\li 'ring1' and 'ring2' are each either a valid keyring or NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #DNS_R_EXPECTEDTSIG - A TSIG was expected but not seen
+ *\li #DNS_R_UNEXPECTEDTSIG - A TSIG was seen but not expected
+ *\li #DNS_R_TSIGERRORSET - the TSIG verified but ->error was set
+ * and this is a query
+ *\li #DNS_R_CLOCKSKEW - the TSIG failed to verify because of
+ * the time was out of the allowed range.
+ *\li #DNS_R_TSIGVERIFYFAILURE - the TSIG failed to verify
+ *\li #DNS_R_EXPECTEDRESPONSE - the message was set over TCP and
+ * should have been a response,
+ * but was not.
+ */
+
+isc_result_t
+dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
+ dns_name_t *algorithm, dns_tsig_keyring_t *ring);
+/*%<
+ * Returns the TSIG key corresponding to this name and (possibly)
+ * algorithm. Also increments the key's reference counter.
+ *
+ * Requires:
+ *\li 'tsigkey' is not NULL
+ *\li '*tsigkey' is NULL
+ *\li 'name' is a valid dns_name_t
+ *\li 'algorithm' is a valid dns_name_t or NULL
+ *\li 'ring' is a valid keyring
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOTFOUND
+ */
+
+
+isc_result_t
+dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp);
+/*%<
+ * Create an empty TSIG key ring.
+ *
+ * Requires:
+ *\li 'mctx' is not NULL
+ *\li 'ringp' is not NULL, and '*ringp' is NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+
+void
+dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp);
+/*%<
+ * Destroy a TSIG key ring.
+ *
+ * Requires:
+ *\li 'ringp' is not NULL
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_TSIG_H */
diff --git a/lib/dns/include/dns/ttl.h b/lib/dns/include/dns/ttl.h
new file mode 100644
index 0000000..ad01578
--- /dev/null
+++ b/lib/dns/include/dns/ttl.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2004, 2005 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: ttl.h,v 1.13.18.2 2005/04/29 00:16:24 marka Exp $ */
+
+#ifndef DNS_TTL_H
+#define DNS_TTL_H 1
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+dns_ttl_totext(isc_uint32_t src, isc_boolean_t verbose,
+ isc_buffer_t *target);
+/*%<
+ * Output a TTL or other time interval in a human-readable form.
+ * The time interval is given as a count of seconds in 'src'.
+ * The text representation is appended to 'target'.
+ *
+ * If 'verbose' is ISC_FALSE, use the terse BIND 8 style, like "1w2d3h4m5s".
+ *
+ * If 'verbose' is ISC_TRUE, use a verbose style like the SOA comments
+ * in "dig", like "1 week 2 days 3 hours 4 minutes 5 seconds".
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOSPACE
+ */
+
+isc_result_t
+dns_counter_fromtext(isc_textregion_t *source, isc_uint32_t *ttl);
+/*%<
+ * Converts a counter from either a plain number or a BIND 8 style value.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li DNS_R_SYNTAX
+ */
+
+isc_result_t
+dns_ttl_fromtext(isc_textregion_t *source, isc_uint32_t *ttl);
+/*%<
+ * Converts a ttl from either a plain number or a BIND 8 style value.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li DNS_R_BADTTL
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_TTL_H */
diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h
new file mode 100644
index 0000000..8dcbe57
--- /dev/null
+++ b/lib/dns/include/dns/types.h
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: types.h,v 1.109.18.12 2006/05/02 12:55:31 shane Exp $ */
+
+#ifndef DNS_TYPES_H
+#define DNS_TYPES_H 1
+
+/*! \file
+ * \brief
+ * Including this file gives you type declarations suitable for use in
+ * .h files, which lets us avoid circular type reference problems.
+ * \brief
+ * To actually use a type or get declarations of its methods, you must
+ * include the appropriate .h file too.
+ */
+
+#include <isc/types.h>
+
+typedef struct dns_acache dns_acache_t;
+typedef struct dns_acacheentry dns_acacheentry_t;
+typedef struct dns_acachestats dns_acachestats_t;
+typedef struct dns_acl dns_acl_t;
+typedef struct dns_aclelement dns_aclelement_t;
+typedef struct dns_aclenv dns_aclenv_t;
+typedef struct dns_adb dns_adb_t;
+typedef struct dns_adbaddrinfo dns_adbaddrinfo_t;
+typedef ISC_LIST(dns_adbaddrinfo_t) dns_adbaddrinfolist_t;
+typedef struct dns_adbentry dns_adbentry_t;
+typedef struct dns_adbfind dns_adbfind_t;
+typedef ISC_LIST(dns_adbfind_t) dns_adbfindlist_t;
+typedef struct dns_byaddr dns_byaddr_t;
+typedef struct dns_cache dns_cache_t;
+typedef isc_uint16_t dns_cert_t;
+typedef struct dns_compress dns_compress_t;
+typedef struct dns_db dns_db_t;
+typedef struct dns_dbimplementation dns_dbimplementation_t;
+typedef struct dns_dbiterator dns_dbiterator_t;
+typedef void dns_dbload_t;
+typedef void dns_dbnode_t;
+typedef struct dns_dbtable dns_dbtable_t;
+typedef void dns_dbversion_t;
+typedef struct dns_dlzimplementation dns_dlzimplementation_t;
+typedef struct dns_dlzdb dns_dlzdb_t;
+typedef struct dns_sdlzimplementation dns_sdlzimplementation_t;
+typedef struct dns_decompress dns_decompress_t;
+typedef struct dns_dispatch dns_dispatch_t;
+typedef struct dns_dispatchevent dns_dispatchevent_t;
+typedef struct dns_dispatchlist dns_dispatchlist_t;
+typedef struct dns_dispatchmgr dns_dispatchmgr_t;
+typedef struct dns_dispentry dns_dispentry_t;
+typedef struct dns_dumpctx dns_dumpctx_t;
+typedef struct dns_fetch dns_fetch_t;
+typedef struct dns_fixedname dns_fixedname_t;
+typedef struct dns_forwarders dns_forwarders_t;
+typedef struct dns_fwdtable dns_fwdtable_t;
+typedef isc_uint16_t dns_keyflags_t;
+typedef struct dns_keynode dns_keynode_t;
+typedef struct dns_keytable dns_keytable_t;
+typedef isc_uint16_t dns_keytag_t;
+typedef struct dns_loadctx dns_loadctx_t;
+typedef struct dns_loadmgr dns_loadmgr_t;
+typedef struct dns_message dns_message_t;
+typedef isc_uint16_t dns_messageid_t;
+typedef isc_region_t dns_label_t;
+typedef struct dns_lookup dns_lookup_t;
+typedef struct dns_name dns_name_t;
+typedef ISC_LIST(dns_name_t) dns_namelist_t;
+typedef isc_uint16_t dns_opcode_t;
+typedef unsigned char dns_offsets_t[128];
+typedef struct dns_order dns_order_t;
+typedef struct dns_peer dns_peer_t;
+typedef struct dns_peerlist dns_peerlist_t;
+typedef struct dns_portlist dns_portlist_t;
+typedef struct dns_rbt dns_rbt_t;
+typedef isc_uint16_t dns_rcode_t;
+typedef struct dns_rdata dns_rdata_t;
+typedef struct dns_rdatacallbacks dns_rdatacallbacks_t;
+typedef isc_uint16_t dns_rdataclass_t;
+typedef struct dns_rdatalist dns_rdatalist_t;
+typedef struct dns_rdataset dns_rdataset_t;
+typedef ISC_LIST(dns_rdataset_t) dns_rdatasetlist_t;
+typedef struct dns_rdatasetiter dns_rdatasetiter_t;
+typedef isc_uint16_t dns_rdatatype_t;
+typedef struct dns_request dns_request_t;
+typedef struct dns_requestmgr dns_requestmgr_t;
+typedef struct dns_resolver dns_resolver_t;
+typedef struct dns_sdbimplementation dns_sdbimplementation_t;
+typedef isc_uint8_t dns_secalg_t;
+typedef isc_uint8_t dns_secproto_t;
+typedef struct dns_signature dns_signature_t;
+typedef struct dns_ssurule dns_ssurule_t;
+typedef struct dns_ssutable dns_ssutable_t;
+typedef struct dns_tkeyctx dns_tkeyctx_t;
+typedef isc_uint16_t dns_trust_t;
+typedef struct dns_tsig_keyring dns_tsig_keyring_t;
+typedef struct dns_tsigkey dns_tsigkey_t;
+typedef isc_uint32_t dns_ttl_t;
+typedef struct dns_validator dns_validator_t;
+typedef struct dns_view dns_view_t;
+typedef ISC_LIST(dns_view_t) dns_viewlist_t;
+typedef struct dns_zone dns_zone_t;
+typedef ISC_LIST(dns_zone_t) dns_zonelist_t;
+typedef struct dns_zonemgr dns_zonemgr_t;
+typedef struct dns_zt dns_zt_t;
+
+typedef enum {
+ dns_fwdpolicy_none = 0,
+ dns_fwdpolicy_first = 1,
+ dns_fwdpolicy_only = 2
+} dns_fwdpolicy_t;
+
+typedef enum {
+ dns_namereln_none = 0,
+ dns_namereln_contains = 1,
+ dns_namereln_subdomain = 2,
+ dns_namereln_equal = 3,
+ dns_namereln_commonancestor = 4
+} dns_namereln_t;
+
+typedef enum {
+ dns_one_answer, dns_many_answers
+} dns_transfer_format_t;
+
+typedef enum {
+ dns_dbtype_zone = 0, dns_dbtype_cache = 1, dns_dbtype_stub = 3
+} dns_dbtype_t;
+
+typedef enum {
+ dns_notifytype_no = 0,
+ dns_notifytype_yes = 1,
+ dns_notifytype_explicit = 2,
+ dns_notifytype_masteronly = 3
+} dns_notifytype_t;
+
+typedef enum {
+ dns_dialuptype_no = 0,
+ dns_dialuptype_yes = 1,
+ dns_dialuptype_notify = 2,
+ dns_dialuptype_notifypassive = 3,
+ dns_dialuptype_refresh = 4,
+ dns_dialuptype_passive = 5
+} dns_dialuptype_t;
+
+typedef enum {
+ dns_masterformat_none = 0,
+ dns_masterformat_text = 1,
+ dns_masterformat_raw = 2
+} dns_masterformat_t;
+
+/*
+ * These are generated by gen.c.
+ */
+#include <dns/enumtype.h> /* Provides dns_rdatatype_t. */
+#include <dns/enumclass.h> /* Provides dns_rdataclass_t. */
+
+/*%
+ * rcodes.
+ */
+enum {
+ /*
+ * Standard rcodes.
+ */
+ dns_rcode_noerror = 0,
+#define dns_rcode_noerror ((dns_rcode_t)dns_rcode_noerror)
+ dns_rcode_formerr = 1,
+#define dns_rcode_formerr ((dns_rcode_t)dns_rcode_formerr)
+ dns_rcode_servfail = 2,
+#define dns_rcode_servfail ((dns_rcode_t)dns_rcode_servfail)
+ dns_rcode_nxdomain = 3,
+#define dns_rcode_nxdomain ((dns_rcode_t)dns_rcode_nxdomain)
+ dns_rcode_notimp = 4,
+#define dns_rcode_notimp ((dns_rcode_t)dns_rcode_notimp)
+ dns_rcode_refused = 5,
+#define dns_rcode_refused ((dns_rcode_t)dns_rcode_refused)
+ dns_rcode_yxdomain = 6,
+#define dns_rcode_yxdomain ((dns_rcode_t)dns_rcode_yxdomain)
+ dns_rcode_yxrrset = 7,
+#define dns_rcode_yxrrset ((dns_rcode_t)dns_rcode_yxrrset)
+ dns_rcode_nxrrset = 8,
+#define dns_rcode_nxrrset ((dns_rcode_t)dns_rcode_nxrrset)
+ dns_rcode_notauth = 9,
+#define dns_rcode_notauth ((dns_rcode_t)dns_rcode_notauth)
+ dns_rcode_notzone = 10,
+#define dns_rcode_notzone ((dns_rcode_t)dns_rcode_notzone)
+ /*
+ * Extended rcodes.
+ */
+ dns_rcode_badvers = 16
+#define dns_rcode_badvers ((dns_rcode_t)dns_rcode_badvers)
+};
+
+/*%
+ * TSIG errors.
+ */
+enum {
+ dns_tsigerror_badsig = 16,
+ dns_tsigerror_badkey = 17,
+ dns_tsigerror_badtime = 18,
+ dns_tsigerror_badmode = 19,
+ dns_tsigerror_badname = 20,
+ dns_tsigerror_badalg = 21,
+ dns_tsigerror_badtrunc = 22
+};
+
+/*%
+ * Opcodes.
+ */
+enum {
+ dns_opcode_query = 0,
+#define dns_opcode_query ((dns_opcode_t)dns_opcode_query)
+ dns_opcode_iquery = 1,
+#define dns_opcode_iquery ((dns_opcode_t)dns_opcode_iquery)
+ dns_opcode_status = 2,
+#define dns_opcode_status ((dns_opcode_t)dns_opcode_status)
+ dns_opcode_notify = 4,
+#define dns_opcode_notify ((dns_opcode_t)dns_opcode_notify)
+ dns_opcode_update = 5 /* dynamic update */
+#define dns_opcode_update ((dns_opcode_t)dns_opcode_update)
+};
+
+/*%
+ * Trust levels. Must be kept in sync with trustnames[] in masterdump.c.
+ */
+enum {
+ /* Sentinel value; no data should have this trust level. */
+ dns_trust_none = 0,
+#define dns_trust_none ((dns_trust_t)dns_trust_none)
+
+ /*% Subject to DNSSEC validation but has not yet been validated */
+ dns_trust_pending = 1,
+#define dns_trust_pending ((dns_trust_t)dns_trust_pending)
+
+ /*% Received in the additional section of a response. */
+ dns_trust_additional = 2,
+#define dns_trust_additional ((dns_trust_t)dns_trust_additional)
+
+ /* Received in a referral response. */
+ dns_trust_glue = 3,
+#define dns_trust_glue ((dns_trust_t)dns_trust_glue)
+
+ /* Answser from a non-authoritative server */
+ dns_trust_answer = 4,
+#define dns_trust_answer ((dns_trust_t)dns_trust_answer)
+
+ /* Received in the authority section as part of an
+ authoritative response */
+ dns_trust_authauthority = 5,
+#define dns_trust_authauthority ((dns_trust_t)dns_trust_authauthority)
+
+ /* Answser from an authoritative server */
+ dns_trust_authanswer = 6,
+#define dns_trust_authanswer ((dns_trust_t)dns_trust_authanswer)
+
+ /* Successfully DNSSEC validated */
+ dns_trust_secure = 7,
+#define dns_trust_secure ((dns_trust_t)dns_trust_secure)
+
+ /* This server is authoritative */
+ dns_trust_ultimate = 8
+#define dns_trust_ultimate ((dns_trust_t)dns_trust_ultimate)
+};
+
+/*%
+ * Name checking severites.
+ */
+typedef enum {
+ dns_severity_ignore,
+ dns_severity_warn,
+ dns_severity_fail
+} dns_severity_t;
+
+/*
+ * Functions.
+ */
+typedef void
+(*dns_dumpdonefunc_t)(void *, isc_result_t);
+
+typedef void
+(*dns_loaddonefunc_t)(void *, isc_result_t);
+
+typedef isc_result_t
+(*dns_addrdatasetfunc_t)(void *, dns_name_t *, dns_rdataset_t *);
+
+typedef isc_result_t
+(*dns_additionaldatafunc_t)(void *, dns_name_t *, dns_rdatatype_t);
+
+typedef isc_result_t
+(*dns_digestfunc_t)(void *, isc_region_t *);
+
+typedef void
+(*dns_xfrindone_t)(dns_zone_t *, isc_result_t);
+
+typedef void
+(*dns_updatecallback_t)(void *, isc_result_t, dns_message_t *);
+
+typedef int
+(*dns_rdatasetorderfunc_t)(const dns_rdata_t *, const void *);
+
+typedef isc_boolean_t
+(*dns_checkmxfunc_t)(dns_zone_t *, dns_name_t *, dns_name_t *);
+
+typedef isc_boolean_t
+(*dns_checksrvfunc_t)(dns_zone_t *, dns_name_t *, dns_name_t *);
+
+typedef isc_boolean_t
+(*dns_checknsfunc_t)(dns_zone_t *, dns_name_t *, dns_name_t *,
+ dns_rdataset_t *, dns_rdataset_t *);
+
+typedef isc_boolean_t
+(*dns_isselffunc_t)(dns_view_t *, dns_tsigkey_t *, isc_sockaddr_t *,
+ isc_sockaddr_t *, dns_rdataclass_t, void *);
+
+#endif /* DNS_TYPES_H */
diff --git a/lib/dns/include/dns/validator.h b/lib/dns/include/dns/validator.h
new file mode 100644
index 0000000..c94fc3a
--- /dev/null
+++ b/lib/dns/include/dns/validator.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: validator.h,v 1.27.18.10 2007/09/26 04:39:45 each Exp $ */
+
+#ifndef DNS_VALIDATOR_H
+#define DNS_VALIDATOR_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ *
+ * \brief
+ * DNS Validator
+ * This is the BIND 9 validator, the module responsible for validating the
+ * rdatasets and negative responses (messages). It makes use of zones in
+ * the view and may fetch RRset to complete trust chains. It implements
+ * DNSSEC as specified in RFC 4033, 4034 and 4035.
+ *
+ * It can also optionally implement ISC's DNSSEC look-aside validation.
+ *
+ * Correct operation is critical to preventing spoofed answers from secure
+ * zones being accepted.
+ *
+ * MP:
+ *\li The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li RFCs: 1034, 1035, 2181, 4033, 4034, 4035.
+ */
+
+#include <isc/lang.h>
+#include <isc/event.h>
+#include <isc/mutex.h>
+
+#include <dns/fixedname.h>
+#include <dns/types.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h> /* for dns_rdata_rrsig_t */
+
+#include <dst/dst.h>
+
+/*%
+ * A dns_validatorevent_t is sent when a 'validation' completes.
+ * \brief
+ * 'name', 'rdataset', 'sigrdataset', and 'message' are the values that were
+ * supplied when dns_validator_create() was called. They are returned to the
+ * caller so that they may be freed.
+ *
+ * If the RESULT is ISC_R_SUCCESS and the answer is secure then
+ * proofs[] will contain the the names of the NSEC records that hold the
+ * various proofs. Note the same name may appear multiple times.
+ */
+typedef struct dns_validatorevent {
+ ISC_EVENT_COMMON(struct dns_validatorevent);
+ dns_validator_t * validator;
+ isc_result_t result;
+ /*
+ * Name and type of the response to be validated.
+ */
+ dns_name_t * name;
+ dns_rdatatype_t type;
+ /*
+ * Rdata and RRSIG (if any) for positive responses.
+ */
+ dns_rdataset_t * rdataset;
+ dns_rdataset_t * sigrdataset;
+ /*
+ * The full response. Required for negative responses.
+ * Also required for positive wildcard responses.
+ */
+ dns_message_t * message;
+ /*
+ * Proofs to be cached.
+ */
+ dns_name_t * proofs[3];
+} dns_validatorevent_t;
+
+#define DNS_VALIDATOR_NOQNAMEPROOF 0
+#define DNS_VALIDATOR_NODATAPROOF 1
+#define DNS_VALIDATOR_NOWILDCARDPROOF 2
+
+/*%
+ * A validator object represents a validation in progress.
+ * \brief
+ * Clients are strongly discouraged from using this type directly, with
+ * the exception of the 'link' field, which may be used directly for
+ * whatever purpose the client desires.
+ */
+struct dns_validator {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mutex_t lock;
+ dns_view_t * view;
+ /* Locked by lock. */
+ unsigned int options;
+ unsigned int attributes;
+ dns_validatorevent_t * event;
+ dns_fetch_t * fetch;
+ dns_validator_t * subvalidator;
+ dns_validator_t * parent;
+ dns_keytable_t * keytable;
+ dns_keynode_t * keynode;
+ dst_key_t * key;
+ dns_rdata_rrsig_t * siginfo;
+ isc_task_t * task;
+ isc_taskaction_t action;
+ void * arg;
+ unsigned int labels;
+ dns_rdataset_t * currentset;
+ isc_boolean_t seensig;
+ dns_rdataset_t * keyset;
+ dns_rdataset_t * dsset;
+ dns_rdataset_t * soaset;
+ dns_rdataset_t * nsecset;
+ dns_name_t * soaname;
+ dns_rdataset_t frdataset;
+ dns_rdataset_t fsigrdataset;
+ dns_fixedname_t fname;
+ dns_fixedname_t wild;
+ ISC_LINK(dns_validator_t) link;
+ dns_rdataset_t dlv;
+ dns_fixedname_t dlvsep;
+ isc_boolean_t havedlvsep;
+ isc_boolean_t mustbesecure;
+ unsigned int dlvlabels;
+ unsigned int depth;
+};
+
+/*%
+ * dns_validator_create() options.
+ */
+#define DNS_VALIDATOR_DLV 1U
+#define DNS_VALIDATOR_DEFER 2U
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
+ dns_message_t *message, unsigned int options,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_validator_t **validatorp);
+/*%<
+ * Start a DNSSEC validation.
+ *
+ * This validates a response to the question given by
+ * 'name' and 'type'.
+ *
+ * To validate a positive response, the response data is
+ * given by 'rdataset' and 'sigrdataset'. If 'sigrdataset'
+ * is NULL, the data is presumed insecure and an attempt
+ * is made to prove its insecurity by finding the appropriate
+ * null key.
+ *
+ * The complete response message may be given in 'message',
+ * to make available any authority section NSECs that may be
+ * needed for validation of a response resulting from a
+ * wildcard expansion (though no such wildcard validation
+ * is implemented yet). If the complete response message
+ * is not available, 'message' is NULL.
+ *
+ * To validate a negative response, the complete negative response
+ * message is given in 'message'. The 'rdataset', and
+ * 'sigrdataset' arguments must be NULL, but the 'name' and 'type'
+ * arguments must be provided.
+ *
+ * The validation is performed in the context of 'view'.
+ *
+ * When the validation finishes, a dns_validatorevent_t with
+ * the given 'action' and 'arg' are sent to 'task'.
+ * Its 'result' field will be ISC_R_SUCCESS iff the
+ * response was successfully proven to be either secure or
+ * part of a known insecure domain.
+ *
+ * options:
+ * If DNS_VALIDATOR_DLV is set the caller knows there is not a
+ * trusted key and the validator should immediately attempt to validate
+ * the answer by looking for a appopriate DLV RRset.
+ */
+
+void
+dns_validator_send(dns_validator_t *validator);
+/*%<
+ * Send a deferred validation request
+ *
+ * Requires:
+ * 'validator' to points to a valid DNSSEC validator.
+ */
+
+void
+dns_validator_cancel(dns_validator_t *validator);
+/*%<
+ * Cancel a DNSSEC validation in progress.
+ *
+ * Requires:
+ *\li 'validator' points to a valid DNSSEC validator, which
+ * may or may not already have completed.
+ *
+ * Ensures:
+ *\li It the validator has not already sent its completion
+ * event, it will send it with result code ISC_R_CANCELED.
+ */
+
+void
+dns_validator_destroy(dns_validator_t **validatorp);
+/*%<
+ * Destroy a DNSSEC validator.
+ *
+ * Requires:
+ *\li '*validatorp' points to a valid DNSSEC validator.
+ * \li The validator must have completed and sent its completion
+ * event.
+ *
+ * Ensures:
+ *\li All resources used by the validator are freed.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_VALIDATOR_H */
diff --git a/lib/dns/include/dns/version.h b/lib/dns/include/dns/version.h
new file mode 100644
index 0000000..bb254534
--- /dev/null
+++ b/lib/dns/include/dns/version.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005 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: version.h,v 1.3.18.2 2005/04/29 00:16:25 marka Exp $ */
+
+/*! \file */
+
+#include <isc/platform.h>
+
+LIBDNS_EXTERNAL_DATA extern const char dns_version[];
+
+LIBDNS_EXTERNAL_DATA extern const unsigned int dns_libinterface;
+LIBDNS_EXTERNAL_DATA extern const unsigned int dns_librevision;
+LIBDNS_EXTERNAL_DATA extern const unsigned int dns_libage;
diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h
new file mode 100644
index 0000000..ea3d4c7
--- /dev/null
+++ b/lib/dns/include/dns/view.h
@@ -0,0 +1,804 @@
+/*
+ * Copyright (C) 2004-2006 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: view.h,v 1.91.18.9 2006/03/09 23:38:21 marka Exp $ */
+
+#ifndef DNS_VIEW_H
+#define DNS_VIEW_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * DNS View
+ *
+ * A "view" is a DNS namespace, together with an optional resolver and a
+ * forwarding policy. A "DNS namespace" is a (possibly empty) set of
+ * authoritative zones together with an optional cache and optional
+ * "hints" information.
+ *
+ * Views start out "unfrozen". In this state, core attributes like
+ * the cache, set of zones, and forwarding policy may be set. While
+ * "unfrozen", the caller (e.g. nameserver configuration loading
+ * code), must ensure exclusive access to the view. When the view is
+ * "frozen", the core attributes become immutable, and the view module
+ * will ensure synchronization. Freezing allows the view's core attributes
+ * to be accessed without locking.
+ *
+ * MP:
+ *\li Before the view is frozen, the caller must ensure synchronization.
+ *
+ *\li After the view is frozen, the module guarantees appropriate
+ * synchronization of any data structures it creates and manipulates.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li None.
+ */
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/event.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/refcount.h>
+#include <isc/rwlock.h>
+#include <isc/stdtime.h>
+
+#include <dns/acl.h>
+#include <dns/fixedname.h>
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+struct dns_view {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ dns_rdataclass_t rdclass;
+ char * name;
+ dns_zt_t * zonetable;
+ dns_dlzdb_t * dlzdatabase;
+ dns_resolver_t * resolver;
+ dns_adb_t * adb;
+ dns_requestmgr_t * requestmgr;
+ dns_acache_t * acache;
+ dns_cache_t * cache;
+ dns_db_t * cachedb;
+ dns_db_t * hints;
+ dns_keytable_t * secroots;
+ dns_keytable_t * trustedkeys;
+ isc_mutex_t lock;
+ isc_boolean_t frozen;
+ isc_task_t * task;
+ isc_event_t resevent;
+ isc_event_t adbevent;
+ isc_event_t reqevent;
+ /* Configurable data. */
+ dns_tsig_keyring_t * statickeys;
+ dns_tsig_keyring_t * dynamickeys;
+ dns_peerlist_t * peers;
+ dns_order_t * order;
+ dns_fwdtable_t * fwdtable;
+ isc_boolean_t recursion;
+ isc_boolean_t auth_nxdomain;
+ isc_boolean_t additionalfromcache;
+ isc_boolean_t additionalfromauth;
+ isc_boolean_t minimalresponses;
+ isc_boolean_t enablednssec;
+ isc_boolean_t enablevalidation;
+ isc_boolean_t acceptexpired;
+ dns_transfer_format_t transfer_format;
+ dns_acl_t * queryacl;
+ dns_acl_t * recursionacl;
+ dns_acl_t * sortlist;
+ isc_boolean_t requestixfr;
+ isc_boolean_t provideixfr;
+ dns_ttl_t maxcachettl;
+ dns_ttl_t maxncachettl;
+ in_port_t dstport;
+ dns_aclenv_t aclenv;
+ dns_rdatatype_t preferred_glue;
+ isc_boolean_t flush;
+ dns_namelist_t * delonly;
+ isc_boolean_t rootdelonly;
+ dns_namelist_t * rootexclude;
+ isc_boolean_t checknames;
+ dns_name_t * dlv;
+ dns_fixedname_t dlv_fixed;
+ isc_uint16_t maxudp;
+
+ /*
+ * Configurable data for server use only,
+ * locked by server configuration lock.
+ */
+ dns_acl_t * matchclients;
+ dns_acl_t * matchdestinations;
+ isc_boolean_t matchrecursiveonly;
+
+ /* Locked by themselves. */
+ isc_refcount_t references;
+
+ /* Locked by lock. */
+ unsigned int weakrefs;
+ unsigned int attributes;
+ /* Under owner's locking control. */
+ ISC_LINK(struct dns_view) link;
+};
+
+#define DNS_VIEW_MAGIC ISC_MAGIC('V','i','e','w')
+#define DNS_VIEW_VALID(view) ISC_MAGIC_VALID(view, DNS_VIEW_MAGIC)
+
+#define DNS_VIEWATTR_RESSHUTDOWN 0x01
+#define DNS_VIEWATTR_ADBSHUTDOWN 0x02
+#define DNS_VIEWATTR_REQSHUTDOWN 0x04
+
+isc_result_t
+dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
+ const char *name, dns_view_t **viewp);
+/*%<
+ * Create a view.
+ *
+ * Notes:
+ *
+ *\li The newly created view has no cache, no resolver, and an empty
+ * zone table. The view is not frozen.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li 'rdclass' is a valid class.
+ *
+ *\li 'name' is a valid C string.
+ *
+ *\li viewp != NULL && *viewp == NULL
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *
+ *\li Other errors are possible.
+ */
+
+void
+dns_view_attach(dns_view_t *source, dns_view_t **targetp);
+/*%<
+ * Attach '*targetp' to 'source'.
+ *
+ * Requires:
+ *
+ *\li 'source' is a valid, frozen view.
+ *
+ *\li 'targetp' points to a NULL dns_view_t *.
+ *
+ * Ensures:
+ *
+ *\li *targetp is attached to source.
+ *
+ *\li While *targetp is attached, the view will not shut down.
+ */
+
+void
+dns_view_detach(dns_view_t **viewp);
+/*%<
+ * Detach '*viewp' from its view.
+ *
+ * Requires:
+ *
+ *\li 'viewp' points to a valid dns_view_t *
+ *
+ * Ensures:
+ *
+ *\li *viewp is NULL.
+ */
+
+void
+dns_view_flushanddetach(dns_view_t **viewp);
+/*%<
+ * Detach '*viewp' from its view. If this was the last reference
+ * uncommited changed in zones will be flushed to disk.
+ *
+ * Requires:
+ *
+ *\li 'viewp' points to a valid dns_view_t *
+ *
+ * Ensures:
+ *
+ *\li *viewp is NULL.
+ */
+
+void
+dns_view_weakattach(dns_view_t *source, dns_view_t **targetp);
+/*%<
+ * Weakly attach '*targetp' to 'source'.
+ *
+ * Requires:
+ *
+ *\li 'source' is a valid, frozen view.
+ *
+ *\li 'targetp' points to a NULL dns_view_t *.
+ *
+ * Ensures:
+ *
+ *\li *targetp is attached to source.
+ *
+ * \li While *targetp is attached, the view will not be freed.
+ */
+
+void
+dns_view_weakdetach(dns_view_t **targetp);
+/*%<
+ * Detach '*viewp' from its view.
+ *
+ * Requires:
+ *
+ *\li 'viewp' points to a valid dns_view_t *.
+ *
+ * Ensures:
+ *
+ *\li *viewp is NULL.
+ */
+
+isc_result_t
+dns_view_createresolver(dns_view_t *view,
+ isc_taskmgr_t *taskmgr, unsigned int ntasks,
+ isc_socketmgr_t *socketmgr,
+ isc_timermgr_t *timermgr,
+ unsigned int options,
+ dns_dispatchmgr_t *dispatchmgr,
+ dns_dispatch_t *dispatchv4,
+ dns_dispatch_t *dispatchv6);
+/*%<
+ * Create a resolver and address database for the view.
+ *
+ * Requires:
+ *
+ *\li 'view' is a valid, unfrozen view.
+ *
+ *\li 'view' does not have a resolver already.
+ *
+ *\li The requirements of dns_resolver_create() apply to 'taskmgr',
+ * 'ntasks', 'socketmgr', 'timermgr', 'options', 'dispatchv4', and
+ * 'dispatchv6'.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *
+ *\li Any error that dns_resolver_create() can return.
+ */
+
+void
+dns_view_setcache(dns_view_t *view, dns_cache_t *cache);
+/*%<
+ * Set the view's cache database.
+ *
+ * Requires:
+ *
+ *\li 'view' is a valid, unfrozen view.
+ *
+ *\li 'cache' is a valid cache.
+ *
+ * Ensures:
+ *
+ * \li The cache of 'view' is 'cached.
+ *
+ *\li If this is not the first call to dns_view_setcache() for this
+ * view, then previously set cache is detached.
+ */
+
+void
+dns_view_sethints(dns_view_t *view, dns_db_t *hints);
+/*%<
+ * Set the view's hints database.
+ *
+ * Requires:
+ *
+ *\li 'view' is a valid, unfrozen view, whose hints database has not been
+ * set.
+ *
+ *\li 'hints' is a valid zone database.
+ *
+ * Ensures:
+ *
+ * \li The hints database of 'view' is 'hints'.
+ */
+
+void
+dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring);
+/*%<
+ * Set the view's static TSIG keys
+ *
+ * Requires:
+ *
+ * \li 'view' is a valid, unfrozen view, whose static TSIG keyring has not
+ * been set.
+ *
+ *\li 'ring' is a valid TSIG keyring
+ *
+ * Ensures:
+ *
+ *\li The static TSIG keyring of 'view' is 'ring'.
+ */
+
+void
+dns_view_setdstport(dns_view_t *view, in_port_t dstport);
+/*%<
+ * Set the view's destination port. This is the port to
+ * which outgoing queries are sent. The default is 53,
+ * the standard DNS port.
+ *
+ * Requires:
+ *
+ *\li 'view' is a valid view.
+ *
+ *\li 'dstport' is a valid TCP/UDP port number.
+ *
+ * Ensures:
+ *\li External name servers will be assumed to be listning
+ * on 'dstport'. For servers whose address has already
+ * obtained obtained at the time of the call, the view may
+ * continue to use the previously set port until the address
+ * times out from the view's address database.
+ */
+
+
+isc_result_t
+dns_view_addzone(dns_view_t *view, dns_zone_t *zone);
+/*%<
+ * Add zone 'zone' to 'view'.
+ *
+ * Requires:
+ *
+ *\li 'view' is a valid, unfrozen view.
+ *
+ *\li 'zone' is a valid zone.
+ */
+
+void
+dns_view_freeze(dns_view_t *view);
+/*%<
+ * Freeze view.
+ *
+ * Requires:
+ *
+ *\li 'view' is a valid, unfrozen view.
+ *
+ * Ensures:
+ *
+ *\li 'view' is frozen.
+ */
+
+isc_result_t
+dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
+ isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
+ dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
+/*%<
+ * Find an rdataset whose owner name is 'name', and whose type is
+ * 'type'.
+ *
+ * Notes:
+ *
+ *\li See the description of dns_db_find() for information about 'options'.
+ * If the caller sets #DNS_DBFIND_GLUEOK, it must ensure that 'name'
+ * and 'type' are appropriate for glue retrieval.
+ *
+ *\li If 'now' is zero, then the current time will be used.
+ *
+ *\li If 'use_hints' is ISC_TRUE, and the view has a hints database, then
+ * it will be searched last. If the answer is found in the hints
+ * database, the result code will be DNS_R_HINT. If the name is found
+ * in the hints database but not the type, the result code will be
+ * #DNS_R_HINTNXRRSET.
+ *
+ *\li 'foundname' must meet the requirements of dns_db_find().
+ *
+ *\li If 'sigrdataset' is not NULL, and there is a SIG rdataset which
+ * covers 'type', then 'sigrdataset' will be bound to it.
+ *
+ * Requires:
+ *
+ *\li 'view' is a valid, frozen view.
+ *
+ *\li 'name' is valid name.
+ *
+ *\li 'type' is a valid dns_rdatatype_t, and is not a meta query type
+ * except dns_rdatatype_any.
+ *
+ *\li dbp == NULL || *dbp == NULL
+ *
+ *\li nodep == NULL || *nodep == NULL. If nodep != NULL, dbp != NULL.
+ *
+ *\li 'foundname' is a valid name with a dedicated buffer or NULL.
+ *
+ *\li 'rdataset' is a valid, disassociated rdataset.
+ *
+ *\li 'sigrdataset' is NULL, or is a valid, disassociated rdataset.
+ *
+ * Ensures:
+ *
+ *\li In successful cases, 'rdataset', and possibly 'sigrdataset', are
+ * bound to the found data.
+ *
+ *\li If dbp != NULL, it points to the database containing the data.
+ *
+ *\li If nodep != NULL, it points to the database node containing the data.
+ *
+ *\li If foundname != NULL, it contains the full name of the found data.
+ *
+ * Returns:
+ *
+ *\li Any result that dns_db_find() can return, with the exception of
+ * #DNS_R_DELEGATION.
+ */
+
+isc_result_t
+dns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
+ isc_stdtime_t now, unsigned int options,
+ isc_boolean_t use_hints,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
+/*%<
+ * Find an rdataset whose owner name is 'name', and whose type is
+ * 'type'.
+ *
+ * Notes:
+ *
+ *\li This routine is appropriate for simple, exact-match queries of the
+ * view. 'name' must be a canonical name; there is no DNAME or CNAME
+ * processing.
+ *
+ *\li See the description of dns_db_find() for information about 'options'.
+ * If the caller sets DNS_DBFIND_GLUEOK, it must ensure that 'name'
+ * and 'type' are appropriate for glue retrieval.
+ *
+ *\li If 'now' is zero, then the current time will be used.
+ *
+ *\li If 'use_hints' is ISC_TRUE, and the view has a hints database, then
+ * it will be searched last. If the answer is found in the hints
+ * database, the result code will be DNS_R_HINT. If the name is found
+ * in the hints database but not the type, the result code will be
+ * DNS_R_HINTNXRRSET.
+ *
+ *\li If 'sigrdataset' is not NULL, and there is a SIG rdataset which
+ * covers 'type', then 'sigrdataset' will be bound to it.
+ *
+ * Requires:
+ *
+ *\li 'view' is a valid, frozen view.
+ *
+ *\li 'name' is valid name.
+ *
+ *\li 'type' is a valid dns_rdatatype_t, and is not a meta query type
+ * (e.g. dns_rdatatype_any), or dns_rdatatype_rrsig.
+ *
+ *\li 'rdataset' is a valid, disassociated rdataset.
+ *
+ *\li 'sigrdataset' is NULL, or is a valid, disassociated rdataset.
+ *
+ * Ensures:
+ *
+ *\li In successful cases, 'rdataset', and possibly 'sigrdataset', are
+ * bound to the found data.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS Success; result is desired type.
+ *\li DNS_R_GLUE Success; result is glue.
+ *\li DNS_R_HINT Success; result is a hint.
+ *\li DNS_R_NCACHENXDOMAIN Success; result is a ncache entry.
+ *\li DNS_R_NCACHENXRRSET Success; result is a ncache entry.
+ *\li DNS_R_NXDOMAIN The name does not exist.
+ *\li DNS_R_NXRRSET The rrset does not exist.
+ *\li #ISC_R_NOTFOUND No matching data found,
+ * or an error occurred.
+ */
+
+/*% See dns_view_findzonecut2() */
+isc_result_t
+dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
+ isc_stdtime_t now, unsigned int options,
+ isc_boolean_t use_hints,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
+
+isc_result_t
+dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
+ isc_stdtime_t now, unsigned int options,
+ isc_boolean_t use_hints, isc_boolean_t use_cache,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
+/*%<
+ * Find the best known zonecut containing 'name'.
+ *
+ * This uses local authority, cache, and optionally hints data.
+ * No external queries are performed.
+ *
+ * Notes:
+ *
+ *\li If 'now' is zero, then the current time will be used.
+ *
+ *\li If 'use_hints' is ISC_TRUE, and the view has a hints database, then
+ * it will be searched last.
+ *
+ *\li If 'use_cache' is ISC_TRUE, and the view has a cache, then it will be
+ * searched.
+ *
+ *\li If 'sigrdataset' is not NULL, and there is a SIG rdataset which
+ * covers 'type', then 'sigrdataset' will be bound to it.
+ *
+ *\li If the DNS_DBFIND_NOEXACT option is set, then the zonecut returned
+ * (if any) will be the deepest known ancestor of 'name'.
+ *
+ * Requires:
+ *
+ *\li 'view' is a valid, frozen view.
+ *
+ *\li 'name' is valid name.
+ *
+ *\li 'rdataset' is a valid, disassociated rdataset.
+ *
+ *\li 'sigrdataset' is NULL, or is a valid, disassociated rdataset.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS Success.
+ *
+ *\li Many other results are possible.
+ */
+
+isc_result_t
+dns_viewlist_find(dns_viewlist_t *list, const char *name,
+ dns_rdataclass_t rdclass, dns_view_t **viewp);
+/*%<
+ * Search for a view with name 'name' and class 'rdclass' in 'list'.
+ * If found, '*viewp' is (strongly) attached to it.
+ *
+ * Requires:
+ *
+ *\li 'viewp' points to a NULL dns_view_t *.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS A matching view was found.
+ *\li #ISC_R_NOTFOUND No matching view was found.
+ */
+
+isc_result_t
+dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep);
+/*%<
+ * Search for the zone 'name' in the zone table of 'view'.
+ * If found, 'zonep' is (strongly) attached to it. There
+ * are no partial matches.
+ *
+ * Requires:
+ *
+ *\li 'zonep' points to a NULL dns_zone_t *.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS A matching zone was found.
+ *\li #ISC_R_NOTFOUND No matching zone was found.
+ *\li others An error occurred.
+ */
+
+isc_result_t
+dns_view_load(dns_view_t *view, isc_boolean_t stop);
+
+isc_result_t
+dns_view_loadnew(dns_view_t *view, isc_boolean_t stop);
+/*%<
+ * Load zones attached to this view. dns_view_load() loads
+ * all zones whose master file has changed since the last
+ * load; dns_view_loadnew() loads only zones that have never
+ * been loaded.
+ *
+ * If 'stop' is ISC_TRUE, stop on the first error and return it.
+ * If 'stop' is ISC_FALSE, ignore errors.
+ *
+ * Requires:
+ *
+ *\li 'view' is valid.
+ */
+
+isc_result_t
+dns_view_gettsig(dns_view_t *view, dns_name_t *keyname,
+ dns_tsigkey_t **keyp);
+/*%<
+ * Find the TSIG key configured in 'view' with name 'keyname',
+ * if any.
+ *
+ * Reqires:
+ *\li keyp points to a NULL dns_tsigkey_t *.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS A key was found and '*keyp' now points to it.
+ *\li #ISC_R_NOTFOUND No key was found.
+ *\li others An error occurred.
+ */
+
+isc_result_t
+dns_view_getpeertsig(dns_view_t *view, isc_netaddr_t *peeraddr,
+ dns_tsigkey_t **keyp);
+/*%<
+ * Find the TSIG key configured in 'view' for the server whose
+ * address is 'peeraddr', if any.
+ *
+ * Reqires:
+ * keyp points to a NULL dns_tsigkey_t *.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS A key was found and '*keyp' now points to it.
+ *\li #ISC_R_NOTFOUND No key was found.
+ *\li others An error occurred.
+ */
+
+isc_result_t
+dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg);
+/*%<
+ * Verifies the signature of a message.
+ *
+ * Requires:
+ *
+ *\li 'view' is a valid view.
+ *\li 'source' is a valid buffer containing the message
+ *\li 'msg' is a valid message
+ *
+ * Returns:
+ *\li see dns_tsig_verify()
+ */
+
+void
+dns_view_dialup(dns_view_t *view);
+/*%<
+ * Perform dialup-time maintenance on the zones of 'view'.
+ */
+
+isc_result_t
+dns_view_dumpdbtostream(dns_view_t *view, FILE *fp);
+/*%<
+ * Dump the current state of the view 'view' to the stream 'fp'
+ * for purposes of analysis or debugging.
+ *
+ * Currently the dumped state includes the view's cache; in the future
+ * it may also include other state such as the address database.
+ * It will not not include authoritative data since it is voluminous and
+ * easily obtainable by other means.
+ *
+ * Requires:
+ *
+ *\li 'view' is valid.
+ *
+ *\li 'fp' refers to a file open for writing.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS The cache was successfully dumped.
+ * \li others An error occurred (see dns_master_dump)
+ */
+
+isc_result_t
+dns_view_flushcache(dns_view_t *view);
+/*%<
+ * Flush the view's cache (and ADB).
+ *
+ * Requires:
+ * 'view' is valid.
+ *
+ * No other tasks are executing.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_view_flushname(dns_view_t *view, dns_name_t *);
+/*%<
+ * Flush the given name from the view's cache (and ADB).
+ *
+ * Requires:
+ *\li 'view' is valid.
+ *\li 'name' is valid.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * other returns are failures.
+ */
+
+isc_result_t
+dns_view_adddelegationonly(dns_view_t *view, dns_name_t *name);
+/*%<
+ * Add the given name to the delegation only table.
+ *
+ *
+ * Requires:
+ *\li 'view' is valid.
+ *\li 'name' is valid.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name);
+/*%<
+ * Add the given name to be excluded from the root-delegation-only.
+ *
+ *
+ * Requires:
+ *\li 'view' is valid.
+ *\li 'name' is valid.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+isc_boolean_t
+dns_view_isdelegationonly(dns_view_t *view, dns_name_t *name);
+/*%<
+ * Check if 'name' is in the delegation only table or if
+ * rootdelonly is set that name is not being excluded.
+ *
+ * Requires:
+ *\li 'view' is valid.
+ *\li 'name' is valid.
+ *
+ * Returns:
+ *\li #ISC_TRUE if the name is is the table.
+ *\li #ISC_FALSE othewise.
+ */
+
+void
+dns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value);
+/*%<
+ * Set the root delegation only flag.
+ *
+ * Requires:
+ *\li 'view' is valid.
+ */
+
+isc_boolean_t
+dns_view_getrootdelonly(dns_view_t *view);
+/*%<
+ * Get the root delegation only flag.
+ *
+ * Requires:
+ *\li 'view' is valid.
+ */
+
+isc_result_t
+dns_view_freezezones(dns_view_t *view, isc_boolean_t freeze);
+/*%<
+ * Freeze/thaw updates to master zones.
+ *
+ * Requires:
+ * \li 'view' is valid.
+ */
+#endif /* DNS_VIEW_H */
diff --git a/lib/dns/include/dns/xfrin.h b/lib/dns/include/dns/xfrin.h
new file mode 100644
index 0000000..fcd482e
--- /dev/null
+++ b/lib/dns/include/dns/xfrin.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2004-2006 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: xfrin.h,v 1.20.18.5 2006/07/20 01:10:30 marka Exp $ */
+
+#ifndef DNS_XFRIN_H
+#define DNS_XFRIN_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Incoming zone transfers (AXFR + IXFR).
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+/***
+ *** Types
+ ***/
+
+/*%
+ * A transfer in progress. This is an opaque type.
+ */
+typedef struct dns_xfrin_ctx dns_xfrin_ctx_t;
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+/*% see dns_xfrin_create2() */
+isc_result_t
+dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
+ isc_sockaddr_t *masteraddr, dns_tsigkey_t *tsigkey,
+ isc_mem_t *mctx, isc_timermgr_t *timermgr,
+ isc_socketmgr_t *socketmgr, isc_task_t *task,
+ dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp);
+
+isc_result_t
+dns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype,
+ isc_sockaddr_t *masteraddr, isc_sockaddr_t *sourceaddr,
+ dns_tsigkey_t *tsigkey, isc_mem_t *mctx,
+ isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
+ isc_task_t *task, dns_xfrindone_t done,
+ dns_xfrin_ctx_t **xfrp);
+/*%<
+ * Attempt to start an incoming zone transfer of 'zone'
+ * from 'masteraddr', creating a dns_xfrin_ctx_t object to
+ * manage it. Attach '*xfrp' to the newly created object.
+ *
+ * Iff ISC_R_SUCCESS is returned, '*done' is guaranteed to be
+ * called in the context of 'task', with 'zone' and a result
+ * code as arguments when the transfer finishes.
+ *
+ * Requires:
+ *\li 'xfrtype' is dns_rdatatype_axfr, dns_rdatatype_ixfr
+ * or dns_rdatatype_soa (soa query followed by axfr if
+ * serial is greater than current serial).
+ *
+ *\li If 'xfrtype' is dns_rdatatype_ixfr or dns_rdatatype_soa,
+ * the zone has a database.
+ */
+
+void
+dns_xfrin_shutdown(dns_xfrin_ctx_t *xfr);
+/*%<
+ * If the zone transfer 'xfr' has already finished,
+ * do nothing. Otherwise, abort it and cause it to call
+ * its done callback with a status of ISC_R_CANCELLED.
+ */
+
+void
+dns_xfrin_detach(dns_xfrin_ctx_t **xfrp);
+/*%<
+ * Detach a reference to a zone transfer object.
+ * Caller to maintain external locking if required.
+ */
+
+void
+dns_xfrin_attach(dns_xfrin_ctx_t *source, dns_xfrin_ctx_t **target);
+/*%<
+ * Caller to maintain external locking if required.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_XFRIN_H */
diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h
new file mode 100644
index 0000000..7cb8272
--- /dev/null
+++ b/lib/dns/include/dns/zone.h
@@ -0,0 +1,1586 @@
+/*
+ * Copyright (C) 2004-2006 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: zone.h,v 1.126.18.19 2006/08/01 03:45:21 marka Exp $ */
+
+#ifndef DNS_ZONE_H
+#define DNS_ZONE_H 1
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdio.h>
+
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+#include <isc/rwlock.h>
+
+#include <dns/masterdump.h>
+#include <dns/types.h>
+
+typedef enum {
+ dns_zone_none,
+ dns_zone_master,
+ dns_zone_slave,
+ dns_zone_stub
+} dns_zonetype_t;
+
+#define DNS_ZONEOPT_SERVERS 0x00000001U /*%< perform server checks */
+#define DNS_ZONEOPT_PARENTS 0x00000002U /*%< perform parent checks */
+#define DNS_ZONEOPT_CHILDREN 0x00000004U /*%< perform child checks */
+#define DNS_ZONEOPT_NOTIFY 0x00000008U /*%< perform NOTIFY */
+#define DNS_ZONEOPT_MANYERRORS 0x00000010U /*%< return many errors on load */
+#define DNS_ZONEOPT_IXFRFROMDIFFS 0x00000020U /*%< calculate differences */
+#define DNS_ZONEOPT_NOMERGE 0x00000040U /*%< don't merge journal */
+#define DNS_ZONEOPT_CHECKNS 0x00000080U /*%< check if NS's are addresses */
+#define DNS_ZONEOPT_FATALNS 0x00000100U /*%< DNS_ZONEOPT_CHECKNS is fatal */
+#define DNS_ZONEOPT_MULTIMASTER 0x00000200U /*%< this zone has multiple masters */
+#define DNS_ZONEOPT_USEALTXFRSRC 0x00000400U /*%< use alternate transfer sources */
+#define DNS_ZONEOPT_CHECKNAMES 0x00000800U /*%< check-names */
+#define DNS_ZONEOPT_CHECKNAMESFAIL 0x00001000U /*%< fatal check-name failures */
+#define DNS_ZONEOPT_CHECKWILDCARD 0x00002000U /*%< check for internal wildcards */
+#define DNS_ZONEOPT_CHECKMX 0x00004000U /*%< check-mx */
+#define DNS_ZONEOPT_CHECKMXFAIL 0x00008000U /*%< fatal check-mx failures */
+#define DNS_ZONEOPT_CHECKINTEGRITY 0x00010000U /*%< perform integrity checks */
+#define DNS_ZONEOPT_CHECKSIBLING 0x00020000U /*%< perform sibling glue checks */
+#define DNS_ZONEOPT_NOCHECKNS 0x00040000U /*%< disable IN NS address checks */
+#define DNS_ZONEOPT_WARNMXCNAME 0x00080000U /*%< warn on MX CNAME check */
+#define DNS_ZONEOPT_IGNOREMXCNAME 0x00100000U /*%< ignore MX CNAME check */
+#define DNS_ZONEOPT_WARNSRVCNAME 0x00200000U /*%< warn on SRV CNAME check */
+#define DNS_ZONEOPT_IGNORESRVCNAME 0x00400000U /*%< ignore SRV CNAME check */
+#define DNS_ZONEOPT_UPDATECHECKKSK 0x00800000U /*%< check dnskey KSK flag */
+
+#ifndef NOMINUM_PUBLIC
+/*
+ * Nominum specific options build down.
+ */
+#define DNS_ZONEOPT_NOTIFYFORWARD 0x80000000U /* forward notify to master */
+#endif /* NOMINUM_PUBLIC */
+
+#ifndef DNS_ZONE_MINREFRESH
+#define DNS_ZONE_MINREFRESH 300 /*%< 5 minutes */
+#endif
+#ifndef DNS_ZONE_MAXREFRESH
+#define DNS_ZONE_MAXREFRESH 2419200 /*%< 4 weeks */
+#endif
+#ifndef DNS_ZONE_DEFAULTREFRESH
+#define DNS_ZONE_DEFAULTREFRESH 3600 /*%< 1 hour */
+#endif
+#ifndef DNS_ZONE_MINRETRY
+#define DNS_ZONE_MINRETRY 300 /*%< 5 minutes */
+#endif
+#ifndef DNS_ZONE_MAXRETRY
+#define DNS_ZONE_MAXRETRY 1209600 /*%< 2 weeks */
+#endif
+#ifndef DNS_ZONE_DEFAULTRETRY
+#define DNS_ZONE_DEFAULTRETRY 60 /*%< 1 minute, subject to
+ exponential backoff */
+#endif
+
+#define DNS_ZONESTATE_XFERRUNNING 1
+#define DNS_ZONESTATE_XFERDEFERRED 2
+#define DNS_ZONESTATE_SOAQUERY 3
+#define DNS_ZONESTATE_ANY 4
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx);
+/*%<
+ * Creates a new empty zone and attach '*zonep' to it.
+ *
+ * Requires:
+ *\li 'zonep' to point to a NULL pointer.
+ *\li 'mctx' to be a valid memory context.
+ *
+ * Ensures:
+ *\li '*zonep' refers to a valid zone.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ */
+
+void
+dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass);
+/*%<
+ * Sets the class of a zone. This operation can only be performed
+ * once on a zone.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li dns_zone_setclass() not to have been called since the zone was
+ * created.
+ *\li 'rdclass' != dns_rdataclass_none.
+ */
+
+dns_rdataclass_t
+dns_zone_getclass(dns_zone_t *zone);
+/*%<
+ * Returns the current zone class.
+ *
+ * Requires:
+ *\li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type);
+/*%<
+ * Sets the zone type. This operation can only be performed once on
+ * a zone.
+ *
+ * Requires:
+ *\li 'zone' to be a valid zone.
+ *\li dns_zone_settype() not to have been called since the zone was
+ * created.
+ *\li 'type' != dns_zone_none
+ */
+
+void
+dns_zone_setview(dns_zone_t *zone, dns_view_t *view);
+/*%<
+ * Associate the zone with a view.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+dns_view_t *
+dns_zone_getview(dns_zone_t *zone);
+/*%<
+ * Returns the zone's associated view.
+ *
+ * Requires:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin);
+/*%<
+ * Sets the zones origin to 'origin'.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'origin' to be non NULL.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+dns_name_t *
+dns_zone_getorigin(dns_zone_t *zone);
+/*%<
+ * Returns the value of the origin.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_setfile(dns_zone_t *zone, const char *file);
+
+isc_result_t
+dns_zone_setfile2(dns_zone_t *zone, const char *file,
+ dns_masterformat_t format);
+/*%<
+ * Sets the name of the master file in the format of 'format' from which
+ * the zone loads its database to 'file'.
+ *
+ * For zones that have no associated master file, 'file' will be NULL.
+ *
+ * For zones with persistent databases, the file name
+ * setting is ignored.
+ *
+ * dns_zone_setfile() is a backward-compatible form of
+ * dns_zone_setfile2(), which always specifies the
+ * dns_masterformat_text (RFC1035) format.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *
+ * Returns:
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_SUCCESS
+ */
+
+const char *
+dns_zone_getfile(dns_zone_t *zone);
+/*%<
+ * Gets the name of the zone's master file, if any.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ *
+ * Returns:
+ *\li Pointer to null-terminated file name, or NULL.
+ */
+
+isc_result_t
+dns_zone_load(dns_zone_t *zone);
+
+isc_result_t
+dns_zone_loadnew(dns_zone_t *zone);
+/*%<
+ * Cause the database to be loaded from its backing store.
+ * Confirm that the minimum requirements for the zone type are
+ * met, otherwise DNS_R_BADZONE is returned.
+ *
+ * dns_zone_loadnew() only loads zones that are not yet loaded.
+ * dns_zone_load() also loads zones that are already loaded and
+ * and whose master file has changed since the last load.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *
+ * Returns:
+ *\li #ISC_R_UNEXPECTED
+ *\li #ISC_R_SUCCESS
+ *\li DNS_R_CONTINUE Incremental load has been queued.
+ *\li DNS_R_UPTODATE The zone has already been loaded based on
+ * file system timestamps.
+ *\li DNS_R_BADZONE
+ *\li Any result value from dns_db_load().
+ */
+
+void
+dns_zone_attach(dns_zone_t *source, dns_zone_t **target);
+/*%<
+ * Attach '*target' to 'source' incrementing its external
+ * reference count.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'target' to be non NULL and '*target' to be NULL.
+ */
+
+void
+dns_zone_detach(dns_zone_t **zonep);
+/*%<
+ * Detach from a zone decrementing its external reference count.
+ * If this was the last external reference to the zone it will be
+ * shut down and eventually freed.
+ *
+ * Require:
+ *\li 'zonep' to point to a valid zone.
+ */
+
+void
+dns_zone_iattach(dns_zone_t *source, dns_zone_t **target);
+/*%<
+ * Attach '*target' to 'source' incrementing its internal
+ * reference count. This is intended for use by operations
+ * such as zone transfers that need to prevent the zone
+ * object from being freed but not from shutting down.
+ *
+ * Require:
+ *\li The caller is running in the context of the zone's task.
+ *\li 'zone' to be a valid zone.
+ *\li 'target' to be non NULL and '*target' to be NULL.
+ */
+
+void
+dns_zone_idetach(dns_zone_t **zonep);
+/*%<
+ * Detach from a zone decrementing its internal reference count.
+ * If there are no more internal or external references to the
+ * zone, it will be freed.
+ *
+ * Require:
+ *\li The caller is running in the context of the zone's task.
+ *\li 'zonep' to point to a valid zone.
+ */
+
+void
+dns_zone_setflag(dns_zone_t *zone, unsigned int flags, isc_boolean_t value);
+/*%<
+ * Sets ('value' == 'ISC_TRUE') / clears ('value' == 'IS_FALSE')
+ * zone flags. Valid flag bits are DNS_ZONE_F_*.
+ *
+ * Requires
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_getdb(dns_zone_t *zone, dns_db_t **dbp);
+/*%<
+ * Attach '*dbp' to the database to if it exists otherwise
+ * return DNS_R_NOTLOADED.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'dbp' to be != NULL && '*dbp' == NULL.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li DNS_R_NOTLOADED
+ */
+
+isc_result_t
+dns_zone_setdbtype(dns_zone_t *zone,
+ unsigned int dbargc, const char * const *dbargv);
+/*%<
+ * Sets the database type to dbargv[0] and database arguments
+ * to subsequent dbargv elements.
+ * 'db_type' is not checked to see if it is a valid database type.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'database' to be non NULL.
+ *\li 'dbargc' to be >= 1
+ *\li 'dbargv' to point to dbargc NULL-terminated strings
+ *
+ * Returns:
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_SUCCESS
+ */
+
+isc_result_t
+dns_zone_getdbtype(dns_zone_t *zone, char ***argv, isc_mem_t *mctx);
+/*%<
+ * Returns the current dbtype. isc_mem_free() should be used
+ * to free 'argv' after use.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'argv' to be non NULL and *argv to be NULL.
+ *\li 'mctx' to be valid.
+ *
+ * Returns:
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_SUCCESS
+ */
+
+void
+dns_zone_markdirty(dns_zone_t *zone);
+/*%<
+ * Mark a zone as 'dirty'.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_expire(dns_zone_t *zone);
+/*%<
+ * Mark the zone as expired. If the zone requires dumping cause it to
+ * be initiated. Set the refresh and retry intervals to there default
+ * values and unload the zone.
+ *
+ * Require
+ *\li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_refresh(dns_zone_t *zone);
+/*%<
+ * Initiate zone up to date checks. The zone must already be being
+ * managed.
+ *
+ * Require
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_flush(dns_zone_t *zone);
+/*%<
+ * Write the zone to database if there are uncommited changes.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_dump(dns_zone_t *zone);
+/*%<
+ * Write the zone to database.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_dumptostream(dns_zone_t *zone, FILE *fd);
+
+isc_result_t
+dns_zone_dumptostream2(dns_zone_t *zone, FILE *fd, dns_masterformat_t format,
+ const dns_master_style_t *style);
+/*%<
+ * Write the zone to stream 'fd' in the specified 'format'.
+ * If the 'format' is dns_masterformat_text (RFC1035), 'style' also
+ * specifies the file style (e.g., &dns_master_style_default).
+ *
+ * dns_zone_dumptostream() is a backward-compatible form of
+ * dns_zone_dumptostream2(), which always uses the dns_masterformat_text
+ * format and the dns_master_style_default style.
+ *
+ * Note that dns_zone_dumptostream2() is the most flexible form. It
+ * can also provide the functionality of dns_zone_fulldumptostream().
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'fd' to be a stream open for writing.
+ */
+
+isc_result_t
+dns_zone_fulldumptostream(dns_zone_t *zone, FILE *fd);
+/*%<
+ * The same as dns_zone_dumptostream, but dumps the zone with
+ * different dump settings (dns_master_style_full).
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'fd' to be a stream open for writing.
+ */
+
+void
+dns_zone_maintenance(dns_zone_t *zone);
+/*%<
+ * Perform regular maintenace on the zone. This is called as a
+ * result of a zone being managed.
+ *
+ * Require
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_setmasters(dns_zone_t *zone, const isc_sockaddr_t *masters,
+ isc_uint32_t count);
+isc_result_t
+dns_zone_setmasterswithkeys(dns_zone_t *zone,
+ const isc_sockaddr_t *masters,
+ dns_name_t **keynames,
+ isc_uint32_t count);
+/*%<
+ * Set the list of master servers for the zone.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'masters' array of isc_sockaddr_t with port set or NULL.
+ *\li 'count' the number of masters.
+ *\li 'keynames' array of dns_name_t's for tsig keys or NULL.
+ *
+ * \li dns_zone_setmasters() is just a wrapper to setmasterswithkeys(),
+ * passing NULL in the keynames field.
+ *
+ * \li If 'masters' is NULL then 'count' must be zero.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li Any result dns_name_dup() can return, if keynames!=NULL
+ */
+
+isc_result_t
+dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify,
+ isc_uint32_t count);
+/*%<
+ * Set the list of additional servers to be notified when
+ * a zone changes. To clear the list use 'count = 0'.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'notify' to be non-NULL if count != 0.
+ *\li 'count' to be the number of notifyees.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+void
+dns_zone_unload(dns_zone_t *zone);
+/*%<
+ * detach the database from the zone structure.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_setoption(dns_zone_t *zone, unsigned int option, isc_boolean_t value);
+/*%<
+ * Set given options on ('value' == ISC_TRUE) or off ('value' ==
+ * #ISC_FALSE).
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+unsigned int
+dns_zone_getoptions(dns_zone_t *zone);
+/*%<
+ * Returns the current zone options.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_setminrefreshtime(dns_zone_t *zone, isc_uint32_t val);
+/*%<
+ * Set the minimum refresh time.
+ *
+ * Requires:
+ *\li 'zone' is valid.
+ *\li val > 0.
+ */
+
+void
+dns_zone_setmaxrefreshtime(dns_zone_t *zone, isc_uint32_t val);
+/*%<
+ * Set the maximum refresh time.
+ *
+ * Requires:
+ *\li 'zone' is valid.
+ *\li val > 0.
+ */
+
+void
+dns_zone_setminretrytime(dns_zone_t *zone, isc_uint32_t val);
+/*%<
+ * Set the minimum retry time.
+ *
+ * Requires:
+ *\li 'zone' is valid.
+ *\li val > 0.
+ */
+
+void
+dns_zone_setmaxretrytime(dns_zone_t *zone, isc_uint32_t val);
+/*%<
+ * Set the maximum retry time.
+ *
+ * Requires:
+ *\li 'zone' is valid.
+ * val > 0.
+ */
+
+isc_result_t
+dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource);
+isc_result_t
+dns_zone_setaltxfrsource4(dns_zone_t *zone,
+ const isc_sockaddr_t *xfrsource);
+/*%<
+ * Set the source address to be used in IPv4 zone transfers.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'xfrsource' to contain the address.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ */
+
+isc_sockaddr_t *
+dns_zone_getxfrsource4(dns_zone_t *zone);
+isc_sockaddr_t *
+dns_zone_getaltxfrsource4(dns_zone_t *zone);
+/*%<
+ * Returns the source address set by a previous dns_zone_setxfrsource4
+ * call, or the default of inaddr_any, port 0.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource);
+isc_result_t
+dns_zone_setaltxfrsource6(dns_zone_t *zone,
+ const isc_sockaddr_t *xfrsource);
+/*%<
+ * Set the source address to be used in IPv6 zone transfers.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'xfrsource' to contain the address.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ */
+
+isc_sockaddr_t *
+dns_zone_getxfrsource6(dns_zone_t *zone);
+isc_sockaddr_t *
+dns_zone_getaltxfrsource6(dns_zone_t *zone);
+/*%<
+ * Returns the source address set by a previous dns_zone_setxfrsource6
+ * call, or the default of in6addr_any, port 0.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc);
+/*%<
+ * Set the source address to be used with IPv4 NOTIFY messages.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'notifysrc' to contain the address.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ */
+
+isc_sockaddr_t *
+dns_zone_getnotifysrc4(dns_zone_t *zone);
+/*%<
+ * Returns the source address set by a previous dns_zone_setnotifysrc4
+ * call, or the default of inaddr_any, port 0.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc);
+/*%<
+ * Set the source address to be used with IPv6 NOTIFY messages.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'notifysrc' to contain the address.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ */
+
+isc_sockaddr_t *
+dns_zone_getnotifysrc6(dns_zone_t *zone);
+/*%<
+ * Returns the source address set by a previous dns_zone_setnotifysrc6
+ * call, or the default of in6addr_any, port 0.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_setnotifyacl(dns_zone_t *zone, dns_acl_t *acl);
+/*%<
+ * Sets the notify acl list for the zone.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'acl' to be a valid acl.
+ */
+
+void
+dns_zone_setqueryacl(dns_zone_t *zone, dns_acl_t *acl);
+/*%<
+ * Sets the query acl list for the zone.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'acl' to be a valid acl.
+ */
+
+void
+dns_zone_setupdateacl(dns_zone_t *zone, dns_acl_t *acl);
+/*%<
+ * Sets the update acl list for the zone.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'acl' to be valid acl.
+ */
+
+void
+dns_zone_setforwardacl(dns_zone_t *zone, dns_acl_t *acl);
+/*%<
+ * Sets the forward unsigned updates acl list for the zone.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'acl' to be valid acl.
+ */
+
+void
+dns_zone_setxfracl(dns_zone_t *zone, dns_acl_t *acl);
+/*%<
+ * Sets the transfer acl list for the zone.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'acl' to be valid acl.
+ */
+
+dns_acl_t *
+dns_zone_getnotifyacl(dns_zone_t *zone);
+/*%<
+ * Returns the current notify acl or NULL.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *
+ * Returns:
+ *\li acl a pointer to the acl.
+ *\li NULL
+ */
+
+dns_acl_t *
+dns_zone_getqueryacl(dns_zone_t *zone);
+/*%<
+ * Returns the current query acl or NULL.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *
+ * Returns:
+ *\li acl a pointer to the acl.
+ *\li NULL
+ */
+
+dns_acl_t *
+dns_zone_getupdateacl(dns_zone_t *zone);
+/*%<
+ * Returns the current update acl or NULL.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *
+ * Returns:
+ *\li acl a pointer to the acl.
+ *\li NULL
+ */
+
+dns_acl_t *
+dns_zone_getforwardacl(dns_zone_t *zone);
+/*%<
+ * Returns the current forward unsigned updates acl or NULL.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *
+ * Returns:
+ *\li acl a pointer to the acl.
+ *\li NULL
+ */
+
+dns_acl_t *
+dns_zone_getxfracl(dns_zone_t *zone);
+/*%<
+ * Returns the current transfer acl or NULL.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *
+ * Returns:
+ *\li acl a pointer to the acl.
+ *\li NULL
+ */
+
+void
+dns_zone_clearupdateacl(dns_zone_t *zone);
+/*%<
+ * Clear the current update acl.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_clearforwardacl(dns_zone_t *zone);
+/*%<
+ * Clear the current forward unsigned updates acl.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_clearnotifyacl(dns_zone_t *zone);
+/*%<
+ * Clear the current notify acl.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_clearqueryacl(dns_zone_t *zone);
+/*%<
+ * Clear the current query acl.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_clearxfracl(dns_zone_t *zone);
+/*%<
+ * Clear the current transfer acl.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_boolean_t
+dns_zone_getupdatedisabled(dns_zone_t *zone);
+/*%<
+ * Return update disabled.
+ */
+
+void
+dns_zone_setupdatedisabled(dns_zone_t *zone, isc_boolean_t state);
+/*%<
+ * Set update disabled.
+ */
+
+isc_boolean_t
+dns_zone_getzeronosoattl(dns_zone_t *zone);
+/*%<
+ * Return zero-no-soa-ttl status.
+ */
+
+void
+dns_zone_setzeronosoattl(dns_zone_t *zone, isc_boolean_t state);
+/*%<
+ * Set zero-no-soa-ttl status.
+ */
+
+void
+dns_zone_setchecknames(dns_zone_t *zone, dns_severity_t severity);
+/*%<
+ * Set the severity of name checking when loading a zone.
+ *
+ * Require:
+ * \li 'zone' to be a valid zone.
+ */
+
+dns_severity_t
+dns_zone_getchecknames(dns_zone_t *zone);
+/*%<
+ * Return the current severity of name checking.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_setjournalsize(dns_zone_t *zone, isc_int32_t size);
+/*%<
+ * Sets the journal size for the zone.
+ *
+ * Requires:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_int32_t
+dns_zone_getjournalsize(dns_zone_t *zone);
+/*%<
+ * Return the journal size as set with a previous call to
+ * dns_zone_setjournalsize().
+ *
+ * Requires:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
+ dns_message_t *msg);
+/*%<
+ * Tell the zone that it has recieved a NOTIFY message from another
+ * server. This may cause some zone maintainence activity to occur.
+ *
+ * Requires:
+ *\li 'zone' to be a valid zone.
+ *\li '*from' to contain the address of the server from which 'msg'
+ * was recieved.
+ *\li 'msg' a message with opcode NOTIFY and qr clear.
+ *
+ * Returns:
+ *\li DNS_R_REFUSED
+ *\li DNS_R_NOTIMP
+ *\li DNS_R_FORMERR
+ *\li DNS_R_SUCCESS
+ */
+
+void
+dns_zone_setmaxxfrin(dns_zone_t *zone, isc_uint32_t maxxfrin);
+/*%<
+ * Set the maximum time (in seconds) that a zone transfer in (AXFR/IXFR)
+ * of this zone will use before being aborted.
+ *
+ * Requires:
+ * \li 'zone' to be valid initialised zone.
+ */
+
+isc_uint32_t
+dns_zone_getmaxxfrin(dns_zone_t *zone);
+/*%<
+ * Returns the maximum transfer time for this zone. This will be
+ * either the value set by the last call to dns_zone_setmaxxfrin() or
+ * the default value of 1 hour.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ */
+
+void
+dns_zone_setmaxxfrout(dns_zone_t *zone, isc_uint32_t maxxfrout);
+/*%<
+ * Set the maximum time (in seconds) that a zone transfer out (AXFR/IXFR)
+ * of this zone will use before being aborted.
+ *
+ * Requires:
+ * \li 'zone' to be valid initialised zone.
+ */
+
+isc_uint32_t
+dns_zone_getmaxxfrout(dns_zone_t *zone);
+/*%<
+ * Returns the maximum transfer time for this zone. This will be
+ * either the value set by the last call to dns_zone_setmaxxfrout() or
+ * the default value of 1 hour.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ */
+
+isc_result_t
+dns_zone_setjournal(dns_zone_t *zone, const char *journal);
+/*%<
+ * Sets the filename used for journaling updates / IXFR transfers.
+ * The default journal name is set by dns_zone_setfile() to be
+ * "file.jnl". If 'journal' is NULL, the zone will have no
+ * journal name.
+ *
+ * Requires:
+ *\li 'zone' to be a valid zone.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+char *
+dns_zone_getjournal(dns_zone_t *zone);
+/*%<
+ * Returns the journal name associated with this zone.
+ * If no journal has been set this will be NULL.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ */
+
+dns_zonetype_t
+dns_zone_gettype(dns_zone_t *zone);
+/*%<
+ * Returns the type of the zone (master/slave/etc.)
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ */
+
+void
+dns_zone_settask(dns_zone_t *zone, isc_task_t *task);
+/*%<
+ * Give a zone a task to work with. Any current task will be detached.
+ *
+ * Requires:
+ *\li 'zone' to be valid.
+ *\li 'task' to be valid.
+ */
+
+void
+dns_zone_gettask(dns_zone_t *zone, isc_task_t **target);
+/*%<
+ * Attach '*target' to the zone's task.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ *\li 'zone' to have a task.
+ *\li 'target' to be != NULL && '*target' == NULL.
+ */
+
+void
+dns_zone_notify(dns_zone_t *zone);
+/*%<
+ * Generate notify events for this zone.
+ *
+ * Requires:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump);
+/*%<
+ * Replace the database of "zone" with a new database "db".
+ *
+ * If "dump" is ISC_TRUE, then the new zone contents are dumped
+ * into to the zone's master file for persistence. When replacing
+ * a zone database by one just loaded from a master file, set
+ * "dump" to ISC_FALSE to avoid a redunant redump of the data just
+ * loaded. Otherwise, it should be set to ISC_TRUE.
+ *
+ * If the "diff-on-reload" option is enabled in the configuration file,
+ * the differences between the old and the new database are added to the
+ * journal file, and the master file dump is postponed.
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ *
+ * Returns:
+ * \li DNS_R_SUCCESS
+ * \li DNS_R_BADZONE zone failed basic consistancy checks:
+ * * a single SOA must exist
+ * * some NS records must exist.
+ * Others
+ */
+
+isc_uint32_t
+dns_zone_getidlein(dns_zone_t *zone);
+/*%<
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ *
+ * Returns:
+ * \li number of seconds of idle time before we abort the transfer in.
+ */
+
+void
+dns_zone_setidlein(dns_zone_t *zone, isc_uint32_t idlein);
+/*%<
+ * \li Set the idle timeout for transfer the.
+ * \li Zero set the default value, 1 hour.
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ */
+
+isc_uint32_t
+dns_zone_getidleout(dns_zone_t *zone);
+/*%<
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ *
+ * Returns:
+ * \li number of seconds of idle time before we abort a transfer out.
+ */
+
+void
+dns_zone_setidleout(dns_zone_t *zone, isc_uint32_t idleout);
+/*%<
+ * \li Set the idle timeout for transfers out.
+ * \li Zero set the default value, 1 hour.
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_getssutable(dns_zone_t *zone, dns_ssutable_t **table);
+/*%<
+ * Get the simple-secure-update policy table.
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_setssutable(dns_zone_t *zone, dns_ssutable_t *table);
+/*%<
+ * Set / clear the simple-secure-update policy table.
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ */
+
+isc_mem_t *
+dns_zone_getmctx(dns_zone_t *zone);
+/*%<
+ * Get the memory context of a zone.
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ */
+
+dns_zonemgr_t *
+dns_zone_getmgr(dns_zone_t *zone);
+/*%<
+ * If 'zone' is managed return the zone manager otherwise NULL.
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_setsigvalidityinterval(dns_zone_t *zone, isc_uint32_t interval);
+/*%<
+ * Set the zone's SIG validity interval. This is the length of time
+ * for which DNSSEC signatures created as a result of dynamic updates
+ * to secure zones will remain valid, in seconds.
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ */
+
+isc_uint32_t
+dns_zone_getsigvalidityinterval(dns_zone_t *zone);
+/*%<
+ * Get the zone's SIG validity interval.
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype);
+/*%<
+ * Sets zone notify method to "notifytype"
+ */
+
+isc_result_t
+dns_zone_forwardupdate(dns_zone_t *zone, dns_message_t *msg,
+ dns_updatecallback_t callback, void *callback_arg);
+/*%<
+ * Forward 'msg' to each master in turn until we get an answer or we
+ * have exausted the list of masters. 'callback' will be called with
+ * ISC_R_SUCCESS if we get an answer and the returned message will be
+ * passed as 'answer_message', otherwise a non ISC_R_SUCCESS result code
+ * will be passed and answer_message will be NULL. The callback function
+ * is responsible for destroying 'answer_message'.
+ * (callback)(callback_arg, result, answer_message);
+ *
+ * Require:
+ *\li 'zone' to be valid
+ *\li 'msg' to be valid.
+ *\li 'callback' to be non NULL.
+ * Returns:
+ *\li #ISC_R_SUCCESS if the message has been forwarded,
+ *\li #ISC_R_NOMEMORY
+ *\li Others
+ */
+
+isc_result_t
+dns_zone_next(dns_zone_t *zone, dns_zone_t **next);
+/*%<
+ * Find the next zone in the list of managed zones.
+ *
+ * Requires:
+ *\li 'zone' to be valid
+ *\li The zone manager for the indicated zone MUST be locked
+ * by the caller. This is not checked.
+ *\li 'next' be non-NULL, and '*next' be NULL.
+ *
+ * Ensures:
+ *\li 'next' points to a valid zone (result ISC_R_SUCCESS) or to NULL
+ * (result ISC_R_NOMORE).
+ */
+
+isc_result_t
+dns_zone_first(dns_zonemgr_t *zmgr, dns_zone_t **first);
+/*%<
+ * Find the first zone in the list of managed zones.
+ *
+ * Requires:
+ *\li 'zonemgr' to be valid
+ *\li The zone manager for the indicated zone MUST be locked
+ * by the caller. This is not checked.
+ *\li 'first' be non-NULL, and '*first' be NULL
+ *
+ * Ensures:
+ *\li 'first' points to a valid zone (result ISC_R_SUCCESS) or to NULL
+ * (result ISC_R_NOMORE).
+ */
+
+isc_result_t
+dns_zone_setkeydirectory(dns_zone_t *zone, const char *directory);
+/*%<
+ * Sets the name of the directory where private keys used for
+ * online signing of dynamic zones are found.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *
+ * Returns:
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_SUCCESS
+ */
+
+const char *
+dns_zone_getkeydirectory(dns_zone_t *zone);
+/*%<
+ * Gets the name of the directory where private keys used for
+ * online signing of dynamic zones are found.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ *
+ * Returns:
+ * Pointer to null-terminated file name, or NULL.
+ */
+
+
+isc_result_t
+dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
+ isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
+ dns_zonemgr_t **zmgrp);
+/*%<
+ * Create a zone manager.
+ *
+ * Requires:
+ *\li 'mctx' to be a valid memory context.
+ *\li 'taskmgr' to be a valid task manager.
+ *\li 'timermgr' to be a valid timer manager.
+ *\li 'zmgrp' to point to a NULL pointer.
+ */
+
+isc_result_t
+dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone);
+/*%<
+ * Bring the zone under control of a zone manager.
+ *
+ * Require:
+ *\li 'zmgr' to be a valid zone manager.
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr);
+/*%<
+ * Force zone maintenance of all zones managed by 'zmgr' at its
+ * earliest conveniene.
+ */
+
+void
+dns_zonemgr_resumexfrs(dns_zonemgr_t *zmgr);
+/*%<
+ * Attempt to start any stalled zone transfers.
+ */
+
+void
+dns_zonemgr_shutdown(dns_zonemgr_t *zmgr);
+/*%<
+ * Shut down the zone manager.
+ *
+ * Requires:
+ *\li 'zmgr' to be a valid zone manager.
+ */
+
+void
+dns_zonemgr_attach(dns_zonemgr_t *source, dns_zonemgr_t **target);
+/*%<
+ * Attach '*target' to 'source' incrementing its external
+ * reference count.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ *\li 'target' to be non NULL and '*target' to be NULL.
+ */
+
+void
+dns_zonemgr_detach(dns_zonemgr_t **zmgrp);
+/*%<
+ * Detach from a zone manager.
+ *
+ * Requires:
+ *\li '*zmgrp' is a valid, non-NULL zone manager pointer.
+ *
+ * Ensures:
+ *\li '*zmgrp' is NULL.
+ */
+
+void
+dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone);
+/*%<
+ * Release 'zone' from the managed by 'zmgr'. 'zmgr' is implicitly
+ * detached from 'zone'.
+ *
+ * Requires:
+ *\li 'zmgr' to be a valid zone manager.
+ *\li 'zone' to be a valid zone.
+ *\li 'zmgr' == 'zone->zmgr'
+ *
+ * Ensures:
+ *\li 'zone->zmgr' == NULL;
+ */
+
+void
+dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, isc_uint32_t value);
+/*%<
+ * Set the maximum number of simultaneous transfers in allowed by
+ * the zone manager.
+ *
+ * Requires:
+ *\li 'zmgr' to be a valid zone manager.
+ */
+
+isc_uint32_t
+dns_zonemgr_getttransfersin(dns_zonemgr_t *zmgr);
+/*%<
+ * Return the the maximum number of simultaneous transfers in allowed.
+ *
+ * Requires:
+ *\li 'zmgr' to be a valid zone manager.
+ */
+
+void
+dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, isc_uint32_t value);
+/*%<
+ * Set the number of zone transfers allowed per nameserver.
+ *
+ * Requires:
+ *\li 'zmgr' to be a valid zone manager
+ */
+
+isc_uint32_t
+dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr);
+/*%<
+ * Return the number of transfers allowed per nameserver.
+ *
+ * Requires:
+ *\li 'zmgr' to be a valid zone manager.
+ */
+
+void
+dns_zonemgr_setiolimit(dns_zonemgr_t *zmgr, isc_uint32_t iolimit);
+/*%<
+ * Set the number of simultaneous file descriptors available for
+ * reading and writing masterfiles.
+ *
+ * Requires:
+ *\li 'zmgr' to be a valid zone manager.
+ *\li 'iolimit' to be positive.
+ */
+
+isc_uint32_t
+dns_zonemgr_getiolimit(dns_zonemgr_t *zmgr);
+/*%<
+ * Get the number of simultaneous file descriptors available for
+ * reading and writing masterfiles.
+ *
+ * Requires:
+ *\li 'zmgr' to be a valid zone manager.
+ */
+
+void
+dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value);
+/*%<
+ * Set the number of SOA queries sent per second.
+ *
+ * Requires:
+ *\li 'zmgr' to be a valid zone manager
+ */
+
+unsigned int
+dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr);
+/*%<
+ * Return the number of SOA queries sent per second.
+ *
+ * Requires:
+ *\li 'zmgr' to be a valid zone manager.
+ */
+
+unsigned int
+dns_zonemgr_getcount(dns_zonemgr_t *zmgr, int state);
+/*%<
+ * Returns the number of zones in the specified state.
+ *
+ * Requires:
+ *\li 'zmgr' to be a valid zone manager.
+ *\li 'state' to be a valid DNS_ZONESTATE_ constant.
+ */
+
+void
+dns_zone_forcereload(dns_zone_t *zone);
+/*%<
+ * Force a reload of specified zone.
+ *
+ * Requires:
+ *\li 'zone' to be a valid zone.
+ */
+
+isc_boolean_t
+dns_zone_isforced(dns_zone_t *zone);
+/*%<
+ * Check if the zone is waiting a forced reload.
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ */
+
+isc_result_t
+dns_zone_setstatistics(dns_zone_t *zone, isc_boolean_t on);
+/*%<
+ * Make the zone keep or not keep an array of statistics
+ * counter.
+ *
+ * Requires:
+ * \li zone be a valid zone.
+ */
+
+isc_uint64_t *
+dns_zone_getstatscounters(dns_zone_t *zone);
+/*%<
+ * Requires:
+ * zone be a valid zone.
+ *
+ * Returns:
+ * \li A pointer to the zone's array of statistics counters,
+ * or NULL if it has none.
+ */
+
+void
+dns_zone_dialup(dns_zone_t *zone);
+/*%<
+ * Perform dialup-time maintenance on 'zone'.
+ */
+
+void
+dns_zone_setdialup(dns_zone_t *zone, dns_dialuptype_t dialup);
+/*%<
+ * Set the dialup type of 'zone' to 'dialup'.
+ *
+ * Requires:
+ * \li 'zone' to be valid initialised zone.
+ *\li 'dialup' to be a valid dialup type.
+ */
+
+void
+dns_zone_log(dns_zone_t *zone, int level, const char *msg, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+/*%<
+ * Log the message 'msg...' at 'level', including text that identifies
+ * the message as applying to 'zone'.
+ */
+
+void
+dns_zone_logc(dns_zone_t *zone, isc_logcategory_t *category, int level,
+ const char *msg, ...) ISC_FORMAT_PRINTF(4, 5);
+/*%<
+ * Log the message 'msg...' at 'level', including text that identifies
+ * the message as applying to 'zone'.
+ */
+
+void
+dns_zone_name(dns_zone_t *zone, char *buf, size_t len);
+/*%<
+ * Return the name of the zone with class and view.
+ *
+ * Requires:
+ *\li 'zone' to be valid.
+ *\li 'buf' to be non NULL.
+ */
+
+isc_result_t
+dns_zone_checknames(dns_zone_t *zone, dns_name_t *name, dns_rdata_t *rdata);
+/*
+ * Check if this record meets the check-names policy.
+ *
+ * Requires:
+ * 'zone' to be valid.
+ * 'name' to be valid.
+ * 'rdata' to be valid.
+ *
+ * Returns:
+ * DNS_R_SUCCESS passed checks.
+ * DNS_R_BADOWNERNAME failed ownername checks.
+ * DNS_R_BADNAME failed rdata checks.
+ */
+
+void
+dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache);
+/*
+ * Associate the zone with an additional cache.
+ *
+ * Require:
+ * 'zone' to be a valid zone.
+ * 'acache' to be a non NULL pointer.
+ *
+ * Ensures:
+ * 'zone' will have a reference to 'acache'
+ */
+
+void
+dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx);
+/*
+ * Set the post load integrity callback function 'checkmx'.
+ * 'checkmx' will be called if the MX is not within the zone.
+ *
+ * Require:
+ * 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_setchecksrv(dns_zone_t *zone, dns_checkmxfunc_t checksrv);
+/*
+ * Set the post load integrity callback function 'checksrv'.
+ * 'checksrv' will be called if the SRV TARGET is not within the zone.
+ *
+ * Require:
+ * 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns);
+/*
+ * Set the post load integrity callback function 'checkmx'.
+ * 'checkmx' will be called if the MX is not within the zone.
+ *
+ * Require:
+ * 'zone' to be a valid zone.
+ */
+
+void
+dns_zone_setnotifydelay(dns_zone_t *zone, isc_uint32_t delay);
+/*
+ * Set the minimum delay between sets of notify messages.
+ *
+ * Requires:
+ * 'zone' to be valid.
+ */
+
+isc_uint32_t
+dns_zone_getnotifydelay(dns_zone_t *zone);
+/*
+ * Get the minimum delay between sets of notify messages.
+ *
+ * Requires:
+ * 'zone' to be valid.
+ */
+
+void
+dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg);
+/*
+ * Set the isself callback function and argument.
+ *
+ * isc_boolean_t
+ * isself(dns_view_t *myview, dns_tsigkey_t *mykey, isc_netaddr_t *srcaddr,
+ * isc_netaddr_t *destaddr, dns_rdataclass_t rdclass, void *arg);
+ *
+ * 'isself' returns ISC_TRUE if a non-recursive query from 'srcaddr' to
+ * 'destaddr' with optional key 'mykey' for class 'rdclass' would be
+ * delivered to 'myview'.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_ZONE_H */
diff --git a/lib/dns/include/dns/zonekey.h b/lib/dns/include/dns/zonekey.h
new file mode 100644
index 0000000..ba4e076
--- /dev/null
+++ b/lib/dns/include/dns/zonekey.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2004, 2005 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: zonekey.h,v 1.4.18.2 2005/04/29 00:16:26 marka Exp $ */
+
+#ifndef DNS_ZONEKEY_H
+#define DNS_ZONEKEY_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_boolean_t
+dns_zonekey_iszonekey(dns_rdata_t *keyrdata);
+/*%<
+ * Determines if the key record contained in the rdata is a zone key.
+ *
+ * Requires:
+ * 'keyrdata' is not NULL.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_ZONEKEY_H */
diff --git a/lib/dns/include/dns/zt.h b/lib/dns/include/dns/zt.h
new file mode 100644
index 0000000..436ef4c
--- /dev/null
+++ b/lib/dns/include/dns/zt.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2004, 2005 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: zt.h,v 1.30.18.3 2005/04/27 05:01:42 sra Exp $ */
+
+#ifndef DNS_ZT_H
+#define DNS_ZT_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+#define DNS_ZTFIND_NOEXACT 0x01
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **zt);
+/*%<
+ * Creates a new zone table.
+ *
+ * Requires:
+ * \li 'mctx' to be initialized.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS on success.
+ * \li #ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone);
+/*%<
+ * Mounts the zone on the zone table.
+ *
+ * Requires:
+ * \li 'zt' to be valid
+ * \li 'zone' to be valid
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_EXISTS
+ * \li #ISC_R_NOSPACE
+ * \li #ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone);
+/*%<
+ * Unmount the given zone from the table.
+ *
+ * Requires:
+ * 'zt' to be valid
+ * \li 'zone' to be valid
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND
+ * \li #ISC_R_NOMEMORY
+ */
+
+isc_result_t
+dns_zt_find(dns_zt_t *zt, dns_name_t *name, unsigned int options,
+ dns_name_t *foundname, dns_zone_t **zone);
+/*%<
+ * Find the best match for 'name' in 'zt'. If foundname is non NULL
+ * then the name of the zone found is returned.
+ *
+ * Notes:
+ * \li If the DNS_ZTFIND_NOEXACT is set, the best partial match (if any)
+ * to 'name' will be returned.
+ *
+ * Requires:
+ * \li 'zt' to be valid
+ * \li 'name' to be valid
+ * \li 'foundname' to be initialized and associated with a fixedname or NULL
+ * \li 'zone' to be non NULL and '*zone' to be NULL
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #DNS_R_PARTIALMATCH
+ * \li #ISC_R_NOTFOUND
+ * \li #ISC_R_NOSPACE
+ */
+
+void
+dns_zt_detach(dns_zt_t **ztp);
+/*%<
+ * Detach the given zonetable, if the reference count goes to zero the
+ * zonetable will be freed. In either case 'ztp' is set to NULL.
+ *
+ * Requires:
+ * \li '*ztp' to be valid
+ */
+
+void
+dns_zt_flushanddetach(dns_zt_t **ztp);
+/*%<
+ * Detach the given zonetable, if the reference count goes to zero the
+ * zonetable will be flushed and then freed. In either case 'ztp' is
+ * set to NULL.
+ *
+ * Requires:
+ * \li '*ztp' to be valid
+ */
+
+void
+dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp);
+/*%<
+ * Attach 'zt' to '*ztp'.
+ *
+ * Requires:
+ * \li 'zt' to be valid
+ * \li '*ztp' to be NULL
+ */
+
+isc_result_t
+dns_zt_load(dns_zt_t *zt, isc_boolean_t stop);
+
+isc_result_t
+dns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop);
+/*%<
+ * Load all zones in the table. If 'stop' is ISC_TRUE,
+ * stop on the first error and return it. If 'stop'
+ * is ISC_FALSE, ignore errors.
+ *
+ * dns_zt_loadnew() only loads zones that are not yet loaded.
+ * dns_zt_load() also loads zones that are already loaded and
+ * and whose master file has changed since the last load.
+ *
+ * Requires:
+ * \li 'zt' to be valid
+ */
+
+isc_result_t
+dns_zt_freezezones(dns_zt_t *zt, isc_boolean_t freeze);
+/*%<
+ * Freeze/thaw updates to master zones.
+ * Any pending updates will be flushed.
+ * Zones will be reloaded on thaw.
+ */
+
+isc_result_t
+dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop,
+ isc_result_t (*action)(dns_zone_t *, void *), void *uap);
+
+isc_result_t
+dns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub,
+ isc_result_t (*action)(dns_zone_t *, void *), void *uap);
+/*%<
+ * Apply a given 'action' to all zone zones in the table.
+ * If 'stop' is 'ISC_TRUE' then walking the zone tree will stop if
+ * 'action' does not return ISC_R_SUCCESS.
+ *
+ * Requires:
+ * \li 'zt' to be valid.
+ * \li 'action' to be non NULL.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS if action was applied to all nodes. If 'stop' is
+ * ISC_FALSE and 'sub' is non NULL then the first error (if any)
+ * reported by 'action' is returned in '*sub';
+ * any error code from 'action'.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_ZT_H */
diff --git a/lib/dns/include/dst/Makefile.in b/lib/dns/include/dst/Makefile.in
new file mode 100644
index 0000000..deaa221
--- /dev/null
+++ b/lib/dns/include/dst/Makefile.in
@@ -0,0 +1,37 @@
+# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-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: Makefile.in,v 1.1.6.1 2004/12/09 04:41:47 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = dst.h lib.h result.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/dst
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/dst ; \
+ done
diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h
new file mode 100644
index 0000000..8d99186
--- /dev/null
+++ b/lib/dns/include/dst/dst.h
@@ -0,0 +1,620 @@
+/*
+ * Copyright (C) 2004-2006 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: dst.h,v 1.1.6.5 2006/01/27 23:57:44 marka Exp $ */
+
+#ifndef DST_DST_H
+#define DST_DST_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+/*%
+ * The dst_key structure is opaque. Applications should use the accessor
+ * functions provided to retrieve key attributes. If an application needs
+ * to set attributes, new accessor functions will be written.
+ */
+
+typedef struct dst_key dst_key_t;
+typedef struct dst_context dst_context_t;
+
+/* DST algorithm codes */
+#define DST_ALG_UNKNOWN 0
+#define DST_ALG_RSAMD5 1
+#define DST_ALG_RSA DST_ALG_RSAMD5 /*%< backwards compatibility */
+#define DST_ALG_DH 2
+#define DST_ALG_DSA 3
+#define DST_ALG_ECC 4
+#define DST_ALG_RSASHA1 5
+#define DST_ALG_HMACMD5 157
+#define DST_ALG_GSSAPI 160
+#define DST_ALG_HMACSHA1 161 /* XXXMPA */
+#define DST_ALG_HMACSHA224 162 /* XXXMPA */
+#define DST_ALG_HMACSHA256 163 /* XXXMPA */
+#define DST_ALG_HMACSHA384 164 /* XXXMPA */
+#define DST_ALG_HMACSHA512 165 /* XXXMPA */
+#define DST_ALG_PRIVATE 254
+#define DST_ALG_EXPAND 255
+#define DST_MAX_ALGS 255
+
+/*% A buffer of this size is large enough to hold any key */
+#define DST_KEY_MAXSIZE 1280
+
+/*%
+ * A buffer of this size is large enough to hold the textual representation
+ * of any key
+ */
+#define DST_KEY_MAXTEXTSIZE 2048
+
+/*% 'Type' for dst_read_key() */
+#define DST_TYPE_KEY 0x1000000 /* KEY key */
+#define DST_TYPE_PRIVATE 0x2000000
+#define DST_TYPE_PUBLIC 0x4000000
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags);
+/*%<
+ * Initializes the DST subsystem.
+ *
+ * Requires:
+ * \li "mctx" is a valid memory context
+ * \li "ectx" is a valid entropy context
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOMEMORY
+ *
+ * Ensures:
+ * \li DST is properly initialized.
+ */
+
+void
+dst_lib_destroy(void);
+/*%<
+ * Releases all resources allocated by DST.
+ */
+
+isc_boolean_t
+dst_algorithm_supported(unsigned int alg);
+/*%<
+ * Checks that a given algorithm is supported by DST.
+ *
+ * Returns:
+ * \li ISC_TRUE
+ * \li ISC_FALSE
+ */
+
+isc_result_t
+dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp);
+/*%<
+ * Creates a context to be used for a sign or verify operation.
+ *
+ * Requires:
+ * \li "key" is a valid key.
+ * \li "mctx" is a valid memory context.
+ * \li dctxp != NULL && *dctxp == NULL
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOMEMORY
+ *
+ * Ensures:
+ * \li *dctxp will contain a usable context.
+ */
+
+void
+dst_context_destroy(dst_context_t **dctxp);
+/*%<
+ * Destroys all memory associated with a context.
+ *
+ * Requires:
+ * \li *dctxp != NULL && *dctxp == NULL
+ *
+ * Ensures:
+ * \li *dctxp == NULL
+ */
+
+isc_result_t
+dst_context_adddata(dst_context_t *dctx, const isc_region_t *data);
+/*%<
+ * Incrementally adds data to the context to be used in a sign or verify
+ * operation.
+ *
+ * Requires:
+ * \li "dctx" is a valid context
+ * \li "data" is a valid region
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li DST_R_SIGNFAILURE
+ * \li all other errors indicate failure
+ */
+
+isc_result_t
+dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig);
+/*%<
+ * Computes a signature using the data and key stored in the context.
+ *
+ * Requires:
+ * \li "dctx" is a valid context.
+ * \li "sig" is a valid buffer.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li DST_R_VERIFYFAILURE
+ * \li all other errors indicate failure
+ *
+ * Ensures:
+ * \li "sig" will contain the signature
+ */
+
+isc_result_t
+dst_context_verify(dst_context_t *dctx, isc_region_t *sig);
+/*%<
+ * Verifies the signature using the data and key stored in the context.
+ *
+ * Requires:
+ * \li "dctx" is a valid context.
+ * \li "sig" is a valid region.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li all other errors indicate failure
+ *
+ * Ensures:
+ * \li "sig" will contain the signature
+ */
+
+isc_result_t
+dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
+ isc_buffer_t *secret);
+/*%<
+ * Computes a shared secret from two (Diffie-Hellman) keys.
+ *
+ * Requires:
+ * \li "pub" is a valid key that can be used to derive a shared secret
+ * \li "priv" is a valid private key that can be used to derive a shared secret
+ * \li "secret" is a valid buffer
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li any other result indicates failure
+ *
+ * Ensures:
+ * \li If successful, secret will contain the derived shared secret.
+ */
+
+isc_result_t
+dst_key_fromfile(dns_name_t *name, dns_keytag_t id, unsigned int alg, int type,
+ const char *directory, isc_mem_t *mctx, dst_key_t **keyp);
+/*%<
+ * Reads a key from permanent storage. The key can either be a public or
+ * private key, and is specified by name, algorithm, and id. If a private key
+ * is specified, the public key must also be present. If directory is NULL,
+ * the current directory is assumed.
+ *
+ * Requires:
+ * \li "name" is a valid absolute dns name.
+ * \li "id" is a valid key tag identifier.
+ * \li "alg" is a supported key algorithm.
+ * \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union.
+ * DST_TYPE_KEY look for a KEY record otherwise DNSKEY
+ * \li "mctx" is a valid memory context.
+ * \li "keyp" is not NULL and "*keyp" is NULL.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li any other result indicates failure
+ *
+ * Ensures:
+ * \li If successful, *keyp will contain a valid key.
+ */
+
+isc_result_t
+dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx,
+ dst_key_t **keyp);
+/*%<
+ * Reads a key from permanent storage. The key can either be a public or
+ * key, and is specified by filename. If a private key is specified, the
+ * public key must also be present.
+ *
+ * Requires:
+ * \li "filename" is not NULL
+ * \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union
+ * DST_TYPE_KEY look for a KEY record otherwise DNSKEY
+ * \li "mctx" is a valid memory context
+ * \li "keyp" is not NULL and "*keyp" is NULL.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li any other result indicates failure
+ *
+ * Ensures:
+ * \li If successful, *keyp will contain a valid key.
+ */
+
+
+isc_result_t
+dst_key_read_public(const char *filename, int type,
+ isc_mem_t *mctx, dst_key_t **keyp);
+/*%<
+ * Reads a public key from permanent storage. The key must be a public key.
+ *
+ * Requires:
+ * \li "filename" is not NULL
+ * \li "type" is DST_TYPE_KEY look for a KEY record otherwise DNSKEY
+ * \li "mctx" is a valid memory context
+ * \li "keyp" is not NULL and "*keyp" is NULL.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li DST_R_BADKEYTYPE if the key type is not the expected one
+ * \li ISC_R_UNEXPECTEDTOKEN if the file can not be parsed as a public key
+ * \li any other result indicates failure
+ *
+ * Ensures:
+ * \li If successful, *keyp will contain a valid key.
+ */
+
+isc_result_t
+dst_key_tofile(const dst_key_t *key, int type, const char *directory);
+/*%<
+ * Writes a key to permanent storage. The key can either be a public or
+ * private key. Public keys are written in DNS format and private keys
+ * are written as a set of base64 encoded values. If directory is NULL,
+ * the current directory is assumed.
+ *
+ * Requires:
+ * \li "key" is a valid key.
+ * \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li any other result indicates failure
+ */
+
+isc_result_t
+dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass,
+ isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
+/*%<
+ * Converts a DNS KEY record into a DST key.
+ *
+ * Requires:
+ * \li "name" is a valid absolute dns name.
+ * \li "source" is a valid buffer. There must be at least 4 bytes available.
+ * \li "mctx" is a valid memory context.
+ * \li "keyp" is not NULL and "*keyp" is NULL.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li any other result indicates failure
+ *
+ * Ensures:
+ * \li If successful, *keyp will contain a valid key, and the consumed
+ * pointer in data will be advanced.
+ */
+
+isc_result_t
+dst_key_todns(const dst_key_t *key, isc_buffer_t *target);
+/*%<
+ * Converts a DST key into a DNS KEY record.
+ *
+ * Requires:
+ * \li "key" is a valid key.
+ * \li "target" is a valid buffer. There must be at least 4 bytes unused.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li any other result indicates failure
+ *
+ * Ensures:
+ * \li If successful, the used pointer in 'target' is advanced by at least 4.
+ */
+
+isc_result_t
+dst_key_frombuffer(dns_name_t *name, unsigned int alg,
+ unsigned int flags, unsigned int protocol,
+ dns_rdataclass_t rdclass,
+ isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
+/*%<
+ * Converts a buffer containing DNS KEY RDATA into a DST key.
+ *
+ * Requires:
+ *\li "name" is a valid absolute dns name.
+ *\li "alg" is a supported key algorithm.
+ *\li "source" is a valid buffer.
+ *\li "mctx" is a valid memory context.
+ *\li "keyp" is not NULL and "*keyp" is NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ * \li any other result indicates failure
+ *
+ * Ensures:
+ *\li If successful, *keyp will contain a valid key, and the consumed
+ * pointer in source will be advanced.
+ */
+
+isc_result_t
+dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target);
+/*%<
+ * Converts a DST key into DNS KEY RDATA format.
+ *
+ * Requires:
+ *\li "key" is a valid key.
+ *\li "target" is a valid buffer.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ * \li any other result indicates failure
+ *
+ * Ensures:
+ *\li If successful, the used pointer in 'target' is advanced.
+ */
+
+isc_result_t
+dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer);
+/*%<
+ * Converts a public key into a private key, reading the private key
+ * information from the buffer. The buffer should contain the same data
+ * as the .private key file would.
+ *
+ * Requires:
+ *\li "key" is a valid public key.
+ *\li "buffer" is not NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ * \li any other result indicates failure
+ *
+ * Ensures:
+ *\li If successful, key will contain a valid private key.
+ */
+
+
+isc_result_t
+dst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx,
+ dst_key_t **keyp);
+/*%<
+ * Converts a GSSAPI opaque context id into a DST key.
+ *
+ * Requires:
+ *\li "name" is a valid absolute dns name.
+ *\li "opaque" is a GSSAPI context id.
+ *\li "mctx" is a valid memory context.
+ *\li "keyp" is not NULL and "*keyp" is NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ * \li any other result indicates failure
+ *
+ * Ensures:
+ *\li If successful, *keyp will contain a valid key and be responsible for
+ * the context id.
+ */
+
+isc_result_t
+dst_key_generate(dns_name_t *name, unsigned int alg,
+ unsigned int bits, unsigned int param,
+ unsigned int flags, unsigned int protocol,
+ dns_rdataclass_t rdclass,
+ isc_mem_t *mctx, dst_key_t **keyp);
+/*%<
+ * Generate a DST key (or keypair) with the supplied parameters. The
+ * interpretation of the "param" field depends on the algorithm:
+ * \code
+ * RSA: exponent
+ * 0 use exponent 3
+ * !0 use Fermat4 (2^16 + 1)
+ * DH: generator
+ * 0 default - use well known prime if bits == 768 or 1024,
+ * otherwise use 2 as the generator.
+ * !0 use this value as the generator.
+ * DSA: unused
+ * HMACMD5: entropy
+ * 0 default - require good entropy
+ * !0 lack of good entropy is ok
+ *\endcode
+ *
+ * Requires:
+ *\li "name" is a valid absolute dns name.
+ *\li "keyp" is not NULL and "*keyp" is NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ * \li any other result indicates failure
+ *
+ * Ensures:
+ *\li If successful, *keyp will contain a valid key.
+ */
+
+isc_boolean_t
+dst_key_compare(const dst_key_t *key1, const dst_key_t *key2);
+/*%<
+ * Compares two DST keys.
+ *
+ * Requires:
+ *\li "key1" is a valid key.
+ *\li "key2" is a valid key.
+ *
+ * Returns:
+ *\li ISC_TRUE
+ * \li ISC_FALSE
+ */
+
+isc_boolean_t
+dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2);
+/*%<
+ * Compares the parameters of two DST keys. This is used to determine if
+ * two (Diffie-Hellman) keys can be used to derive a shared secret.
+ *
+ * Requires:
+ *\li "key1" is a valid key.
+ *\li "key2" is a valid key.
+ *
+ * Returns:
+ *\li ISC_TRUE
+ * \li ISC_FALSE
+ */
+
+void
+dst_key_free(dst_key_t **keyp);
+/*%<
+ * Release all memory associated with the key.
+ *
+ * Requires:
+ *\li "keyp" is not NULL and "*keyp" is a valid key.
+ *
+ * Ensures:
+ *\li All memory associated with "*keyp" will be freed.
+ *\li *keyp == NULL
+ */
+
+/*%<
+ * Accessor functions to obtain key fields.
+ *
+ * Require:
+ *\li "key" is a valid key.
+ */
+dns_name_t *
+dst_key_name(const dst_key_t *key);
+
+unsigned int
+dst_key_size(const dst_key_t *key);
+
+unsigned int
+dst_key_proto(const dst_key_t *key);
+
+unsigned int
+dst_key_alg(const dst_key_t *key);
+
+isc_uint32_t
+dst_key_flags(const dst_key_t *key);
+
+dns_keytag_t
+dst_key_id(const dst_key_t *key);
+
+dns_rdataclass_t
+dst_key_class(const dst_key_t *key);
+
+isc_boolean_t
+dst_key_isprivate(const dst_key_t *key);
+
+isc_boolean_t
+dst_key_iszonekey(const dst_key_t *key);
+
+isc_boolean_t
+dst_key_isnullkey(const dst_key_t *key);
+
+isc_result_t
+dst_key_buildfilename(const dst_key_t *key, int type,
+ const char *directory, isc_buffer_t *out);
+/*%<
+ * Generates the filename used by dst to store the specified key.
+ * If directory is NULL, the current directory is assumed.
+ *
+ * Requires:
+ *\li "key" is a valid key
+ *\li "type" is either DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or 0 for no suffix.
+ *\li "out" is a valid buffer
+ *
+ * Ensures:
+ *\li the file name will be written to "out", and the used pointer will
+ * be advanced.
+ */
+
+isc_result_t
+dst_key_sigsize(const dst_key_t *key, unsigned int *n);
+/*%<
+ * Computes the size of a signature generated by the given key.
+ *
+ * Requires:
+ *\li "key" is a valid key.
+ *\li "n" is not NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li DST_R_UNSUPPORTEDALG
+ *
+ * Ensures:
+ *\li "n" stores the size of a generated signature
+ */
+
+isc_result_t
+dst_key_secretsize(const dst_key_t *key, unsigned int *n);
+/*%<
+ * Computes the size of a shared secret generated by the given key.
+ *
+ * Requires:
+ *\li "key" is a valid key.
+ *\li "n" is not NULL
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li DST_R_UNSUPPORTEDALG
+ *
+ * Ensures:
+ *\li "n" stores the size of a generated shared secret
+ */
+
+isc_uint16_t
+dst_region_computeid(const isc_region_t *source, unsigned int alg);
+/*%<
+ * Computes the key id of the key stored in the provided region with the
+ * given algorithm.
+ *
+ * Requires:
+ *\li "source" contains a valid, non-NULL region.
+ *
+ * Returns:
+ *\li the key id
+ */
+
+isc_uint16_t
+dst_key_getbits(const dst_key_t *key);
+/*
+ * Get the number of digest bits required (0 == MAX).
+ *
+ * Requires:
+ * "key" is a valid key.
+ */
+
+void
+dst_key_setbits(dst_key_t *key, isc_uint16_t bits);
+/*
+ * Set the number of digest bits required (0 == MAX).
+ *
+ * Requires:
+ * "key" is a valid key.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DST_DST_H */
diff --git a/lib/dns/include/dst/gssapi.h b/lib/dns/include/dst/gssapi.h
new file mode 100644
index 0000000..e30fb0c
--- /dev/null
+++ b/lib/dns/include/dst/gssapi.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2004, 2005 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: gssapi.h,v 1.1.6.3 2005/04/29 00:16:28 marka Exp $ */
+
+#ifndef DST_GSSAPI_H
+#define DST_GSSAPI_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred);
+
+isc_result_t
+dst_gssapi_initctx(dns_name_t *name, void *cred,
+ isc_region_t *intoken, isc_buffer_t *outtoken,
+ void **context);
+
+isc_result_t
+dst_gssapi_acceptctx(dns_name_t *name, void *cred,
+ isc_region_t *intoken, isc_buffer_t *outtoken,
+ void **context);
+
+/*
+ * XXX
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DST_GSSAPI_H */
diff --git a/lib/dns/include/dst/lib.h b/lib/dns/include/dst/lib.h
new file mode 100644
index 0000000..bd71261
--- /dev/null
+++ b/lib/dns/include/dst/lib.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2004, 2005 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: lib.h,v 1.1.6.3 2005/04/29 00:16:29 marka Exp $ */
+
+#ifndef DST_LIB_H
+#define DST_LIB_H 1
+
+/*! \file */
+
+#include <isc/types.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+LIBDNS_EXTERNAL_DATA extern isc_msgcat_t *dst_msgcat;
+
+void
+dst_lib_initmsgcat(void);
+/*
+ * Initialize the DST library's message catalog, dst_msgcat, if it
+ * has not already been initialized.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DST_LIB_H */
diff --git a/lib/dns/include/dst/result.h b/lib/dns/include/dst/result.h
new file mode 100644
index 0000000..aa03b73
--- /dev/null
+++ b/lib/dns/include/dst/result.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2004, 2005 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: result.h,v 1.1.6.3 2005/04/29 00:16:29 marka Exp $ */
+
+#ifndef DST_RESULT_H
+#define DST_RESULT_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/resultclass.h>
+
+/*
+ * Nothing in this file truly depends on <isc/result.h>, but the
+ * DST result codes are considered to be publicly derived from
+ * the ISC result codes, so including this file buys you the ISC_R_
+ * namespace too.
+ */
+#include <isc/result.h> /* Contractual promise. */
+
+#define DST_R_UNSUPPORTEDALG (ISC_RESULTCLASS_DST + 0)
+#define DST_R_OPENSSLFAILURE (ISC_RESULTCLASS_DST + 1)
+#define DST_R_NOCRYPTO (ISC_RESULTCLASS_DST + 2)
+#define DST_R_NULLKEY (ISC_RESULTCLASS_DST + 3)
+#define DST_R_INVALIDPUBLICKEY (ISC_RESULTCLASS_DST + 4)
+#define DST_R_INVALIDPRIVATEKEY (ISC_RESULTCLASS_DST + 5)
+/* 6 is unused */
+#define DST_R_WRITEERROR (ISC_RESULTCLASS_DST + 7)
+#define DST_R_INVALIDPARAM (ISC_RESULTCLASS_DST + 8)
+/* 9 is unused */
+/* 10 is unused */
+#define DST_R_SIGNFAILURE (ISC_RESULTCLASS_DST + 11)
+/* 12 is unused */
+/* 13 is unused */
+#define DST_R_VERIFYFAILURE (ISC_RESULTCLASS_DST + 14)
+#define DST_R_NOTPUBLICKEY (ISC_RESULTCLASS_DST + 15)
+#define DST_R_NOTPRIVATEKEY (ISC_RESULTCLASS_DST + 16)
+#define DST_R_KEYCANNOTCOMPUTESECRET (ISC_RESULTCLASS_DST + 17)
+#define DST_R_COMPUTESECRETFAILURE (ISC_RESULTCLASS_DST + 18)
+#define DST_R_NORANDOMNESS (ISC_RESULTCLASS_DST + 19)
+#define DST_R_BADKEYTYPE (ISC_RESULTCLASS_DST + 20)
+
+#define DST_R_NRESULTS 21 /* Number of results */
+
+ISC_LANG_BEGINDECLS
+
+const char *
+dst_result_totext(isc_result_t);
+
+void
+dst_result_register(void);
+
+ISC_LANG_ENDDECLS
+
+#endif /* DST_RESULT_H */
diff --git a/lib/dns/journal.c b/lib/dns/journal.c
new file mode 100644
index 0000000..6cfb5af
--- /dev/null
+++ b/lib/dns/journal.c
@@ -0,0 +1,2182 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2002 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: journal.c,v 1.86.18.12 2007/09/07 05:21:41 marka Exp $ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <isc/file.h>
+#include <isc/mem.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/compress.h>
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/diff.h>
+#include <dns/fixedname.h>
+#include <dns/journal.h>
+#include <dns/log.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/result.h>
+#include <dns/soa.h>
+
+/*! \file
+ * \brief Journalling.
+ *
+ * A journal file consists of
+ *
+ * \li A fixed-size header of type journal_rawheader_t.
+ *
+ * \li The index. This is an unordered array of index entries
+ * of type journal_rawpos_t giving the locations
+ * of some arbitrary subset of the journal's addressable
+ * transactions. The index entries are used as hints to
+ * speed up the process of locating a transaction with a given
+ * serial number. Unused index entries have an "offset"
+ * field of zero. The size of the index can vary between
+ * journal files, but does not change during the lifetime
+ * of a file. The size can be zero.
+ *
+ * \li The journal data. This consists of one or more transactions.
+ * Each transaction begins with a transaction header of type
+ * journal_rawxhdr_t. The transaction header is followed by a
+ * sequence of RRs, similar in structure to an IXFR difference
+ * sequence (RFC1995). That is, the pre-transaction SOA,
+ * zero or more other deleted RRs, the post-transaction SOA,
+ * and zero or more other added RRs. Unlike in IXFR, each RR
+ * is prefixed with a 32-bit length.
+ *
+ * The journal data part grows as new transactions are
+ * appended to the file. Only those transactions
+ * whose serial number is current-(2^31-1) to current
+ * are considered "addressable" and may be pointed
+ * to from the header or index. They may be preceded
+ * by old transactions that are no longer addressable,
+ * and they may be followed by transactions that were
+ * appended to the journal but never committed by updating
+ * the "end" position in the header. The latter will
+ * be overwritten when new transactions are added.
+ */
+/*%
+ * When true, accept IXFR difference sequences where the
+ * SOA serial number does not change (BIND 8 sends such
+ * sequences).
+ */
+static isc_boolean_t bind8_compat = ISC_TRUE; /* XXX config */
+
+/**************************************************************************/
+/*
+ * Miscellaneous utilities.
+ */
+
+#define JOURNAL_COMMON_LOGARGS \
+ dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_JOURNAL
+
+#define JOURNAL_DEBUG_LOGARGS(n) \
+ JOURNAL_COMMON_LOGARGS, ISC_LOG_DEBUG(n)
+
+/*%
+ * It would be non-sensical (or at least obtuse) to use FAIL() with an
+ * ISC_R_SUCCESS code, but the test 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)
+
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto failure; \
+ } while (0)
+
+static isc_result_t index_to_disk(dns_journal_t *);
+
+static inline isc_uint32_t
+decode_uint32(unsigned char *p) {
+ return ((p[0] << 24) +
+ (p[1] << 16) +
+ (p[2] << 8) +
+ (p[3] << 0));
+}
+
+static inline void
+encode_uint32(isc_uint32_t val, unsigned char *p) {
+ p[0] = (isc_uint8_t)(val >> 24);
+ p[1] = (isc_uint8_t)(val >> 16);
+ p[2] = (isc_uint8_t)(val >> 8);
+ p[3] = (isc_uint8_t)(val >> 0);
+}
+
+isc_result_t
+dns_db_createsoatuple(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx,
+ dns_diffop_t op, dns_difftuple_t **tp)
+{
+ isc_result_t result;
+ dns_dbnode_t *node;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_name_t *zonename;
+
+ zonename = dns_db_origin(db);
+
+ node = NULL;
+ result = dns_db_findnode(db, zonename, ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto nonode;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0,
+ (isc_stdtime_t)0, &rdataset, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto freenode;
+
+ result = dns_rdataset_first(&rdataset);
+ if (result != ISC_R_SUCCESS)
+ goto freenode;
+
+ dns_rdataset_current(&rdataset, &rdata);
+
+ result = dns_difftuple_create(mctx, op, zonename, rdataset.ttl,
+ &rdata, tp);
+
+ dns_rdataset_disassociate(&rdataset);
+ dns_db_detachnode(db, &node);
+ return (ISC_R_SUCCESS);
+
+ freenode:
+ dns_db_detachnode(db, &node);
+ nonode:
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "missing SOA");
+ return (result);
+}
+
+/* Journalling */
+
+/*%
+ * On-disk representation of a "pointer" to a journal entry.
+ * These are used in the journal header to locate the beginning
+ * and end of the journal, and in the journal index to locate
+ * other transactions.
+ */
+typedef struct {
+ unsigned char serial[4]; /*%< SOA serial before update. */
+ /*
+ * XXXRTH Should offset be 8 bytes?
+ * XXXDCL ... probably, since isc_offset_t is 8 bytes on many OSs.
+ * XXXAG ... but we will not be able to seek >2G anyway on many
+ * platforms as long as we are using fseek() rather
+ * than lseek().
+ */
+ unsigned char offset[4]; /*%< Offset from beginning of file. */
+} journal_rawpos_t;
+
+
+/*%
+ * The header is of a fixed size, with some spare room for future
+ * extensions.
+ */
+#define JOURNAL_HEADER_SIZE 64 /* Bytes. */
+
+/*%
+ * The on-disk representation of the journal header.
+ * All numbers are stored in big-endian order.
+ */
+typedef union {
+ struct {
+ /*% File format version ID. */
+ unsigned char format[16];
+ /*% Position of the first addressable transaction */
+ journal_rawpos_t begin;
+ /*% Position of the next (yet nonexistent) transaction. */
+ journal_rawpos_t end;
+ /*% Number of index entries following the header. */
+ unsigned char index_size[4];
+ } h;
+ /* Pad the header to a fixed size. */
+ unsigned char pad[JOURNAL_HEADER_SIZE];
+} journal_rawheader_t;
+
+/*%
+ * The on-disk representation of the transaction header.
+ * There is one of these at the beginning of each transaction.
+ */
+typedef struct {
+ unsigned char size[4]; /*%< In bytes, excluding header. */
+ unsigned char serial0[4]; /*%< SOA serial before update. */
+ unsigned char serial1[4]; /*%< SOA serial after update. */
+} journal_rawxhdr_t;
+
+/*%
+ * The on-disk representation of the RR header.
+ * There is one of these at the beginning of each RR.
+ */
+typedef struct {
+ unsigned char size[4]; /*%< In bytes, excluding header. */
+} journal_rawrrhdr_t;
+
+/*%
+ * The in-core representation of the journal header.
+ */
+typedef struct {
+ isc_uint32_t serial;
+ isc_offset_t offset;
+} journal_pos_t;
+
+#define POS_VALID(pos) ((pos).offset != 0)
+#define POS_INVALIDATE(pos) ((pos).offset = 0, (pos).serial = 0)
+
+typedef struct {
+ unsigned char format[16];
+ journal_pos_t begin;
+ journal_pos_t end;
+ isc_uint32_t index_size;
+} journal_header_t;
+
+/*%
+ * The in-core representation of the transaction header.
+ */
+
+typedef struct {
+ isc_uint32_t size;
+ isc_uint32_t serial0;
+ isc_uint32_t serial1;
+} journal_xhdr_t;
+
+/*%
+ * The in-core representation of the RR header.
+ */
+typedef struct {
+ isc_uint32_t size;
+} journal_rrhdr_t;
+
+
+/*%
+ * Initial contents to store in the header of a newly created
+ * journal file.
+ *
+ * The header starts with the magic string ";BIND LOG V9\n"
+ * to identify the file as a BIND 9 journal file. An ASCII
+ * identification string is used rather than a binary magic
+ * number to be consistent with BIND 8 (BIND 8 journal files
+ * are ASCII text files).
+ */
+
+static journal_header_t
+initial_journal_header = { ";BIND LOG V9\n", { 0, 0 }, { 0, 0 }, 0 };
+
+#define JOURNAL_EMPTY(h) ((h)->begin.offset == (h)->end.offset)
+
+typedef enum {
+ JOURNAL_STATE_INVALID,
+ JOURNAL_STATE_READ,
+ JOURNAL_STATE_WRITE,
+ JOURNAL_STATE_TRANSACTION
+} journal_state_t;
+
+struct dns_journal {
+ unsigned int magic; /*%< JOUR */
+ isc_mem_t *mctx; /*%< Memory context */
+ journal_state_t state;
+ const char *filename; /*%< Journal file name */
+ FILE * fp; /*%< File handle */
+ isc_offset_t offset; /*%< Current file offset */
+ journal_header_t header; /*%< In-core journal header */
+ unsigned char *rawindex; /*%< In-core buffer for journal index in on-disk format */
+ journal_pos_t *index; /*%< In-core journal index */
+
+ /*% Current transaction state (when writing). */
+ struct {
+ unsigned int n_soa; /*%< Number of SOAs seen */
+ journal_pos_t pos[2]; /*%< Begin/end position */
+ } x;
+
+ /*% Iteration state (when reading). */
+ struct {
+ /* These define the part of the journal we iterate over. */
+ journal_pos_t bpos; /*%< Position before first, */
+ journal_pos_t epos; /*%< and after last transaction */
+ /* The rest is iterator state. */
+ isc_uint32_t current_serial; /*%< Current SOA serial */
+ isc_buffer_t source; /*%< Data from disk */
+ isc_buffer_t target; /*%< Data from _fromwire check */
+ dns_decompress_t dctx; /*%< Dummy decompression ctx */
+ dns_name_t name; /*%< Current domain name */
+ dns_rdata_t rdata; /*%< Current rdata */
+ isc_uint32_t ttl; /*%< Current TTL */
+ unsigned int xsize; /*%< Size of transaction data */
+ unsigned int xpos; /*%< Current position in it */
+ isc_result_t result; /*%< Result of last call */
+ } it;
+};
+
+#define DNS_JOURNAL_MAGIC ISC_MAGIC('J', 'O', 'U', 'R')
+#define DNS_JOURNAL_VALID(t) ISC_MAGIC_VALID(t, DNS_JOURNAL_MAGIC)
+
+static void
+journal_pos_decode(journal_rawpos_t *raw, journal_pos_t *cooked) {
+ cooked->serial = decode_uint32(raw->serial);
+ cooked->offset = decode_uint32(raw->offset);
+}
+
+static void
+journal_pos_encode(journal_rawpos_t *raw, journal_pos_t *cooked) {
+ encode_uint32(cooked->serial, raw->serial);
+ encode_uint32(cooked->offset, raw->offset);
+}
+
+static void
+journal_header_decode(journal_rawheader_t *raw, journal_header_t *cooked) {
+ INSIST(sizeof(cooked->format) == sizeof(raw->h.format));
+ memcpy(cooked->format, raw->h.format, sizeof(cooked->format));
+ journal_pos_decode(&raw->h.begin, &cooked->begin);
+ journal_pos_decode(&raw->h.end, &cooked->end);
+ cooked->index_size = decode_uint32(raw->h.index_size);
+}
+
+static void
+journal_header_encode(journal_header_t *cooked, journal_rawheader_t *raw) {
+ INSIST(sizeof(cooked->format) == sizeof(raw->h.format));
+ memset(raw->pad, 0, sizeof(raw->pad));
+ memcpy(raw->h.format, cooked->format, sizeof(raw->h.format));
+ journal_pos_encode(&raw->h.begin, &cooked->begin);
+ journal_pos_encode(&raw->h.end, &cooked->end);
+ encode_uint32(cooked->index_size, raw->h.index_size);
+}
+
+/*
+ * Journal file I/O subroutines, with error checking and reporting.
+ */
+static isc_result_t
+journal_seek(dns_journal_t *j, isc_uint32_t offset) {
+ isc_result_t result;
+ result = isc_stdio_seek(j->fp, (long)offset, SEEK_SET);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: seek: %s", j->filename,
+ isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+ j->offset = offset;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+journal_read(dns_journal_t *j, void *mem, size_t nbytes) {
+ isc_result_t result;
+
+ result = isc_stdio_read(mem, 1, nbytes, j->fp, NULL);
+ if (result != ISC_R_SUCCESS) {
+ if (result == ISC_R_EOF)
+ return (ISC_R_NOMORE);
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: read: %s",
+ j->filename, isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+ j->offset += nbytes;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+journal_write(dns_journal_t *j, void *mem, size_t nbytes) {
+ isc_result_t result;
+
+ result = isc_stdio_write(mem, 1, nbytes, j->fp, NULL);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: write: %s",
+ j->filename, isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+ j->offset += nbytes;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+journal_fsync(dns_journal_t *j) {
+ isc_result_t result;
+ result = isc_stdio_flush(j->fp);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: flush: %s",
+ j->filename, isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+ result = isc_stdio_sync(j->fp);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: fsync: %s",
+ j->filename, isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Read/write a transaction header at the current file position.
+ */
+
+static isc_result_t
+journal_read_xhdr(dns_journal_t *j, journal_xhdr_t *xhdr) {
+ journal_rawxhdr_t raw;
+ isc_result_t result;
+ result = journal_read(j, &raw, sizeof(raw));
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ xhdr->size = decode_uint32(raw.size);
+ xhdr->serial0 = decode_uint32(raw.serial0);
+ xhdr->serial1 = decode_uint32(raw.serial1);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+journal_write_xhdr(dns_journal_t *j, isc_uint32_t size,
+ isc_uint32_t serial0, isc_uint32_t serial1)
+{
+ journal_rawxhdr_t raw;
+ encode_uint32(size, raw.size);
+ encode_uint32(serial0, raw.serial0);
+ encode_uint32(serial1, raw.serial1);
+ return (journal_write(j, &raw, sizeof(raw)));
+}
+
+
+/*
+ * Read an RR header at the current file position.
+ */
+
+static isc_result_t
+journal_read_rrhdr(dns_journal_t *j, journal_rrhdr_t *rrhdr) {
+ journal_rawrrhdr_t raw;
+ isc_result_t result;
+ result = journal_read(j, &raw, sizeof(raw));
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ rrhdr->size = decode_uint32(raw.size);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+journal_file_create(isc_mem_t *mctx, const char *filename) {
+ FILE *fp = NULL;
+ isc_result_t result;
+ journal_header_t header;
+ journal_rawheader_t rawheader;
+ int index_size = 56; /* XXX configurable */
+ int size;
+ void *mem; /* Memory for temporary index image. */
+
+ INSIST(sizeof(journal_rawheader_t) == JOURNAL_HEADER_SIZE);
+
+ result = isc_stdio_open(filename, "wb", &fp);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: create: %s",
+ filename, isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+
+ header = initial_journal_header;
+ header.index_size = index_size;
+ journal_header_encode(&header, &rawheader);
+
+ size = sizeof(journal_rawheader_t) +
+ index_size * sizeof(journal_rawpos_t);
+
+ mem = isc_mem_get(mctx, size);
+ if (mem == NULL) {
+ (void)isc_stdio_close(fp);
+ (void)isc_file_remove(filename);
+ return (ISC_R_NOMEMORY);
+ }
+ memset(mem, 0, size);
+ memcpy(mem, &rawheader, sizeof(rawheader));
+
+ result = isc_stdio_write(mem, 1, (size_t) size, fp, NULL);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: write: %s",
+ filename, isc_result_totext(result));
+ (void)isc_stdio_close(fp);
+ (void)isc_file_remove(filename);
+ isc_mem_put(mctx, mem, size);
+ return (ISC_R_UNEXPECTED);
+ }
+ isc_mem_put(mctx, mem, size);
+
+ result = isc_stdio_close(fp);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: close: %s",
+ filename, isc_result_totext(result));
+ (void)isc_file_remove(filename);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
+ isc_boolean_t create, dns_journal_t **journalp) {
+ FILE *fp = NULL;
+ isc_result_t result;
+ journal_rawheader_t rawheader;
+ dns_journal_t *j;
+
+ INSIST(journalp != NULL && *journalp == NULL);
+ j = isc_mem_get(mctx, sizeof(*j));
+ if (j == NULL)
+ return (ISC_R_NOMEMORY);
+
+ j->mctx = mctx;
+ j->state = JOURNAL_STATE_INVALID;
+ j->fp = NULL;
+ j->filename = filename;
+ j->index = NULL;
+ j->rawindex = NULL;
+
+ result = isc_stdio_open(j->filename, write ? "rb+" : "rb", &fp);
+
+ if (result == ISC_R_FILENOTFOUND) {
+ if (create) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS,
+ ISC_LOG_INFO,
+ "journal file %s does not exist, "
+ "creating it",
+ j->filename);
+ CHECK(journal_file_create(mctx, filename));
+ /*
+ * Retry.
+ */
+ result = isc_stdio_open(j->filename, "rb+", &fp);
+ } else {
+ FAIL(ISC_R_NOTFOUND);
+ }
+ }
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: open: %s",
+ j->filename, isc_result_totext(result));
+ FAIL(ISC_R_UNEXPECTED);
+ }
+
+ j->fp = fp;
+
+ /*
+ * Set magic early so that seek/read can succeed.
+ */
+ j->magic = DNS_JOURNAL_MAGIC;
+
+ CHECK(journal_seek(j, 0));
+ CHECK(journal_read(j, &rawheader, sizeof(rawheader)));
+
+ if (memcmp(rawheader.h.format, initial_journal_header.format,
+ sizeof(initial_journal_header.format)) != 0) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: journal format not recognized",
+ j->filename);
+ FAIL(ISC_R_UNEXPECTED);
+ }
+ journal_header_decode(&rawheader, &j->header);
+
+ /*
+ * If there is an index, read the raw index into a dynamically
+ * allocated buffer and then convert it into a cooked index.
+ */
+ if (j->header.index_size != 0) {
+ unsigned int i;
+ unsigned int rawbytes;
+ unsigned char *p;
+
+ rawbytes = j->header.index_size * sizeof(journal_rawpos_t);
+ j->rawindex = isc_mem_get(mctx, rawbytes);
+ if (j->rawindex == NULL)
+ FAIL(ISC_R_NOMEMORY);
+
+ CHECK(journal_read(j, j->rawindex, rawbytes));
+
+ j->index = isc_mem_get(mctx, j->header.index_size *
+ sizeof(journal_pos_t));
+ if (j->index == NULL)
+ FAIL(ISC_R_NOMEMORY);
+
+ p = j->rawindex;
+ for (i = 0; i < j->header.index_size; i++) {
+ j->index[i].serial = decode_uint32(p);
+ p += 4;
+ j->index[i].offset = decode_uint32(p);
+ p += 4;
+ }
+ INSIST(p == j->rawindex + rawbytes);
+ }
+ j->offset = -1; /* Invalid, must seek explicitly. */
+
+ /*
+ * Initialize the iterator.
+ */
+ dns_name_init(&j->it.name, NULL);
+ dns_rdata_init(&j->it.rdata);
+
+ /*
+ * Set up empty initial buffers for uncheched and checked
+ * wire format RR data. They will be reallocated
+ * later.
+ */
+ isc_buffer_init(&j->it.source, NULL, 0);
+ isc_buffer_init(&j->it.target, NULL, 0);
+ dns_decompress_init(&j->it.dctx, -1, DNS_DECOMPRESS_NONE);
+
+ j->state =
+ write ? JOURNAL_STATE_WRITE : JOURNAL_STATE_READ;
+
+ *journalp = j;
+ return (ISC_R_SUCCESS);
+
+ failure:
+ j->magic = 0;
+ if (j->index != NULL) {
+ isc_mem_put(j->mctx, j->index, j->header.index_size *
+ sizeof(journal_rawpos_t));
+ j->index = NULL;
+ }
+ if (j->fp != NULL)
+ (void)isc_stdio_close(j->fp);
+ isc_mem_put(j->mctx, j, sizeof(*j));
+ return (result);
+}
+
+isc_result_t
+dns_journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
+ dns_journal_t **journalp) {
+ isc_result_t result;
+ int namelen;
+ char backup[1024];
+
+ result = journal_open(mctx, filename, write, write, journalp);
+ if (result == ISC_R_NOTFOUND) {
+ namelen = strlen(filename);
+ if (namelen > 4 && strcmp(filename + namelen - 4, ".jnl") == 0)
+ namelen -= 4;
+
+ result = isc_string_printf(backup, sizeof(backup), "%.*s.jbk",
+ namelen, filename);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = journal_open(mctx, backup, write, write, journalp);
+ }
+ return (result);
+}
+
+/*
+ * A comparison function defining the sorting order for
+ * entries in the IXFR-style journal file.
+ *
+ * The IXFR format requires that deletions are sorted before
+ * additions, and within either one, SOA records are sorted
+ * before others.
+ *
+ * Also sort the non-SOA records by type as a courtesy to the
+ * server receiving the IXFR - it may help reduce the amount of
+ * rdataset merging it has to do.
+ */
+static int
+ixfr_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 = (b->op == DNS_DIFFOP_DEL) - (a->op == DNS_DIFFOP_DEL);
+ if (r != 0)
+ return (r);
+
+ r = (b->rdata.type == dns_rdatatype_soa) -
+ (a->rdata.type == dns_rdatatype_soa);
+ if (r != 0)
+ return (r);
+
+ r = (a->rdata.type - b->rdata.type);
+ return (r);
+}
+
+/*
+ * Advance '*pos' to the next journal transaction.
+ *
+ * Requires:
+ * *pos refers to a valid journal transaction.
+ *
+ * Ensures:
+ * When ISC_R_SUCCESS is returned,
+ * *pos refers to the next journal transaction.
+ *
+ * Returns one of:
+ *
+ * ISC_R_SUCCESS
+ * ISC_R_NOMORE *pos pointed at the last transaction
+ * Other results due to file errors are possible.
+ */
+static isc_result_t
+journal_next(dns_journal_t *j, journal_pos_t *pos) {
+ isc_result_t result;
+ journal_xhdr_t xhdr;
+ REQUIRE(DNS_JOURNAL_VALID(j));
+
+ result = journal_seek(j, pos->offset);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (pos->serial == j->header.end.serial)
+ return (ISC_R_NOMORE);
+ /*
+ * Read the header of the current transaction.
+ * This will return ISC_R_NOMORE if we are at EOF.
+ */
+ result = journal_read_xhdr(j, &xhdr);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Check serial number consistency.
+ */
+ if (xhdr.serial0 != pos->serial) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: journal file corrupt: "
+ "expected serial %u, got %u",
+ j->filename, pos->serial, xhdr.serial0);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ /*
+ * Check for offset wraparound.
+ */
+ if ((isc_offset_t)(pos->offset + sizeof(journal_rawxhdr_t) + xhdr.size)
+ < pos->offset) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: offset too large", j->filename);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ pos->offset += sizeof(journal_rawxhdr_t) + xhdr.size;
+ pos->serial = xhdr.serial1;
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * If the index of the journal 'j' contains an entry "better"
+ * than '*best_guess', replace '*best_guess' with it.
+ *
+ * "Better" means having a serial number closer to 'serial'
+ * but not greater than 'serial'.
+ */
+static void
+index_find(dns_journal_t *j, isc_uint32_t serial, journal_pos_t *best_guess) {
+ unsigned int i;
+ if (j->index == NULL)
+ return;
+ for (i = 0; i < j->header.index_size; i++) {
+ if (POS_VALID(j->index[i]) &&
+ DNS_SERIAL_GE(serial, j->index[i].serial) &&
+ DNS_SERIAL_GT(j->index[i].serial, best_guess->serial))
+ *best_guess = j->index[i];
+ }
+}
+
+/*
+ * Add a new index entry. If there is no room, make room by removing
+ * the odd-numbered entries and compacting the others into the first
+ * half of the index. This decimates old index entries exponentially
+ * over time, so that the index always contains a much larger fraction
+ * of recent serial numbers than of old ones. This is deliberate -
+ * most index searches are for outgoing IXFR, and IXFR tends to request
+ * recent versions more often than old ones.
+ */
+static void
+index_add(dns_journal_t *j, journal_pos_t *pos) {
+ unsigned int i;
+ if (j->index == NULL)
+ return;
+ /*
+ * Search for a vacant position.
+ */
+ for (i = 0; i < j->header.index_size; i++) {
+ if (! POS_VALID(j->index[i]))
+ break;
+ }
+ if (i == j->header.index_size) {
+ unsigned int k = 0;
+ /*
+ * Found no vacant position. Make some room.
+ */
+ for (i = 0; i < j->header.index_size; i += 2) {
+ j->index[k++] = j->index[i];
+ }
+ i = k; /* 'i' identifies the first vacant position. */
+ while (k < j->header.index_size) {
+ POS_INVALIDATE(j->index[k]);
+ k++;
+ }
+ }
+ INSIST(i < j->header.index_size);
+ INSIST(! POS_VALID(j->index[i]));
+
+ /*
+ * Store the new index entry.
+ */
+ j->index[i] = *pos;
+}
+
+/*
+ * Invalidate any existing index entries that could become
+ * ambiguous when a new transaction with number 'serial' is added.
+ */
+static void
+index_invalidate(dns_journal_t *j, isc_uint32_t serial) {
+ unsigned int i;
+ if (j->index == NULL)
+ return;
+ for (i = 0; i < j->header.index_size; i++) {
+ if (! DNS_SERIAL_GT(serial, j->index[i].serial))
+ POS_INVALIDATE(j->index[i]);
+ }
+}
+
+/*
+ * Try to find a transaction with initial serial number 'serial'
+ * in the journal 'j'.
+ *
+ * If found, store its position at '*pos' and return ISC_R_SUCCESS.
+ *
+ * If 'serial' is current (= the ending serial number of the
+ * last transaction in the journal), set '*pos' to
+ * the position immediately following the last transaction and
+ * return ISC_R_SUCCESS.
+ *
+ * If 'serial' is within the range of addressable serial numbers
+ * covered by the journal but that particular serial number is missing
+ * (from the journal, not just from the index), return ISC_R_NOTFOUND.
+ *
+ * If 'serial' is outside the range of addressable serial numbers
+ * covered by the journal, return ISC_R_RANGE.
+ *
+ */
+static isc_result_t
+journal_find(dns_journal_t *j, isc_uint32_t serial, journal_pos_t *pos) {
+ isc_result_t result;
+ journal_pos_t current_pos;
+ REQUIRE(DNS_JOURNAL_VALID(j));
+
+ if (DNS_SERIAL_GT(j->header.begin.serial, serial))
+ return (ISC_R_RANGE);
+ if (DNS_SERIAL_GT(serial, j->header.end.serial))
+ return (ISC_R_RANGE);
+ if (serial == j->header.end.serial) {
+ *pos = j->header.end;
+ return (ISC_R_SUCCESS);
+ }
+
+ current_pos = j->header.begin;
+ index_find(j, serial, &current_pos);
+
+ while (current_pos.serial != serial) {
+ if (DNS_SERIAL_GT(current_pos.serial, serial))
+ return (ISC_R_NOTFOUND);
+ result = journal_next(j, &current_pos);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ *pos = current_pos;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_journal_begin_transaction(dns_journal_t *j) {
+ isc_uint32_t offset;
+ isc_result_t result;
+ journal_rawxhdr_t hdr;
+
+ REQUIRE(DNS_JOURNAL_VALID(j));
+ REQUIRE(j->state == JOURNAL_STATE_WRITE);
+
+ /*
+ * Find the file offset where the new transaction should
+ * be written, and seek there.
+ */
+ if (JOURNAL_EMPTY(&j->header)) {
+ offset = sizeof(journal_rawheader_t) +
+ j->header.index_size * sizeof(journal_rawpos_t);
+ } else {
+ offset = j->header.end.offset;
+ }
+ j->x.pos[0].offset = offset;
+ j->x.pos[1].offset = offset; /* Initial value, will be incremented. */
+ j->x.n_soa = 0;
+
+ CHECK(journal_seek(j, offset));
+
+ /*
+ * Write a dummy transaction header of all zeroes to reserve
+ * space. It will be filled in when the transaction is
+ * finished.
+ */
+ memset(&hdr, 0, sizeof(hdr));
+ CHECK(journal_write(j, &hdr, sizeof(hdr)));
+ j->x.pos[1].offset = j->offset;
+
+ j->state = JOURNAL_STATE_TRANSACTION;
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+isc_result_t
+dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff) {
+ dns_difftuple_t *t;
+ isc_buffer_t buffer;
+ void *mem = NULL;
+ unsigned int size;
+ isc_result_t result;
+ isc_region_t used;
+
+ REQUIRE(DNS_DIFF_VALID(diff));
+ REQUIRE(j->state == JOURNAL_STATE_TRANSACTION);
+
+ isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "writing to journal");
+ (void)dns_diff_print(diff, NULL);
+
+ /*
+ * Pass 1: determine the buffer size needed, and
+ * keep track of SOA serial numbers.
+ */
+ size = 0;
+ for (t = ISC_LIST_HEAD(diff->tuples); t != NULL;
+ t = ISC_LIST_NEXT(t, link))
+ {
+ if (t->rdata.type == dns_rdatatype_soa) {
+ if (j->x.n_soa < 2)
+ j->x.pos[j->x.n_soa].serial =
+ dns_soa_getserial(&t->rdata);
+ j->x.n_soa++;
+ }
+ size += sizeof(journal_rawrrhdr_t);
+ size += t->name.length; /* XXX should have access macro? */
+ size += 10;
+ size += t->rdata.length;
+ }
+
+ mem = isc_mem_get(j->mctx, size);
+ if (mem == NULL)
+ return (ISC_R_NOMEMORY);
+
+ isc_buffer_init(&buffer, mem, size);
+
+ /*
+ * Pass 2. Write RRs to buffer.
+ */
+ for (t = ISC_LIST_HEAD(diff->tuples); t != NULL;
+ t = ISC_LIST_NEXT(t, link))
+ {
+ /*
+ * Write the RR header.
+ */
+ isc_buffer_putuint32(&buffer, t->name.length + 10 +
+ t->rdata.length);
+ /*
+ * Write the owner name, RR header, and RR data.
+ */
+ isc_buffer_putmem(&buffer, t->name.ndata, t->name.length);
+ isc_buffer_putuint16(&buffer, t->rdata.type);
+ isc_buffer_putuint16(&buffer, t->rdata.rdclass);
+ isc_buffer_putuint32(&buffer, t->ttl);
+ INSIST(t->rdata.length < 65536);
+ isc_buffer_putuint16(&buffer, (isc_uint16_t)t->rdata.length);
+ INSIST(isc_buffer_availablelength(&buffer) >= t->rdata.length);
+ isc_buffer_putmem(&buffer, t->rdata.data, t->rdata.length);
+ }
+
+ isc_buffer_usedregion(&buffer, &used);
+ INSIST(used.length == size);
+
+ j->x.pos[1].offset += used.length;
+
+ /*
+ * Write the buffer contents to the journal file.
+ */
+ CHECK(journal_write(j, used.base, used.length));
+
+ result = ISC_R_SUCCESS;
+
+ failure:
+ if (mem != NULL)
+ isc_mem_put(j->mctx, mem, size);
+ return (result);
+
+}
+
+isc_result_t
+dns_journal_commit(dns_journal_t *j) {
+ isc_result_t result;
+ journal_rawheader_t rawheader;
+
+ REQUIRE(DNS_JOURNAL_VALID(j));
+ REQUIRE(j->state == JOURNAL_STATE_TRANSACTION);
+
+ /*
+ * Perform some basic consistency checks.
+ */
+ if (j->x.n_soa != 2) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: malformed transaction: %d SOAs",
+ j->filename, j->x.n_soa);
+ return (ISC_R_UNEXPECTED);
+ }
+ if (! (DNS_SERIAL_GT(j->x.pos[1].serial, j->x.pos[0].serial) ||
+ (bind8_compat &&
+ j->x.pos[1].serial == j->x.pos[0].serial)))
+ {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: malformed transaction: serial number "
+ "would decrease", j->filename);
+ return (ISC_R_UNEXPECTED);
+ }
+ if (! JOURNAL_EMPTY(&j->header)) {
+ if (j->x.pos[0].serial != j->header.end.serial) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "malformed transaction: "
+ "%s last serial %u != "
+ "transaction first serial %u",
+ j->filename,
+ j->header.end.serial,
+ j->x.pos[0].serial);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+ /*
+ * Some old journal entries may become non-addressable
+ * when we increment the current serial number. Purge them
+ * by stepping header.begin forward to the first addressable
+ * transaction. Also purge them from the index.
+ */
+ if (! JOURNAL_EMPTY(&j->header)) {
+ while (! DNS_SERIAL_GT(j->x.pos[1].serial,
+ j->header.begin.serial)) {
+ CHECK(journal_next(j, &j->header.begin));
+ }
+ index_invalidate(j, j->x.pos[1].serial);
+ }
+#ifdef notyet
+ if (DNS_SERIAL_GT(last_dumped_serial, j->x.pos[1].serial)) {
+ force_dump(...);
+ }
+#endif
+
+ /*
+ * Commit the transaction data to stable storage.
+ */
+ CHECK(journal_fsync(j));
+
+ /*
+ * Update the transaction header.
+ */
+ CHECK(journal_seek(j, j->x.pos[0].offset));
+ CHECK(journal_write_xhdr(j, (j->x.pos[1].offset - j->x.pos[0].offset) -
+ sizeof(journal_rawxhdr_t),
+ j->x.pos[0].serial, j->x.pos[1].serial));
+
+ /*
+ * Update the journal header.
+ */
+ if (JOURNAL_EMPTY(&j->header)) {
+ j->header.begin = j->x.pos[0];
+ }
+ j->header.end = j->x.pos[1];
+ journal_header_encode(&j->header, &rawheader);
+ CHECK(journal_seek(j, 0));
+ CHECK(journal_write(j, &rawheader, sizeof(rawheader)));
+
+ /*
+ * Update the index.
+ */
+ index_add(j, &j->x.pos[0]);
+
+ /*
+ * Convert the index into on-disk format and write
+ * it to disk.
+ */
+ CHECK(index_to_disk(j));
+
+ /*
+ * Commit the header to stable storage.
+ */
+ CHECK(journal_fsync(j));
+
+ /*
+ * We no longer have a transaction open.
+ */
+ j->state = JOURNAL_STATE_WRITE;
+
+ result = ISC_R_SUCCESS;
+
+ failure:
+ return (result);
+}
+
+isc_result_t
+dns_journal_write_transaction(dns_journal_t *j, dns_diff_t *diff) {
+ isc_result_t result;
+ CHECK(dns_diff_sort(diff, ixfr_order));
+ CHECK(dns_journal_begin_transaction(j));
+ CHECK(dns_journal_writediff(j, diff));
+ CHECK(dns_journal_commit(j));
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+void
+dns_journal_destroy(dns_journal_t **journalp) {
+ dns_journal_t *j = *journalp;
+ REQUIRE(DNS_JOURNAL_VALID(j));
+
+ j->it.result = ISC_R_FAILURE;
+ dns_name_invalidate(&j->it.name);
+ dns_decompress_invalidate(&j->it.dctx);
+ if (j->rawindex != NULL)
+ isc_mem_put(j->mctx, j->rawindex, j->header.index_size *
+ sizeof(journal_rawpos_t));
+ if (j->index != NULL)
+ isc_mem_put(j->mctx, j->index, j->header.index_size *
+ sizeof(journal_pos_t));
+ if (j->it.target.base != NULL)
+ isc_mem_put(j->mctx, j->it.target.base, j->it.target.length);
+ if (j->it.source.base != NULL)
+ isc_mem_put(j->mctx, j->it.source.base, j->it.source.length);
+
+ if (j->fp != NULL)
+ (void)isc_stdio_close(j->fp);
+ j->magic = 0;
+ isc_mem_put(j->mctx, j, sizeof(*j));
+ *journalp = NULL;
+}
+
+/*
+ * Roll the open journal 'j' into the database 'db'.
+ * A new database version will be created.
+ */
+
+/* XXX Share code with incoming IXFR? */
+
+static isc_result_t
+roll_forward(dns_journal_t *j, dns_db_t *db) {
+ isc_buffer_t source; /* Transaction data from disk */
+ isc_buffer_t target; /* Ditto after _fromwire check */
+ isc_uint32_t db_serial; /* Database SOA serial */
+ isc_uint32_t end_serial; /* Last journal SOA serial */
+ isc_result_t result;
+ dns_dbversion_t *ver = NULL;
+ journal_pos_t pos;
+ dns_diff_t diff;
+ unsigned int n_soa = 0;
+ unsigned int n_put = 0;
+
+ REQUIRE(DNS_JOURNAL_VALID(j));
+ REQUIRE(DNS_DB_VALID(db));
+
+ dns_diff_init(j->mctx, &diff);
+
+ /*
+ * Set up empty initial buffers for uncheched and checked
+ * wire format transaction data. They will be reallocated
+ * later.
+ */
+ isc_buffer_init(&source, NULL, 0);
+ isc_buffer_init(&target, NULL, 0);
+
+ /*
+ * Create the new database version.
+ */
+ CHECK(dns_db_newversion(db, &ver));
+
+ /*
+ * Get the current database SOA serial number.
+ */
+ CHECK(dns_db_getsoaserial(db, ver, &db_serial));
+
+ /*
+ * Locate a journal entry for the current database serial.
+ */
+ CHECK(journal_find(j, db_serial, &pos));
+ /*
+ * XXX do more drastic things, like marking zone stale,
+ * if this fails?
+ */
+ /*
+ * XXXRTH The zone code should probably mark the zone as bad and
+ * scream loudly into the log if this is a dynamic update
+ * log reply that failed.
+ */
+
+ end_serial = dns_journal_last_serial(j);
+ if (db_serial == end_serial)
+ CHECK(DNS_R_UPTODATE);
+
+ CHECK(dns_journal_iter_init(j, db_serial, end_serial));
+
+ for (result = dns_journal_first_rr(j);
+ result == ISC_R_SUCCESS;
+ result = dns_journal_next_rr(j))
+ {
+ dns_name_t *name;
+ isc_uint32_t ttl;
+ dns_rdata_t *rdata;
+ dns_difftuple_t *tuple = NULL;
+
+ name = NULL;
+ rdata = NULL;
+ dns_journal_current_rr(j, &name, &ttl, &rdata);
+
+ if (rdata->type == dns_rdatatype_soa) {
+ n_soa++;
+ if (n_soa == 2)
+ db_serial = j->it.current_serial;
+ }
+
+ if (n_soa == 3)
+ n_soa = 1;
+ if (n_soa == 0) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: journal file corrupt: missing "
+ "initial SOA", j->filename);
+ FAIL(ISC_R_UNEXPECTED);
+ }
+ CHECK(dns_difftuple_create(diff.mctx, n_soa == 1 ?
+ DNS_DIFFOP_DEL : DNS_DIFFOP_ADD,
+ name, ttl, rdata, &tuple));
+ dns_diff_append(&diff, &tuple);
+
+ if (++n_put > 100) {
+ isc_log_write(JOURNAL_DEBUG_LOGARGS(3),
+ "%s: applying diff to database (%u)",
+ j->filename, db_serial);
+ (void)dns_diff_print(&diff, NULL);
+ CHECK(dns_diff_apply(&diff, db, ver));
+ dns_diff_clear(&diff);
+ n_put = 0;
+ }
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ CHECK(result);
+
+ if (n_put != 0) {
+ isc_log_write(JOURNAL_DEBUG_LOGARGS(3),
+ "%s: applying final diff to database (%u)",
+ j->filename, db_serial);
+ (void)dns_diff_print(&diff, NULL);
+ CHECK(dns_diff_apply(&diff, db, ver));
+ dns_diff_clear(&diff);
+ }
+
+ failure:
+ if (ver != NULL)
+ dns_db_closeversion(db, &ver, result == ISC_R_SUCCESS ?
+ ISC_TRUE : ISC_FALSE);
+
+ if (source.base != NULL)
+ isc_mem_put(j->mctx, source.base, source.length);
+ if (target.base != NULL)
+ isc_mem_put(j->mctx, target.base, target.length);
+
+ dns_diff_clear(&diff);
+
+ return (result);
+}
+
+isc_result_t
+dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, const char *filename) {
+ dns_journal_t *j;
+ isc_result_t result;
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(filename != NULL);
+
+ j = NULL;
+ result = dns_journal_open(mctx, filename, ISC_FALSE, &j);
+ if (result == ISC_R_NOTFOUND) {
+ isc_log_write(JOURNAL_DEBUG_LOGARGS(3),
+ "no journal file, but that's OK");
+ return (DNS_R_NOJOURNAL);
+ }
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (JOURNAL_EMPTY(&j->header))
+ result = DNS_R_UPTODATE;
+ else
+ result = roll_forward(j, db);
+
+ dns_journal_destroy(&j);
+
+ return (result);
+}
+
+isc_result_t
+dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
+ dns_journal_t *j;
+ isc_buffer_t source; /* Transaction data from disk */
+ isc_buffer_t target; /* Ditto after _fromwire check */
+ isc_uint32_t start_serial; /* Database SOA serial */
+ isc_uint32_t end_serial; /* Last journal SOA serial */
+ isc_result_t result;
+ dns_diff_t diff;
+ unsigned int n_soa = 0;
+ unsigned int n_put = 0;
+
+ REQUIRE(filename != NULL);
+
+ j = NULL;
+ result = dns_journal_open(mctx, filename, ISC_FALSE, &j);
+ if (result == ISC_R_NOTFOUND) {
+ isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no journal file");
+ return (DNS_R_NOJOURNAL);
+ }
+
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "journal open failure: %s: %s",
+ isc_result_totext(result), j->filename);
+ return (result);
+ }
+
+ dns_diff_init(j->mctx, &diff);
+
+ /*
+ * Set up empty initial buffers for uncheched and checked
+ * wire format transaction data. They will be reallocated
+ * later.
+ */
+ isc_buffer_init(&source, NULL, 0);
+ isc_buffer_init(&target, NULL, 0);
+
+ start_serial = dns_journal_first_serial(j);
+ end_serial = dns_journal_last_serial(j);
+
+ CHECK(dns_journal_iter_init(j, start_serial, end_serial));
+
+ for (result = dns_journal_first_rr(j);
+ result == ISC_R_SUCCESS;
+ result = dns_journal_next_rr(j))
+ {
+ dns_name_t *name;
+ isc_uint32_t ttl;
+ dns_rdata_t *rdata;
+ dns_difftuple_t *tuple = NULL;
+
+ name = NULL;
+ rdata = NULL;
+ dns_journal_current_rr(j, &name, &ttl, &rdata);
+
+ if (rdata->type == dns_rdatatype_soa)
+ n_soa++;
+
+ if (n_soa == 3)
+ n_soa = 1;
+ if (n_soa == 0) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: journal file corrupt: missing "
+ "initial SOA", j->filename);
+ FAIL(ISC_R_UNEXPECTED);
+ }
+ CHECK(dns_difftuple_create(diff.mctx, n_soa == 1 ?
+ DNS_DIFFOP_DEL : DNS_DIFFOP_ADD,
+ name, ttl, rdata, &tuple));
+ dns_diff_append(&diff, &tuple);
+
+ if (++n_put > 100) {
+ result = dns_diff_print(&diff, file);
+ dns_diff_clear(&diff);
+ n_put = 0;
+ if (result != ISC_R_SUCCESS)
+ break;
+ }
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ CHECK(result);
+
+ if (n_put != 0) {
+ result = dns_diff_print(&diff, file);
+ dns_diff_clear(&diff);
+ }
+ goto cleanup;
+
+ failure:
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: cannot print: journal file corrupt", j->filename);
+
+ cleanup:
+ if (source.base != NULL)
+ isc_mem_put(j->mctx, source.base, source.length);
+ if (target.base != NULL)
+ isc_mem_put(j->mctx, target.base, target.length);
+
+ dns_diff_clear(&diff);
+ dns_journal_destroy(&j);
+
+ return (result);
+}
+
+/**************************************************************************/
+/*
+ * Miscellaneous accessors.
+ */
+isc_uint32_t dns_journal_first_serial(dns_journal_t *j) {
+ return (j->header.begin.serial);
+}
+
+isc_uint32_t dns_journal_last_serial(dns_journal_t *j) {
+ return (j->header.end.serial);
+}
+
+/**************************************************************************/
+/*
+ * Iteration support.
+ *
+ * When serving an outgoing IXFR, we transmit a part the journal starting
+ * at the serial number in the IXFR request and ending at the serial
+ * number that is current when the IXFR request arrives. The ending
+ * serial number is not necessarily at the end of the journal:
+ * the journal may grow while the IXFR is in progress, but we stop
+ * when we reach the serial number that was current when the IXFR started.
+ */
+
+static isc_result_t read_one_rr(dns_journal_t *j);
+
+/*
+ * Make sure the buffer 'b' is has at least 'size' bytes
+ * allocated, and clear it.
+ *
+ * Requires:
+ * Either b->base is NULL, or it points to b->length bytes of memory
+ * previously allocated by isc_mem_get().
+ */
+
+static isc_result_t
+size_buffer(isc_mem_t *mctx, isc_buffer_t *b, unsigned size) {
+ if (b->length < size) {
+ void *mem = isc_mem_get(mctx, size);
+ if (mem == NULL)
+ return (ISC_R_NOMEMORY);
+ if (b->base != NULL)
+ isc_mem_put(mctx, b->base, b->length);
+ b->base = mem;
+ b->length = size;
+ }
+ isc_buffer_clear(b);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_journal_iter_init(dns_journal_t *j,
+ isc_uint32_t begin_serial, isc_uint32_t end_serial)
+{
+ isc_result_t result;
+
+ CHECK(journal_find(j, begin_serial, &j->it.bpos));
+ INSIST(j->it.bpos.serial == begin_serial);
+
+ CHECK(journal_find(j, end_serial, &j->it.epos));
+ INSIST(j->it.epos.serial == end_serial);
+
+ result = ISC_R_SUCCESS;
+ failure:
+ j->it.result = result;
+ return (j->it.result);
+}
+
+
+isc_result_t
+dns_journal_first_rr(dns_journal_t *j) {
+ isc_result_t result;
+
+ /*
+ * Seek to the beginning of the first transaction we are
+ * interested in.
+ */
+ CHECK(journal_seek(j, j->it.bpos.offset));
+ j->it.current_serial = j->it.bpos.serial;
+
+ j->it.xsize = 0; /* We have no transaction data yet... */
+ j->it.xpos = 0; /* ...and haven't used any of it. */
+
+ return (read_one_rr(j));
+
+ failure:
+ return (result);
+}
+
+static isc_result_t
+read_one_rr(dns_journal_t *j) {
+ isc_result_t result;
+
+ dns_rdatatype_t rdtype;
+ dns_rdataclass_t rdclass;
+ unsigned int rdlen;
+ isc_uint32_t ttl;
+ journal_xhdr_t xhdr;
+ journal_rrhdr_t rrhdr;
+
+ INSIST(j->offset <= j->it.epos.offset);
+ if (j->offset == j->it.epos.offset)
+ return (ISC_R_NOMORE);
+ if (j->it.xpos == j->it.xsize) {
+ /*
+ * We are at a transaction boundary.
+ * Read another transaction header.
+ */
+ CHECK(journal_read_xhdr(j, &xhdr));
+ if (xhdr.size == 0) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: journal corrupt: empty transaction",
+ j->filename);
+ FAIL(ISC_R_UNEXPECTED);
+ }
+ if (xhdr.serial0 != j->it.current_serial) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: journal file corrupt: "
+ "expected serial %u, got %u",
+ j->filename,
+ j->it.current_serial, xhdr.serial0);
+ FAIL(ISC_R_UNEXPECTED);
+ }
+ j->it.xsize = xhdr.size;
+ j->it.xpos = 0;
+ }
+ /*
+ * Read an RR.
+ */
+ CHECK(journal_read_rrhdr(j, &rrhdr));
+ /*
+ * Perform a sanity check on the journal RR size.
+ * The smallest possible RR has a 1-byte owner name
+ * and a 10-byte header. The largest possible
+ * RR has 65535 bytes of data, a header, and a maximum-
+ * size owner name, well below 70 k total.
+ */
+ if (rrhdr.size < 1+10 || rrhdr.size > 70000) {
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: journal corrupt: impossible RR size "
+ "(%d bytes)", j->filename, rrhdr.size);
+ FAIL(ISC_R_UNEXPECTED);
+ }
+
+ CHECK(size_buffer(j->mctx, &j->it.source, rrhdr.size));
+ CHECK(journal_read(j, j->it.source.base, rrhdr.size));
+ isc_buffer_add(&j->it.source, rrhdr.size);
+
+ /*
+ * The target buffer is made the same size
+ * as the source buffer, with the assumption that when
+ * no compression in present, the output of dns_*_fromwire()
+ * is no larger than the input.
+ */
+ CHECK(size_buffer(j->mctx, &j->it.target, rrhdr.size));
+
+ /*
+ * Parse the owner name. We don't know where it
+ * ends yet, so we make the entire "remaining"
+ * part of the buffer "active".
+ */
+ isc_buffer_setactive(&j->it.source,
+ j->it.source.used - j->it.source.current);
+ CHECK(dns_name_fromwire(&j->it.name, &j->it.source,
+ &j->it.dctx, 0, &j->it.target));
+
+ /*
+ * Check that the RR header is there, and parse it.
+ */
+ if (isc_buffer_remaininglength(&j->it.source) < 10)
+ FAIL(DNS_R_FORMERR);
+
+ rdtype = isc_buffer_getuint16(&j->it.source);
+ rdclass = isc_buffer_getuint16(&j->it.source);
+ ttl = isc_buffer_getuint32(&j->it.source);
+ rdlen = isc_buffer_getuint16(&j->it.source);
+
+ /*
+ * Parse the rdata.
+ */
+ if (isc_buffer_remaininglength(&j->it.source) != rdlen)
+ FAIL(DNS_R_FORMERR);
+ isc_buffer_setactive(&j->it.source, rdlen);
+ dns_rdata_reset(&j->it.rdata);
+ CHECK(dns_rdata_fromwire(&j->it.rdata, rdclass,
+ rdtype, &j->it.source, &j->it.dctx,
+ 0, &j->it.target));
+ j->it.ttl = ttl;
+
+ j->it.xpos += sizeof(journal_rawrrhdr_t) + rrhdr.size;
+ if (rdtype == dns_rdatatype_soa) {
+ /* XXX could do additional consistency checks here */
+ j->it.current_serial = dns_soa_getserial(&j->it.rdata);
+ }
+
+ result = ISC_R_SUCCESS;
+
+ failure:
+ j->it.result = result;
+ return (result);
+}
+
+isc_result_t
+dns_journal_next_rr(dns_journal_t *j) {
+ j->it.result = read_one_rr(j);
+ return (j->it.result);
+}
+
+void
+dns_journal_current_rr(dns_journal_t *j, dns_name_t **name, isc_uint32_t *ttl,
+ dns_rdata_t **rdata)
+{
+ REQUIRE(j->it.result == ISC_R_SUCCESS);
+ *name = &j->it.name;
+ *ttl = j->it.ttl;
+ *rdata = &j->it.rdata;
+}
+
+/**************************************************************************/
+/*
+ * Generating diffs from databases
+ */
+
+/*
+ * Construct a diff containing all the RRs at the current name of the
+ * database iterator 'dbit' in database 'db', version 'ver'.
+ * Set '*name' to the current name, and append the diff to 'diff'.
+ * All new tuples will have the operation 'op'.
+ *
+ * Requires: 'name' must have buffer large enough to hold the name.
+ * Typically, a dns_fixedname_t would be used.
+ */
+static isc_result_t
+get_name_diff(dns_db_t *db, dns_dbversion_t *ver, isc_stdtime_t now,
+ dns_dbiterator_t *dbit, dns_name_t *name, dns_diffop_t op,
+ dns_diff_t *diff)
+{
+ isc_result_t result;
+ dns_dbnode_t *node = NULL;
+ dns_rdatasetiter_t *rdsiter = NULL;
+ dns_difftuple_t *tuple = NULL;
+
+ result = dns_dbiterator_current(dbit, &node, name);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_db_allrdatasets(db, node, ver, now, &rdsiter);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_node;
+
+ for (result = dns_rdatasetiter_first(rdsiter);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(rdsiter))
+ {
+ dns_rdataset_t rdataset;
+
+ dns_rdataset_init(&rdataset);
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset))
+ {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_difftuple_create(diff->mctx, op, name,
+ rdataset.ttl, &rdata,
+ &tuple);
+ if (result != ISC_R_SUCCESS) {
+ dns_rdataset_disassociate(&rdataset);
+ goto cleanup_iterator;
+ }
+ dns_diff_append(diff, &tuple);
+ }
+ dns_rdataset_disassociate(&rdataset);
+ if (result != ISC_R_NOMORE)
+ goto cleanup_iterator;
+ }
+ if (result != ISC_R_NOMORE)
+ goto cleanup_iterator;
+
+ result = ISC_R_SUCCESS;
+
+ cleanup_iterator:
+ dns_rdatasetiter_destroy(&rdsiter);
+
+ cleanup_node:
+ dns_db_detachnode(db, &node);
+
+ return (result);
+}
+
+/*
+ * Comparison function for use by dns_diff_subtract when sorting
+ * the diffs to be subtracted. The sort keys are the rdata type
+ * and the rdata itself. The owner name is ignored, because
+ * it is known to be the same for all tuples.
+ */
+static int
+rdata_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 = (b->rdata.type - a->rdata.type);
+ if (r != 0)
+ return (r);
+ r = dns_rdata_compare(&a->rdata, &b->rdata);
+ return (r);
+}
+
+static isc_result_t
+dns_diff_subtract(dns_diff_t diff[2], dns_diff_t *r) {
+ isc_result_t result;
+ dns_difftuple_t *p[2];
+ int i, t;
+ isc_boolean_t append;
+
+ CHECK(dns_diff_sort(&diff[0], rdata_order));
+ CHECK(dns_diff_sort(&diff[1], rdata_order));
+
+ for (;;) {
+ p[0] = ISC_LIST_HEAD(diff[0].tuples);
+ p[1] = ISC_LIST_HEAD(diff[1].tuples);
+ if (p[0] == NULL && p[1] == NULL)
+ break;
+
+ for (i = 0; i < 2; i++)
+ if (p[!i] == NULL) {
+ ISC_LIST_UNLINK(diff[i].tuples, p[i], link);
+ ISC_LIST_APPEND(r->tuples, p[i], link);
+ goto next;
+ }
+ t = rdata_order(&p[0], &p[1]);
+ if (t < 0) {
+ ISC_LIST_UNLINK(diff[0].tuples, p[0], link);
+ ISC_LIST_APPEND(r->tuples, p[0], link);
+ goto next;
+ }
+ if (t > 0) {
+ ISC_LIST_UNLINK(diff[1].tuples, p[1], link);
+ ISC_LIST_APPEND(r->tuples, p[1], link);
+ goto next;
+ }
+ INSIST(t == 0);
+ /*
+ * Identical RRs in both databases; skip them both
+ * if the ttl differs.
+ */
+ append = ISC_TF(p[0]->ttl != p[1]->ttl);
+ for (i = 0; i < 2; i++) {
+ ISC_LIST_UNLINK(diff[i].tuples, p[i], link);
+ if (append) {
+ ISC_LIST_APPEND(r->tuples, p[i], link);
+ } else {
+ dns_difftuple_free(&p[i]);
+ }
+ }
+ next: ;
+ }
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+/*
+ * Compare the databases 'dba' and 'dbb' and generate a journal
+ * entry containing the changes to make 'dba' from 'dbb' (note
+ * the order). This journal entry will consist of a single,
+ * possibly very large transaction.
+ */
+
+isc_result_t
+dns_db_diff(isc_mem_t *mctx,
+ dns_db_t *dba, dns_dbversion_t *dbvera,
+ dns_db_t *dbb, dns_dbversion_t *dbverb,
+ const char *journal_filename)
+{
+ dns_db_t *db[2];
+ dns_dbversion_t *ver[2];
+ dns_dbiterator_t *dbit[2] = { NULL, NULL };
+ isc_boolean_t have[2] = { ISC_FALSE, ISC_FALSE };
+ dns_fixedname_t fixname[2];
+ isc_result_t result, itresult[2];
+ dns_diff_t diff[2], resultdiff;
+ int i, t;
+ dns_journal_t *journal = NULL;
+
+ db[0] = dba, db[1] = dbb;
+ ver[0] = dbvera, ver[1] = dbverb;
+
+ dns_diff_init(mctx, &diff[0]);
+ dns_diff_init(mctx, &diff[1]);
+ dns_diff_init(mctx, &resultdiff);
+
+ dns_fixedname_init(&fixname[0]);
+ dns_fixedname_init(&fixname[1]);
+
+ result = dns_journal_open(mctx, journal_filename, ISC_TRUE, &journal);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_db_createiterator(db[0], ISC_FALSE, &dbit[0]);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_journal;
+ result = dns_db_createiterator(db[1], ISC_FALSE, &dbit[1]);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_interator0;
+
+ itresult[0] = dns_dbiterator_first(dbit[0]);
+ itresult[1] = dns_dbiterator_first(dbit[1]);
+
+ for (;;) {
+ for (i = 0; i < 2; i++) {
+ if (! have[i] && itresult[i] == ISC_R_SUCCESS) {
+ CHECK(get_name_diff(db[i], ver[i], 0, dbit[i],
+ dns_fixedname_name(&fixname[i]),
+ i == 0 ?
+ DNS_DIFFOP_ADD :
+ DNS_DIFFOP_DEL,
+ &diff[i]));
+ itresult[i] = dns_dbiterator_next(dbit[i]);
+ have[i] = ISC_TRUE;
+ }
+ }
+
+ if (! have[0] && ! have[1]) {
+ INSIST(ISC_LIST_EMPTY(diff[0].tuples));
+ INSIST(ISC_LIST_EMPTY(diff[1].tuples));
+ break;
+ }
+
+ for (i = 0; i < 2; i++) {
+ if (! have[!i]) {
+ ISC_LIST_APPENDLIST(resultdiff.tuples,
+ diff[i].tuples, link);
+ INSIST(ISC_LIST_EMPTY(diff[i].tuples));
+ have[i] = ISC_FALSE;
+ goto next;
+ }
+ }
+
+ t = dns_name_compare(dns_fixedname_name(&fixname[0]),
+ dns_fixedname_name(&fixname[1]));
+ if (t < 0) {
+ ISC_LIST_APPENDLIST(resultdiff.tuples,
+ diff[0].tuples, link);
+ INSIST(ISC_LIST_EMPTY(diff[0].tuples));
+ have[0] = ISC_FALSE;
+ continue;
+ }
+ if (t > 0) {
+ ISC_LIST_APPENDLIST(resultdiff.tuples,
+ diff[1].tuples, link);
+ INSIST(ISC_LIST_EMPTY(diff[1].tuples));
+ have[1] = ISC_FALSE;
+ continue;
+ }
+ INSIST(t == 0);
+ CHECK(dns_diff_subtract(diff, &resultdiff));
+ INSIST(ISC_LIST_EMPTY(diff[0].tuples));
+ INSIST(ISC_LIST_EMPTY(diff[1].tuples));
+ have[0] = have[1] = ISC_FALSE;
+ next: ;
+ }
+ if (itresult[0] != ISC_R_NOMORE)
+ FAIL(itresult[0]);
+ if (itresult[1] != ISC_R_NOMORE)
+ FAIL(itresult[1]);
+
+ if (ISC_LIST_EMPTY(resultdiff.tuples)) {
+ isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no changes");
+ } else {
+ CHECK(dns_journal_write_transaction(journal, &resultdiff));
+ }
+ INSIST(ISC_LIST_EMPTY(diff[0].tuples));
+ INSIST(ISC_LIST_EMPTY(diff[1].tuples));
+
+ failure:
+ dns_diff_clear(&resultdiff);
+ dns_dbiterator_destroy(&dbit[1]);
+ cleanup_interator0:
+ dns_dbiterator_destroy(&dbit[0]);
+ cleanup_journal:
+ dns_journal_destroy(&journal);
+ return (result);
+}
+
+isc_result_t
+dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
+ isc_uint32_t target_size)
+{
+ unsigned int i;
+ journal_pos_t best_guess;
+ journal_pos_t current_pos;
+ dns_journal_t *j = NULL;
+ dns_journal_t *new = NULL;
+ journal_rawheader_t rawheader;
+ unsigned int copy_length;
+ int namelen;
+ char *buf = NULL;
+ unsigned int size = 0;
+ isc_result_t result;
+ unsigned int indexend;
+ char newname[1024];
+ char backup[1024];
+ isc_boolean_t is_backup = ISC_FALSE;
+
+ namelen = strlen(filename);
+ if (namelen > 4 && strcmp(filename + namelen - 4, ".jnl") == 0)
+ namelen -= 4;
+
+ result = isc_string_printf(newname, sizeof(newname), "%.*s.jnw",
+ namelen, filename);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = isc_string_printf(backup, sizeof(backup), "%.*s.jbk",
+ namelen, filename);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = journal_open(mctx, filename, ISC_FALSE, ISC_FALSE, &j);
+ if (result == ISC_R_NOTFOUND) {
+ is_backup = ISC_TRUE;
+ result = journal_open(mctx, backup, ISC_FALSE, ISC_FALSE, &j);
+ }
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (JOURNAL_EMPTY(&j->header)) {
+ dns_journal_destroy(&j);
+ return (ISC_R_SUCCESS);
+ }
+
+ if (DNS_SERIAL_GT(j->header.begin.serial, serial) ||
+ DNS_SERIAL_GT(serial, j->header.end.serial)) {
+ dns_journal_destroy(&j);
+ return (ISC_R_RANGE);
+ }
+
+ /*
+ * Cope with very small target sizes.
+ */
+ indexend = sizeof(journal_rawheader_t) +
+ j->header.index_size * sizeof(journal_rawpos_t);
+ if (target_size < indexend * 2)
+ target_size = target_size/2 + indexend;
+
+ /*
+ * See if there is any work to do.
+ */
+ if ((isc_uint32_t) j->header.end.offset < target_size) {
+ dns_journal_destroy(&j);
+ return (ISC_R_SUCCESS);
+ }
+
+ CHECK(journal_open(mctx, newname, ISC_TRUE, ISC_TRUE, &new));
+
+ /*
+ * Remove overhead so space test below can succeed.
+ */
+ if (target_size >= indexend)
+ target_size -= indexend;
+
+ /*
+ * Find if we can create enough free space.
+ */
+ best_guess = j->header.begin;
+ for (i = 0; i < j->header.index_size; i++) {
+ if (POS_VALID(j->index[i]) &&
+ DNS_SERIAL_GE(serial, j->index[i].serial) &&
+ ((isc_uint32_t)(j->header.end.offset - j->index[i].offset)
+ >= target_size / 2) &&
+ j->index[i].offset > best_guess.offset)
+ best_guess = j->index[i];
+ }
+
+ current_pos = best_guess;
+ while (current_pos.serial != serial) {
+ CHECK(journal_next(j, &current_pos));
+ if (current_pos.serial == j->header.end.serial)
+ break;
+
+ if (DNS_SERIAL_GE(serial, current_pos.serial) &&
+ ((isc_uint32_t)(j->header.end.offset - current_pos.offset)
+ >= (target_size / 2)) &&
+ current_pos.offset > best_guess.offset)
+ best_guess = current_pos;
+ else
+ break;
+ }
+
+ INSIST(best_guess.serial != j->header.end.serial);
+ if (best_guess.serial != serial)
+ CHECK(journal_next(j, &best_guess));
+
+ /*
+ * We should now be roughly half target_size provided
+ * we did not reach 'serial'. If not we will just copy
+ * all uncommitted deltas regardless of the size.
+ */
+ copy_length = j->header.end.offset - best_guess.offset;
+
+ if (copy_length != 0) {
+ /*
+ * Copy best_guess to end into space just freed.
+ */
+ size = 64*1024;
+ if (copy_length < size)
+ size = copy_length;
+ buf = isc_mem_get(mctx, size);
+ if (buf == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto failure;
+ }
+
+ CHECK(journal_seek(j, best_guess.offset));
+ CHECK(journal_seek(new, indexend));
+ for (i = 0; i < copy_length; i += size) {
+ unsigned int len = (copy_length - i) > size ? size :
+ (copy_length - i);
+ CHECK(journal_read(j, buf, len));
+ CHECK(journal_write(new, buf, len));
+ }
+
+ CHECK(journal_fsync(new));
+
+ /*
+ * Compute new header.
+ */
+ new->header.begin.serial = best_guess.serial;
+ new->header.begin.offset = indexend;
+ new->header.end.serial = j->header.end.serial;
+ new->header.end.offset = indexend + copy_length;
+
+ /*
+ * Update the journal header.
+ */
+ journal_header_encode(&new->header, &rawheader);
+ CHECK(journal_seek(new, 0));
+ CHECK(journal_write(new, &rawheader, sizeof(rawheader)));
+ CHECK(journal_fsync(new));
+
+ /*
+ * Build new index.
+ */
+ current_pos = new->header.begin;
+ while (current_pos.serial != new->header.end.serial) {
+ index_add(new, &current_pos);
+ CHECK(journal_next(new, &current_pos));
+ }
+
+ /*
+ * Write index.
+ */
+ CHECK(index_to_disk(new));
+ CHECK(journal_fsync(new));
+
+ indexend = new->header.end.offset;
+ }
+ dns_journal_destroy(&new);
+
+ /*
+ * With a UFS file system this should just succeed and be atomic.
+ * Any IXFR outs will just continue and the old journal will be
+ * removed on final close.
+ *
+ * With MSDOS / NTFS we need to do a two stage rename triggered
+ * bu EEXISTS. Hopefully all IXFR's that were active at the last
+ * rename are now complete.
+ */
+ if (rename(newname, filename) == -1) {
+ if (errno == EACCES && !is_backup) {
+ result = isc_file_remove(backup);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_FILENOTFOUND)
+ goto failure;
+ if (rename(filename, backup) == -1)
+ goto maperrno;
+ if (rename(newname, filename) == -1)
+ goto maperrno;
+ (void)isc_file_remove(backup);
+ } else {
+ maperrno:
+ result = ISC_R_FAILURE;
+ goto failure;
+ }
+ }
+
+ dns_journal_destroy(&j);
+ result = ISC_R_SUCCESS;
+
+ failure:
+ (void)isc_file_remove(newname);
+ if (buf != NULL)
+ isc_mem_put(mctx, buf, size);
+ if (j != NULL)
+ dns_journal_destroy(&j);
+ if (new != NULL)
+ dns_journal_destroy(&new);
+ return (result);
+}
+
+static isc_result_t
+index_to_disk(dns_journal_t *j) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ if (j->header.index_size != 0) {
+ unsigned int i;
+ unsigned char *p;
+ unsigned int rawbytes;
+
+ rawbytes = j->header.index_size * sizeof(journal_rawpos_t);
+
+ p = j->rawindex;
+ for (i = 0; i < j->header.index_size; i++) {
+ encode_uint32(j->index[i].serial, p);
+ p += 4;
+ encode_uint32(j->index[i].offset, p);
+ p += 4;
+ }
+ INSIST(p == j->rawindex + rawbytes);
+
+ CHECK(journal_seek(j, sizeof(journal_rawheader_t)));
+ CHECK(journal_write(j, j->rawindex, rawbytes));
+ }
+failure:
+ return (result);
+}
diff --git a/lib/dns/key.c b/lib/dns/key.c
new file mode 100644
index 0000000..b0f2c0a
--- /dev/null
+++ b/lib/dns/key.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2004-2006 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: key.c,v 1.1.6.6 2006/01/27 23:57:44 marka Exp $ */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <isc/region.h>
+#include <isc/util.h>
+
+#include <dns/keyvalues.h>
+
+#include <dst/dst.h>
+
+#include "dst_internal.h"
+
+isc_uint16_t
+dst_region_computeid(const isc_region_t *source, unsigned int alg) {
+ isc_uint32_t ac;
+ const unsigned char *p;
+ int size;
+
+ REQUIRE(source != NULL);
+ REQUIRE(source->length >= 4);
+
+ p = source->base;
+ size = source->length;
+
+ if (alg == DST_ALG_RSAMD5)
+ return ((p[size - 3] << 8) + p[size - 2]);
+
+ for (ac = 0; size > 1; size -= 2, p += 2)
+ ac += ((*p) << 8) + *(p + 1);
+
+ if (size > 0)
+ ac += ((*p) << 8);
+ ac += (ac >> 16) & 0xffff;
+
+ return ((isc_uint16_t)(ac & 0xffff));
+}
+
+dns_name_t *
+dst_key_name(const dst_key_t *key) {
+ REQUIRE(VALID_KEY(key));
+ return (key->key_name);
+}
+
+unsigned int
+dst_key_size(const dst_key_t *key) {
+ REQUIRE(VALID_KEY(key));
+ return (key->key_size);
+}
+
+unsigned int
+dst_key_proto(const dst_key_t *key) {
+ REQUIRE(VALID_KEY(key));
+ return (key->key_proto);
+}
+
+unsigned int
+dst_key_alg(const dst_key_t *key) {
+ REQUIRE(VALID_KEY(key));
+ return (key->key_alg);
+}
+
+isc_uint32_t
+dst_key_flags(const dst_key_t *key) {
+ REQUIRE(VALID_KEY(key));
+ return (key->key_flags);
+}
+
+dns_keytag_t
+dst_key_id(const dst_key_t *key) {
+ REQUIRE(VALID_KEY(key));
+ return (key->key_id);
+}
+
+dns_rdataclass_t
+dst_key_class(const dst_key_t *key) {
+ REQUIRE(VALID_KEY(key));
+ return (key->key_class);
+}
+
+isc_boolean_t
+dst_key_iszonekey(const dst_key_t *key) {
+ REQUIRE(VALID_KEY(key));
+
+ if ((key->key_flags & DNS_KEYTYPE_NOAUTH) != 0)
+ return (ISC_FALSE);
+ if ((key->key_flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
+ return (ISC_FALSE);
+ if (key->key_proto != DNS_KEYPROTO_DNSSEC &&
+ key->key_proto != DNS_KEYPROTO_ANY)
+ return (ISC_FALSE);
+ return (ISC_TRUE);
+}
+
+isc_boolean_t
+dst_key_isnullkey(const dst_key_t *key) {
+ REQUIRE(VALID_KEY(key));
+
+ if ((key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
+ return (ISC_FALSE);
+ if ((key->key_flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
+ return (ISC_FALSE);
+ if (key->key_proto != DNS_KEYPROTO_DNSSEC &&
+ key->key_proto != DNS_KEYPROTO_ANY)
+ return (ISC_FALSE);
+ return (ISC_TRUE);
+}
+
+void
+dst_key_setbits(dst_key_t *key, isc_uint16_t bits) {
+ unsigned int maxbits;
+ REQUIRE(VALID_KEY(key));
+ if (bits != 0) {
+ RUNTIME_CHECK(dst_key_sigsize(key, &maxbits) == ISC_R_SUCCESS);
+ maxbits *= 8;
+ REQUIRE(bits <= maxbits);
+ }
+ key->key_bits = bits;
+}
+
+isc_uint16_t
+dst_key_getbits(const dst_key_t *key) {
+ REQUIRE(VALID_KEY(key));
+ return (key->key_bits);
+}
+
+/*! \file */
diff --git a/lib/dns/keytable.c b/lib/dns/keytable.c
new file mode 100644
index 0000000..ec0f8e4
--- /dev/null
+++ b/lib/dns/keytable.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2004, 2005 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: keytable.c,v 1.28.18.4 2005/12/05 00:00:03 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/rwlock.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/util.h>
+
+#include <dns/keytable.h>
+#include <dns/fixedname.h>
+#include <dns/rbt.h>
+#include <dns/result.h>
+
+struct dns_keytable {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ isc_rwlock_t rwlock;
+ /* Locked by lock. */
+ isc_uint32_t active_nodes;
+ /* Locked by rwlock. */
+ isc_uint32_t references;
+ dns_rbt_t *table;
+};
+
+#define KEYTABLE_MAGIC ISC_MAGIC('K', 'T', 'b', 'l')
+#define VALID_KEYTABLE(kt) ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC)
+
+struct dns_keynode {
+ unsigned int magic;
+ dst_key_t * key;
+ struct dns_keynode * next;
+};
+
+#define KEYNODE_MAGIC ISC_MAGIC('K', 'N', 'o', 'd')
+#define VALID_KEYNODE(kn) ISC_MAGIC_VALID(kn, KEYNODE_MAGIC)
+
+static void
+free_keynode(void *node, void *arg) {
+ dns_keynode_t *keynode = node;
+ isc_mem_t *mctx = arg;
+
+ REQUIRE(VALID_KEYNODE(keynode));
+ dst_key_free(&keynode->key);
+ if (keynode->next != NULL)
+ free_keynode(keynode->next, mctx);
+ isc_mem_put(mctx, keynode, sizeof(dns_keynode_t));
+}
+
+isc_result_t
+dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) {
+ dns_keytable_t *keytable;
+ isc_result_t result;
+
+ /*
+ * Create a keytable.
+ */
+
+ REQUIRE(keytablep != NULL && *keytablep == NULL);
+
+ keytable = isc_mem_get(mctx, sizeof(*keytable));
+ if (keytable == NULL)
+ return (ISC_R_NOMEMORY);
+
+ keytable->table = NULL;
+ result = dns_rbt_create(mctx, free_keynode, mctx, &keytable->table);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_keytable;
+
+ result = isc_mutex_init(&keytable->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_rbt;
+
+ result = isc_rwlock_init(&keytable->rwlock, 0, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+
+ keytable->mctx = mctx;
+ keytable->active_nodes = 0;
+ keytable->references = 1;
+ keytable->magic = KEYTABLE_MAGIC;
+ *keytablep = keytable;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_lock:
+ DESTROYLOCK(&keytable->lock);
+
+ cleanup_rbt:
+ dns_rbt_destroy(&keytable->table);
+
+ cleanup_keytable:
+ isc_mem_put(mctx, keytable, sizeof(*keytable));
+
+ return (result);
+}
+
+
+void
+dns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp) {
+
+ /*
+ * Attach *targetp to source.
+ */
+
+ REQUIRE(VALID_KEYTABLE(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ RWLOCK(&source->rwlock, isc_rwlocktype_write);
+
+ INSIST(source->references > 0);
+ source->references++;
+ INSIST(source->references != 0);
+
+ RWUNLOCK(&source->rwlock, isc_rwlocktype_write);
+
+ *targetp = source;
+}
+
+void
+dns_keytable_detach(dns_keytable_t **keytablep) {
+ isc_boolean_t destroy = ISC_FALSE;
+ dns_keytable_t *keytable;
+
+ /*
+ * Detach *keytablep from its keytable.
+ */
+
+ REQUIRE(keytablep != NULL && VALID_KEYTABLE(*keytablep));
+
+ keytable = *keytablep;
+
+ RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
+
+ INSIST(keytable->references > 0);
+ keytable->references--;
+ LOCK(&keytable->lock);
+ if (keytable->references == 0 && keytable->active_nodes == 0)
+ destroy = ISC_TRUE;
+ UNLOCK(&keytable->lock);
+
+ RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
+
+ if (destroy) {
+ dns_rbt_destroy(&keytable->table);
+ isc_rwlock_destroy(&keytable->rwlock);
+ DESTROYLOCK(&keytable->lock);
+ keytable->magic = 0;
+ isc_mem_put(keytable->mctx, keytable, sizeof(*keytable));
+ }
+
+ *keytablep = NULL;
+}
+
+isc_result_t
+dns_keytable_add(dns_keytable_t *keytable, dst_key_t **keyp) {
+ isc_result_t result;
+ dns_keynode_t *knode;
+ dns_rbtnode_t *node;
+ dns_name_t *keyname;
+
+ /*
+ * Add '*keyp' to 'keytable'.
+ */
+
+ REQUIRE(VALID_KEYTABLE(keytable));
+ REQUIRE(keyp != NULL);
+
+ keyname = dst_key_name(*keyp);
+
+ knode = isc_mem_get(keytable->mctx, sizeof(*knode));
+ if (knode == NULL)
+ return (ISC_R_NOMEMORY);
+
+ RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
+
+ node = NULL;
+ result = dns_rbt_addnode(keytable->table, keyname, &node);
+
+ if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) {
+ knode->magic = KEYNODE_MAGIC;
+ knode->key = *keyp;
+ knode->next = node->data;
+ node->data = knode;
+ *keyp = NULL;
+ knode = NULL;
+ result = ISC_R_SUCCESS;
+ }
+
+ RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
+
+ if (knode != NULL)
+ isc_mem_put(keytable->mctx, knode, sizeof(*knode));
+
+ return (result);
+}
+
+isc_result_t
+dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name,
+ dns_secalg_t algorithm, dns_keytag_t tag,
+ dns_keynode_t **keynodep)
+{
+ isc_result_t result;
+ dns_keynode_t *knode;
+ void *data;
+
+ /*
+ * Search for a key named 'name', matching 'algorithm' and 'tag' in
+ * 'keytable'.
+ */
+
+ REQUIRE(VALID_KEYTABLE(keytable));
+ REQUIRE(dns_name_isabsolute(name));
+ REQUIRE(keynodep != NULL && *keynodep == NULL);
+
+ RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
+
+ /*
+ * Note we don't want the DNS_R_PARTIALMATCH from dns_rbt_findname()
+ * as that indicates that 'name' was not found.
+ *
+ * DNS_R_PARTIALMATCH indicates that the name was found but we
+ * didn't get a match on algorithm and key id arguments.
+ */
+ knode = NULL;
+ data = NULL;
+ result = dns_rbt_findname(keytable->table, name, 0, NULL, &data);
+
+ if (result == ISC_R_SUCCESS) {
+ INSIST(data != NULL);
+ for (knode = data; knode != NULL; knode = knode->next) {
+ if (algorithm == dst_key_alg(knode->key)
+ && tag == dst_key_id(knode->key))
+ break;
+ }
+ if (knode != NULL) {
+ LOCK(&keytable->lock);
+ keytable->active_nodes++;
+ UNLOCK(&keytable->lock);
+ *keynodep = knode;
+ } else
+ result = DNS_R_PARTIALMATCH;
+ } else if (result == DNS_R_PARTIALMATCH)
+ result = ISC_R_NOTFOUND;
+
+ RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
+
+ return (result);
+}
+
+isc_result_t
+dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
+ dns_keynode_t **nextnodep)
+{
+ isc_result_t result;
+ dns_keynode_t *knode;
+
+ /*
+ * Search for the next key with the same properties as 'keynode' in
+ * 'keytable'.
+ */
+
+ REQUIRE(VALID_KEYTABLE(keytable));
+ REQUIRE(VALID_KEYNODE(keynode));
+ REQUIRE(nextnodep != NULL && *nextnodep == NULL);
+
+ for (knode = keynode->next; knode != NULL; knode = knode->next) {
+ if (dst_key_alg(keynode->key) == dst_key_alg(knode->key) &&
+ dst_key_id(keynode->key) == dst_key_id(knode->key))
+ break;
+ }
+ if (knode != NULL) {
+ LOCK(&keytable->lock);
+ keytable->active_nodes++;
+ UNLOCK(&keytable->lock);
+ result = ISC_R_SUCCESS;
+ *nextnodep = knode;
+ } else
+ result = ISC_R_NOTFOUND;
+
+ return (result);
+}
+
+isc_result_t
+dns_keytable_finddeepestmatch(dns_keytable_t *keytable, dns_name_t *name,
+ dns_name_t *foundname)
+{
+ isc_result_t result;
+ void *data;
+
+ /*
+ * Search for the deepest match in 'keytable'.
+ */
+
+ REQUIRE(VALID_KEYTABLE(keytable));
+ REQUIRE(dns_name_isabsolute(name));
+ REQUIRE(foundname != NULL);
+
+ RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
+
+ data = NULL;
+ result = dns_rbt_findname(keytable->table, name, 0, foundname, &data);
+
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
+ result = ISC_R_SUCCESS;
+
+ RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
+
+ return (result);
+}
+
+void
+dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep)
+{
+ /*
+ * Give back a keynode found via dns_keytable_findkeynode().
+ */
+
+ REQUIRE(VALID_KEYTABLE(keytable));
+ REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));
+
+ LOCK(&keytable->lock);
+ INSIST(keytable->active_nodes > 0);
+ keytable->active_nodes--;
+ UNLOCK(&keytable->lock);
+
+ *keynodep = NULL;
+}
+
+isc_result_t
+dns_keytable_issecuredomain(dns_keytable_t *keytable, dns_name_t *name,
+ isc_boolean_t *wantdnssecp)
+{
+ isc_result_t result;
+ void *data;
+
+ /*
+ * Is 'name' at or beneath a trusted key?
+ */
+
+ REQUIRE(VALID_KEYTABLE(keytable));
+ REQUIRE(dns_name_isabsolute(name));
+ REQUIRE(wantdnssecp != NULL);
+
+ RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
+
+ data = NULL;
+ result = dns_rbt_findname(keytable->table, name, 0, NULL, &data);
+
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+ INSIST(data != NULL);
+ *wantdnssecp = ISC_TRUE;
+ result = ISC_R_SUCCESS;
+ } else if (result == ISC_R_NOTFOUND) {
+ *wantdnssecp = ISC_FALSE;
+ result = ISC_R_SUCCESS;
+ }
+
+ RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
+
+ return (result);
+}
+
+dst_key_t *
+dns_keynode_key(dns_keynode_t *keynode) {
+
+ /*
+ * Get the DST key associated with keynode.
+ */
+
+ REQUIRE(VALID_KEYNODE(keynode));
+
+ return (keynode->key);
+}
diff --git a/lib/dns/lib.c b/lib/dns/lib.c
new file mode 100644
index 0000000..423908a
--- /dev/null
+++ b/lib/dns/lib.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2004, 2005 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: lib.c,v 1.11.18.3 2005/08/15 01:46:50 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/once.h>
+#include <isc/msgcat.h>
+#include <isc/util.h>
+
+#include <dns/lib.h>
+
+/***
+ *** Globals
+ ***/
+
+LIBDNS_EXTERNAL_DATA unsigned int dns_pps = 0U;
+LIBDNS_EXTERNAL_DATA isc_msgcat_t * dns_msgcat = NULL;
+
+
+/***
+ *** Private
+ ***/
+
+static isc_once_t msgcat_once = ISC_ONCE_INIT;
+
+
+/***
+ *** Functions
+ ***/
+
+static void
+open_msgcat(void) {
+ isc_msgcat_open("libdns.cat", &dns_msgcat);
+}
+
+void
+dns_lib_initmsgcat(void) {
+
+ /*
+ * Initialize the DNS library's message catalog, dns_msgcat, if it
+ * has not already been initialized.
+ */
+
+ RUNTIME_CHECK(isc_once_do(&msgcat_once, open_msgcat) == ISC_R_SUCCESS);
+}
diff --git a/lib/dns/log.c b/lib/dns/log.c
new file mode 100644
index 0000000..939ea36
--- /dev/null
+++ b/lib/dns/log.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2004, 2005 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: log.c,v 1.36.18.4 2005/09/05 00:18:24 marka Exp $ */
+
+/*! \file */
+
+/* Principal Authors: DCL */
+
+#include <config.h>
+
+#include <isc/util.h>
+
+#include <dns/log.h>
+
+/*%
+ * When adding a new category, be sure to add the appropriate
+ * #define to <dns/log.h>.
+ */
+LIBDNS_EXTERNAL_DATA isc_logcategory_t dns_categories[] = {
+ { "notify", 0 },
+ { "database", 0 },
+ { "security", 0 },
+ { "_placeholder", 0 },
+ { "dnssec", 0 },
+ { "resolver", 0 },
+ { "xfer-in", 0 },
+ { "xfer-out", 0 },
+ { "dispatch", 0 },
+ { "lame-servers", 0 },
+ { "delegation-only", 0 },
+ { NULL, 0 }
+};
+
+/*%
+ * When adding a new module, be sure to add the appropriate
+ * #define to <dns/log.h>.
+ */
+LIBDNS_EXTERNAL_DATA isc_logmodule_t dns_modules[] = {
+ { "dns/db", 0 },
+ { "dns/rbtdb", 0 },
+ { "dns/rbtdb64", 0 },
+ { "dns/rbt", 0 },
+ { "dns/rdata", 0 },
+ { "dns/master", 0 },
+ { "dns/message", 0 },
+ { "dns/cache", 0 },
+ { "dns/config", 0 },
+ { "dns/resolver", 0 },
+ { "dns/zone", 0 },
+ { "dns/journal", 0 },
+ { "dns/adb", 0 },
+ { "dns/xfrin", 0 },
+ { "dns/xfrout", 0 },
+ { "dns/acl", 0 },
+ { "dns/validator", 0 },
+ { "dns/dispatch", 0 },
+ { "dns/request", 0 },
+ { "dns/masterdump", 0 },
+ { "dns/tsig", 0 },
+ { "dns/tkey", 0 },
+ { "dns/sdb", 0 },
+ { "dns/diff", 0 },
+ { "dns/hints", 0 },
+ { "dns/acache", 0 },
+ { "dns/dlz", 0 },
+ { NULL, 0 }
+};
+
+LIBDNS_EXTERNAL_DATA isc_log_t *dns_lctx = NULL;
+
+void
+dns_log_init(isc_log_t *lctx) {
+ REQUIRE(lctx != NULL);
+
+ isc_log_registercategories(lctx, dns_categories);
+ isc_log_registermodules(lctx, dns_modules);
+}
+
+void
+dns_log_setcontext(isc_log_t *lctx) {
+ dns_lctx = lctx;
+}
diff --git a/lib/dns/lookup.c b/lib/dns/lookup.c
new file mode 100644
index 0000000..a3ddad4
--- /dev/null
+++ b/lib/dns/lookup.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lookup.c,v 1.14.18.7 2007/08/28 07:20:04 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/netaddr.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/task.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/events.h>
+#include <dns/lookup.h>
+#include <dns/rdata.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+#include <dns/view.h>
+
+struct dns_lookup {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ isc_mutex_t lock;
+ dns_rdatatype_t type;
+ dns_fixedname_t name;
+ /* Locked by lock. */
+ unsigned int options;
+ isc_task_t * task;
+ dns_view_t * view;
+ dns_lookupevent_t * event;
+ dns_fetch_t * fetch;
+ unsigned int restarts;
+ isc_boolean_t canceled;
+ dns_rdataset_t rdataset;
+ dns_rdataset_t sigrdataset;
+};
+
+#define LOOKUP_MAGIC ISC_MAGIC('l', 'o', 'o', 'k')
+#define VALID_LOOKUP(l) ISC_MAGIC_VALID((l), LOOKUP_MAGIC)
+
+#define MAX_RESTARTS 16
+
+static void lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event);
+
+static void
+fetch_done(isc_task_t *task, isc_event_t *event) {
+ dns_lookup_t *lookup = event->ev_arg;
+ dns_fetchevent_t *fevent;
+
+ UNUSED(task);
+ REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
+ REQUIRE(VALID_LOOKUP(lookup));
+ REQUIRE(lookup->task == task);
+ fevent = (dns_fetchevent_t *)event;
+ REQUIRE(fevent->fetch == lookup->fetch);
+
+ lookup_find(lookup, fevent);
+}
+
+static inline isc_result_t
+start_fetch(dns_lookup_t *lookup) {
+ isc_result_t result;
+
+ /*
+ * The caller must be holding the lookup's lock.
+ */
+
+ REQUIRE(lookup->fetch == NULL);
+
+ result = dns_resolver_createfetch(lookup->view->resolver,
+ dns_fixedname_name(&lookup->name),
+ lookup->type,
+ NULL, NULL, NULL, 0,
+ lookup->task, fetch_done, lookup,
+ &lookup->rdataset,
+ &lookup->sigrdataset,
+ &lookup->fetch);
+
+ return (result);
+}
+
+static isc_result_t
+build_event(dns_lookup_t *lookup) {
+ dns_name_t *name = NULL;
+ dns_rdataset_t *rdataset = NULL;
+ dns_rdataset_t *sigrdataset = NULL;
+ isc_result_t result;
+
+ name = isc_mem_get(lookup->mctx, sizeof(dns_name_t));
+ if (name == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto fail;
+ }
+ dns_name_init(name, NULL);
+ result = dns_name_dup(dns_fixedname_name(&lookup->name),
+ lookup->mctx, name);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+
+ if (dns_rdataset_isassociated(&lookup->rdataset)) {
+ rdataset = isc_mem_get(lookup->mctx, sizeof(dns_rdataset_t));
+ if (rdataset == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto fail;
+ }
+ dns_rdataset_init(rdataset);
+ dns_rdataset_clone(&lookup->rdataset, rdataset);
+ }
+
+ if (dns_rdataset_isassociated(&lookup->sigrdataset)) {
+ sigrdataset = isc_mem_get(lookup->mctx,
+ sizeof(dns_rdataset_t));
+ if (sigrdataset == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto fail;
+ }
+ dns_rdataset_init(sigrdataset);
+ dns_rdataset_clone(&lookup->sigrdataset, sigrdataset);
+ }
+
+ lookup->event->name = name;
+ lookup->event->rdataset = rdataset;
+ lookup->event->sigrdataset = sigrdataset;
+
+ return (ISC_R_SUCCESS);
+
+ fail:
+ if (name != NULL) {
+ if (dns_name_dynamic(name))
+ dns_name_free(name, lookup->mctx);
+ isc_mem_put(lookup->mctx, name, sizeof(dns_name_t));
+ }
+ if (rdataset != NULL) {
+ if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+ isc_mem_put(lookup->mctx, rdataset, sizeof(dns_rdataset_t));
+ }
+ return (result);
+}
+
+static isc_result_t
+view_find(dns_lookup_t *lookup, dns_name_t *foundname) {
+ isc_result_t result;
+ dns_name_t *name = dns_fixedname_name(&lookup->name);
+ dns_rdatatype_t type;
+
+ if (lookup->type == dns_rdatatype_rrsig)
+ type = dns_rdatatype_any;
+ else
+ type = lookup->type;
+
+ result = dns_view_find(lookup->view, name, type, 0, 0, ISC_FALSE,
+ &lookup->event->db, &lookup->event->node,
+ foundname, &lookup->rdataset,
+ &lookup->sigrdataset);
+ return (result);
+}
+
+static void
+lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) {
+ isc_result_t result;
+ isc_boolean_t want_restart;
+ isc_boolean_t send_event;
+ dns_name_t *name, *fname, *prefix;
+ dns_fixedname_t foundname, fixed;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned int nlabels;
+ int order;
+ dns_namereln_t namereln;
+ dns_rdata_cname_t cname;
+ dns_rdata_dname_t dname;
+
+ REQUIRE(VALID_LOOKUP(lookup));
+
+ LOCK(&lookup->lock);
+
+ result = ISC_R_SUCCESS;
+ name = dns_fixedname_name(&lookup->name);
+
+ do {
+ lookup->restarts++;
+ want_restart = ISC_FALSE;
+ send_event = ISC_TRUE;
+
+ if (event == NULL && !lookup->canceled) {
+ dns_fixedname_init(&foundname);
+ fname = dns_fixedname_name(&foundname);
+ INSIST(!dns_rdataset_isassociated(&lookup->rdataset));
+ INSIST(!dns_rdataset_isassociated
+ (&lookup->sigrdataset));
+ /*
+ * If we have restarted then clear the old node. */
+ if (lookup->event->node != NULL) {
+ INSIST(lookup->event->db != NULL);
+ dns_db_detachnode(lookup->event->db,
+ &lookup->event->node);
+ }
+ if (lookup->event->db != NULL)
+ dns_db_detach(&lookup->event->db);
+ result = view_find(lookup, fname);
+ if (result == ISC_R_NOTFOUND) {
+ /*
+ * We don't know anything about the name.
+ * Launch a fetch.
+ */
+ if (lookup->event->node != NULL) {
+ INSIST(lookup->event->db != NULL);
+ dns_db_detachnode(lookup->event->db,
+ &lookup->event->node);
+ }
+ if (lookup->event->db != NULL)
+ dns_db_detach(&lookup->event->db);
+ result = start_fetch(lookup);
+ if (result == ISC_R_SUCCESS)
+ send_event = ISC_FALSE;
+ goto done;
+ }
+ } else if (event != NULL) {
+ result = event->result;
+ fname = dns_fixedname_name(&event->foundname);
+ dns_resolver_destroyfetch(&lookup->fetch);
+ INSIST(event->rdataset == &lookup->rdataset);
+ INSIST(event->sigrdataset == &lookup->sigrdataset);
+ } else
+ fname = NULL; /* Silence compiler warning. */
+
+ /*
+ * If we've been canceled, forget about the result.
+ */
+ if (lookup->canceled)
+ result = ISC_R_CANCELED;
+
+ switch (result) {
+ case ISC_R_SUCCESS:
+ result = build_event(lookup);
+ if (event == NULL)
+ break;
+ if (event->db != NULL)
+ dns_db_attach(event->db, &lookup->event->db);
+ if (event->node != NULL)
+ dns_db_attachnode(lookup->event->db,
+ event->node,
+ &lookup->event->node);
+ break;
+ case DNS_R_CNAME:
+ /*
+ * Copy the CNAME's target into the lookup's
+ * query name and start over.
+ */
+ result = dns_rdataset_first(&lookup->rdataset);
+ if (result != ISC_R_SUCCESS)
+ break;
+ dns_rdataset_current(&lookup->rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &cname, NULL);
+ dns_rdata_reset(&rdata);
+ if (result != ISC_R_SUCCESS)
+ break;
+ result = dns_name_copy(&cname.cname, name, NULL);
+ dns_rdata_freestruct(&cname);
+ if (result == ISC_R_SUCCESS) {
+ want_restart = ISC_TRUE;
+ send_event = ISC_FALSE;
+ }
+ break;
+ case DNS_R_DNAME:
+ namereln = dns_name_fullcompare(name, fname, &order,
+ &nlabels);
+ INSIST(namereln == dns_namereln_subdomain);
+ /*
+ * Get the target name of the DNAME.
+ */
+ result = dns_rdataset_first(&lookup->rdataset);
+ if (result != ISC_R_SUCCESS)
+ break;
+ dns_rdataset_current(&lookup->rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &dname, NULL);
+ dns_rdata_reset(&rdata);
+ if (result != ISC_R_SUCCESS)
+ break;
+ /*
+ * Construct the new query name and start over.
+ */
+ dns_fixedname_init(&fixed);
+ prefix = dns_fixedname_name(&fixed);
+ dns_name_split(name, nlabels, prefix, NULL);
+ result = dns_name_concatenate(prefix, &dname.dname,
+ name, NULL);
+ dns_rdata_freestruct(&dname);
+ if (result == ISC_R_SUCCESS) {
+ want_restart = ISC_TRUE;
+ send_event = ISC_FALSE;
+ }
+ break;
+ default:
+ send_event = ISC_TRUE;
+ }
+
+ if (dns_rdataset_isassociated(&lookup->rdataset))
+ dns_rdataset_disassociate(&lookup->rdataset);
+ if (dns_rdataset_isassociated(&lookup->sigrdataset))
+ dns_rdataset_disassociate(&lookup->sigrdataset);
+
+ done:
+ if (event != NULL) {
+ if (event->node != NULL)
+ dns_db_detachnode(event->db, &event->node);
+ if (event->db != NULL)
+ dns_db_detach(&event->db);
+ isc_event_free(ISC_EVENT_PTR(&event));
+ }
+
+ /*
+ * Limit the number of restarts.
+ */
+ if (want_restart && lookup->restarts == MAX_RESTARTS) {
+ want_restart = ISC_FALSE;
+ result = ISC_R_QUOTA;
+ send_event = ISC_TRUE;
+ }
+
+ } while (want_restart);
+
+ if (send_event) {
+ lookup->event->result = result;
+ lookup->event->ev_sender = lookup;
+ isc_task_sendanddetach(&lookup->task,
+ (isc_event_t **)&lookup->event);
+ dns_view_detach(&lookup->view);
+ }
+
+ UNLOCK(&lookup->lock);
+}
+
+static void
+levent_destroy(isc_event_t *event) {
+ dns_lookupevent_t *levent;
+ isc_mem_t *mctx;
+
+ REQUIRE(event->ev_type == DNS_EVENT_LOOKUPDONE);
+ mctx = event->ev_destroy_arg;
+ levent = (dns_lookupevent_t *)event;
+
+ if (levent->name != NULL) {
+ if (dns_name_dynamic(levent->name))
+ dns_name_free(levent->name, mctx);
+ isc_mem_put(mctx, levent->name, sizeof(dns_name_t));
+ }
+ if (levent->rdataset != NULL) {
+ dns_rdataset_disassociate(levent->rdataset);
+ isc_mem_put(mctx, levent->rdataset, sizeof(dns_rdataset_t));
+ }
+ if (levent->sigrdataset != NULL) {
+ dns_rdataset_disassociate(levent->sigrdataset);
+ isc_mem_put(mctx, levent->sigrdataset, sizeof(dns_rdataset_t));
+ }
+ if (levent->node != NULL)
+ dns_db_detachnode(levent->db, &levent->node);
+ if (levent->db != NULL)
+ dns_db_detach(&levent->db);
+ isc_mem_put(mctx, event, event->ev_size);
+}
+
+isc_result_t
+dns_lookup_create(isc_mem_t *mctx, dns_name_t *name, dns_rdatatype_t type,
+ dns_view_t *view, unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg, dns_lookup_t **lookupp)
+{
+ isc_result_t result;
+ dns_lookup_t *lookup;
+ isc_event_t *ievent;
+
+ lookup = isc_mem_get(mctx, sizeof(*lookup));
+ if (lookup == NULL)
+ return (ISC_R_NOMEMORY);
+ lookup->mctx = mctx;
+ lookup->options = options;
+
+ ievent = isc_event_allocate(mctx, lookup, DNS_EVENT_LOOKUPDONE,
+ action, arg, sizeof(*lookup->event));
+ if (ievent == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_lookup;
+ }
+ lookup->event = (dns_lookupevent_t *)ievent;
+ lookup->event->ev_destroy = levent_destroy;
+ lookup->event->ev_destroy_arg = mctx;
+ lookup->event->result = ISC_R_FAILURE;
+ lookup->event->name = NULL;
+ lookup->event->rdataset = NULL;
+ lookup->event->sigrdataset = NULL;
+ lookup->event->db = NULL;
+ lookup->event->node = NULL;
+
+ lookup->task = NULL;
+ isc_task_attach(task, &lookup->task);
+
+ result = isc_mutex_init(&lookup->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_event;
+
+ dns_fixedname_init(&lookup->name);
+
+ result = dns_name_copy(name, dns_fixedname_name(&lookup->name), NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+
+ lookup->type = type;
+ lookup->view = NULL;
+ dns_view_attach(view, &lookup->view);
+ lookup->fetch = NULL;
+ lookup->restarts = 0;
+ lookup->canceled = ISC_FALSE;
+ dns_rdataset_init(&lookup->rdataset);
+ dns_rdataset_init(&lookup->sigrdataset);
+ lookup->magic = LOOKUP_MAGIC;
+
+ *lookupp = lookup;
+
+ lookup_find(lookup, NULL);
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_lock:
+ DESTROYLOCK(&lookup->lock);
+
+ cleanup_event:
+ ievent = (isc_event_t *)lookup->event;
+ isc_event_free(&ievent);
+ lookup->event = NULL;
+
+ isc_task_detach(&lookup->task);
+
+ cleanup_lookup:
+ isc_mem_put(mctx, lookup, sizeof(*lookup));
+
+ return (result);
+}
+
+void
+dns_lookup_cancel(dns_lookup_t *lookup) {
+ REQUIRE(VALID_LOOKUP(lookup));
+
+ LOCK(&lookup->lock);
+
+ if (!lookup->canceled) {
+ lookup->canceled = ISC_TRUE;
+ if (lookup->fetch != NULL) {
+ INSIST(lookup->view != NULL);
+ dns_resolver_cancelfetch(lookup->fetch);
+ }
+ }
+
+ UNLOCK(&lookup->lock);
+}
+
+void
+dns_lookup_destroy(dns_lookup_t **lookupp) {
+ dns_lookup_t *lookup;
+
+ REQUIRE(lookupp != NULL);
+ lookup = *lookupp;
+ REQUIRE(VALID_LOOKUP(lookup));
+ REQUIRE(lookup->event == NULL);
+ REQUIRE(lookup->task == NULL);
+ REQUIRE(lookup->view == NULL);
+ if (dns_rdataset_isassociated(&lookup->rdataset))
+ dns_rdataset_disassociate(&lookup->rdataset);
+ if (dns_rdataset_isassociated(&lookup->sigrdataset))
+ dns_rdataset_disassociate(&lookup->sigrdataset);
+
+ DESTROYLOCK(&lookup->lock);
+ lookup->magic = 0;
+ isc_mem_put(lookup->mctx, lookup, sizeof(*lookup));
+
+ *lookupp = NULL;
+}
diff --git a/lib/dns/master.c b/lib/dns/master.c
new file mode 100644
index 0000000..aa04be0
--- /dev/null
+++ b/lib/dns/master.c
@@ -0,0 +1,2833 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: master.c,v 1.148.18.18 2007/08/28 07:20:04 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/event.h>
+#include <isc/lex.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/serial.h>
+#include <isc/stdio.h>
+#include <isc/stdtime.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/util.h>
+
+#include <dns/callbacks.h>
+#include <dns/events.h>
+#include <dns/fixedname.h>
+#include <dns/master.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/rdatatype.h>
+#include <dns/result.h>
+#include <dns/soa.h>
+#include <dns/time.h>
+#include <dns/ttl.h>
+
+/*!
+ * Grow the number of dns_rdatalist_t (#RDLSZ) and dns_rdata_t (#RDSZ) structures
+ * by these sizes when we need to.
+ *
+ */
+/*% RDLSZ reflects the number of different types with the same name expected. */
+#define RDLSZ 32
+/*%
+ * RDSZ reflects the number of rdata expected at a give name that can fit into
+ * 64k.
+ */
+#define RDSZ 512
+
+#define NBUFS 4
+#define MAXWIRESZ 255
+
+/*%
+ * Target buffer size and minimum target size.
+ * MINTSIZ must be big enough to hold the largest rdata record.
+ * \brief
+ * TSIZ >= MINTSIZ
+ */
+#define TSIZ (128*1024)
+/*%
+ * max message size - header - root - type - class - ttl - rdlen
+ */
+#define MINTSIZ (65535 - 12 - 1 - 2 - 2 - 4 - 2)
+/*%
+ * Size for tokens in the presentation format,
+ * The largest tokens are the base64 blocks in KEY and CERT records,
+ * Largest key allowed is about 1372 bytes but
+ * there is no fixed upper bound on CERT records.
+ * 2K is too small for some X.509s, 8K is overkill.
+ */
+#define TOKENSIZ (8*1024)
+
+#define DNS_MASTER_BUFSZ 2048
+
+typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t;
+
+typedef struct dns_incctx dns_incctx_t;
+
+/*%
+ * Master file load state.
+ */
+
+struct dns_loadctx {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ dns_masterformat_t format;
+
+ dns_rdatacallbacks_t *callbacks;
+ isc_task_t *task;
+ dns_loaddonefunc_t done;
+ void *done_arg;
+
+ /* Common methods */
+ isc_result_t (*openfile)(dns_loadctx_t *lctx,
+ const char *filename);
+ isc_result_t (*load)(dns_loadctx_t *lctx);
+
+ /* Members specific to the text format: */
+ isc_lex_t *lex;
+ isc_boolean_t keep_lex;
+ unsigned int options;
+ isc_boolean_t ttl_known;
+ isc_boolean_t default_ttl_known;
+ isc_boolean_t warn_1035;
+ isc_boolean_t warn_tcr;
+ isc_boolean_t warn_sigexpired;
+ isc_boolean_t seen_include;
+ isc_uint32_t ttl;
+ isc_uint32_t default_ttl;
+ dns_rdataclass_t zclass;
+ dns_fixedname_t fixed_top;
+ dns_name_t *top; /*%< top of zone */
+
+ /* Members specific to the raw format: */
+ FILE *f;
+ isc_boolean_t first;
+
+ /* Which fixed buffers we are using? */
+ unsigned int loop_cnt; /*% records per quantum,
+ * 0 => all. */
+ isc_boolean_t canceled;
+ isc_mutex_t lock;
+ isc_result_t result;
+ /* locked by lock */
+ isc_uint32_t references;
+ dns_incctx_t *inc;
+};
+
+struct dns_incctx {
+ dns_incctx_t *parent;
+ dns_name_t *origin;
+ dns_name_t *current;
+ dns_name_t *glue;
+ dns_fixedname_t fixed[NBUFS]; /* working buffers */
+ unsigned int in_use[NBUFS]; /* covert to bitmap? */
+ int glue_in_use;
+ int current_in_use;
+ int origin_in_use;
+ isc_boolean_t drop;
+ unsigned int glue_line;
+ unsigned int current_line;
+};
+
+#define DNS_LCTX_MAGIC ISC_MAGIC('L','c','t','x')
+#define DNS_LCTX_VALID(lctx) ISC_MAGIC_VALID(lctx, DNS_LCTX_MAGIC)
+
+#define DNS_AS_STR(t) ((t).value.as_textregion.base)
+
+static isc_result_t
+openfile_text(dns_loadctx_t *lctx, const char *master_file);
+
+static isc_result_t
+openfile_raw(dns_loadctx_t *lctx, const char *master_file);
+
+static isc_result_t
+load_text(dns_loadctx_t *lctx);
+
+static isc_result_t
+load_raw(dns_loadctx_t *lctx);
+
+static isc_result_t
+pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx);
+
+static isc_result_t
+commit(dns_rdatacallbacks_t *, dns_loadctx_t *, rdatalist_head_t *,
+ dns_name_t *, const char *, unsigned int);
+
+static isc_boolean_t
+is_glue(rdatalist_head_t *, dns_name_t *);
+
+static dns_rdatalist_t *
+grow_rdatalist(int, dns_rdatalist_t *, int, rdatalist_head_t *,
+ rdatalist_head_t *, isc_mem_t *mctx);
+
+static dns_rdata_t *
+grow_rdata(int, dns_rdata_t *, int, rdatalist_head_t *, rdatalist_head_t *,
+ isc_mem_t *);
+
+static void
+load_quantum(isc_task_t *task, isc_event_t *event);
+
+static isc_result_t
+task_send(dns_loadctx_t *lctx);
+
+static void
+loadctx_destroy(dns_loadctx_t *lctx);
+
+#define GETTOKEN(lexer, options, token, eol) \
+ do { \
+ result = gettoken(lexer, options, token, eol, callbacks); \
+ switch (result) { \
+ case ISC_R_SUCCESS: \
+ break; \
+ case ISC_R_UNEXPECTED: \
+ goto insist_and_cleanup; \
+ default: \
+ if (MANYERRS(lctx, result)) { \
+ SETRESULT(lctx, result); \
+ LOGIT(result); \
+ read_till_eol = ISC_TRUE; \
+ goto next_line; \
+ } else \
+ goto log_and_cleanup; \
+ } \
+ if ((token)->type == isc_tokentype_special) { \
+ result = DNS_R_SYNTAX; \
+ if (MANYERRS(lctx, result)) { \
+ SETRESULT(lctx, result); \
+ LOGIT(result); \
+ read_till_eol = ISC_TRUE; \
+ goto next_line; \
+ } else \
+ goto log_and_cleanup; \
+ } \
+ } while (0)
+
+#define COMMITALL \
+ do { \
+ result = commit(callbacks, lctx, &current_list, \
+ ictx->current, source, ictx->current_line); \
+ if (MANYERRS(lctx, result)) { \
+ SETRESULT(lctx, result); \
+ } else if (result != ISC_R_SUCCESS) \
+ goto insist_and_cleanup; \
+ result = commit(callbacks, lctx, &glue_list, \
+ ictx->glue, source, ictx->glue_line); \
+ if (MANYERRS(lctx, result)) { \
+ SETRESULT(lctx, result); \
+ } else if (result != ISC_R_SUCCESS) \
+ goto insist_and_cleanup; \
+ rdcount = 0; \
+ rdlcount = 0; \
+ isc_buffer_init(&target, target_mem, target_size); \
+ rdcount_save = rdcount; \
+ rdlcount_save = rdlcount; \
+ } while (0)
+
+#define WARNUNEXPECTEDEOF(lexer) \
+ do { \
+ if (isc_lex_isfile(lexer)) \
+ (*callbacks->warn)(callbacks, \
+ "%s: file does not end with newline", \
+ source); \
+ } while (0)
+
+#define EXPECTEOL \
+ do { \
+ GETTOKEN(lctx->lex, 0, &token, ISC_TRUE); \
+ if (token.type != isc_tokentype_eol) { \
+ isc_lex_ungettoken(lctx->lex, &token); \
+ result = DNS_R_EXTRATOKEN; \
+ if (MANYERRS(lctx, result)) { \
+ SETRESULT(lctx, result); \
+ LOGIT(result); \
+ read_till_eol = ISC_TRUE; \
+ continue; \
+ } else if (result != ISC_R_SUCCESS) \
+ goto log_and_cleanup; \
+ } \
+ } while (0)
+
+#define MANYERRS(lctx, result) \
+ ((result != ISC_R_SUCCESS) && \
+ (result != ISC_R_IOERROR) && \
+ ((lctx)->options & DNS_MASTER_MANYERRORS) != 0)
+
+#define SETRESULT(lctx, r) \
+ do { \
+ if ((lctx)->result == ISC_R_SUCCESS) \
+ (lctx)->result = r; \
+ } while (0)
+
+#define LOGITFILE(result, filename) \
+ if (result == ISC_R_INVALIDFILE || result == ISC_R_FILENOTFOUND || \
+ result == ISC_R_IOERROR || result == ISC_R_TOOMANYOPENFILES || \
+ result == ISC_R_NOPERM) \
+ (*callbacks->error)(callbacks, "%s: %s:%lu: %s: %s", \
+ "dns_master_load", source, line, \
+ filename, dns_result_totext(result)); \
+ else LOGIT(result)
+
+#define LOGIT(result) \
+ if (result == ISC_R_NOMEMORY) \
+ (*callbacks->error)(callbacks, "dns_master_load: %s", \
+ dns_result_totext(result)); \
+ else \
+ (*callbacks->error)(callbacks, "%s: %s:%lu: %s", \
+ "dns_master_load", \
+ source, line, dns_result_totext(result))
+
+
+static unsigned char in_addr_arpa_data[] = "\007IN-ADDR\004ARPA";
+static unsigned char in_addr_arpa_offsets[] = { 0, 8, 13 };
+static const dns_name_t in_addr_arpa =
+{
+ DNS_NAME_MAGIC,
+ in_addr_arpa_data, 14, 3,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ in_addr_arpa_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+static unsigned char ip6_int_data[] = "\003IP6\003INT";
+static unsigned char ip6_int_offsets[] = { 0, 4, 8 };
+static const dns_name_t ip6_int =
+{
+ DNS_NAME_MAGIC,
+ ip6_int_data, 9, 3,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ ip6_int_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+static unsigned char ip6_arpa_data[] = "\003IP6\004ARPA";
+static unsigned char ip6_arpa_offsets[] = { 0, 4, 9 };
+static const dns_name_t ip6_arpa =
+{
+ DNS_NAME_MAGIC,
+ ip6_arpa_data, 10, 3,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ ip6_arpa_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+
+static inline isc_result_t
+gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *token,
+ isc_boolean_t eol, dns_rdatacallbacks_t *callbacks)
+{
+ isc_result_t result;
+
+ options |= ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | ISC_LEXOPT_DNSMULTILINE |
+ ISC_LEXOPT_ESCAPE;
+ result = isc_lex_gettoken(lex, options, token);
+ if (result != ISC_R_SUCCESS) {
+ switch (result) {
+ case ISC_R_NOMEMORY:
+ return (ISC_R_NOMEMORY);
+ default:
+ (*callbacks->error)(callbacks,
+ "dns_master_load: %s:%lu:"
+ " isc_lex_gettoken() failed: %s",
+ isc_lex_getsourcename(lex),
+ isc_lex_getsourceline(lex),
+ isc_result_totext(result));
+ return (result);
+ }
+ /*NOTREACHED*/
+ }
+ if (eol != ISC_TRUE)
+ if (token->type == isc_tokentype_eol ||
+ token->type == isc_tokentype_eof) {
+ (*callbacks->error)(callbacks,
+ "dns_master_load: %s:%lu: unexpected end of %s",
+ isc_lex_getsourcename(lex),
+ isc_lex_getsourceline(lex),
+ (token->type ==
+ isc_tokentype_eol) ?
+ "line" : "file");
+ return (ISC_R_UNEXPECTEDEND);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+
+void
+dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) {
+
+ REQUIRE(target != NULL && *target == NULL);
+ REQUIRE(DNS_LCTX_VALID(source));
+
+ LOCK(&source->lock);
+ INSIST(source->references > 0);
+ source->references++;
+ INSIST(source->references != 0); /* Overflow? */
+ UNLOCK(&source->lock);
+
+ *target = source;
+}
+
+void
+dns_loadctx_detach(dns_loadctx_t **lctxp) {
+ dns_loadctx_t *lctx;
+ isc_boolean_t need_destroy = ISC_FALSE;
+
+ REQUIRE(lctxp != NULL);
+ lctx = *lctxp;
+ REQUIRE(DNS_LCTX_VALID(lctx));
+
+ LOCK(&lctx->lock);
+ INSIST(lctx->references > 0);
+ lctx->references--;
+ if (lctx->references == 0)
+ need_destroy = ISC_TRUE;
+ UNLOCK(&lctx->lock);
+
+ if (need_destroy)
+ loadctx_destroy(lctx);
+ *lctxp = NULL;
+}
+
+static void
+incctx_destroy(isc_mem_t *mctx, dns_incctx_t *ictx) {
+ dns_incctx_t *parent;
+
+ again:
+ parent = ictx->parent;
+ ictx->parent = NULL;
+
+ isc_mem_put(mctx, ictx, sizeof(*ictx));
+
+ if (parent != NULL) {
+ ictx = parent;
+ goto again;
+ }
+}
+
+static void
+loadctx_destroy(dns_loadctx_t *lctx) {
+ isc_mem_t *mctx;
+ isc_result_t result;
+
+ REQUIRE(DNS_LCTX_VALID(lctx));
+
+ lctx->magic = 0;
+ if (lctx->inc != NULL)
+ incctx_destroy(lctx->mctx, lctx->inc);
+
+ if (lctx->f != NULL) {
+ result = isc_stdio_close(lctx->f);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_stdio_close() failed: %s",
+ isc_result_totext(result));
+ }
+ }
+
+ /* isc_lex_destroy() will close all open streams */
+ if (lctx->lex != NULL && !lctx->keep_lex)
+ isc_lex_destroy(&lctx->lex);
+
+ if (lctx->task != NULL)
+ isc_task_detach(&lctx->task);
+ DESTROYLOCK(&lctx->lock);
+ mctx = NULL;
+ isc_mem_attach(lctx->mctx, &mctx);
+ isc_mem_detach(&lctx->mctx);
+ isc_mem_put(mctx, lctx, sizeof(*lctx));
+ isc_mem_detach(&mctx);
+}
+
+static isc_result_t
+incctx_create(isc_mem_t *mctx, dns_name_t *origin, dns_incctx_t **ictxp) {
+ dns_incctx_t *ictx;
+ isc_region_t r;
+ int i;
+
+ ictx = isc_mem_get(mctx, sizeof(*ictx));
+ if (ictx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ for (i = 0; i < NBUFS; i++) {
+ dns_fixedname_init(&ictx->fixed[i]);
+ ictx->in_use[i] = ISC_FALSE;
+ }
+
+ ictx->origin_in_use = 0;
+ ictx->origin = dns_fixedname_name(&ictx->fixed[ictx->origin_in_use]);
+ ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
+ dns_name_toregion(origin, &r);
+ dns_name_fromregion(ictx->origin, &r);
+
+ ictx->glue = NULL;
+ ictx->current = NULL;
+ ictx->glue_in_use = -1;
+ ictx->current_in_use = -1;
+ ictx->parent = NULL;
+ ictx->drop = ISC_FALSE;
+ ictx->glue_line = 0;
+ ictx->current_line = 0;
+
+ *ictxp = ictx;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+loadctx_create(dns_masterformat_t format, isc_mem_t *mctx,
+ unsigned int options, dns_name_t *top,
+ dns_rdataclass_t zclass, dns_name_t *origin,
+ dns_rdatacallbacks_t *callbacks, isc_task_t *task,
+ dns_loaddonefunc_t done, void *done_arg, isc_lex_t *lex,
+ dns_loadctx_t **lctxp)
+{
+ dns_loadctx_t *lctx;
+ isc_result_t result;
+ isc_region_t r;
+ isc_lexspecials_t specials;
+
+ REQUIRE(lctxp != NULL && *lctxp == NULL);
+ REQUIRE(callbacks != NULL);
+ REQUIRE(callbacks->add != NULL);
+ REQUIRE(callbacks->error != NULL);
+ REQUIRE(callbacks->warn != NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(dns_name_isabsolute(top));
+ REQUIRE(dns_name_isabsolute(origin));
+ REQUIRE((task == NULL && done == NULL) ||
+ (task != NULL && done != NULL));
+
+ lctx = isc_mem_get(mctx, sizeof(*lctx));
+ if (lctx == NULL)
+ return (ISC_R_NOMEMORY);
+ result = isc_mutex_init(&lctx->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, lctx, sizeof(*lctx));
+ return (result);
+ }
+
+ lctx->inc = NULL;
+ result = incctx_create(mctx, origin, &lctx->inc);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_ctx;
+
+ lctx->format = format;
+ switch (format) {
+ default:
+ INSIST(0);
+ case dns_masterformat_text:
+ lctx->openfile = openfile_text;
+ lctx->load = load_text;
+ break;
+ case dns_masterformat_raw:
+ lctx->openfile = openfile_raw;
+ lctx->load = load_raw;
+ break;
+ }
+
+ if (lex != NULL) {
+ lctx->lex = lex;
+ lctx->keep_lex = ISC_TRUE;
+ } else {
+ lctx->lex = NULL;
+ result = isc_lex_create(mctx, TOKENSIZ, &lctx->lex);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_inc;
+ lctx->keep_lex = ISC_FALSE;
+ memset(specials, 0, sizeof(specials));
+ specials['('] = 1;
+ specials[')'] = 1;
+ specials['"'] = 1;
+ isc_lex_setspecials(lctx->lex, specials);
+ isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE);
+ }
+
+ lctx->ttl_known = ISC_FALSE;
+ lctx->ttl = 0;
+ lctx->default_ttl_known = ISC_FALSE;
+ lctx->default_ttl = 0;
+ lctx->warn_1035 = ISC_TRUE; /* XXX Argument? */
+ lctx->warn_tcr = ISC_TRUE; /* XXX Argument? */
+ lctx->warn_sigexpired = ISC_TRUE; /* XXX Argument? */
+ lctx->options = options;
+ lctx->seen_include = ISC_FALSE;
+ lctx->zclass = zclass;
+ lctx->result = ISC_R_SUCCESS;
+
+ dns_fixedname_init(&lctx->fixed_top);
+ lctx->top = dns_fixedname_name(&lctx->fixed_top);
+ dns_name_toregion(top, &r);
+ dns_name_fromregion(lctx->top, &r);
+
+ lctx->f = NULL;
+ lctx->first = ISC_TRUE;
+
+ lctx->loop_cnt = (done != NULL) ? 100 : 0;
+ lctx->callbacks = callbacks;
+ lctx->task = NULL;
+ if (task != NULL)
+ isc_task_attach(task, &lctx->task);
+ lctx->done = done;
+ lctx->done_arg = done_arg;
+ lctx->canceled = ISC_FALSE;
+ lctx->mctx = NULL;
+ isc_mem_attach(mctx, &lctx->mctx);
+ lctx->references = 1; /* Implicit attach. */
+ lctx->magic = DNS_LCTX_MAGIC;
+ *lctxp = lctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup_inc:
+ incctx_destroy(mctx, lctx->inc);
+ cleanup_ctx:
+ isc_mem_put(mctx, lctx, sizeof(*lctx));
+ return (result);
+}
+
+static isc_result_t
+genname(char *name, int it, char *buffer, size_t length) {
+ char fmt[sizeof("%04000000000d")];
+ char numbuf[128];
+ char *cp;
+ char mode[2];
+ int delta = 0;
+ isc_textregion_t r;
+ unsigned int n;
+ unsigned int width;
+
+ r.base = buffer;
+ r.length = length;
+
+ while (*name != '\0') {
+ if (*name == '$') {
+ name++;
+ if (*name == '$') {
+ if (r.length == 0)
+ return (ISC_R_NOSPACE);
+ r.base[0] = *name++;
+ isc_textregion_consume(&r, 1);
+ continue;
+ }
+ strcpy(fmt, "%d");
+ /* Get format specifier. */
+ if (*name == '{' ) {
+ n = sscanf(name, "{%d,%u,%1[doxX]}",
+ &delta, &width, mode);
+ switch (n) {
+ case 1:
+ break;
+ case 2:
+ n = snprintf(fmt, sizeof(fmt),
+ "%%0%ud", width);
+ break;
+ case 3:
+ n = snprintf(fmt, sizeof(fmt),
+ "%%0%u%c", width, mode[0]);
+ break;
+ default:
+ return (DNS_R_SYNTAX);
+ }
+ if (n >= sizeof(fmt))
+ return (ISC_R_NOSPACE);
+ /* Skip past closing brace. */
+ while (*name != '\0' && *name++ != '}')
+ continue;
+ }
+ n = snprintf(numbuf, sizeof(numbuf), fmt, it + delta);
+ if (n >= sizeof(numbuf))
+ return (ISC_R_NOSPACE);
+ cp = numbuf;
+ while (*cp != '\0') {
+ if (r.length == 0)
+ return (ISC_R_NOSPACE);
+ r.base[0] = *cp++;
+ isc_textregion_consume(&r, 1);
+ }
+ } else if (*name == '\\') {
+ if (r.length == 0)
+ return (ISC_R_NOSPACE);
+ r.base[0] = *name++;
+ isc_textregion_consume(&r, 1);
+ if (*name == '\0')
+ continue;
+ if (r.length == 0)
+ return (ISC_R_NOSPACE);
+ r.base[0] = *name++;
+ isc_textregion_consume(&r, 1);
+ } else {
+ if (r.length == 0)
+ return (ISC_R_NOSPACE);
+ r.base[0] = *name++;
+ isc_textregion_consume(&r, 1);
+ }
+ }
+ if (r.length == 0)
+ return (ISC_R_NOSPACE);
+ r.base[0] = '\0';
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+openfile_text(dns_loadctx_t *lctx, const char *master_file) {
+ return (isc_lex_openfile(lctx->lex, master_file));
+}
+
+static isc_result_t
+openfile_raw(dns_loadctx_t *lctx, const char *master_file) {
+ isc_result_t result;
+
+ result = isc_stdio_open(master_file, "r", &lctx->f);
+ if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_stdio_open() failed: %s",
+ isc_result_totext(result));
+ }
+
+ return (result);
+}
+
+static isc_result_t
+generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs,
+ const char *source, unsigned int line)
+{
+ char *target_mem = NULL;
+ char *lhsbuf = NULL;
+ char *rhsbuf = NULL;
+ dns_fixedname_t ownerfixed;
+ dns_name_t *owner;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdatacallbacks_t *callbacks;
+ dns_rdatalist_t rdatalist;
+ dns_rdatatype_t type;
+ rdatalist_head_t head;
+ int n;
+ int target_size = MINTSIZ; /* only one rdata at a time */
+ isc_buffer_t buffer;
+ isc_buffer_t target;
+ isc_result_t result;
+ isc_textregion_t r;
+ unsigned int start, stop, step, i;
+ dns_incctx_t *ictx;
+
+ ictx = lctx->inc;
+ callbacks = lctx->callbacks;
+ dns_fixedname_init(&ownerfixed);
+ owner = dns_fixedname_name(&ownerfixed);
+ ISC_LIST_INIT(head);
+
+ target_mem = isc_mem_get(lctx->mctx, target_size);
+ rhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_BUFSZ);
+ lhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_BUFSZ);
+ if (target_mem == NULL || rhsbuf == NULL || lhsbuf == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto error_cleanup;
+ }
+ isc_buffer_init(&target, target_mem, target_size);
+
+ n = sscanf(range, "%u-%u/%u", &start, &stop, &step);
+ if (n < 2 || stop < start) {
+ (*callbacks->error)(callbacks,
+ "%s: %s:%lu: invalid range '%s'",
+ "$GENERATE", source, line, range);
+ result = DNS_R_SYNTAX;
+ goto insist_cleanup;
+ }
+ if (n == 2)
+ step = 1;
+
+ /*
+ * Get type.
+ */
+ r.base = gtype;
+ r.length = strlen(gtype);
+ result = dns_rdatatype_fromtext(&type, &r);
+ if (result != ISC_R_SUCCESS) {
+ (*callbacks->error)(callbacks,
+ "%s: %s:%lu: unknown RR type '%s'",
+ "$GENERATE", source, line, gtype);
+ goto insist_cleanup;
+ }
+
+ switch (type) {
+ case dns_rdatatype_ns:
+ case dns_rdatatype_ptr:
+ case dns_rdatatype_cname:
+ case dns_rdatatype_dname:
+ break;
+
+ case dns_rdatatype_a:
+ case dns_rdatatype_aaaa:
+ if (lctx->zclass == dns_rdataclass_in ||
+ lctx->zclass == dns_rdataclass_ch ||
+ lctx->zclass == dns_rdataclass_hs)
+ break;
+ /* FALLTHROUGH */
+ default:
+ (*callbacks->error)(callbacks,
+ "%s: %s:%lu: unsupported type '%s'",
+ "$GENERATE", source, line, gtype);
+ result = ISC_R_NOTIMPLEMENTED;
+ goto error_cleanup;
+ }
+
+ ISC_LIST_INIT(rdatalist.rdata);
+ ISC_LINK_INIT(&rdatalist, link);
+ for (i = start; i <= stop; i += step) {
+ result = genname(lhs, i, lhsbuf, DNS_MASTER_BUFSZ);
+ if (result != ISC_R_SUCCESS)
+ goto error_cleanup;
+ result = genname(rhs, i, rhsbuf, DNS_MASTER_BUFSZ);
+ if (result != ISC_R_SUCCESS)
+ goto error_cleanup;
+
+ isc_buffer_init(&buffer, lhsbuf, strlen(lhsbuf));
+ isc_buffer_add(&buffer, strlen(lhsbuf));
+ isc_buffer_setactive(&buffer, strlen(lhsbuf));
+ result = dns_name_fromtext(owner, &buffer, ictx->origin,
+ 0, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto error_cleanup;
+
+ if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
+ (lctx->options & DNS_MASTER_SLAVE) == 0 &&
+ !dns_name_issubdomain(owner, lctx->top))
+ {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_name_format(owner, namebuf, sizeof(namebuf));
+ /*
+ * Ignore out-of-zone data.
+ */
+ (*callbacks->warn)(callbacks,
+ "%s:%lu: "
+ "ignoring out-of-zone data (%s)",
+ source, line, namebuf);
+ continue;
+ }
+
+ isc_buffer_init(&buffer, rhsbuf, strlen(rhsbuf));
+ isc_buffer_add(&buffer, strlen(rhsbuf));
+ isc_buffer_setactive(&buffer, strlen(rhsbuf));
+
+ result = isc_lex_openbuffer(lctx->lex, &buffer);
+ if (result != ISC_R_SUCCESS)
+ goto error_cleanup;
+
+ isc_buffer_init(&target, target_mem, target_size);
+ result = dns_rdata_fromtext(&rdata, lctx->zclass, type,
+ lctx->lex, ictx->origin, 0,
+ lctx->mctx, &target, callbacks);
+ RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ goto error_cleanup;
+
+ rdatalist.type = type;
+ rdatalist.covers = 0;
+ rdatalist.rdclass = lctx->zclass;
+ rdatalist.ttl = lctx->ttl;
+ ISC_LIST_PREPEND(head, &rdatalist, link);
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
+ result = commit(callbacks, lctx, &head, owner, source, line);
+ ISC_LIST_UNLINK(rdatalist.rdata, &rdata, link);
+ if (result != ISC_R_SUCCESS)
+ goto error_cleanup;
+ dns_rdata_reset(&rdata);
+ }
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+
+ error_cleanup:
+ if (result == ISC_R_NOMEMORY)
+ (*callbacks->error)(callbacks, "$GENERATE: %s",
+ dns_result_totext(result));
+ else
+ (*callbacks->error)(callbacks, "$GENERATE: %s:%lu: %s",
+ source, line, dns_result_totext(result));
+
+ insist_cleanup:
+ INSIST(result != ISC_R_SUCCESS);
+
+ cleanup:
+ if (target_mem != NULL)
+ isc_mem_put(lctx->mctx, target_mem, target_size);
+ if (lhsbuf != NULL)
+ isc_mem_put(lctx->mctx, lhsbuf, DNS_MASTER_BUFSZ);
+ if (rhsbuf != NULL)
+ isc_mem_put(lctx->mctx, rhsbuf, DNS_MASTER_BUFSZ);
+ return (result);
+}
+
+static void
+limit_ttl(dns_rdatacallbacks_t *callbacks, const char *source, unsigned int line,
+ isc_uint32_t *ttlp)
+{
+ if (*ttlp > 0x7fffffffUL) {
+ (callbacks->warn)(callbacks,
+ "%s: %s:%lu: "
+ "$TTL %lu > MAXTTL, "
+ "setting $TTL to 0",
+ "dns_master_load",
+ source, line,
+ *ttlp);
+ *ttlp = 0;
+ }
+}
+
+static isc_result_t
+check_ns(dns_loadctx_t *lctx, isc_token_t *token, const char *source,
+ unsigned long line)
+{
+ char *tmp = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+ void (*callback)(struct dns_rdatacallbacks *, const char *, ...);
+
+ if ((lctx->options & DNS_MASTER_FATALNS) != 0)
+ callback = lctx->callbacks->error;
+ else
+ callback = lctx->callbacks->warn;
+
+ if (token->type == isc_tokentype_string) {
+ struct in_addr addr;
+ struct in6_addr addr6;
+
+ tmp = isc_mem_strdup(lctx->mctx, DNS_AS_STR(*token));
+ if (tmp == NULL)
+ return (ISC_R_NOMEMORY);
+ /*
+ * Catch both "1.2.3.4" and "1.2.3.4."
+ */
+ if (tmp[strlen(tmp) - 1] == '.')
+ tmp[strlen(tmp) - 1] = '\0';
+ if (inet_aton(tmp, &addr) == 1 ||
+ inet_pton(AF_INET6, tmp, &addr6) == 1)
+ result = DNS_R_NSISADDRESS;
+ }
+ if (result != ISC_R_SUCCESS)
+ (*callback)(lctx->callbacks, "%s:%lu: NS record '%s' "
+ "appears to be an address",
+ source, line, DNS_AS_STR(*token));
+ if (tmp != NULL)
+ isc_mem_free(lctx->mctx, tmp);
+ return (result);
+}
+
+static void
+check_wildcard(dns_incctx_t *ictx, const char *source, unsigned long line,
+ dns_rdatacallbacks_t *callbacks)
+{
+ dns_name_t *name;
+
+ name = (ictx->glue != NULL) ? ictx->glue : ictx->current;
+ if (dns_name_internalwildcard(name)) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ (*callbacks->warn)(callbacks, "%s:%lu: warning: ownername "
+ "'%s' contains an non-terminal wildcard",
+ source, line, namebuf);
+ }
+}
+
+static isc_result_t
+load_text(dns_loadctx_t *lctx) {
+ dns_rdataclass_t rdclass;
+ dns_rdatatype_t type, covers;
+ isc_uint32_t ttl_offset = 0;
+ dns_name_t *new_name;
+ isc_boolean_t current_has_delegation = ISC_FALSE;
+ isc_boolean_t done = ISC_FALSE;
+ isc_boolean_t finish_origin = ISC_FALSE;
+ isc_boolean_t finish_include = ISC_FALSE;
+ isc_boolean_t read_till_eol = ISC_FALSE;
+ isc_boolean_t initialws;
+ char *include_file = NULL;
+ isc_token_t token;
+ isc_result_t result = ISC_R_UNEXPECTED;
+ rdatalist_head_t glue_list;
+ rdatalist_head_t current_list;
+ dns_rdatalist_t *this;
+ dns_rdatalist_t *rdatalist = NULL;
+ dns_rdatalist_t *new_rdatalist;
+ int rdlcount = 0;
+ int rdlcount_save = 0;
+ int rdatalist_size = 0;
+ isc_buffer_t buffer;
+ isc_buffer_t target;
+ isc_buffer_t target_ft;
+ isc_buffer_t target_save;
+ dns_rdata_t *rdata = NULL;
+ dns_rdata_t *new_rdata;
+ int rdcount = 0;
+ int rdcount_save = 0;
+ int rdata_size = 0;
+ unsigned char *target_mem = NULL;
+ int target_size = TSIZ;
+ int new_in_use;
+ unsigned int loop_cnt = 0;
+ isc_mem_t *mctx;
+ dns_rdatacallbacks_t *callbacks;
+ dns_incctx_t *ictx;
+ char *range = NULL;
+ char *lhs = NULL;
+ char *gtype = NULL;
+ char *rhs = NULL;
+ const char *source = "";
+ unsigned long line = 0;
+ isc_boolean_t explicit_ttl;
+ isc_stdtime_t now;
+ char classname1[DNS_RDATACLASS_FORMATSIZE];
+ char classname2[DNS_RDATACLASS_FORMATSIZE];
+ unsigned int options = 0;
+
+ REQUIRE(DNS_LCTX_VALID(lctx));
+ callbacks = lctx->callbacks;
+ mctx = lctx->mctx;
+ ictx = lctx->inc;
+
+ ISC_LIST_INIT(glue_list);
+ ISC_LIST_INIT(current_list);
+
+ isc_stdtime_get(&now);
+
+ /*
+ * Allocate target_size of buffer space. This is greater than twice
+ * the maximum individual RR data size.
+ */
+ target_mem = isc_mem_get(mctx, target_size);
+ if (target_mem == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto log_and_cleanup;
+ }
+ isc_buffer_init(&target, target_mem, target_size);
+ target_save = target;
+
+ if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0)
+ options |= DNS_RDATA_CHECKNAMES;
+ if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0)
+ options |= DNS_RDATA_CHECKNAMESFAIL;
+ if ((lctx->options & DNS_MASTER_CHECKMX) != 0)
+ options |= DNS_RDATA_CHECKMX;
+ if ((lctx->options & DNS_MASTER_CHECKMXFAIL) != 0)
+ options |= DNS_RDATA_CHECKMXFAIL;
+ source = isc_lex_getsourcename(lctx->lex);
+ do {
+ initialws = ISC_FALSE;
+ line = isc_lex_getsourceline(lctx->lex);
+ GETTOKEN(lctx->lex, ISC_LEXOPT_INITIALWS | ISC_LEXOPT_QSTRING,
+ &token, ISC_TRUE);
+ line = isc_lex_getsourceline(lctx->lex);
+
+ if (token.type == isc_tokentype_eof) {
+ if (read_till_eol)
+ WARNUNEXPECTEDEOF(lctx->lex);
+ /* Pop the include stack? */
+ if (ictx->parent != NULL) {
+ COMMITALL;
+ lctx->inc = ictx->parent;
+ ictx->parent = NULL;
+ incctx_destroy(lctx->mctx, ictx);
+ RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS);
+ line = isc_lex_getsourceline(lctx->lex);
+ source = isc_lex_getsourcename(lctx->lex);
+ ictx = lctx->inc;
+ EXPECTEOL;
+ continue;
+ }
+ done = ISC_TRUE;
+ continue;
+ }
+
+ if (token.type == isc_tokentype_eol) {
+ read_till_eol = ISC_FALSE;
+ continue; /* blank line */
+ }
+
+ if (read_till_eol)
+ continue;
+
+ if (token.type == isc_tokentype_initialws) {
+ /*
+ * Still working on the same name.
+ */
+ initialws = ISC_TRUE;
+ } else if (token.type == isc_tokentype_string ||
+ token.type == isc_tokentype_qstring) {
+
+ /*
+ * "$" Support.
+ *
+ * "$ORIGIN" and "$INCLUDE" can both take domain names.
+ * The processing of "$ORIGIN" and "$INCLUDE" extends
+ * across the normal domain name processing.
+ */
+
+ if (strcasecmp(DNS_AS_STR(token), "$ORIGIN") == 0) {
+ GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
+ finish_origin = ISC_TRUE;
+ } else if (strcasecmp(DNS_AS_STR(token),
+ "$TTL") == 0) {
+ GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
+ result =
+ dns_ttl_fromtext(&token.value.as_textregion,
+ &lctx->ttl);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ lctx->ttl = 0;
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ limit_ttl(callbacks, source, line, &lctx->ttl);
+ lctx->default_ttl = lctx->ttl;
+ lctx->default_ttl_known = ISC_TRUE;
+ EXPECTEOL;
+ continue;
+ } else if (strcasecmp(DNS_AS_STR(token),
+ "$INCLUDE") == 0) {
+ COMMITALL;
+ if ((lctx->options & DNS_MASTER_NOINCLUDE)
+ != 0)
+ {
+ (callbacks->error)(callbacks,
+ "%s: %s:%lu: $INCLUDE not allowed",
+ "dns_master_load",
+ source, line);
+ result = DNS_R_REFUSED;
+ goto insist_and_cleanup;
+ }
+ if (ttl_offset != 0) {
+ (callbacks->error)(callbacks,
+ "%s: %s:%lu: $INCLUDE "
+ "may not be used with $DATE",
+ "dns_master_load",
+ source, line);
+ result = DNS_R_SYNTAX;
+ goto insist_and_cleanup;
+ }
+ GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING, &token,
+ ISC_FALSE);
+ if (include_file != NULL)
+ isc_mem_free(mctx, include_file);
+ include_file = isc_mem_strdup(mctx,
+ DNS_AS_STR(token));
+ if (include_file == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto log_and_cleanup;
+ }
+ GETTOKEN(lctx->lex, 0, &token, ISC_TRUE);
+
+ if (token.type == isc_tokentype_eol ||
+ token.type == isc_tokentype_eof) {
+ if (token.type == isc_tokentype_eof)
+ WARNUNEXPECTEDEOF(lctx->lex);
+ isc_lex_ungettoken(lctx->lex, &token);
+ /*
+ * No origin field.
+ */
+ result = pushfile(include_file,
+ ictx->origin, lctx);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ LOGITFILE(result, include_file);
+ continue;
+ } else if (result != ISC_R_SUCCESS) {
+ LOGITFILE(result, include_file);
+ goto insist_and_cleanup;
+ }
+ ictx = lctx->inc;
+ line = isc_lex_getsourceline(lctx->lex);
+ source =
+ isc_lex_getsourcename(lctx->lex);
+ continue;
+ }
+ /*
+ * There is an origin field. Fall through
+ * to domain name processing code and do
+ * the actual inclusion later.
+ */
+ finish_include = ISC_TRUE;
+ } else if (strcasecmp(DNS_AS_STR(token),
+ "$DATE") == 0) {
+ isc_int64_t dump_time64;
+ isc_stdtime_t dump_time, current_time;
+ GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
+ isc_stdtime_get(&current_time);
+ result = dns_time64_fromtext(DNS_AS_STR(token),
+ &dump_time64);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ LOGIT(result);
+ dump_time64 = 0;
+ } else if (result != ISC_R_SUCCESS)
+ goto log_and_cleanup;
+ dump_time = (isc_stdtime_t)dump_time64;
+ if (dump_time != dump_time64) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s: %s:%lu: $DATE outside epoch",
+ "dns_master_load", source, line);
+ result = ISC_R_UNEXPECTED;
+ goto insist_and_cleanup;
+ }
+ if (dump_time > current_time) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s: %s:%lu: "
+ "$DATE in future, using current date",
+ "dns_master_load", source, line);
+ dump_time = current_time;
+ }
+ ttl_offset = current_time - dump_time;
+ EXPECTEOL;
+ continue;
+ } else if (strcasecmp(DNS_AS_STR(token),
+ "$GENERATE") == 0) {
+ /*
+ * Lazy cleanup.
+ */
+ if (range != NULL)
+ isc_mem_free(mctx, range);
+ if (lhs != NULL)
+ isc_mem_free(mctx, lhs);
+ if (gtype != NULL)
+ isc_mem_free(mctx, gtype);
+ if (rhs != NULL)
+ isc_mem_free(mctx, rhs);
+ range = lhs = gtype = rhs = NULL;
+ /* RANGE */
+ GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
+ range = isc_mem_strdup(mctx,
+ DNS_AS_STR(token));
+ if (range == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto log_and_cleanup;
+ }
+ /* LHS */
+ GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
+ lhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
+ if (lhs == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto log_and_cleanup;
+ }
+ rdclass = 0;
+ explicit_ttl = ISC_FALSE;
+ /* CLASS? */
+ GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
+ if (dns_rdataclass_fromtext(&rdclass,
+ &token.value.as_textregion)
+ == ISC_R_SUCCESS) {
+ GETTOKEN(lctx->lex, 0, &token,
+ ISC_FALSE);
+ }
+ /* TTL? */
+ if (dns_ttl_fromtext(&token.value.as_textregion,
+ &lctx->ttl)
+ == ISC_R_SUCCESS) {
+ limit_ttl(callbacks, source, line,
+ &lctx->ttl);
+ lctx->ttl_known = ISC_TRUE;
+ explicit_ttl = ISC_TRUE;
+ GETTOKEN(lctx->lex, 0, &token,
+ ISC_FALSE);
+ }
+ /* CLASS? */
+ if (rdclass == 0 &&
+ dns_rdataclass_fromtext(&rdclass,
+ &token.value.as_textregion)
+ == ISC_R_SUCCESS)
+ GETTOKEN(lctx->lex, 0, &token,
+ ISC_FALSE);
+ /* TYPE */
+ gtype = isc_mem_strdup(mctx,
+ DNS_AS_STR(token));
+ if (gtype == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto log_and_cleanup;
+ }
+ /* RHS */
+ GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
+ rhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
+ if (rhs == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto log_and_cleanup;
+ }
+ if (!lctx->ttl_known &&
+ !lctx->default_ttl_known) {
+ (*callbacks->error)(callbacks,
+ "%s: %s:%lu: no TTL specified",
+ "dns_master_load", source, line);
+ result = DNS_R_NOTTL;
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ lctx->ttl = 0;
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ } else if (!explicit_ttl &&
+ lctx->default_ttl_known) {
+ lctx->ttl = lctx->default_ttl;
+ }
+ /*
+ * If the class specified does not match the
+ * zone's class print out a error message and
+ * exit.
+ */
+ if (rdclass != 0 && rdclass != lctx->zclass) {
+ goto bad_class;
+ }
+ result = generate(lctx, range, lhs, gtype, rhs,
+ source, line);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ EXPECTEOL;
+ continue;
+ } else if (strncasecmp(DNS_AS_STR(token),
+ "$", 1) == 0) {
+ (callbacks->error)(callbacks,
+ "%s: %s:%lu: "
+ "unknown $ directive '%s'",
+ "dns_master_load", source, line,
+ DNS_AS_STR(token));
+ result = DNS_R_SYNTAX;
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ }
+
+ /*
+ * Normal processing resumes.
+ *
+ * Find a free name buffer.
+ */
+ for (new_in_use = 0; new_in_use < NBUFS; new_in_use++)
+ if (!ictx->in_use[new_in_use])
+ break;
+ INSIST(new_in_use < NBUFS);
+ dns_fixedname_init(&ictx->fixed[new_in_use]);
+ new_name = dns_fixedname_name(&ictx->fixed[new_in_use]);
+ isc_buffer_init(&buffer, token.value.as_region.base,
+ token.value.as_region.length);
+ isc_buffer_add(&buffer, token.value.as_region.length);
+ isc_buffer_setactive(&buffer,
+ token.value.as_region.length);
+ result = dns_name_fromtext(new_name, &buffer,
+ ictx->origin, ISC_FALSE, NULL);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ LOGIT(result);
+ read_till_eol = ISC_TRUE;
+ continue;
+ } else if (result != ISC_R_SUCCESS)
+ goto log_and_cleanup;
+
+ /*
+ * Finish $ORIGIN / $INCLUDE processing if required.
+ */
+ if (finish_origin) {
+ if (ictx->origin_in_use != -1)
+ ictx->in_use[ictx->origin_in_use] =
+ ISC_FALSE;
+ ictx->origin_in_use = new_in_use;
+ ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
+ ictx->origin = new_name;
+ finish_origin = ISC_FALSE;
+ EXPECTEOL;
+ continue;
+ }
+ if (finish_include) {
+ finish_include = ISC_FALSE;
+ result = pushfile(include_file, new_name, lctx);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ LOGITFILE(result, include_file);
+ continue;
+ } else if (result != ISC_R_SUCCESS) {
+ LOGITFILE(result, include_file);
+ goto insist_and_cleanup;
+ }
+ ictx = lctx->inc;
+ line = isc_lex_getsourceline(lctx->lex);
+ source = isc_lex_getsourcename(lctx->lex);
+ continue;
+ }
+
+ /*
+ * "$" Processing Finished
+ */
+
+ /*
+ * If we are processing glue and the new name does
+ * not match the current glue name, commit the glue
+ * and pop stacks leaving us in 'normal' processing
+ * state. Linked lists are undone by commit().
+ */
+ if (ictx->glue != NULL &&
+ dns_name_compare(ictx->glue, new_name) != 0) {
+ result = commit(callbacks, lctx, &glue_list,
+ ictx->glue, source,
+ ictx->glue_line);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ if (ictx->glue_in_use != -1)
+ ictx->in_use[ictx->glue_in_use] =
+ ISC_FALSE;
+ ictx->glue_in_use = -1;
+ ictx->glue = NULL;
+ rdcount = rdcount_save;
+ rdlcount = rdlcount_save;
+ target = target_save;
+ }
+
+ /*
+ * If we are in 'normal' processing state and the new
+ * name does not match the current name, see if the
+ * new name is for glue and treat it as such,
+ * otherwise we have a new name so commit what we
+ * have.
+ */
+ if ((ictx->glue == NULL) && (ictx->current == NULL ||
+ dns_name_compare(ictx->current, new_name) != 0)) {
+ if (current_has_delegation &&
+ is_glue(&current_list, new_name)) {
+ rdcount_save = rdcount;
+ rdlcount_save = rdlcount;
+ target_save = target;
+ ictx->glue = new_name;
+ ictx->glue_in_use = new_in_use;
+ ictx->in_use[ictx->glue_in_use] =
+ ISC_TRUE;
+ } else {
+ result = commit(callbacks, lctx,
+ &current_list,
+ ictx->current,
+ source,
+ ictx->current_line);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ rdcount = 0;
+ rdlcount = 0;
+ if (ictx->current_in_use != -1)
+ ictx->in_use[ictx->current_in_use] =
+ ISC_FALSE;
+ ictx->current_in_use = new_in_use;
+ ictx->in_use[ictx->current_in_use] =
+ ISC_TRUE;
+ ictx->current = new_name;
+ current_has_delegation = ISC_FALSE;
+ isc_buffer_init(&target, target_mem,
+ target_size);
+ }
+ /*
+ * Check for internal wildcards.
+ */
+ if ((lctx->options & DNS_MASTER_CHECKWILDCARD)
+ != 0)
+ check_wildcard(ictx, source, line,
+ callbacks);
+
+ }
+ if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
+ (lctx->options & DNS_MASTER_SLAVE) == 0 &&
+ !dns_name_issubdomain(new_name, lctx->top))
+ {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_name_format(new_name, namebuf,
+ sizeof(namebuf));
+ /*
+ * Ignore out-of-zone data.
+ */
+ (*callbacks->warn)(callbacks,
+ "%s:%lu: "
+ "ignoring out-of-zone data (%s)",
+ source, line, namebuf);
+ ictx->drop = ISC_TRUE;
+ } else
+ ictx->drop = ISC_FALSE;
+ } else {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s:%lu: isc_lex_gettoken() returned "
+ "unexpected token type (%d)",
+ source, line, token.type);
+ result = ISC_R_UNEXPECTED;
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ LOGIT(result);
+ continue;
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ }
+
+ /*
+ * Find TTL, class and type. Both TTL and class are optional
+ * and may occur in any order if they exist. TTL and class
+ * come before type which must exist.
+ *
+ * [<TTL>] [<class>] <type> <RDATA>
+ * [<class>] [<TTL>] <type> <RDATA>
+ */
+
+ type = 0;
+ rdclass = 0;
+
+ GETTOKEN(lctx->lex, 0, &token, initialws);
+
+ if (initialws) {
+ if (token.type == isc_tokentype_eol) {
+ read_till_eol = ISC_FALSE;
+ continue; /* blank line */
+ }
+
+ if (token.type == isc_tokentype_eof) {
+ WARNUNEXPECTEDEOF(lctx->lex);
+ read_till_eol = ISC_FALSE;
+ isc_lex_ungettoken(lctx->lex, &token);
+ continue;
+ }
+
+ if (ictx->current == NULL) {
+ (*callbacks->error)(callbacks,
+ "%s:%lu: no current owner name",
+ source, line);
+ result = DNS_R_NOOWNER;
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ read_till_eol = ISC_TRUE;
+ continue;
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ }
+ }
+
+ if (dns_rdataclass_fromtext(&rdclass,
+ &token.value.as_textregion)
+ == ISC_R_SUCCESS)
+ GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
+
+ explicit_ttl = ISC_FALSE;
+ if (dns_ttl_fromtext(&token.value.as_textregion, &lctx->ttl)
+ == ISC_R_SUCCESS) {
+ limit_ttl(callbacks, source, line, &lctx->ttl);
+ explicit_ttl = ISC_TRUE;
+ lctx->ttl_known = ISC_TRUE;
+ GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
+ }
+
+ if (token.type != isc_tokentype_string) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_lex_gettoken() returned unexpected token type");
+ result = ISC_R_UNEXPECTED;
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ read_till_eol = ISC_TRUE;
+ continue;
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ }
+
+ if (rdclass == 0 &&
+ dns_rdataclass_fromtext(&rdclass,
+ &token.value.as_textregion)
+ == ISC_R_SUCCESS)
+ GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
+
+ if (token.type != isc_tokentype_string) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_lex_gettoken() returned unexpected token type");
+ result = ISC_R_UNEXPECTED;
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ read_till_eol = ISC_TRUE;
+ continue;
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ }
+
+ result = dns_rdatatype_fromtext(&type,
+ &token.value.as_textregion);
+ if (result != ISC_R_SUCCESS) {
+ (*callbacks->warn)(callbacks,
+ "%s:%lu: unknown RR type '%.*s'",
+ source, line,
+ token.value.as_textregion.length,
+ token.value.as_textregion.base);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ read_till_eol = ISC_TRUE;
+ continue;
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ }
+
+ /*
+ * If the class specified does not match the zone's class
+ * print out a error message and exit.
+ */
+ if (rdclass != 0 && rdclass != lctx->zclass) {
+ bad_class:
+
+ dns_rdataclass_format(rdclass, classname1,
+ sizeof(classname1));
+ dns_rdataclass_format(lctx->zclass, classname2,
+ sizeof(classname2));
+ (*callbacks->error)(callbacks,
+ "%s:%lu: class '%s' != "
+ "zone class '%s'",
+ source, line,
+ classname1, classname2);
+ result = DNS_R_BADCLASS;
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ read_till_eol = ISC_TRUE;
+ continue;
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ }
+
+ if (type == dns_rdatatype_ns && ictx->glue == NULL)
+ current_has_delegation = ISC_TRUE;
+
+ /*
+ * RFC1123: MD and MF are not allowed to be loaded from
+ * master files.
+ */
+ if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
+ (lctx->options & DNS_MASTER_SLAVE) == 0 &&
+ (type == dns_rdatatype_md || type == dns_rdatatype_mf)) {
+ char typename[DNS_RDATATYPE_FORMATSIZE];
+
+ result = DNS_R_OBSOLETE;
+
+ dns_rdatatype_format(type, typename, sizeof(typename));
+ (*callbacks->error)(callbacks,
+ "%s:%lu: %s '%s': %s",
+ source, line,
+ "type", typename,
+ dns_result_totext(result));
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ } else
+ goto insist_and_cleanup;
+ }
+
+ /*
+ * Find a rdata structure.
+ */
+ if (rdcount == rdata_size) {
+ new_rdata = grow_rdata(rdata_size + RDSZ, rdata,
+ rdata_size, &current_list,
+ &glue_list, mctx);
+ if (new_rdata == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto log_and_cleanup;
+ }
+ rdata_size += RDSZ;
+ rdata = new_rdata;
+ }
+
+ /*
+ * Peek at the NS record.
+ */
+ if (type == dns_rdatatype_ns &&
+ lctx->zclass == dns_rdataclass_in &&
+ (lctx->options & DNS_MASTER_CHECKNS) != 0) {
+
+ GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
+ result = check_ns(lctx, &token, source, line);
+ isc_lex_ungettoken(lctx->lex, &token);
+ if ((lctx->options & DNS_MASTER_FATALNS) != 0) {
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ }
+ }
+
+ /*
+ * Check owner name.
+ */
+ options &= ~DNS_RDATA_CHECKREVERSE;
+ if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0) {
+ isc_boolean_t ok;
+ dns_name_t *name;
+
+ name = (ictx->glue != NULL) ? ictx->glue :
+ ictx->current;
+ ok = dns_rdata_checkowner(name, lctx->zclass, type,
+ ISC_TRUE);
+ if (!ok) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ const char *desc;
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ result = DNS_R_BADOWNERNAME;
+ desc = dns_result_totext(result);
+ if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0) {
+ (*callbacks->error)(callbacks,
+ "%s:%lu: %s: %s",
+ source, line,
+ namebuf, desc);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ } else if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ } else {
+ (*callbacks->warn)(callbacks,
+ "%s:%lu: %s: %s",
+ source, line,
+ namebuf, desc);
+ }
+ }
+ if (type == dns_rdatatype_ptr &&
+ (dns_name_issubdomain(name, &in_addr_arpa) ||
+ dns_name_issubdomain(name, &ip6_arpa) ||
+ dns_name_issubdomain(name, &ip6_int)))
+ options |= DNS_RDATA_CHECKREVERSE;
+ }
+
+ /*
+ * Read rdata contents.
+ */
+ dns_rdata_init(&rdata[rdcount]);
+ target_ft = target;
+ result = dns_rdata_fromtext(&rdata[rdcount], lctx->zclass,
+ type, lctx->lex, ictx->origin,
+ options, lctx->mctx, &target,
+ callbacks);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ continue;
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+
+ if (ictx->drop) {
+ target = target_ft;
+ continue;
+ }
+
+ if (type == dns_rdatatype_soa &&
+ (lctx->options & DNS_MASTER_ZONE) != 0 &&
+ dns_name_compare(ictx->current, lctx->top) != 0) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_name_format(ictx->current, namebuf,
+ sizeof(namebuf));
+ (*callbacks->error)(callbacks,
+ "%s:%lu: SOA "
+ "record not at top of zone (%s)",
+ source, line, namebuf);
+ result = DNS_R_NOTZONETOP;
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ read_till_eol = ISC_TRUE;
+ target = target_ft;
+ continue;
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ }
+
+
+ if (type == dns_rdatatype_rrsig ||
+ type == dns_rdatatype_sig)
+ covers = dns_rdata_covers(&rdata[rdcount]);
+ else
+ covers = 0;
+
+ if (!lctx->ttl_known && !lctx->default_ttl_known) {
+ if (type == dns_rdatatype_soa) {
+ (*callbacks->warn)(callbacks,
+ "%s:%lu: no TTL specified; "
+ "using SOA MINTTL instead",
+ source, line);
+ lctx->ttl = dns_soa_getminimum(&rdata[rdcount]);
+ limit_ttl(callbacks, source, line, &lctx->ttl);
+ lctx->default_ttl = lctx->ttl;
+ lctx->default_ttl_known = ISC_TRUE;
+ } else if ((lctx->options & DNS_MASTER_HINT) != 0) {
+ /*
+ * Zero TTL's are fine for hints.
+ */
+ lctx->ttl = 0;
+ lctx->default_ttl = lctx->ttl;
+ lctx->default_ttl_known = ISC_TRUE;
+ } else {
+ (*callbacks->warn)(callbacks,
+ "%s:%lu: no TTL specified; "
+ "zone rejected",
+ source, line);
+ result = DNS_R_NOTTL;
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ lctx->ttl = 0;
+ } else {
+ goto insist_and_cleanup;
+ }
+ }
+ } else if (!explicit_ttl && lctx->default_ttl_known) {
+ lctx->ttl = lctx->default_ttl;
+ } else if (!explicit_ttl && lctx->warn_1035) {
+ (*callbacks->warn)(callbacks,
+ "%s:%lu: "
+ "using RFC1035 TTL semantics",
+ source, line);
+ lctx->warn_1035 = ISC_FALSE;
+ }
+
+ if (type == dns_rdatatype_rrsig && lctx->warn_sigexpired) {
+ dns_rdata_rrsig_t sig;
+ (void)dns_rdata_tostruct(&rdata[rdcount], &sig, NULL);
+ if (isc_serial_lt(sig.timeexpire, now)) {
+ (*callbacks->warn)(callbacks,
+ "%s:%lu: "
+ "signature has expired",
+ source, line);
+ lctx->warn_sigexpired = ISC_FALSE;
+ }
+ }
+
+ if ((type == dns_rdatatype_sig || type == dns_rdatatype_nxt) &&
+ lctx->warn_tcr && (lctx->options & DNS_MASTER_ZONE) != 0 &&
+ (lctx->options & DNS_MASTER_SLAVE) == 0) {
+ (*callbacks->warn)(callbacks, "%s:%lu: old style DNSSEC "
+ " zone detected", source, line);
+ lctx->warn_tcr = ISC_FALSE;
+ }
+
+ if ((lctx->options & DNS_MASTER_AGETTL) != 0) {
+ /*
+ * Adjust the TTL for $DATE. If the RR has already
+ * expired, ignore it.
+ */
+ if (lctx->ttl < ttl_offset)
+ continue;
+ lctx->ttl -= ttl_offset;
+ }
+
+ /*
+ * Find type in rdatalist.
+ * If it does not exist create new one and prepend to list
+ * as this will mimimise list traversal.
+ */
+ if (ictx->glue != NULL)
+ this = ISC_LIST_HEAD(glue_list);
+ else
+ this = ISC_LIST_HEAD(current_list);
+
+ while (this != NULL) {
+ if (this->type == type && this->covers == covers)
+ break;
+ this = ISC_LIST_NEXT(this, link);
+ }
+
+ if (this == NULL) {
+ if (rdlcount == rdatalist_size) {
+ new_rdatalist =
+ grow_rdatalist(rdatalist_size + RDLSZ,
+ rdatalist,
+ rdatalist_size,
+ &current_list,
+ &glue_list,
+ mctx);
+ if (new_rdatalist == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto log_and_cleanup;
+ }
+ rdatalist = new_rdatalist;
+ rdatalist_size += RDLSZ;
+ }
+ this = &rdatalist[rdlcount++];
+ this->type = type;
+ this->covers = covers;
+ this->rdclass = lctx->zclass;
+ this->ttl = lctx->ttl;
+ ISC_LIST_INIT(this->rdata);
+ if (ictx->glue != NULL)
+ ISC_LIST_INITANDPREPEND(glue_list, this, link);
+ else
+ ISC_LIST_INITANDPREPEND(current_list, this,
+ link);
+ } else if (this->ttl != lctx->ttl) {
+ (*callbacks->warn)(callbacks,
+ "%s:%lu: "
+ "TTL set to prior TTL (%lu)",
+ source, line, this->ttl);
+ lctx->ttl = this->ttl;
+ }
+
+ ISC_LIST_APPEND(this->rdata, &rdata[rdcount], link);
+ if (ictx->glue != NULL)
+ ictx->glue_line = line;
+ else
+ ictx->current_line = line;
+ rdcount++;
+
+ /*
+ * We must have at least 64k as rdlen is 16 bits.
+ * If we don't commit everything we have so far.
+ */
+ if ((target.length - target.used) < MINTSIZ)
+ COMMITALL;
+ next_line:
+ ;
+ } while (!done && (lctx->loop_cnt == 0 || loop_cnt++ < lctx->loop_cnt));
+
+ /*
+ * Commit what has not yet been committed.
+ */
+ result = commit(callbacks, lctx, &current_list, ictx->current,
+ source, ictx->current_line);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+ result = commit(callbacks, lctx, &glue_list, ictx->glue,
+ source, ictx->glue_line);
+ if (MANYERRS(lctx, result)) {
+ SETRESULT(lctx, result);
+ } else if (result != ISC_R_SUCCESS)
+ goto insist_and_cleanup;
+
+ if (!done) {
+ INSIST(lctx->done != NULL && lctx->task != NULL);
+ result = DNS_R_CONTINUE;
+ } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS) {
+ result = lctx->result;
+ } else if (result == ISC_R_SUCCESS && lctx->seen_include)
+ result = DNS_R_SEENINCLUDE;
+ goto cleanup;
+
+ log_and_cleanup:
+ LOGIT(result);
+
+ insist_and_cleanup:
+ INSIST(result != ISC_R_SUCCESS);
+
+ cleanup:
+ while ((this = ISC_LIST_HEAD(current_list)) != NULL)
+ ISC_LIST_UNLINK(current_list, this, link);
+ while ((this = ISC_LIST_HEAD(glue_list)) != NULL)
+ ISC_LIST_UNLINK(glue_list, this, link);
+ if (rdatalist != NULL)
+ isc_mem_put(mctx, rdatalist,
+ rdatalist_size * sizeof(*rdatalist));
+ if (rdata != NULL)
+ isc_mem_put(mctx, rdata, rdata_size * sizeof(*rdata));
+ if (target_mem != NULL)
+ isc_mem_put(mctx, target_mem, target_size);
+ if (include_file != NULL)
+ isc_mem_free(mctx, include_file);
+ if (range != NULL)
+ isc_mem_free(mctx, range);
+ if (lhs != NULL)
+ isc_mem_free(mctx, lhs);
+ if (gtype != NULL)
+ isc_mem_free(mctx, gtype);
+ if (rhs != NULL)
+ isc_mem_free(mctx, rhs);
+ return (result);
+}
+
+static isc_result_t
+pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx) {
+ isc_result_t result;
+ dns_incctx_t *ictx;
+ dns_incctx_t *new = NULL;
+ isc_region_t r;
+ int new_in_use;
+
+ REQUIRE(master_file != NULL);
+ REQUIRE(DNS_LCTX_VALID(lctx));
+
+ ictx = lctx->inc;
+ lctx->seen_include = ISC_TRUE;
+
+ result = incctx_create(lctx->mctx, origin, &new);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /* Set current domain. */
+ if (ictx->glue != NULL || ictx->current != NULL) {
+ for (new_in_use = 0; new_in_use < NBUFS; new_in_use++)
+ if (!new->in_use[new_in_use])
+ break;
+ INSIST(new_in_use < NBUFS);
+ new->current_in_use = new_in_use;
+ new->current =
+ dns_fixedname_name(&new->fixed[new->current_in_use]);
+ new->in_use[new->current_in_use] = ISC_TRUE;
+ dns_name_toregion((ictx->glue != NULL) ?
+ ictx->glue : ictx->current, &r);
+ dns_name_fromregion(new->current, &r);
+ new->drop = ictx->drop;
+ }
+
+ result = (lctx->openfile)(lctx, master_file);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ new->parent = ictx;
+ lctx->inc = new;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (new != NULL)
+ incctx_destroy(lctx->mctx, new);
+ return (result);
+}
+
+static inline isc_result_t
+read_and_check(isc_boolean_t do_read, isc_buffer_t *buffer,
+ size_t len, FILE *f)
+{
+ isc_result_t result;
+
+ if (do_read) {
+ INSIST(isc_buffer_availablelength(buffer) >= len);
+ result = isc_stdio_read(isc_buffer_used(buffer), 1, len,
+ f, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_add(buffer, len);
+ } else if (isc_buffer_remaininglength(buffer) < len)
+ return (ISC_R_RANGE);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+load_raw(dns_loadctx_t *lctx) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_boolean_t done = ISC_FALSE;
+ unsigned int loop_cnt = 0;
+ dns_rdatacallbacks_t *callbacks;
+ unsigned char namebuf[DNS_NAME_MAXWIRE];
+ isc_region_t r;
+ dns_name_t name;
+ rdatalist_head_t head, dummy;
+ dns_rdatalist_t rdatalist;
+ isc_mem_t *mctx = lctx->mctx;
+ dns_rdata_t *rdata = NULL;
+ unsigned int rdata_size = 0;
+ int target_size = TSIZ;
+ isc_buffer_t target;
+ unsigned char *target_mem = NULL;
+
+ REQUIRE(DNS_LCTX_VALID(lctx));
+ callbacks = lctx->callbacks;
+
+ if (lctx->first) {
+ dns_masterrawheader_t header;
+ isc_uint32_t format, version, dumptime;
+ size_t hdrlen = sizeof(format) + sizeof(version) +
+ sizeof(dumptime);
+
+ INSIST(hdrlen <= sizeof(header));
+ isc_buffer_init(&target, &header, sizeof(header));
+
+ result = isc_stdio_read(&header, 1, hdrlen, lctx->f, NULL);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_stdio_read failed: %s",
+ isc_result_totext(result));
+ return (result);
+ }
+ isc_buffer_add(&target, hdrlen);
+ format = isc_buffer_getuint32(&target);
+ if (format != dns_masterformat_raw) {
+ (*callbacks->error)(callbacks,
+ "dns_master_load: "
+ "file format mismatch");
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+
+ version = isc_buffer_getuint32(&target);
+ if (version > DNS_RAWFORMAT_VERSION) {
+ (*callbacks->error)(callbacks,
+ "dns_master_load: "
+ "unsupported file format version");
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+
+ /* Empty read: currently, we do not use dumptime */
+ dumptime = isc_buffer_getuint32(&target);
+
+ lctx->first = ISC_FALSE;
+ }
+
+ ISC_LIST_INIT(head);
+ ISC_LIST_INIT(dummy);
+ dns_rdatalist_init(&rdatalist);
+
+ /*
+ * Allocate target_size of buffer space. This is greater than twice
+ * the maximum individual RR data size.
+ */
+ target_mem = isc_mem_get(mctx, target_size);
+ if (target_mem == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ isc_buffer_init(&target, target_mem, target_size);
+
+ /*
+ * In the following loop, we regard any error fatal regardless of
+ * whether "MANYERRORS" is set in the context option. This is because
+ * normal errors should already have been checked at creation time.
+ * Besides, it is very unlikely that we can recover from an error
+ * in this format, and so trying to continue parsing erroneous data
+ * does not really make sense.
+ */
+ for (loop_cnt = 0;
+ (lctx->loop_cnt == 0 || loop_cnt < lctx->loop_cnt);
+ loop_cnt++) {
+ unsigned int i, rdcount, consumed_name;
+ isc_uint16_t namelen;
+ isc_uint32_t totallen;
+ size_t minlen, readlen;
+ isc_boolean_t sequential_read = ISC_FALSE;
+
+ /* Read the data length */
+ isc_buffer_clear(&target);
+ INSIST(isc_buffer_availablelength(&target) >=
+ sizeof(totallen));
+ result = isc_stdio_read(target.base, 1, sizeof(totallen),
+ lctx->f, NULL);
+ if (result == ISC_R_EOF) {
+ result = ISC_R_SUCCESS;
+ done = ISC_TRUE;
+ break;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ isc_buffer_add(&target, sizeof(totallen));
+ totallen = isc_buffer_getuint32(&target);
+ /*
+ * Validation: the input data must at least contain the common
+ * header.
+ */
+ minlen = sizeof(totallen) + sizeof(isc_uint16_t) +
+ sizeof(isc_uint16_t) + sizeof(isc_uint16_t) +
+ sizeof(isc_uint32_t) + sizeof(isc_uint32_t);
+ if (totallen < minlen) {
+ result = ISC_R_RANGE;
+ goto cleanup;
+ }
+ totallen -= sizeof(totallen);
+
+ isc_buffer_clear(&target);
+ if (totallen > isc_buffer_availablelength(&target)) {
+ /*
+ * The default buffer size should typically be large
+ * enough to store the entire RRset. We could try to
+ * allocate enough space if this is not the case, but
+ * it might cause a hazardous result when "totallen"
+ * is forged. Thus, we'd rather take an inefficient
+ * but robust approach in this atypical case: read
+ * data step by step, and commit partial data when
+ * necessary. Note that the buffer must be large
+ * enough to store the "header part", owner name, and
+ * at least one rdata (however large it is).
+ */
+ sequential_read = ISC_TRUE;
+ readlen = minlen - sizeof(totallen);
+ } else {
+ /*
+ * Typical case. We can read the whole RRset at once
+ * with the default buffer.
+ */
+ readlen = totallen;
+ }
+ result = isc_stdio_read(target.base, 1, readlen,
+ lctx->f, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ isc_buffer_add(&target, readlen);
+
+ /* Construct RRset headers */
+ rdatalist.rdclass = isc_buffer_getuint16(&target);
+ rdatalist.type = isc_buffer_getuint16(&target);
+ rdatalist.covers = isc_buffer_getuint16(&target);
+ rdatalist.ttl = isc_buffer_getuint32(&target);
+ rdcount = isc_buffer_getuint32(&target);
+ if (rdcount == 0) {
+ result = ISC_R_RANGE;
+ goto cleanup;
+ }
+ INSIST(isc_buffer_consumedlength(&target) <= readlen);
+
+ /* Owner name: length followed by name */
+ result = read_and_check(sequential_read, &target,
+ sizeof(namelen), lctx->f);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ namelen = isc_buffer_getuint16(&target);
+ if (namelen > sizeof(namebuf)) {
+ result = ISC_R_RANGE;
+ goto cleanup;
+ }
+
+ result = read_and_check(sequential_read, &target, namelen,
+ lctx->f);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ isc_buffer_setactive(&target, (unsigned int)namelen);
+ isc_buffer_activeregion(&target, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+ isc_buffer_forward(&target, (unsigned int)namelen);
+ consumed_name = isc_buffer_consumedlength(&target);
+
+ /* Rdata contents. */
+ if (rdcount > rdata_size) {
+ dns_rdata_t *new_rdata = NULL;
+
+ new_rdata = grow_rdata(rdata_size + RDSZ, rdata,
+ rdata_size, &head,
+ &dummy, mctx);
+ if (new_rdata == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ rdata_size += RDSZ;
+ rdata = new_rdata;
+ }
+
+ continue_read:
+ for (i = 0; i < rdcount; i++) {
+ isc_uint16_t rdlen;
+
+ dns_rdata_init(&rdata[i]);
+
+ if (sequential_read &&
+ isc_buffer_availablelength(&target) < MINTSIZ) {
+ unsigned int j;
+
+ INSIST(i > 0); /* detect an infinite loop */
+
+ /* Partial Commit. */
+ ISC_LIST_APPEND(head, &rdatalist, link);
+ result = commit(callbacks, lctx, &head, &name,
+ NULL, 0);
+ for (j = 0; j < i; j++) {
+ ISC_LIST_UNLINK(rdatalist.rdata,
+ &rdata[j], link);
+ dns_rdata_reset(&rdata[j]);
+ }
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ /* Rewind the buffer and continue */
+ isc_buffer_clear(&target);
+ isc_buffer_add(&target, consumed_name);
+ isc_buffer_forward(&target, consumed_name);
+
+ rdcount -= i;
+ i = 0;
+
+ goto continue_read;
+ }
+
+ /* rdata length */
+ result = read_and_check(sequential_read, &target,
+ sizeof(rdlen), lctx->f);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ rdlen = isc_buffer_getuint16(&target);
+
+ /* rdata */
+ result = read_and_check(sequential_read, &target,
+ rdlen, lctx->f);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ isc_buffer_setactive(&target, (unsigned int)rdlen);
+ isc_buffer_activeregion(&target, &r);
+ isc_buffer_forward(&target, (unsigned int)rdlen);
+ dns_rdata_fromregion(&rdata[i], rdatalist.rdclass,
+ rdatalist.type, &r);
+
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata[i], link);
+ }
+
+ /*
+ * Sanity check. Still having remaining space is not
+ * necessarily critical, but it very likely indicates broken
+ * or malformed data.
+ */
+ if (isc_buffer_remaininglength(&target) != 0) {
+ result = ISC_R_RANGE;
+ goto cleanup;
+ }
+
+ ISC_LIST_APPEND(head, &rdatalist, link);
+
+ /* Commit this RRset. rdatalist will be unlinked. */
+ result = commit(callbacks, lctx, &head, &name, NULL, 0);
+
+ for (i = 0; i < rdcount; i++) {
+ ISC_LIST_UNLINK(rdatalist.rdata, &rdata[i], link);
+ dns_rdata_reset(&rdata[i]);
+ }
+
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ }
+
+ if (!done) {
+ INSIST(lctx->done != NULL && lctx->task != NULL);
+ result = DNS_R_CONTINUE;
+ } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS)
+ result = lctx->result;
+
+ cleanup:
+ if (rdata != NULL)
+ isc_mem_put(mctx, rdata, rdata_size * sizeof(*rdata));
+ if (target_mem != NULL)
+ isc_mem_put(mctx, target_mem, target_size);
+ if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE) {
+ (*callbacks->error)(callbacks, "dns_master_load: %s",
+ dns_result_totext(result));
+ }
+
+ return (result);
+}
+
+isc_result_t
+dns_master_loadfile(const char *master_file, dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass, unsigned int options,
+ dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
+{
+ return (dns_master_loadfile2(master_file, top, origin, zclass, options,
+ callbacks, mctx, dns_masterformat_text));
+}
+
+isc_result_t
+dns_master_loadfile2(const char *master_file, dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass, unsigned int options,
+ dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
+ dns_masterformat_t format)
+{
+ dns_loadctx_t *lctx = NULL;
+ isc_result_t result;
+
+ result = loadctx_create(format, mctx, options, top, zclass, origin,
+ callbacks, NULL, NULL, NULL, NULL, &lctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = (lctx->openfile)(lctx, master_file);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = (lctx->load)(lctx);
+ INSIST(result != DNS_R_CONTINUE);
+
+ cleanup:
+ dns_loadctx_detach(&lctx);
+ return (result);
+}
+
+isc_result_t
+dns_master_loadfileinc(const char *master_file, dns_name_t *top,
+ dns_name_t *origin, dns_rdataclass_t zclass,
+ unsigned int options, dns_rdatacallbacks_t *callbacks,
+ isc_task_t *task, dns_loaddonefunc_t done,
+ void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx)
+{
+ return (dns_master_loadfileinc2(master_file, top, origin, zclass,
+ options, callbacks, task, done,
+ done_arg, lctxp, mctx,
+ dns_masterformat_text));
+}
+
+isc_result_t
+dns_master_loadfileinc2(const char *master_file, dns_name_t *top,
+ dns_name_t *origin, dns_rdataclass_t zclass,
+ unsigned int options, dns_rdatacallbacks_t *callbacks,
+ isc_task_t *task, dns_loaddonefunc_t done,
+ void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx,
+ dns_masterformat_t format)
+{
+ dns_loadctx_t *lctx = NULL;
+ isc_result_t result;
+
+ REQUIRE(task != NULL);
+ REQUIRE(done != NULL);
+
+ result = loadctx_create(format, mctx, options, top, zclass, origin,
+ callbacks, task, done, done_arg, NULL, &lctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = (lctx->openfile)(lctx, master_file);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = task_send(lctx);
+ if (result == ISC_R_SUCCESS) {
+ dns_loadctx_attach(lctx, lctxp);
+ return (DNS_R_CONTINUE);
+ }
+
+ cleanup:
+ dns_loadctx_detach(&lctx);
+ return (result);
+}
+
+isc_result_t
+dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
+ dns_rdataclass_t zclass, unsigned int options,
+ dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
+{
+ isc_result_t result;
+ dns_loadctx_t *lctx = NULL;
+
+ REQUIRE(stream != NULL);
+
+ result = loadctx_create(dns_masterformat_text, mctx, options, top,
+ zclass, origin, callbacks, NULL, NULL, NULL,
+ NULL, &lctx);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = isc_lex_openstream(lctx->lex, stream);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = (lctx->load)(lctx);
+ INSIST(result != DNS_R_CONTINUE);
+
+ cleanup:
+ if (lctx != NULL)
+ dns_loadctx_detach(&lctx);
+ return (result);
+}
+
+isc_result_t
+dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin,
+ dns_rdataclass_t zclass, unsigned int options,
+ dns_rdatacallbacks_t *callbacks, isc_task_t *task,
+ dns_loaddonefunc_t done, void *done_arg,
+ dns_loadctx_t **lctxp, isc_mem_t *mctx)
+{
+ isc_result_t result;
+ dns_loadctx_t *lctx = NULL;
+
+ REQUIRE(stream != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(done != NULL);
+
+ result = loadctx_create(dns_masterformat_text, mctx, options, top,
+ zclass, origin, callbacks, task, done,
+ done_arg, NULL, &lctx);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = isc_lex_openstream(lctx->lex, stream);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = task_send(lctx);
+ if (result == ISC_R_SUCCESS) {
+ dns_loadctx_attach(lctx, lctxp);
+ return (DNS_R_CONTINUE);
+ }
+
+ cleanup:
+ if (lctx != NULL)
+ dns_loadctx_detach(&lctx);
+ return (result);
+}
+
+isc_result_t
+dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top,
+ dns_name_t *origin, dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
+{
+ isc_result_t result;
+ dns_loadctx_t *lctx = NULL;
+
+ REQUIRE(buffer != NULL);
+
+ result = loadctx_create(dns_masterformat_text, mctx, options, top,
+ zclass, origin, callbacks, NULL, NULL, NULL,
+ NULL, &lctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = isc_lex_openbuffer(lctx->lex, buffer);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = (lctx->load)(lctx);
+ INSIST(result != DNS_R_CONTINUE);
+
+ cleanup:
+ dns_loadctx_detach(&lctx);
+ return (result);
+}
+
+isc_result_t
+dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top,
+ dns_name_t *origin, dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks, isc_task_t *task,
+ dns_loaddonefunc_t done, void *done_arg,
+ dns_loadctx_t **lctxp, isc_mem_t *mctx)
+{
+ isc_result_t result;
+ dns_loadctx_t *lctx = NULL;
+
+ REQUIRE(buffer != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(done != NULL);
+
+ result = loadctx_create(dns_masterformat_text, mctx, options, top,
+ zclass, origin, callbacks, task, done,
+ done_arg, NULL, &lctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = isc_lex_openbuffer(lctx->lex, buffer);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = task_send(lctx);
+ if (result == ISC_R_SUCCESS) {
+ dns_loadctx_attach(lctx, lctxp);
+ return (DNS_R_CONTINUE);
+ }
+
+ cleanup:
+ dns_loadctx_detach(&lctx);
+ return (result);
+}
+
+isc_result_t
+dns_master_loadlexer(isc_lex_t *lex, dns_name_t *top,
+ dns_name_t *origin, dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
+{
+ isc_result_t result;
+ dns_loadctx_t *lctx = NULL;
+
+ REQUIRE(lex != NULL);
+
+ result = loadctx_create(dns_masterformat_text, mctx, options, top,
+ zclass, origin, callbacks, NULL, NULL, NULL,
+ lex, &lctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = (lctx->load)(lctx);
+ INSIST(result != DNS_R_CONTINUE);
+
+ dns_loadctx_detach(&lctx);
+ return (result);
+}
+
+isc_result_t
+dns_master_loadlexerinc(isc_lex_t *lex, dns_name_t *top,
+ dns_name_t *origin, dns_rdataclass_t zclass,
+ unsigned int options,
+ dns_rdatacallbacks_t *callbacks, isc_task_t *task,
+ dns_loaddonefunc_t done, void *done_arg,
+ dns_loadctx_t **lctxp, isc_mem_t *mctx)
+{
+ isc_result_t result;
+ dns_loadctx_t *lctx = NULL;
+
+ REQUIRE(lex != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(done != NULL);
+
+ result = loadctx_create(dns_masterformat_text, mctx, options, top,
+ zclass, origin, callbacks, task, done,
+ done_arg, lex, &lctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = task_send(lctx);
+ if (result == ISC_R_SUCCESS) {
+ dns_loadctx_attach(lctx, lctxp);
+ return (DNS_R_CONTINUE);
+ }
+
+ dns_loadctx_detach(&lctx);
+ return (result);
+}
+
+/*
+ * Grow the slab of dns_rdatalist_t structures.
+ * Re-link glue and current list.
+ */
+static dns_rdatalist_t *
+grow_rdatalist(int new_len, dns_rdatalist_t *old, int old_len,
+ rdatalist_head_t *current, rdatalist_head_t *glue,
+ isc_mem_t *mctx)
+{
+ dns_rdatalist_t *new;
+ int rdlcount = 0;
+ ISC_LIST(dns_rdatalist_t) save;
+ dns_rdatalist_t *this;
+
+ new = isc_mem_get(mctx, new_len * sizeof(*new));
+ if (new == NULL)
+ return (NULL);
+
+ ISC_LIST_INIT(save);
+ this = ISC_LIST_HEAD(*current);
+ while ((this = ISC_LIST_HEAD(*current)) != NULL) {
+ ISC_LIST_UNLINK(*current, this, link);
+ ISC_LIST_APPEND(save, this, link);
+ }
+ while ((this = ISC_LIST_HEAD(save)) != NULL) {
+ ISC_LIST_UNLINK(save, this, link);
+ new[rdlcount] = *this;
+ ISC_LIST_APPEND(*current, &new[rdlcount], link);
+ rdlcount++;
+ }
+
+ ISC_LIST_INIT(save);
+ this = ISC_LIST_HEAD(*glue);
+ while ((this = ISC_LIST_HEAD(*glue)) != NULL) {
+ ISC_LIST_UNLINK(*glue, this, link);
+ ISC_LIST_APPEND(save, this, link);
+ }
+ while ((this = ISC_LIST_HEAD(save)) != NULL) {
+ ISC_LIST_UNLINK(save, this, link);
+ new[rdlcount] = *this;
+ ISC_LIST_APPEND(*glue, &new[rdlcount], link);
+ rdlcount++;
+ }
+
+ INSIST(rdlcount == old_len);
+ if (old != NULL)
+ isc_mem_put(mctx, old, old_len * sizeof(*old));
+ return (new);
+}
+
+/*
+ * Grow the slab of rdata structs.
+ * Re-link the current and glue chains.
+ */
+static dns_rdata_t *
+grow_rdata(int new_len, dns_rdata_t *old, int old_len,
+ rdatalist_head_t *current, rdatalist_head_t *glue,
+ isc_mem_t *mctx)
+{
+ dns_rdata_t *new;
+ int rdcount = 0;
+ ISC_LIST(dns_rdata_t) save;
+ dns_rdatalist_t *this;
+ dns_rdata_t *rdata;
+
+ new = isc_mem_get(mctx, new_len * sizeof(*new));
+ if (new == NULL)
+ return (NULL);
+ memset(new, 0, new_len * sizeof(*new));
+
+ /*
+ * Copy current relinking.
+ */
+ this = ISC_LIST_HEAD(*current);
+ while (this != NULL) {
+ ISC_LIST_INIT(save);
+ while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
+ ISC_LIST_UNLINK(this->rdata, rdata, link);
+ ISC_LIST_APPEND(save, rdata, link);
+ }
+ while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
+ ISC_LIST_UNLINK(save, rdata, link);
+ new[rdcount] = *rdata;
+ ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
+ rdcount++;
+ }
+ this = ISC_LIST_NEXT(this, link);
+ }
+
+ /*
+ * Copy glue relinking.
+ */
+ this = ISC_LIST_HEAD(*glue);
+ while (this != NULL) {
+ ISC_LIST_INIT(save);
+ while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
+ ISC_LIST_UNLINK(this->rdata, rdata, link);
+ ISC_LIST_APPEND(save, rdata, link);
+ }
+ while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
+ ISC_LIST_UNLINK(save, rdata, link);
+ new[rdcount] = *rdata;
+ ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
+ rdcount++;
+ }
+ this = ISC_LIST_NEXT(this, link);
+ }
+ INSIST(rdcount == old_len);
+ if (old != NULL)
+ isc_mem_put(mctx, old, old_len * sizeof(*old));
+ return (new);
+}
+
+/*
+ * Convert each element from a rdatalist_t to rdataset then call commit.
+ * Unlink each element as we go.
+ */
+
+static isc_result_t
+commit(dns_rdatacallbacks_t *callbacks, dns_loadctx_t *lctx,
+ rdatalist_head_t *head, dns_name_t *owner,
+ const char *source, unsigned int line)
+{
+ dns_rdatalist_t *this;
+ dns_rdataset_t dataset;
+ isc_result_t result;
+ char namebuf[DNS_NAME_FORMATSIZE];
+ void (*error)(struct dns_rdatacallbacks *, const char *, ...);
+
+ this = ISC_LIST_HEAD(*head);
+ error = callbacks->error;
+
+ if (this == NULL)
+ return (ISC_R_SUCCESS);
+ do {
+ dns_rdataset_init(&dataset);
+ RUNTIME_CHECK(dns_rdatalist_tordataset(this, &dataset)
+ == ISC_R_SUCCESS);
+ dataset.trust = dns_trust_ultimate;
+ result = ((*callbacks->add)(callbacks->add_private, owner,
+ &dataset));
+ if (result == ISC_R_NOMEMORY) {
+ (*error)(callbacks, "dns_master_load: %s",
+ dns_result_totext(result));
+ } else if (result != ISC_R_SUCCESS) {
+ dns_name_format(owner, namebuf,
+ sizeof(namebuf));
+ if (source != NULL) {
+ (*error)(callbacks, "%s: %s:%lu: %s: %s",
+ "dns_master_load", source, line,
+ namebuf, dns_result_totext(result));
+ } else {
+ (*error)(callbacks, "%s: %s: %s",
+ "dns_master_load", namebuf,
+ dns_result_totext(result));
+ }
+ }
+ if (MANYERRS(lctx, result))
+ SETRESULT(lctx, result);
+ else if (result != ISC_R_SUCCESS)
+ return (result);
+ ISC_LIST_UNLINK(*head, this, link);
+ this = ISC_LIST_HEAD(*head);
+ } while (this != NULL);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Returns ISC_TRUE if one of the NS rdata's contains 'owner'.
+ */
+
+static isc_boolean_t
+is_glue(rdatalist_head_t *head, dns_name_t *owner) {
+ dns_rdatalist_t *this;
+ dns_rdata_t *rdata;
+ isc_region_t region;
+ dns_name_t name;
+
+ /*
+ * Find NS rrset.
+ */
+ this = ISC_LIST_HEAD(*head);
+ while (this != NULL) {
+ if (this->type == dns_rdatatype_ns)
+ break;
+ this = ISC_LIST_NEXT(this, link);
+ }
+ if (this == NULL)
+ return (ISC_FALSE);
+
+ rdata = ISC_LIST_HEAD(this->rdata);
+ while (rdata != NULL) {
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ if (dns_name_compare(&name, owner) == 0)
+ return (ISC_TRUE);
+ rdata = ISC_LIST_NEXT(rdata, link);
+ }
+ return (ISC_FALSE);
+}
+
+static void
+load_quantum(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ dns_loadctx_t *lctx;
+
+ REQUIRE(event != NULL);
+ lctx = event->ev_arg;
+ REQUIRE(DNS_LCTX_VALID(lctx));
+
+ if (lctx->canceled)
+ result = ISC_R_CANCELED;
+ else
+ result = (lctx->load)(lctx);
+ if (result == DNS_R_CONTINUE) {
+ event->ev_arg = lctx;
+ isc_task_send(task, &event);
+ } else {
+ (lctx->done)(lctx->done_arg, result);
+ isc_event_free(&event);
+ dns_loadctx_detach(&lctx);
+ }
+}
+
+static isc_result_t
+task_send(dns_loadctx_t *lctx) {
+ isc_event_t *event;
+
+ event = isc_event_allocate(lctx->mctx, NULL,
+ DNS_EVENT_MASTERQUANTUM,
+ load_quantum, lctx, sizeof(*event));
+ if (event == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_task_send(lctx->task, &event);
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_loadctx_cancel(dns_loadctx_t *lctx) {
+ REQUIRE(DNS_LCTX_VALID(lctx));
+
+ LOCK(&lctx->lock);
+ lctx->canceled = ISC_TRUE;
+ UNLOCK(&lctx->lock);
+}
diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c
new file mode 100644
index 0000000..03716e2
--- /dev/null
+++ b/lib/dns/masterdump.c
@@ -0,0 +1,1738 @@
+/*
+ * Copyright (C) 2004-2006 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: masterdump.c,v 1.73.18.14 2006/08/08 06:39:36 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <isc/event.h>
+#include <isc/file.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/events.h>
+#include <dns/fixedname.h>
+#include <dns/lib.h>
+#include <dns/log.h>
+#include <dns/master.h>
+#include <dns/masterdump.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/rdatatype.h>
+#include <dns/result.h>
+#include <dns/time.h>
+#include <dns/ttl.h>
+
+#define DNS_DCTX_MAGIC ISC_MAGIC('D', 'c', 't', 'x')
+#define DNS_DCTX_VALID(d) ISC_MAGIC_VALID(d, DNS_DCTX_MAGIC)
+
+#define RETERR(x) do { \
+ isc_result_t _r = (x); \
+ if (_r != ISC_R_SUCCESS) \
+ return (_r); \
+ } while (0)
+
+struct dns_master_style {
+ unsigned int flags; /* DNS_STYLEFLAG_* */
+ unsigned int ttl_column;
+ unsigned int class_column;
+ unsigned int type_column;
+ unsigned int rdata_column;
+ unsigned int line_length;
+ unsigned int tab_width;
+};
+
+/*%
+ * The maximum length of the newline+indentation that is output
+ * when inserting a line break in an RR. This effectively puts an
+ * upper limits on the value of "rdata_column", because if it is
+ * very large, the tabs and spaces needed to reach it will not fit.
+ */
+#define DNS_TOTEXT_LINEBREAK_MAXLEN 100
+
+/*%
+ * Context structure for a masterfile dump in progress.
+ */
+typedef struct dns_totext_ctx {
+ dns_master_style_t style;
+ isc_boolean_t class_printed;
+ char * linebreak;
+ char linebreak_buf[DNS_TOTEXT_LINEBREAK_MAXLEN];
+ dns_name_t * origin;
+ dns_name_t * neworigin;
+ dns_fixedname_t origin_fixname;
+ isc_uint32_t current_ttl;
+ isc_boolean_t current_ttl_valid;
+} dns_totext_ctx_t;
+
+LIBDNS_EXTERNAL_DATA const dns_master_style_t
+dns_master_style_default = {
+ DNS_STYLEFLAG_OMIT_OWNER |
+ DNS_STYLEFLAG_OMIT_CLASS |
+ DNS_STYLEFLAG_REL_OWNER |
+ DNS_STYLEFLAG_REL_DATA |
+ DNS_STYLEFLAG_OMIT_TTL |
+ DNS_STYLEFLAG_TTL |
+ DNS_STYLEFLAG_COMMENT |
+ DNS_STYLEFLAG_MULTILINE,
+ 24, 24, 24, 32, 80, 8
+};
+
+LIBDNS_EXTERNAL_DATA const dns_master_style_t
+dns_master_style_full = {
+ DNS_STYLEFLAG_COMMENT,
+ 46, 46, 46, 64, 120, 8
+};
+
+LIBDNS_EXTERNAL_DATA const dns_master_style_t
+dns_master_style_explicitttl = {
+ DNS_STYLEFLAG_OMIT_OWNER |
+ DNS_STYLEFLAG_OMIT_CLASS |
+ DNS_STYLEFLAG_REL_OWNER |
+ DNS_STYLEFLAG_REL_DATA |
+ DNS_STYLEFLAG_COMMENT |
+ DNS_STYLEFLAG_MULTILINE,
+ 24, 32, 32, 40, 80, 8
+};
+
+LIBDNS_EXTERNAL_DATA const dns_master_style_t
+dns_master_style_cache = {
+ DNS_STYLEFLAG_OMIT_OWNER |
+ DNS_STYLEFLAG_OMIT_CLASS |
+ DNS_STYLEFLAG_MULTILINE |
+ DNS_STYLEFLAG_TRUST |
+ DNS_STYLEFLAG_NCACHE,
+ 24, 32, 32, 40, 80, 8
+};
+
+LIBDNS_EXTERNAL_DATA const dns_master_style_t
+dns_master_style_simple = {
+ 0,
+ 24, 32, 32, 40, 80, 8
+};
+
+/*%
+ * A style suitable for dns_rdataset_totext().
+ */
+LIBDNS_EXTERNAL_DATA const dns_master_style_t
+dns_master_style_debug = {
+ DNS_STYLEFLAG_REL_OWNER,
+ 24, 32, 40, 48, 80, 8
+};
+
+
+#define N_SPACES 10
+static char spaces[N_SPACES+1] = " ";
+
+#define N_TABS 10
+static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t";
+
+struct dns_dumpctx {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ unsigned int references;
+ isc_boolean_t canceled;
+ isc_boolean_t first;
+ isc_boolean_t do_date;
+ isc_stdtime_t now;
+ FILE *f;
+ dns_db_t *db;
+ dns_dbversion_t *version;
+ dns_dbiterator_t *dbiter;
+ dns_totext_ctx_t tctx;
+ isc_task_t *task;
+ dns_dumpdonefunc_t done;
+ void *done_arg;
+ unsigned int nodes;
+ /* dns_master_dumpinc() */
+ char *file;
+ char *tmpfile;
+ dns_masterformat_t format;
+ isc_result_t (*dumpsets)(isc_mem_t *mctx, dns_name_t *name,
+ dns_rdatasetiter_t *rdsiter,
+ dns_totext_ctx_t *ctx,
+ isc_buffer_t *buffer, FILE *f);
+};
+
+#define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
+
+/*%
+ * Output tabs and spaces to go from column '*current' to
+ * column 'to', and update '*current' to reflect the new
+ * current column.
+ */
+static isc_result_t
+indent(unsigned int *current, unsigned int to, int tabwidth,
+ isc_buffer_t *target)
+{
+ isc_region_t r;
+ unsigned char *p;
+ unsigned int from;
+ int ntabs, nspaces, t;
+
+ from = *current;
+
+ if (to < from + 1)
+ to = from + 1;
+
+ ntabs = to / tabwidth - from / tabwidth;
+ if (ntabs < 0)
+ ntabs = 0;
+
+ if (ntabs > 0) {
+ isc_buffer_availableregion(target, &r);
+ if (r.length < (unsigned) ntabs)
+ return (ISC_R_NOSPACE);
+ p = r.base;
+
+ t = ntabs;
+ while (t) {
+ int n = t;
+ if (n > N_TABS)
+ n = N_TABS;
+ memcpy(p, tabs, n);
+ p += n;
+ t -= n;
+ }
+ isc_buffer_add(target, ntabs);
+ from = (to / tabwidth) * tabwidth;
+ }
+
+ nspaces = to - from;
+ INSIST(nspaces >= 0);
+
+ isc_buffer_availableregion(target, &r);
+ if (r.length < (unsigned) nspaces)
+ return (ISC_R_NOSPACE);
+ p = r.base;
+
+ t = nspaces;
+ while (t) {
+ int n = t;
+ if (n > N_SPACES)
+ n = N_SPACES;
+ memcpy(p, spaces, n);
+ p += n;
+ t -= n;
+ }
+ isc_buffer_add(target, nspaces);
+
+ *current = to;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) {
+ isc_result_t result;
+
+ REQUIRE(style->tab_width != 0);
+
+ ctx->style = *style;
+ ctx->class_printed = ISC_FALSE;
+
+ dns_fixedname_init(&ctx->origin_fixname);
+
+ /*
+ * Set up the line break string if needed.
+ */
+ if ((ctx->style.flags & DNS_STYLEFLAG_MULTILINE) != 0) {
+ isc_buffer_t buf;
+ isc_region_t r;
+ unsigned int col = 0;
+
+ isc_buffer_init(&buf, ctx->linebreak_buf,
+ sizeof(ctx->linebreak_buf));
+
+ isc_buffer_availableregion(&buf, &r);
+ if (r.length < 1)
+ return (DNS_R_TEXTTOOLONG);
+ r.base[0] = '\n';
+ isc_buffer_add(&buf, 1);
+
+ result = indent(&col, ctx->style.rdata_column,
+ ctx->style.tab_width, &buf);
+ /*
+ * Do not return ISC_R_NOSPACE if the line break string
+ * buffer is too small, because that would just make
+ * dump_rdataset() retry indenfinitely with ever
+ * bigger target buffers. That's a different buffer,
+ * so it won't help. Use DNS_R_TEXTTOOLONG as a substitute.
+ */
+ if (result == ISC_R_NOSPACE)
+ return (DNS_R_TEXTTOOLONG);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ isc_buffer_availableregion(&buf, &r);
+ if (r.length < 1)
+ return (DNS_R_TEXTTOOLONG);
+ r.base[0] = '\0';
+ isc_buffer_add(&buf, 1);
+ ctx->linebreak = ctx->linebreak_buf;
+ } else {
+ ctx->linebreak = NULL;
+ }
+
+ ctx->origin = NULL;
+ ctx->neworigin = NULL;
+ ctx->current_ttl = 0;
+ ctx->current_ttl_valid = ISC_FALSE;
+
+ return (ISC_R_SUCCESS);
+}
+
+#define INDENT_TO(col) \
+ do { \
+ if ((result = indent(&column, ctx->style.col, \
+ ctx->style.tab_width, target)) \
+ != ISC_R_SUCCESS) \
+ return (result); \
+ } while (0)
+
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target) {
+ unsigned int l;
+ isc_region_t region;
+
+ isc_buffer_availableregion(target, &region);
+ l = strlen(source);
+
+ if (l > region.length)
+ return (ISC_R_NOSPACE);
+
+ memcpy(region.base, source, l);
+ isc_buffer_add(target, l);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Convert 'rdataset' to master file text format according to 'ctx',
+ * storing the result in 'target'. If 'owner_name' is NULL, it
+ * is omitted; otherwise 'owner_name' must be valid and have at least
+ * one label.
+ */
+
+static isc_result_t
+rdataset_totext(dns_rdataset_t *rdataset,
+ dns_name_t *owner_name,
+ dns_totext_ctx_t *ctx,
+ isc_boolean_t omit_final_dot,
+ isc_buffer_t *target)
+{
+ isc_result_t result;
+ unsigned int column;
+ isc_boolean_t first = ISC_TRUE;
+ isc_uint32_t current_ttl;
+ isc_boolean_t current_ttl_valid;
+ dns_rdatatype_t type;
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+
+ rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
+ result = dns_rdataset_first(rdataset);
+ REQUIRE(result == ISC_R_SUCCESS);
+
+ current_ttl = ctx->current_ttl;
+ current_ttl_valid = ctx->current_ttl_valid;
+
+ do {
+ column = 0;
+
+ /*
+ * Owner name.
+ */
+ if (owner_name != NULL &&
+ ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 &&
+ !first))
+ {
+ unsigned int name_start = target->used;
+ RETERR(dns_name_totext(owner_name,
+ omit_final_dot,
+ target));
+ column += target->used - name_start;
+ }
+
+ /*
+ * TTL.
+ */
+ if ((ctx->style.flags & DNS_STYLEFLAG_NO_TTL) == 0 &&
+ !((ctx->style.flags & DNS_STYLEFLAG_OMIT_TTL) != 0 &&
+ current_ttl_valid &&
+ rdataset->ttl == current_ttl))
+ {
+ char ttlbuf[64];
+ isc_region_t r;
+ unsigned int length;
+
+ INDENT_TO(ttl_column);
+ length = snprintf(ttlbuf, sizeof(ttlbuf), "%u",
+ rdataset->ttl);
+ INSIST(length <= sizeof(ttlbuf));
+ isc_buffer_availableregion(target, &r);
+ if (r.length < length)
+ return (ISC_R_NOSPACE);
+ memcpy(r.base, ttlbuf, length);
+ isc_buffer_add(target, length);
+ column += length;
+
+ /*
+ * If the $TTL directive is not in use, the TTL we
+ * just printed becomes the default for subsequent RRs.
+ */
+ if ((ctx->style.flags & DNS_STYLEFLAG_TTL) == 0) {
+ current_ttl = rdataset->ttl;
+ current_ttl_valid = ISC_TRUE;
+ }
+ }
+
+ /*
+ * Class.
+ */
+ if ((ctx->style.flags & DNS_STYLEFLAG_NO_CLASS) == 0 &&
+ ((ctx->style.flags & DNS_STYLEFLAG_OMIT_CLASS) == 0 ||
+ ctx->class_printed == ISC_FALSE))
+ {
+ unsigned int class_start;
+ INDENT_TO(class_column);
+ class_start = target->used;
+ result = dns_rdataclass_totext(rdataset->rdclass,
+ target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ column += (target->used - class_start);
+ }
+
+ /*
+ * Type.
+ */
+
+ if (rdataset->type == 0) {
+ type = rdataset->covers;
+ } else {
+ type = rdataset->type;
+ }
+
+ {
+ unsigned int type_start;
+ INDENT_TO(type_column);
+ type_start = target->used;
+ if (rdataset->type == 0)
+ RETERR(str_totext("\\-", target));
+ result = dns_rdatatype_totext(type, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ column += (target->used - type_start);
+ }
+
+ /*
+ * Rdata.
+ */
+ INDENT_TO(rdata_column);
+ if (rdataset->type == 0) {
+ if (NXDOMAIN(rdataset))
+ RETERR(str_totext(";-$NXDOMAIN\n", target));
+ else
+ RETERR(str_totext(";-$NXRRSET\n", target));
+ } else {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_region_t r;
+
+ dns_rdataset_current(rdataset, &rdata);
+
+ RETERR(dns_rdata_tofmttext(&rdata,
+ ctx->origin,
+ ctx->style.flags,
+ ctx->style.line_length -
+ ctx->style.rdata_column,
+ ctx->linebreak,
+ target));
+
+ isc_buffer_availableregion(target, &r);
+ if (r.length < 1)
+ return (ISC_R_NOSPACE);
+ r.base[0] = '\n';
+ isc_buffer_add(target, 1);
+ }
+
+ first = ISC_FALSE;
+ result = dns_rdataset_next(rdataset);
+ } while (result == ISC_R_SUCCESS);
+
+ if (result != ISC_R_NOMORE)
+ return (result);
+
+ /*
+ * Update the ctx state to reflect what we just printed.
+ * This is done last, only when we are sure we will return
+ * success, because this function may be called multiple
+ * times with increasing buffer sizes until it succeeds,
+ * and failed attempts must not update the state prematurely.
+ */
+ ctx->class_printed = ISC_TRUE;
+ ctx->current_ttl= current_ttl;
+ ctx->current_ttl_valid = current_ttl_valid;
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Print the name, type, and class of an empty rdataset,
+ * such as those used to represent the question section
+ * of a DNS message.
+ */
+static isc_result_t
+question_totext(dns_rdataset_t *rdataset,
+ dns_name_t *owner_name,
+ dns_totext_ctx_t *ctx,
+ isc_boolean_t omit_final_dot,
+ isc_buffer_t *target)
+{
+ unsigned int column;
+ isc_result_t result;
+ isc_region_t r;
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ result = dns_rdataset_first(rdataset);
+ REQUIRE(result == ISC_R_NOMORE);
+
+ column = 0;
+
+ /* Owner name */
+ {
+ unsigned int name_start = target->used;
+ RETERR(dns_name_totext(owner_name,
+ omit_final_dot,
+ target));
+ column += target->used - name_start;
+ }
+
+ /* Class */
+ {
+ unsigned int class_start;
+ INDENT_TO(class_column);
+ class_start = target->used;
+ result = dns_rdataclass_totext(rdataset->rdclass, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ column += (target->used - class_start);
+ }
+
+ /* Type */
+ {
+ unsigned int type_start;
+ INDENT_TO(type_column);
+ type_start = target->used;
+ result = dns_rdatatype_totext(rdataset->type, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ column += (target->used - type_start);
+ }
+
+ isc_buffer_availableregion(target, &r);
+ if (r.length < 1)
+ return (ISC_R_NOSPACE);
+ r.base[0] = '\n';
+ isc_buffer_add(target, 1);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_rdataset_totext(dns_rdataset_t *rdataset,
+ dns_name_t *owner_name,
+ isc_boolean_t omit_final_dot,
+ isc_boolean_t question,
+ isc_buffer_t *target)
+{
+ dns_totext_ctx_t ctx;
+ isc_result_t result;
+ result = totext_ctx_init(&dns_master_style_debug, &ctx);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "could not set master file style");
+ return (ISC_R_UNEXPECTED);
+ }
+
+ /*
+ * The caller might want to give us an empty owner
+ * name (e.g. if they are outputting into a master
+ * file and this rdataset has the same name as the
+ * previous one.)
+ */
+ if (dns_name_countlabels(owner_name) == 0)
+ owner_name = NULL;
+
+ if (question)
+ return (question_totext(rdataset, owner_name, &ctx,
+ omit_final_dot, target));
+ else
+ return (rdataset_totext(rdataset, owner_name, &ctx,
+ omit_final_dot, target));
+}
+
+isc_result_t
+dns_master_rdatasettotext(dns_name_t *owner_name,
+ dns_rdataset_t *rdataset,
+ const dns_master_style_t *style,
+ isc_buffer_t *target)
+{
+ dns_totext_ctx_t ctx;
+ isc_result_t result;
+ result = totext_ctx_init(style, &ctx);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "could not set master file style");
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (rdataset_totext(rdataset, owner_name, &ctx,
+ ISC_FALSE, target));
+}
+
+isc_result_t
+dns_master_questiontotext(dns_name_t *owner_name,
+ dns_rdataset_t *rdataset,
+ const dns_master_style_t *style,
+ isc_buffer_t *target)
+{
+ dns_totext_ctx_t ctx;
+ isc_result_t result;
+ result = totext_ctx_init(style, &ctx);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "could not set master file style");
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (question_totext(rdataset, owner_name, &ctx,
+ ISC_FALSE, target));
+}
+
+/*
+ * Print an rdataset. 'buffer' is a scratch buffer, which must have been
+ * dynamically allocated by the caller. It must be large enough to
+ * hold the result from dns_ttl_totext(). If more than that is needed,
+ * the buffer will be grown automatically.
+ */
+
+static isc_result_t
+dump_rdataset(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
+ dns_totext_ctx_t *ctx,
+ isc_buffer_t *buffer, FILE *f)
+{
+ isc_region_t r;
+ isc_result_t result;
+
+ REQUIRE(buffer->length > 0);
+
+ /*
+ * Output a $TTL directive if needed.
+ */
+
+ if ((ctx->style.flags & DNS_STYLEFLAG_TTL) != 0) {
+ if (ctx->current_ttl_valid == ISC_FALSE ||
+ ctx->current_ttl != rdataset->ttl)
+ {
+ if ((ctx->style.flags & DNS_STYLEFLAG_COMMENT) != 0)
+ {
+ isc_buffer_clear(buffer);
+ result = dns_ttl_totext(rdataset->ttl,
+ ISC_TRUE, buffer);
+ INSIST(result == ISC_R_SUCCESS);
+ isc_buffer_usedregion(buffer, &r);
+ fprintf(f, "$TTL %u\t; %.*s\n", rdataset->ttl,
+ (int) r.length, (char *) r.base);
+ } else {
+ fprintf(f, "$TTL %u\n", rdataset->ttl);
+ }
+ ctx->current_ttl = rdataset->ttl;
+ ctx->current_ttl_valid = ISC_TRUE;
+ }
+ }
+
+ isc_buffer_clear(buffer);
+
+ /*
+ * Generate the text representation of the rdataset into
+ * the buffer. If the buffer is too small, grow it.
+ */
+ for (;;) {
+ int newlength;
+ void *newmem;
+ result = rdataset_totext(rdataset, name, ctx,
+ ISC_FALSE, buffer);
+ if (result != ISC_R_NOSPACE)
+ break;
+
+ newlength = buffer->length * 2;
+ newmem = isc_mem_get(mctx, newlength);
+ if (newmem == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_mem_put(mctx, buffer->base, buffer->length);
+ isc_buffer_init(buffer, newmem, newlength);
+ }
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Write the buffer contents to the master file.
+ */
+ isc_buffer_usedregion(buffer, &r);
+ result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
+
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "master file write failed: %s",
+ isc_result_totext(result));
+ return (result);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Define the order in which rdatasets should be printed in zone
+ * files. We will print SOA and NS records before others, SIGs
+ * immediately following the things they sign, and order everything
+ * else by RR number. This is all just for aesthetics and
+ * compatibility with buggy software that expects the SOA to be first;
+ * the DNS specifications allow any order.
+ */
+
+static int
+dump_order(const dns_rdataset_t *rds) {
+ int t;
+ int sig;
+ if (rds->type == dns_rdatatype_rrsig) {
+ t = rds->covers;
+ sig = 1;
+ } else {
+ t = rds->type;
+ sig = 0;
+ }
+ switch (t) {
+ case dns_rdatatype_soa:
+ t = 0;
+ break;
+ case dns_rdatatype_ns:
+ t = 1;
+ break;
+ default:
+ t += 2;
+ break;
+ }
+ return (t << 1) + sig;
+}
+
+static int
+dump_order_compare(const void *a, const void *b) {
+ return (dump_order(*((const dns_rdataset_t * const *) a)) -
+ dump_order(*((const dns_rdataset_t * const *) b)));
+}
+
+/*
+ * Dump all the rdatasets of a domain name to a master file. We make
+ * a "best effort" attempt to sort the RRsets in a nice order, but if
+ * there are more than MAXSORT RRsets, we punt and only sort them in
+ * groups of MAXSORT. This is not expected to ever happen in practice
+ * since much less than 64 RR types have been registered with the
+ * IANA, so far, and the output will be correct (though not
+ * aesthetically pleasing) even if it does happen.
+ */
+
+#define MAXSORT 64
+
+static const char *trustnames[] = {
+ "none",
+ "pending",
+ "additional",
+ "glue",
+ "answer",
+ "authauthority",
+ "authanswer",
+ "secure",
+ "local" /* aka ultimate */
+};
+
+static isc_result_t
+dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name,
+ dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
+ isc_buffer_t *buffer, FILE *f)
+{
+ isc_result_t itresult, dumpresult;
+ isc_region_t r;
+ dns_rdataset_t rdatasets[MAXSORT];
+ dns_rdataset_t *sorted[MAXSORT];
+ int i, n;
+
+ itresult = dns_rdatasetiter_first(rdsiter);
+ dumpresult = ISC_R_SUCCESS;
+
+ if (itresult == ISC_R_SUCCESS && ctx->neworigin != NULL) {
+ isc_buffer_clear(buffer);
+ itresult = dns_name_totext(ctx->neworigin, ISC_FALSE, buffer);
+ RUNTIME_CHECK(itresult == ISC_R_SUCCESS);
+ isc_buffer_usedregion(buffer, &r);
+ fprintf(f, "$ORIGIN %.*s\n", (int) r.length, (char *) r.base);
+ ctx->neworigin = NULL;
+ }
+
+ again:
+ for (i = 0;
+ itresult == ISC_R_SUCCESS && i < MAXSORT;
+ itresult = dns_rdatasetiter_next(rdsiter), i++) {
+ dns_rdataset_init(&rdatasets[i]);
+ dns_rdatasetiter_current(rdsiter, &rdatasets[i]);
+ sorted[i] = &rdatasets[i];
+ }
+ n = i;
+ INSIST(n <= MAXSORT);
+
+ qsort(sorted, n, sizeof(sorted[0]), dump_order_compare);
+
+ for (i = 0; i < n; i++) {
+ dns_rdataset_t *rds = sorted[i];
+ if (ctx->style.flags & DNS_STYLEFLAG_TRUST) {
+ unsigned int trust = rds->trust;
+ INSIST(trust < (sizeof(trustnames) /
+ sizeof(trustnames[0])));
+ fprintf(f, "; %s\n", trustnames[trust]);
+ }
+ if (rds->type == 0 &&
+ (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
+ /* Omit negative cache entries */
+ } else {
+ isc_result_t result =
+ dump_rdataset(mctx, name, rds, ctx,
+ buffer, f);
+ if (result != ISC_R_SUCCESS)
+ dumpresult = result;
+ if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0)
+ name = NULL;
+ }
+ dns_rdataset_disassociate(rds);
+ }
+
+ if (dumpresult != ISC_R_SUCCESS)
+ return (dumpresult);
+
+ /*
+ * If we got more data than could be sorted at once,
+ * go handle the rest.
+ */
+ if (itresult == ISC_R_SUCCESS)
+ goto again;
+
+ if (itresult == ISC_R_NOMORE)
+ itresult = ISC_R_SUCCESS;
+
+ return (itresult);
+}
+
+/*
+ * Dump given RRsets in the "raw" format.
+ */
+static isc_result_t
+dump_rdataset_raw(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
+ isc_buffer_t *buffer, FILE *f)
+{
+ isc_result_t result;
+ isc_uint32_t totallen;
+ isc_uint16_t dlen;
+ isc_region_t r, r_hdr;
+
+ REQUIRE(buffer->length > 0);
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+
+ restart:
+ totallen = 0;
+ result = dns_rdataset_first(rdataset);
+ REQUIRE(result == ISC_R_SUCCESS);
+
+ isc_buffer_clear(buffer);
+
+ /*
+ * Common header and owner name (length followed by name)
+ * These fields should be in a moderate length, so we assume we
+ * can store all of them in the initial buffer.
+ */
+ isc_buffer_availableregion(buffer, &r_hdr);
+ INSIST(r_hdr.length >= sizeof(dns_masterrawrdataset_t));
+ isc_buffer_putuint32(buffer, totallen); /* XXX: leave space */
+ isc_buffer_putuint16(buffer, rdataset->rdclass); /* 16-bit class */
+ isc_buffer_putuint16(buffer, rdataset->type); /* 16-bit type */
+ isc_buffer_putuint16(buffer, rdataset->covers); /* same as type */
+ isc_buffer_putuint32(buffer, rdataset->ttl); /* 32-bit TTL */
+ isc_buffer_putuint32(buffer, dns_rdataset_count(rdataset));
+ totallen = isc_buffer_usedlength(buffer);
+ INSIST(totallen <= sizeof(dns_masterrawrdataset_t));
+
+ dns_name_toregion(name, &r);
+ INSIST(isc_buffer_availablelength(buffer) >=
+ (sizeof(dlen) + r.length));
+ dlen = (isc_uint16_t)r.length;
+ isc_buffer_putuint16(buffer, dlen);
+ isc_buffer_copyregion(buffer, &r);
+ totallen += sizeof(dlen) + r.length;
+
+ do {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_region_t r;
+
+ dns_rdataset_current(rdataset, &rdata);
+ dns_rdata_toregion(&rdata, &r);
+ INSIST(r.length <= 0xffffU);
+ dlen = (isc_uint16_t)r.length;
+
+ /*
+ * Copy the rdata into the buffer. If the buffer is too small,
+ * grow it. This should be rare, so we'll simply restart the
+ * entire procedure (or should we copy the old data and
+ * continue?).
+ */
+ if (isc_buffer_availablelength(buffer) <
+ sizeof(dlen) + r.length) {
+ int newlength;
+ void *newmem;
+
+ newlength = buffer->length * 2;
+ newmem = isc_mem_get(mctx, newlength);
+ if (newmem == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_mem_put(mctx, buffer->base, buffer->length);
+ isc_buffer_init(buffer, newmem, newlength);
+ goto restart;
+ }
+ isc_buffer_putuint16(buffer, dlen);
+ isc_buffer_copyregion(buffer, &r);
+ totallen += sizeof(dlen) + r.length;
+
+ result = dns_rdataset_next(rdataset);
+ } while (result == ISC_R_SUCCESS);
+
+ if (result != ISC_R_NOMORE)
+ return (result);
+
+ /*
+ * Fill in the total length field.
+ * XXX: this is a bit tricky. Since we have already "used" the space
+ * for the total length in the buffer, we first remember the entire
+ * buffer length in the region, "rewind", and then write the value.
+ */
+ isc_buffer_usedregion(buffer, &r);
+ isc_buffer_clear(buffer);
+ isc_buffer_putuint32(buffer, totallen);
+ INSIST(isc_buffer_usedlength(buffer) < totallen);
+
+ /*
+ * Write the buffer contents to the raw master file.
+ */
+ result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
+
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "raw master file write failed: %s",
+ isc_result_totext(result));
+ return (result);
+ }
+
+ return (result);
+}
+
+static isc_result_t
+dump_rdatasets_raw(isc_mem_t *mctx, dns_name_t *name,
+ dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
+ isc_buffer_t *buffer, FILE *f)
+{
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+
+ for (result = dns_rdatasetiter_first(rdsiter);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(rdsiter)) {
+
+ dns_rdataset_init(&rdataset);
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+
+ if (rdataset.type == 0 &&
+ (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
+ /* Omit negative cache entries */
+ } else {
+ result = dump_rdataset_raw(mctx, name, &rdataset,
+ buffer, f);
+ }
+ dns_rdataset_disassociate(&rdataset);
+ }
+
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ return (result);
+}
+
+/*
+ * Initial size of text conversion buffer. The buffer is used
+ * for several purposes: converting origin names, rdatasets,
+ * $DATE timestamps, and comment strings for $TTL directives.
+ *
+ * When converting rdatasets, it is dynamically resized, but
+ * when converting origins, timestamps, etc it is not. Therefore,
+ * the initial size must large enough to hold the longest possible
+ * text representation of any domain name (for $ORIGIN).
+ */
+static const int initial_buffer_length = 1200;
+
+static isc_result_t
+dumptostreaminc(dns_dumpctx_t *dctx);
+
+static void
+dumpctx_destroy(dns_dumpctx_t *dctx) {
+
+ dctx->magic = 0;
+ DESTROYLOCK(&dctx->lock);
+ if (dctx->version != NULL)
+ dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
+ dns_dbiterator_destroy(&dctx->dbiter);
+ dns_db_detach(&dctx->db);
+ if (dctx->task != NULL)
+ isc_task_detach(&dctx->task);
+ if (dctx->file != NULL)
+ isc_mem_free(dctx->mctx, dctx->file);
+ if (dctx->tmpfile != NULL)
+ isc_mem_free(dctx->mctx, dctx->tmpfile);
+ isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx));
+}
+
+void
+dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) {
+
+ REQUIRE(DNS_DCTX_VALID(source));
+ REQUIRE(target != NULL && *target == NULL);
+
+ LOCK(&source->lock);
+ INSIST(source->references > 0);
+ source->references++;
+ INSIST(source->references != 0); /* Overflow? */
+ UNLOCK(&source->lock);
+
+ *target = source;
+}
+
+void
+dns_dumpctx_detach(dns_dumpctx_t **dctxp) {
+ dns_dumpctx_t *dctx;
+ isc_boolean_t need_destroy = ISC_FALSE;
+
+ REQUIRE(dctxp != NULL);
+ dctx = *dctxp;
+ REQUIRE(DNS_DCTX_VALID(dctx));
+
+ *dctxp = NULL;
+
+ LOCK(&dctx->lock);
+ INSIST(dctx->references != 0);
+ dctx->references--;
+ if (dctx->references == 0)
+ need_destroy = ISC_TRUE;
+ UNLOCK(&dctx->lock);
+ if (need_destroy)
+ dumpctx_destroy(dctx);
+}
+
+dns_dbversion_t *
+dns_dumpctx_version(dns_dumpctx_t *dctx) {
+ REQUIRE(DNS_DCTX_VALID(dctx));
+ return (dctx->version);
+}
+
+dns_db_t *
+dns_dumpctx_db(dns_dumpctx_t *dctx) {
+ REQUIRE(DNS_DCTX_VALID(dctx));
+ return (dctx->db);
+}
+
+void
+dns_dumpctx_cancel(dns_dumpctx_t *dctx) {
+ REQUIRE(DNS_DCTX_VALID(dctx));
+
+ LOCK(&dctx->lock);
+ dctx->canceled = ISC_TRUE;
+ UNLOCK(&dctx->lock);
+}
+
+static isc_result_t
+closeandrename(FILE *f, isc_result_t result, const char *temp, const char *file)
+{
+ isc_result_t tresult;
+ isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS);
+
+ if (result == ISC_R_SUCCESS)
+ result = isc_stdio_sync(f);
+ if (result != ISC_R_SUCCESS && logit) {
+ isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
+ "dumping master file: %s: fsync: %s",
+ temp, isc_result_totext(result));
+ logit = ISC_FALSE;
+ }
+ tresult = isc_stdio_close(f);
+ if (result == ISC_R_SUCCESS)
+ result = tresult;
+ if (result != ISC_R_SUCCESS && logit) {
+ isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
+ "dumping master file: %s: fclose: %s",
+ temp, isc_result_totext(result));
+ logit = ISC_FALSE;
+ }
+ if (result == ISC_R_SUCCESS)
+ result = isc_file_rename(temp, file);
+ else
+ (void)isc_file_remove(temp);
+ if (result != ISC_R_SUCCESS && logit) {
+ isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
+ "dumping master file: rename: %s: %s",
+ file, isc_result_totext(result));
+ }
+ return (result);
+}
+
+static void
+dump_quantum(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ isc_result_t tresult;
+ dns_dumpctx_t *dctx;
+
+ REQUIRE(event != NULL);
+ dctx = event->ev_arg;
+ REQUIRE(DNS_DCTX_VALID(dctx));
+ if (dctx->canceled)
+ result = ISC_R_CANCELED;
+ else
+ result = dumptostreaminc(dctx);
+ if (result == DNS_R_CONTINUE) {
+ event->ev_arg = dctx;
+ isc_task_send(task, &event);
+ return;
+ }
+
+ if (dctx->file != NULL) {
+ tresult = closeandrename(dctx->f, result,
+ dctx->tmpfile, dctx->file);
+ if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
+ result = tresult;
+ }
+ (dctx->done)(dctx->done_arg, result);
+ isc_event_free(&event);
+ dns_dumpctx_detach(&dctx);
+}
+
+static isc_result_t
+task_send(dns_dumpctx_t *dctx) {
+ isc_event_t *event;
+
+ event = isc_event_allocate(dctx->mctx, NULL, DNS_EVENT_DUMPQUANTUM,
+ dump_quantum, dctx, sizeof(*event));
+ if (event == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_task_send(dctx->task, &event);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
+ const dns_master_style_t *style, FILE *f, dns_dumpctx_t **dctxp,
+ dns_masterformat_t format)
+{
+ dns_dumpctx_t *dctx;
+ isc_result_t result;
+ isc_boolean_t relative;
+
+ dctx = isc_mem_get(mctx, sizeof(*dctx));
+ if (dctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ dctx->mctx = NULL;
+ dctx->f = f;
+ dctx->dbiter = NULL;
+ dctx->db = NULL;
+ dctx->version = NULL;
+ dctx->done = NULL;
+ dctx->done_arg = NULL;
+ dctx->task = NULL;
+ dctx->nodes = 0;
+ dctx->first = ISC_TRUE;
+ dctx->canceled = ISC_FALSE;
+ dctx->file = NULL;
+ dctx->tmpfile = NULL;
+ dctx->format = format;
+
+ switch (format) {
+ case dns_masterformat_text:
+ dctx->dumpsets = dump_rdatasets_text;
+ break;
+ case dns_masterformat_raw:
+ dctx->dumpsets = dump_rdatasets_raw;
+ break;
+ default:
+ INSIST(0);
+ break;
+ }
+
+ result = totext_ctx_init(style, &dctx->tctx);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "could not set master file style");
+ goto cleanup;
+ }
+
+ isc_stdtime_get(&dctx->now);
+ dns_db_attach(db, &dctx->db);
+
+ dctx->do_date = dns_db_iscache(dctx->db);
+
+ if (dctx->format == dns_masterformat_text &&
+ (dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) {
+ relative = ISC_TRUE;
+ } else
+ relative = ISC_FALSE;
+ result = dns_db_createiterator(dctx->db, relative, &dctx->dbiter);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = isc_mutex_init(&dctx->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ if (version != NULL)
+ dns_db_attachversion(dctx->db, version, &dctx->version);
+ else if (!dns_db_iscache(db))
+ dns_db_currentversion(dctx->db, &dctx->version);
+ isc_mem_attach(mctx, &dctx->mctx);
+ dctx->references = 1;
+ dctx->magic = DNS_DCTX_MAGIC;
+ *dctxp = dctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (dctx->dbiter != NULL)
+ dns_dbiterator_destroy(&dctx->dbiter);
+ if (dctx->db != NULL)
+ dns_db_detach(&dctx->db);
+ if (dctx != NULL)
+ isc_mem_put(mctx, dctx, sizeof(*dctx));
+ return (result);
+}
+
+static isc_result_t
+dumptostreaminc(dns_dumpctx_t *dctx) {
+ isc_result_t result;
+ isc_buffer_t buffer;
+ char *bufmem;
+ isc_region_t r;
+ dns_name_t *name;
+ dns_fixedname_t fixname;
+ unsigned int nodes;
+ dns_masterrawheader_t rawheader;
+ isc_uint32_t now32;
+ isc_time_t start;
+
+ bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
+ if (bufmem == NULL)
+ return (ISC_R_NOMEMORY);
+
+ isc_buffer_init(&buffer, bufmem, initial_buffer_length);
+
+ dns_fixedname_init(&fixname);
+ name = dns_fixedname_name(&fixname);
+
+ if (dctx->first) {
+ switch (dctx->format) {
+ case dns_masterformat_text:
+ /*
+ * If the database has cache semantics, output an
+ * RFC2540 $DATE directive so that the TTLs can be
+ * adjusted when it is reloaded. For zones it is not
+ * really needed, and it would make the file
+ * incompatible with pre-RFC2540 software, so we omit
+ * it in the zone case.
+ */
+ if (dctx->do_date) {
+ result = dns_time32_totext(dctx->now, &buffer);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ isc_buffer_usedregion(&buffer, &r);
+ fprintf(dctx->f, "$DATE %.*s\n",
+ (int) r.length, (char *) r.base);
+ }
+ break;
+ case dns_masterformat_raw:
+ r.base = (unsigned char *)&rawheader;
+ r.length = sizeof(rawheader);
+ isc_buffer_region(&buffer, &r);
+ isc_buffer_putuint32(&buffer, dns_masterformat_raw);
+ isc_buffer_putuint32(&buffer, DNS_RAWFORMAT_VERSION);
+ if (sizeof(now32) != sizeof(dctx->now)) {
+ /*
+ * We assume isc_stdtime_t is a 32-bit integer,
+ * which should be the case on most cases.
+ * If it turns out to be uncommon, we'll need
+ * to bump the version number and revise the
+ * header format.
+ */
+ isc_log_write(dns_lctx,
+ ISC_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTERDUMP,
+ ISC_LOG_INFO,
+ "dumping master file in raw "
+ "format: stdtime is not 32bits");
+ now32 = 0;
+ } else
+ now32 = dctx->now;
+ isc_buffer_putuint32(&buffer, now32);
+ INSIST(isc_buffer_usedlength(&buffer) <=
+ sizeof(rawheader));
+ result = isc_stdio_write(buffer.base, 1,
+ isc_buffer_usedlength(&buffer),
+ dctx->f, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_clear(&buffer);
+ break;
+ default:
+ INSIST(0);
+ }
+
+ result = dns_dbiterator_first(dctx->dbiter);
+ dctx->first = ISC_FALSE;
+ } else
+ result = ISC_R_SUCCESS;
+
+ nodes = dctx->nodes;
+ isc_time_now(&start);
+ while (result == ISC_R_SUCCESS && (dctx->nodes == 0 || nodes--)) {
+ dns_rdatasetiter_t *rdsiter = NULL;
+ dns_dbnode_t *node = NULL;
+
+ result = dns_dbiterator_current(dctx->dbiter, &node, name);
+ if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
+ break;
+ if (result == DNS_R_NEWORIGIN) {
+ dns_name_t *origin =
+ dns_fixedname_name(&dctx->tctx.origin_fixname);
+ result = dns_dbiterator_origin(dctx->dbiter, origin);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ if ((dctx->tctx.style.flags & DNS_STYLEFLAG_REL_DATA) != 0)
+ dctx->tctx.origin = origin;
+ dctx->tctx.neworigin = origin;
+ }
+ result = dns_db_allrdatasets(dctx->db, node, dctx->version,
+ dctx->now, &rdsiter);
+ if (result != ISC_R_SUCCESS) {
+ dns_db_detachnode(dctx->db, &node);
+ goto fail;
+ }
+ result = (dctx->dumpsets)(dctx->mctx, name, rdsiter,
+ &dctx->tctx, &buffer, dctx->f);
+ dns_rdatasetiter_destroy(&rdsiter);
+ if (result != ISC_R_SUCCESS) {
+ dns_db_detachnode(dctx->db, &node);
+ goto fail;
+ }
+ dns_db_detachnode(dctx->db, &node);
+ result = dns_dbiterator_next(dctx->dbiter);
+ }
+
+ /*
+ * Work out how many nodes can be written in the time between
+ * two requests to the nameserver. Smooth the resulting number and
+ * use it as a estimate for the number of nodes to be written in the
+ * next iteration.
+ */
+ if (dctx->nodes != 0 && result == ISC_R_SUCCESS) {
+ unsigned int pps = dns_pps; /* packets per second */
+ unsigned int interval;
+ isc_uint64_t usecs;
+ isc_time_t end;
+
+ isc_time_now(&end);
+ if (pps < 100)
+ pps = 100;
+ interval = 1000000 / pps; /* interval in usecs */
+ if (interval == 0)
+ interval = 1;
+ usecs = isc_time_microdiff(&end, &start);
+ if (usecs == 0) {
+ dctx->nodes = dctx->nodes * 2;
+ if (dctx->nodes > 1000)
+ dctx->nodes = 1000;
+ } else {
+ nodes = dctx->nodes * interval;
+ nodes /= (unsigned int)usecs;
+ if (nodes == 0)
+ nodes = 1;
+ else if (nodes > 1000)
+ nodes = 1000;
+
+ /* Smooth and assign. */
+ dctx->nodes = (nodes + dctx->nodes * 7) / 8;
+
+ isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTERDUMP,
+ ISC_LOG_DEBUG(1),
+ "dumptostreaminc(%p) new nodes -> %d\n",
+ dctx, dctx->nodes);
+ }
+ result = dns_dbiterator_pause(dctx->dbiter);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ result = DNS_R_CONTINUE;
+ } else if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ fail:
+ isc_mem_put(dctx->mctx, buffer.base, buffer.length);
+ return (result);
+}
+
+isc_result_t
+dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db,
+ dns_dbversion_t *version,
+ const dns_master_style_t *style,
+ FILE *f, isc_task_t *task,
+ dns_dumpdonefunc_t done, void *done_arg,
+ dns_dumpctx_t **dctxp)
+{
+ dns_dumpctx_t *dctx = NULL;
+ isc_result_t result;
+
+ REQUIRE(task != NULL);
+ REQUIRE(f != NULL);
+ REQUIRE(done != NULL);
+
+ result = dumpctx_create(mctx, db, version, style, f, &dctx,
+ dns_masterformat_text);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_task_attach(task, &dctx->task);
+ dctx->done = done;
+ dctx->done_arg = done_arg;
+ dctx->nodes = 100;
+
+ result = task_send(dctx);
+ if (result == ISC_R_SUCCESS) {
+ dns_dumpctx_attach(dctx, dctxp);
+ return (DNS_R_CONTINUE);
+ }
+
+ dns_dumpctx_detach(&dctx);
+ return (result);
+}
+
+/*
+ * Dump an entire database into a master file.
+ */
+isc_result_t
+dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db,
+ dns_dbversion_t *version,
+ const dns_master_style_t *style,
+ FILE *f)
+{
+ return (dns_master_dumptostream2(mctx, db, version, style,
+ dns_masterformat_text, f));
+}
+
+isc_result_t
+dns_master_dumptostream2(isc_mem_t *mctx, dns_db_t *db,
+ dns_dbversion_t *version,
+ const dns_master_style_t *style,
+ dns_masterformat_t format, FILE *f)
+{
+ dns_dumpctx_t *dctx = NULL;
+ isc_result_t result;
+
+ result = dumpctx_create(mctx, db, version, style, f, &dctx, format);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dumptostreaminc(dctx);
+ INSIST(result != DNS_R_CONTINUE);
+ dns_dumpctx_detach(&dctx);
+ return (result);
+}
+
+static isc_result_t
+opentmp(isc_mem_t *mctx, const char *file, char **tempp, FILE **fp) {
+ FILE *f = NULL;
+ isc_result_t result;
+ char *tempname = NULL;
+ int tempnamelen;
+
+ tempnamelen = strlen(file) + 20;
+ tempname = isc_mem_allocate(mctx, tempnamelen);
+ if (tempname == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = isc_file_mktemplate(file, tempname, tempnamelen);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = isc_file_openunique(tempname, &f);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
+ "dumping master file: %s: open: %s",
+ tempname, isc_result_totext(result));
+ goto cleanup;
+ }
+ *tempp = tempname;
+ *fp = f;
+ return (ISC_R_SUCCESS);
+
+cleanup:
+ isc_mem_free(mctx, tempname);
+ return (result);
+}
+
+isc_result_t
+dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
+ const dns_master_style_t *style, const char *filename,
+ isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
+ dns_dumpctx_t **dctxp)
+{
+ return (dns_master_dumpinc2(mctx, db, version, style, filename, task,
+ done, done_arg, dctxp,
+ dns_masterformat_text));
+}
+
+isc_result_t
+dns_master_dumpinc2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
+ const dns_master_style_t *style, const char *filename,
+ isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
+ dns_dumpctx_t **dctxp, dns_masterformat_t format)
+{
+ FILE *f = NULL;
+ isc_result_t result;
+ char *tempname = NULL;
+ char *file = NULL;
+ dns_dumpctx_t *dctx = NULL;
+
+ file = isc_mem_strdup(mctx, filename);
+ if (file == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = opentmp(mctx, filename, &tempname, &f);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = dumpctx_create(mctx, db, version, style, f, &dctx, format);
+ if (result != ISC_R_SUCCESS) {
+ (void)isc_stdio_close(f);
+ (void)isc_file_remove(tempname);
+ goto cleanup;
+ }
+
+ isc_task_attach(task, &dctx->task);
+ dctx->done = done;
+ dctx->done_arg = done_arg;
+ dctx->nodes = 100;
+ dctx->file = file;
+ file = NULL;
+ dctx->tmpfile = tempname;
+ tempname = NULL;
+
+ result = task_send(dctx);
+ if (result == ISC_R_SUCCESS) {
+ dns_dumpctx_attach(dctx, dctxp);
+ return (DNS_R_CONTINUE);
+ }
+
+ cleanup:
+ if (dctx != NULL)
+ dns_dumpctx_detach(&dctx);
+ if (file != NULL)
+ isc_mem_free(mctx, file);
+ if (tempname != NULL)
+ isc_mem_free(mctx, tempname);
+ return (result);
+}
+
+isc_result_t
+dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
+ const dns_master_style_t *style, const char *filename)
+{
+ return (dns_master_dump2(mctx, db, version, style, filename,
+ dns_masterformat_text));
+}
+
+isc_result_t
+dns_master_dump2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
+ const dns_master_style_t *style, const char *filename,
+ dns_masterformat_t format)
+{
+ FILE *f = NULL;
+ isc_result_t result;
+ char *tempname;
+ dns_dumpctx_t *dctx = NULL;
+
+ result = opentmp(mctx, filename, &tempname, &f);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dumpctx_create(mctx, db, version, style, f, &dctx, format);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = dumptostreaminc(dctx);
+ INSIST(result != DNS_R_CONTINUE);
+ dns_dumpctx_detach(&dctx);
+
+ result = closeandrename(f, result, tempname, filename);
+
+ cleanup:
+ isc_mem_free(mctx, tempname);
+ return (result);
+}
+
+/*
+ * Dump a database node into a master file.
+ * XXX: this function assumes the text format.
+ */
+isc_result_t
+dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db,
+ dns_dbversion_t *version,
+ dns_dbnode_t *node, dns_name_t *name,
+ const dns_master_style_t *style,
+ FILE *f)
+{
+ isc_result_t result;
+ isc_buffer_t buffer;
+ char *bufmem;
+ isc_stdtime_t now;
+ dns_totext_ctx_t ctx;
+ dns_rdatasetiter_t *rdsiter = NULL;
+
+ result = totext_ctx_init(style, &ctx);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "could not set master file style");
+ return (ISC_R_UNEXPECTED);
+ }
+
+ isc_stdtime_get(&now);
+
+ bufmem = isc_mem_get(mctx, initial_buffer_length);
+ if (bufmem == NULL)
+ return (ISC_R_NOMEMORY);
+
+ isc_buffer_init(&buffer, bufmem, initial_buffer_length);
+
+ result = dns_db_allrdatasets(db, node, version, now, &rdsiter);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ result = dump_rdatasets_text(mctx, name, rdsiter, &ctx, &buffer, f);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ dns_rdatasetiter_destroy(&rdsiter);
+
+ result = ISC_R_SUCCESS;
+
+ failure:
+ isc_mem_put(mctx, buffer.base, buffer.length);
+ return (result);
+}
+
+isc_result_t
+dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
+ dns_dbnode_t *node, dns_name_t *name,
+ const dns_master_style_t *style, const char *filename)
+{
+ FILE *f = NULL;
+ isc_result_t result;
+
+ result = isc_stdio_open(filename, "w", &f);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
+ "dumping node to file: %s: open: %s", filename,
+ isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+
+ result = dns_master_dumpnodetostream(mctx, db, version, node, name,
+ style, f);
+
+ result = isc_stdio_close(f);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
+ "dumping master file: %s: close: %s", filename,
+ isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (result);
+}
+
+isc_result_t
+dns_master_stylecreate(dns_master_style_t **stylep, unsigned int flags,
+ unsigned int ttl_column, unsigned int class_column,
+ unsigned int type_column, unsigned int rdata_column,
+ unsigned int line_length, unsigned int tab_width,
+ isc_mem_t *mctx)
+{
+ dns_master_style_t *style;
+
+ REQUIRE(stylep != NULL && *stylep == NULL);
+ style = isc_mem_get(mctx, sizeof(*style));
+ if (style == NULL)
+ return (ISC_R_NOMEMORY);
+
+ style->flags = flags;
+ style->ttl_column = ttl_column;
+ style->class_column = class_column;
+ style->type_column = type_column;
+ style->rdata_column = rdata_column;
+ style->line_length = line_length;
+ style->tab_width = tab_width;
+
+ *stylep = style;
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_master_styledestroy(dns_master_style_t **stylep, isc_mem_t *mctx) {
+ dns_master_style_t *style;
+
+ REQUIRE(stylep != NULL && *stylep != NULL);
+ style = *stylep;
+ *stylep = NULL;
+ isc_mem_put(mctx, style, sizeof(*style));
+}
diff --git a/lib/dns/message.c b/lib/dns/message.c
new file mode 100644
index 0000000..e8e4948
--- /dev/null
+++ b/lib/dns/message.c
@@ -0,0 +1,3265 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: message.c,v 1.222.18.14 2007/08/28 07:20:04 tbox Exp $ */
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <config.h>
+
+#include <isc/buffer.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/util.h>
+
+#include <dns/dnssec.h>
+#include <dns/keyvalues.h>
+#include <dns/log.h>
+#include <dns/masterdump.h>
+#include <dns/message.h>
+#include <dns/opcode.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/result.h>
+#include <dns/tsig.h>
+#include <dns/view.h>
+
+#define DNS_MESSAGE_OPCODE_MASK 0x7800U
+#define DNS_MESSAGE_OPCODE_SHIFT 11
+#define DNS_MESSAGE_RCODE_MASK 0x000fU
+#define DNS_MESSAGE_FLAG_MASK 0x8ff0U
+#define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U
+#define DNS_MESSAGE_EDNSRCODE_SHIFT 24
+#define DNS_MESSAGE_EDNSVERSION_MASK 0x00ff0000U
+#define DNS_MESSAGE_EDNSVERSION_SHIFT 16
+
+#define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \
+ && ((s) < DNS_SECTION_MAX))
+#define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \
+ && ((s) < DNS_SECTION_MAX))
+#define ADD_STRING(b, s) {if (strlen(s) >= \
+ isc_buffer_availablelength(b)) \
+ return(ISC_R_NOSPACE); else \
+ isc_buffer_putstr(b, s);}
+#define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \
+ && ((s) < DNS_PSEUDOSECTION_MAX))
+
+/*%
+ * This is the size of each individual scratchpad buffer, and the numbers
+ * of various block allocations used within the server.
+ * XXXMLG These should come from a config setting.
+ */
+#define SCRATCHPAD_SIZE 512
+#define NAME_COUNT 8
+#define OFFSET_COUNT 4
+#define RDATA_COUNT 8
+#define RDATALIST_COUNT 8
+#define RDATASET_COUNT RDATALIST_COUNT
+
+/*%
+ * Text representation of the different items, for message_totext
+ * functions.
+ */
+static const char *sectiontext[] = {
+ "QUESTION",
+ "ANSWER",
+ "AUTHORITY",
+ "ADDITIONAL"
+};
+
+static const char *updsectiontext[] = {
+ "ZONE",
+ "PREREQUISITE",
+ "UPDATE",
+ "ADDITIONAL"
+};
+
+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"
+};
+
+
+/*%
+ * "helper" type, which consists of a block of some type, and is linkable.
+ * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
+ * size, or the allocated elements will not be alligned correctly.
+ */
+struct dns_msgblock {
+ unsigned int count;
+ unsigned int remaining;
+ ISC_LINK(dns_msgblock_t) link;
+}; /* dynamically sized */
+
+static inline dns_msgblock_t *
+msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
+
+#define msgblock_get(block, type) \
+ ((type *)msgblock_internalget(block, sizeof(type)))
+
+static inline void *
+msgblock_internalget(dns_msgblock_t *, unsigned int);
+
+static inline void
+msgblock_reset(dns_msgblock_t *);
+
+static inline void
+msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
+
+/*
+ * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory
+ * is free, return NULL.
+ */
+static inline dns_msgblock_t *
+msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
+ unsigned int count)
+{
+ dns_msgblock_t *block;
+ unsigned int length;
+
+ length = sizeof(dns_msgblock_t) + (sizeof_type * count);
+
+ block = isc_mem_get(mctx, length);
+ if (block == NULL)
+ return (NULL);
+
+ block->count = count;
+ block->remaining = count;
+
+ ISC_LINK_INIT(block, link);
+
+ return (block);
+}
+
+/*
+ * Return an element from the msgblock. If no more are available, return
+ * NULL.
+ */
+static inline void *
+msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
+ void *ptr;
+
+ if (block == NULL || block->remaining == 0)
+ return (NULL);
+
+ block->remaining--;
+
+ ptr = (((unsigned char *)block)
+ + sizeof(dns_msgblock_t)
+ + (sizeof_type * block->remaining));
+
+ return (ptr);
+}
+
+static inline void
+msgblock_reset(dns_msgblock_t *block) {
+ block->remaining = block->count;
+}
+
+/*
+ * Release memory associated with a message block.
+ */
+static inline void
+msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
+{
+ unsigned int length;
+
+ length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
+
+ isc_mem_put(mctx, block, length);
+}
+
+/*
+ * Allocate a new dynamic buffer, and attach it to this message as the
+ * "current" buffer. (which is always the last on the list, for our
+ * uses)
+ */
+static inline isc_result_t
+newbuffer(dns_message_t *msg, unsigned int size) {
+ isc_result_t result;
+ isc_buffer_t *dynbuf;
+
+ dynbuf = NULL;
+ result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOMEMORY);
+
+ ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_buffer_t *
+currentbuffer(dns_message_t *msg) {
+ isc_buffer_t *dynbuf;
+
+ dynbuf = ISC_LIST_TAIL(msg->scratchpad);
+ INSIST(dynbuf != NULL);
+
+ return (dynbuf);
+}
+
+static inline void
+releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
+ ISC_LIST_PREPEND(msg->freerdata, rdata, link);
+}
+
+static inline dns_rdata_t *
+newrdata(dns_message_t *msg) {
+ dns_msgblock_t *msgblock;
+ dns_rdata_t *rdata;
+
+ rdata = ISC_LIST_HEAD(msg->freerdata);
+ if (rdata != NULL) {
+ ISC_LIST_UNLINK(msg->freerdata, rdata, link);
+ return (rdata);
+ }
+
+ msgblock = ISC_LIST_TAIL(msg->rdatas);
+ rdata = msgblock_get(msgblock, dns_rdata_t);
+ if (rdata == NULL) {
+ msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
+ RDATA_COUNT);
+ if (msgblock == NULL)
+ return (NULL);
+
+ ISC_LIST_APPEND(msg->rdatas, msgblock, link);
+
+ rdata = msgblock_get(msgblock, dns_rdata_t);
+ }
+
+ dns_rdata_init(rdata);
+ return (rdata);
+}
+
+static inline void
+releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
+ ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
+}
+
+static inline dns_rdatalist_t *
+newrdatalist(dns_message_t *msg) {
+ dns_msgblock_t *msgblock;
+ dns_rdatalist_t *rdatalist;
+
+ rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
+ if (rdatalist != NULL) {
+ ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
+ return (rdatalist);
+ }
+
+ msgblock = ISC_LIST_TAIL(msg->rdatalists);
+ rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
+ if (rdatalist == NULL) {
+ msgblock = msgblock_allocate(msg->mctx,
+ sizeof(dns_rdatalist_t),
+ RDATALIST_COUNT);
+ if (msgblock == NULL)
+ return (NULL);
+
+ ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
+
+ rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
+ }
+
+ return (rdatalist);
+}
+
+static inline dns_offsets_t *
+newoffsets(dns_message_t *msg) {
+ dns_msgblock_t *msgblock;
+ dns_offsets_t *offsets;
+
+ msgblock = ISC_LIST_TAIL(msg->offsets);
+ offsets = msgblock_get(msgblock, dns_offsets_t);
+ if (offsets == NULL) {
+ msgblock = msgblock_allocate(msg->mctx,
+ sizeof(dns_offsets_t),
+ OFFSET_COUNT);
+ if (msgblock == NULL)
+ return (NULL);
+
+ ISC_LIST_APPEND(msg->offsets, msgblock, link);
+
+ offsets = msgblock_get(msgblock, dns_offsets_t);
+ }
+
+ return (offsets);
+}
+
+static inline void
+msginitheader(dns_message_t *m) {
+ m->id = 0;
+ m->flags = 0;
+ m->rcode = 0;
+ m->opcode = 0;
+ m->rdclass = 0;
+}
+
+static inline void
+msginitprivate(dns_message_t *m) {
+ unsigned int i;
+
+ for (i = 0; i < DNS_SECTION_MAX; i++) {
+ m->cursors[i] = NULL;
+ m->counts[i] = 0;
+ }
+ m->opt = NULL;
+ m->sig0 = NULL;
+ m->sig0name = NULL;
+ m->tsig = NULL;
+ m->tsigname = NULL;
+ m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */
+ m->opt_reserved = 0;
+ m->sig_reserved = 0;
+ m->reserved = 0;
+ m->buffer = NULL;
+}
+
+static inline void
+msginittsig(dns_message_t *m) {
+ m->tsigstatus = dns_rcode_noerror;
+ m->querytsigstatus = dns_rcode_noerror;
+ m->tsigkey = NULL;
+ m->tsigctx = NULL;
+ m->sigstart = -1;
+ m->sig0key = NULL;
+ m->sig0status = dns_rcode_noerror;
+ m->timeadjust = 0;
+}
+
+/*
+ * Init elements to default state. Used both when allocating a new element
+ * and when resetting one.
+ */
+static inline void
+msginit(dns_message_t *m) {
+ msginitheader(m);
+ msginitprivate(m);
+ msginittsig(m);
+ m->header_ok = 0;
+ m->question_ok = 0;
+ m->tcp_continuation = 0;
+ m->verified_sig = 0;
+ m->verify_attempted = 0;
+ m->order = NULL;
+ m->order_arg = NULL;
+ m->query.base = NULL;
+ m->query.length = 0;
+ m->free_query = 0;
+ m->saved.base = NULL;
+ m->saved.length = 0;
+ m->free_saved = 0;
+ m->querytsig = NULL;
+}
+
+static inline void
+msgresetnames(dns_message_t *msg, unsigned int first_section) {
+ unsigned int i;
+ dns_name_t *name, *next_name;
+ dns_rdataset_t *rds, *next_rds;
+
+ /*
+ * Clean up name lists by calling the rdataset disassociate function.
+ */
+ for (i = first_section; i < DNS_SECTION_MAX; i++) {
+ name = ISC_LIST_HEAD(msg->sections[i]);
+ while (name != NULL) {
+ next_name = ISC_LIST_NEXT(name, link);
+ ISC_LIST_UNLINK(msg->sections[i], name, link);
+
+ rds = ISC_LIST_HEAD(name->list);
+ while (rds != NULL) {
+ next_rds = ISC_LIST_NEXT(rds, link);
+ ISC_LIST_UNLINK(name->list, rds, link);
+
+ INSIST(dns_rdataset_isassociated(rds));
+ dns_rdataset_disassociate(rds);
+ isc_mempool_put(msg->rdspool, rds);
+ rds = next_rds;
+ }
+ if (dns_name_dynamic(name))
+ dns_name_free(name, msg->mctx);
+ isc_mempool_put(msg->namepool, name);
+ name = next_name;
+ }
+ }
+}
+
+static void
+msgresetopt(dns_message_t *msg)
+{
+ if (msg->opt != NULL) {
+ if (msg->opt_reserved > 0) {
+ dns_message_renderrelease(msg, msg->opt_reserved);
+ msg->opt_reserved = 0;
+ }
+ INSIST(dns_rdataset_isassociated(msg->opt));
+ dns_rdataset_disassociate(msg->opt);
+ isc_mempool_put(msg->rdspool, msg->opt);
+ msg->opt = NULL;
+ }
+}
+
+static void
+msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
+ if (msg->sig_reserved > 0) {
+ dns_message_renderrelease(msg, msg->sig_reserved);
+ msg->sig_reserved = 0;
+ }
+ if (msg->tsig != NULL) {
+ INSIST(dns_rdataset_isassociated(msg->tsig));
+ INSIST(msg->namepool != NULL);
+ if (replying) {
+ INSIST(msg->querytsig == NULL);
+ msg->querytsig = msg->tsig;
+ } else {
+ dns_rdataset_disassociate(msg->tsig);
+ isc_mempool_put(msg->rdspool, msg->tsig);
+ if (msg->querytsig != NULL) {
+ dns_rdataset_disassociate(msg->querytsig);
+ isc_mempool_put(msg->rdspool, msg->querytsig);
+ }
+ }
+ if (dns_name_dynamic(msg->tsigname))
+ dns_name_free(msg->tsigname, msg->mctx);
+ isc_mempool_put(msg->namepool, msg->tsigname);
+ msg->tsig = NULL;
+ msg->tsigname = NULL;
+ } else if (msg->querytsig != NULL && !replying) {
+ dns_rdataset_disassociate(msg->querytsig);
+ isc_mempool_put(msg->rdspool, msg->querytsig);
+ msg->querytsig = NULL;
+ }
+ if (msg->sig0 != NULL) {
+ INSIST(dns_rdataset_isassociated(msg->sig0));
+ dns_rdataset_disassociate(msg->sig0);
+ isc_mempool_put(msg->rdspool, msg->sig0);
+ if (msg->sig0name != NULL) {
+ if (dns_name_dynamic(msg->sig0name))
+ dns_name_free(msg->sig0name, msg->mctx);
+ isc_mempool_put(msg->namepool, msg->sig0name);
+ }
+ msg->sig0 = NULL;
+ msg->sig0name = NULL;
+ }
+}
+
+/*
+ * Free all but one (or everything) for this message. This is used by
+ * both dns_message_reset() and dns_message_destroy().
+ */
+static void
+msgreset(dns_message_t *msg, isc_boolean_t everything) {
+ dns_msgblock_t *msgblock, *next_msgblock;
+ isc_buffer_t *dynbuf, *next_dynbuf;
+ dns_rdata_t *rdata;
+ dns_rdatalist_t *rdatalist;
+
+ msgresetnames(msg, 0);
+ msgresetopt(msg);
+ msgresetsigs(msg, ISC_FALSE);
+
+ /*
+ * Clean up linked lists.
+ */
+
+ /*
+ * Run through the free lists, and just unlink anything found there.
+ * The memory isn't lost since these are part of message blocks we
+ * have allocated.
+ */
+ rdata = ISC_LIST_HEAD(msg->freerdata);
+ while (rdata != NULL) {
+ ISC_LIST_UNLINK(msg->freerdata, rdata, link);
+ rdata = ISC_LIST_HEAD(msg->freerdata);
+ }
+ rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
+ while (rdatalist != NULL) {
+ ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
+ rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
+ }
+
+ dynbuf = ISC_LIST_HEAD(msg->scratchpad);
+ INSIST(dynbuf != NULL);
+ if (!everything) {
+ isc_buffer_clear(dynbuf);
+ dynbuf = ISC_LIST_NEXT(dynbuf, link);
+ }
+ while (dynbuf != NULL) {
+ next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
+ ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
+ isc_buffer_free(&dynbuf);
+ dynbuf = next_dynbuf;
+ }
+
+ msgblock = ISC_LIST_HEAD(msg->rdatas);
+ if (!everything && msgblock != NULL) {
+ msgblock_reset(msgblock);
+ msgblock = ISC_LIST_NEXT(msgblock, link);
+ }
+ while (msgblock != NULL) {
+ next_msgblock = ISC_LIST_NEXT(msgblock, link);
+ ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
+ msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
+ msgblock = next_msgblock;
+ }
+
+ /*
+ * rdatalists could be empty.
+ */
+
+ msgblock = ISC_LIST_HEAD(msg->rdatalists);
+ if (!everything && msgblock != NULL) {
+ msgblock_reset(msgblock);
+ msgblock = ISC_LIST_NEXT(msgblock, link);
+ }
+ while (msgblock != NULL) {
+ next_msgblock = ISC_LIST_NEXT(msgblock, link);
+ ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
+ msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
+ msgblock = next_msgblock;
+ }
+
+ msgblock = ISC_LIST_HEAD(msg->offsets);
+ if (!everything && msgblock != NULL) {
+ msgblock_reset(msgblock);
+ msgblock = ISC_LIST_NEXT(msgblock, link);
+ }
+ while (msgblock != NULL) {
+ next_msgblock = ISC_LIST_NEXT(msgblock, link);
+ ISC_LIST_UNLINK(msg->offsets, msgblock, link);
+ msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
+ msgblock = next_msgblock;
+ }
+
+ if (msg->tsigkey != NULL) {
+ dns_tsigkey_detach(&msg->tsigkey);
+ msg->tsigkey = NULL;
+ }
+
+ if (msg->query.base != NULL) {
+ if (msg->free_query != 0)
+ isc_mem_put(msg->mctx, msg->query.base,
+ msg->query.length);
+ msg->query.base = NULL;
+ msg->query.length = 0;
+ }
+
+ if (msg->saved.base != NULL) {
+ if (msg->free_saved != 0)
+ isc_mem_put(msg->mctx, msg->saved.base,
+ msg->saved.length);
+ msg->saved.base = NULL;
+ msg->saved.length = 0;
+ }
+
+ /*
+ * cleanup the buffer cleanup list
+ */
+ dynbuf = ISC_LIST_HEAD(msg->cleanup);
+ while (dynbuf != NULL) {
+ next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
+ ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
+ isc_buffer_free(&dynbuf);
+ dynbuf = next_dynbuf;
+ }
+
+ /*
+ * Set other bits to normal default values.
+ */
+ if (!everything)
+ msginit(msg);
+
+ ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
+ ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
+}
+
+static unsigned int
+spacefortsig(dns_tsigkey_t *key, int otherlen) {
+ isc_region_t r1, r2;
+ unsigned int x;
+ isc_result_t result;
+
+ /*
+ * The space required for an TSIG record is:
+ *
+ * n1 bytes for the name
+ * 2 bytes for the type
+ * 2 bytes for the class
+ * 4 bytes for the ttl
+ * 2 bytes for the rdlength
+ * n2 bytes for the algorithm name
+ * 6 bytes for the time signed
+ * 2 bytes for the fudge
+ * 2 bytes for the MAC size
+ * x bytes for the MAC
+ * 2 bytes for the original id
+ * 2 bytes for the error
+ * 2 bytes for the other data length
+ * y bytes for the other data (at most)
+ * ---------------------------------
+ * 26 + n1 + n2 + x + y bytes
+ */
+
+ dns_name_toregion(&key->name, &r1);
+ dns_name_toregion(key->algorithm, &r2);
+ if (key->key == NULL)
+ x = 0;
+ else {
+ result = dst_key_sigsize(key->key, &x);
+ if (result != ISC_R_SUCCESS)
+ x = 0;
+ }
+ return (26 + r1.length + r2.length + x + otherlen);
+}
+
+isc_result_t
+dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
+{
+ dns_message_t *m;
+ isc_result_t result;
+ isc_buffer_t *dynbuf;
+ unsigned int i;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(msgp != NULL);
+ REQUIRE(*msgp == NULL);
+ REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
+ || intent == DNS_MESSAGE_INTENTRENDER);
+
+ m = isc_mem_get(mctx, sizeof(dns_message_t));
+ if (m == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /*
+ * No allocations until further notice. Just initialize all lists
+ * and other members that are freed in the cleanup phase here.
+ */
+
+ m->magic = DNS_MESSAGE_MAGIC;
+ m->from_to_wire = intent;
+ msginit(m);
+
+ for (i = 0; i < DNS_SECTION_MAX; i++)
+ ISC_LIST_INIT(m->sections[i]);
+ m->mctx = mctx;
+
+ ISC_LIST_INIT(m->scratchpad);
+ ISC_LIST_INIT(m->cleanup);
+ m->namepool = NULL;
+ m->rdspool = NULL;
+ ISC_LIST_INIT(m->rdatas);
+ ISC_LIST_INIT(m->rdatalists);
+ ISC_LIST_INIT(m->offsets);
+ ISC_LIST_INIT(m->freerdata);
+ ISC_LIST_INIT(m->freerdatalist);
+
+ /*
+ * Ok, it is safe to allocate (and then "goto cleanup" if failure)
+ */
+
+ result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ isc_mempool_setfreemax(m->namepool, NAME_COUNT);
+ isc_mempool_setname(m->namepool, "msg:names");
+
+ result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
+ &m->rdspool);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
+ isc_mempool_setname(m->rdspool, "msg:rdataset");
+
+ dynbuf = NULL;
+ result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
+
+ m->cctx = NULL;
+
+ *msgp = m;
+ return (ISC_R_SUCCESS);
+
+ /*
+ * Cleanup for error returns.
+ */
+ cleanup:
+ dynbuf = ISC_LIST_HEAD(m->scratchpad);
+ if (dynbuf != NULL) {
+ ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
+ isc_buffer_free(&dynbuf);
+ }
+ if (m->namepool != NULL)
+ isc_mempool_destroy(&m->namepool);
+ if (m->rdspool != NULL)
+ isc_mempool_destroy(&m->rdspool);
+ m->magic = 0;
+ isc_mem_put(mctx, m, sizeof(dns_message_t));
+
+ return (ISC_R_NOMEMORY);
+}
+
+void
+dns_message_reset(dns_message_t *msg, unsigned int intent) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
+ || intent == DNS_MESSAGE_INTENTRENDER);
+
+ msgreset(msg, ISC_FALSE);
+ msg->from_to_wire = intent;
+}
+
+void
+dns_message_destroy(dns_message_t **msgp) {
+ dns_message_t *msg;
+
+ REQUIRE(msgp != NULL);
+ REQUIRE(DNS_MESSAGE_VALID(*msgp));
+
+ msg = *msgp;
+ *msgp = NULL;
+
+ msgreset(msg, ISC_TRUE);
+ isc_mempool_destroy(&msg->namepool);
+ isc_mempool_destroy(&msg->rdspool);
+ msg->magic = 0;
+ isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
+}
+
+static isc_result_t
+findname(dns_name_t **foundname, dns_name_t *target,
+ dns_namelist_t *section)
+{
+ dns_name_t *curr;
+
+ for (curr = ISC_LIST_TAIL(*section);
+ curr != NULL;
+ curr = ISC_LIST_PREV(curr, link)) {
+ if (dns_name_equal(curr, target)) {
+ if (foundname != NULL)
+ *foundname = curr;
+ return (ISC_R_SUCCESS);
+ }
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+isc_result_t
+dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, dns_rdatatype_t covers,
+ dns_rdataset_t **rdataset)
+{
+ dns_rdataset_t *curr;
+
+ if (rdataset != NULL) {
+ REQUIRE(*rdataset == NULL);
+ }
+
+ for (curr = ISC_LIST_TAIL(name->list);
+ curr != NULL;
+ curr = ISC_LIST_PREV(curr, link)) {
+ if (curr->rdclass == rdclass &&
+ curr->type == type && curr->covers == covers) {
+ if (rdataset != NULL)
+ *rdataset = curr;
+ return (ISC_R_SUCCESS);
+ }
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+isc_result_t
+dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
+ dns_rdatatype_t covers, dns_rdataset_t **rdataset)
+{
+ dns_rdataset_t *curr;
+
+ REQUIRE(name != NULL);
+ if (rdataset != NULL) {
+ REQUIRE(*rdataset == NULL);
+ }
+
+ for (curr = ISC_LIST_TAIL(name->list);
+ curr != NULL;
+ curr = ISC_LIST_PREV(curr, link)) {
+ if (curr->type == type && curr->covers == covers) {
+ if (rdataset != NULL)
+ *rdataset = curr;
+ return (ISC_R_SUCCESS);
+ }
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+/*
+ * Read a name from buffer "source".
+ */
+static isc_result_t
+getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
+ dns_decompress_t *dctx)
+{
+ isc_buffer_t *scratch;
+ isc_result_t result;
+ unsigned int tries;
+
+ scratch = currentbuffer(msg);
+
+ /*
+ * First try: use current buffer.
+ * Second try: allocate a new buffer and use that.
+ */
+ tries = 0;
+ while (tries < 2) {
+ result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
+ scratch);
+
+ if (result == ISC_R_NOSPACE) {
+ tries++;
+
+ result = newbuffer(msg, SCRATCHPAD_SIZE);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ scratch = currentbuffer(msg);
+ dns_name_reset(name);
+ } else {
+ return (result);
+ }
+ }
+
+ INSIST(0); /* Cannot get here... */
+ return (ISC_R_UNEXPECTED);
+}
+
+static isc_result_t
+getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
+ dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
+ unsigned int rdatalen, dns_rdata_t *rdata)
+{
+ isc_buffer_t *scratch;
+ isc_result_t result;
+ unsigned int tries;
+ unsigned int trysize;
+
+ scratch = currentbuffer(msg);
+
+ isc_buffer_setactive(source, rdatalen);
+
+ /*
+ * First try: use current buffer.
+ * Second try: allocate a new buffer of size
+ * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
+ * (the data will fit if it was not more than 50% compressed)
+ * Subsequent tries: double buffer size on each try.
+ */
+ tries = 0;
+ trysize = 0;
+ /* XXX possibly change this to a while (tries < 2) loop */
+ for (;;) {
+ result = dns_rdata_fromwire(rdata, rdclass, rdtype,
+ source, dctx, 0,
+ scratch);
+
+ if (result == ISC_R_NOSPACE) {
+ if (tries == 0) {
+ trysize = 2 * rdatalen;
+ if (trysize < SCRATCHPAD_SIZE)
+ trysize = SCRATCHPAD_SIZE;
+ } else {
+ INSIST(trysize != 0);
+ if (trysize >= 65535)
+ return (ISC_R_NOSPACE);
+ /* XXX DNS_R_RRTOOLONG? */
+ trysize *= 2;
+ }
+ tries++;
+ result = newbuffer(msg, trysize);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ scratch = currentbuffer(msg);
+ } else {
+ return (result);
+ }
+ }
+}
+
+#define DO_FORMERR \
+ do { \
+ if (best_effort) \
+ seen_problem = ISC_TRUE; \
+ else { \
+ result = DNS_R_FORMERR; \
+ goto cleanup; \
+ } \
+ } while (0)
+
+static isc_result_t
+getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
+ unsigned int options)
+{
+ isc_region_t r;
+ unsigned int count;
+ dns_name_t *name;
+ dns_name_t *name2;
+ dns_offsets_t *offsets;
+ dns_rdataset_t *rdataset;
+ dns_rdatalist_t *rdatalist;
+ isc_result_t result;
+ dns_rdatatype_t rdtype;
+ dns_rdataclass_t rdclass;
+ dns_namelist_t *section;
+ isc_boolean_t free_name;
+ isc_boolean_t best_effort;
+ isc_boolean_t seen_problem;
+
+ section = &msg->sections[DNS_SECTION_QUESTION];
+
+ best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
+ seen_problem = ISC_FALSE;
+
+ name = NULL;
+ rdataset = NULL;
+ rdatalist = NULL;
+
+ for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
+ name = isc_mempool_get(msg->namepool);
+ if (name == NULL)
+ return (ISC_R_NOMEMORY);
+ free_name = ISC_TRUE;
+
+ offsets = newoffsets(msg);
+ if (offsets == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ dns_name_init(name, *offsets);
+
+ /*
+ * Parse the name out of this packet.
+ */
+ isc_buffer_remainingregion(source, &r);
+ isc_buffer_setactive(source, r.length);
+ result = getname(name, source, msg, dctx);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ /*
+ * Run through the section, looking to see if this name
+ * is already there. If it is found, put back the allocated
+ * name since we no longer need it, and set our name pointer
+ * to point to the name we found.
+ */
+ result = findname(&name2, name, section);
+
+ /*
+ * If it is the first name in the section, accept it.
+ *
+ * If it is not, but is not the same as the name already
+ * in the question section, append to the section. Note that
+ * here in the question section this is illegal, so return
+ * FORMERR. In the future, check the opcode to see if
+ * this should be legal or not. In either case we no longer
+ * need this name pointer.
+ */
+ if (result != ISC_R_SUCCESS) {
+ if (!ISC_LIST_EMPTY(*section))
+ DO_FORMERR;
+ ISC_LIST_APPEND(*section, name, link);
+ free_name = ISC_FALSE;
+ } else {
+ isc_mempool_put(msg->namepool, name);
+ name = name2;
+ name2 = NULL;
+ free_name = ISC_FALSE;
+ }
+
+ /*
+ * Get type and class.
+ */
+ isc_buffer_remainingregion(source, &r);
+ if (r.length < 4) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto cleanup;
+ }
+ rdtype = isc_buffer_getuint16(source);
+ rdclass = isc_buffer_getuint16(source);
+
+ /*
+ * If this class is different than the one we already read,
+ * this is an error.
+ */
+ if (msg->state == DNS_SECTION_ANY) {
+ msg->state = DNS_SECTION_QUESTION;
+ msg->rdclass = rdclass;
+ } else if (msg->rdclass != rdclass)
+ DO_FORMERR;
+
+ /*
+ * Can't ask the same question twice.
+ */
+ result = dns_message_find(name, rdclass, rdtype, 0, NULL);
+ if (result == ISC_R_SUCCESS)
+ DO_FORMERR;
+
+ /*
+ * Allocate a new rdatalist.
+ */
+ rdatalist = newrdatalist(msg);
+ if (rdatalist == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ rdataset = isc_mempool_get(msg->rdspool);
+ if (rdataset == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Convert rdatalist to rdataset, and attach the latter to
+ * the name.
+ */
+ rdatalist->type = rdtype;
+ rdatalist->covers = 0;
+ rdatalist->rdclass = rdclass;
+ rdatalist->ttl = 0;
+ ISC_LIST_INIT(rdatalist->rdata);
+
+ dns_rdataset_init(rdataset);
+ result = dns_rdatalist_tordataset(rdatalist, rdataset);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
+
+ ISC_LIST_APPEND(name->list, rdataset, link);
+ rdataset = NULL;
+ }
+
+ if (seen_problem)
+ return (DNS_R_RECOVERABLE);
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (rdataset != NULL) {
+ INSIST(!dns_rdataset_isassociated(rdataset));
+ isc_mempool_put(msg->rdspool, rdataset);
+ }
+#if 0
+ if (rdatalist != NULL)
+ isc_mempool_put(msg->rdlpool, rdatalist);
+#endif
+ if (free_name)
+ isc_mempool_put(msg->namepool, name);
+
+ return (result);
+}
+
+static isc_boolean_t
+update(dns_section_t section, dns_rdataclass_t rdclass) {
+ if (section == DNS_SECTION_PREREQUISITE)
+ return (ISC_TF(rdclass == dns_rdataclass_any ||
+ rdclass == dns_rdataclass_none));
+ if (section == DNS_SECTION_UPDATE)
+ return (ISC_TF(rdclass == dns_rdataclass_any));
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
+ dns_section_t sectionid, unsigned int options)
+{
+ isc_region_t r;
+ unsigned int count, rdatalen;
+ dns_name_t *name;
+ dns_name_t *name2;
+ dns_offsets_t *offsets;
+ dns_rdataset_t *rdataset;
+ dns_rdatalist_t *rdatalist;
+ isc_result_t result;
+ dns_rdatatype_t rdtype, covers;
+ dns_rdataclass_t rdclass;
+ dns_rdata_t *rdata;
+ dns_ttl_t ttl;
+ dns_namelist_t *section;
+ isc_boolean_t free_name, free_rdataset;
+ isc_boolean_t preserve_order, best_effort, seen_problem;
+ isc_boolean_t issigzero;
+
+ preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
+ best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
+ seen_problem = ISC_FALSE;
+
+ for (count = 0; count < msg->counts[sectionid]; count++) {
+ int recstart = source->current;
+ isc_boolean_t skip_name_search, skip_type_search;
+
+ section = &msg->sections[sectionid];
+
+ skip_name_search = ISC_FALSE;
+ skip_type_search = ISC_FALSE;
+ free_name = ISC_FALSE;
+ free_rdataset = ISC_FALSE;
+
+ name = isc_mempool_get(msg->namepool);
+ if (name == NULL)
+ return (ISC_R_NOMEMORY);
+ free_name = ISC_TRUE;
+
+ offsets = newoffsets(msg);
+ if (offsets == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ dns_name_init(name, *offsets);
+
+ /*
+ * Parse the name out of this packet.
+ */
+ isc_buffer_remainingregion(source, &r);
+ isc_buffer_setactive(source, r.length);
+ result = getname(name, source, msg, dctx);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ /*
+ * Get type, class, ttl, and rdatalen. Verify that at least
+ * rdatalen bytes remain. (Some of this is deferred to
+ * later.)
+ */
+ isc_buffer_remainingregion(source, &r);
+ if (r.length < 2 + 2 + 4 + 2) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto cleanup;
+ }
+ rdtype = isc_buffer_getuint16(source);
+ rdclass = isc_buffer_getuint16(source);
+
+ /*
+ * If there was no question section, we may not yet have
+ * established a class. Do so now.
+ */
+ if (msg->state == DNS_SECTION_ANY &&
+ rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
+ rdtype != dns_rdatatype_tsig && /* class is ANY */
+ rdtype != dns_rdatatype_tkey) { /* class is undefined */
+ msg->rdclass = rdclass;
+ msg->state = DNS_SECTION_QUESTION;
+ }
+
+ /*
+ * If this class is different than the one in the question
+ * section, bail.
+ */
+ if (msg->opcode != dns_opcode_update
+ && rdtype != dns_rdatatype_tsig
+ && rdtype != dns_rdatatype_opt
+ && rdtype != dns_rdatatype_dnskey /* in a TKEY query */
+ && rdtype != dns_rdatatype_sig /* SIG(0) */
+ && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
+ && msg->rdclass != dns_rdataclass_any
+ && msg->rdclass != rdclass)
+ DO_FORMERR;
+
+ /*
+ * Special type handling for TSIG, OPT, and TKEY.
+ */
+ if (rdtype == dns_rdatatype_tsig) {
+ /*
+ * If it is a tsig, verify that it is in the
+ * additional data section.
+ */
+ if (sectionid != DNS_SECTION_ADDITIONAL ||
+ rdclass != dns_rdataclass_any ||
+ count != msg->counts[sectionid] - 1)
+ DO_FORMERR;
+ msg->sigstart = recstart;
+ skip_name_search = ISC_TRUE;
+ skip_type_search = ISC_TRUE;
+ } else if (rdtype == dns_rdatatype_opt) {
+ /*
+ * The name of an OPT record must be ".", it
+ * must be in the additional data section, and
+ * it must be the first OPT we've seen.
+ */
+ if (!dns_name_equal(dns_rootname, name) ||
+ msg->opt != NULL)
+ DO_FORMERR;
+ skip_name_search = ISC_TRUE;
+ skip_type_search = ISC_TRUE;
+ } else if (rdtype == dns_rdatatype_tkey) {
+ /*
+ * A TKEY must be in the additional section if this
+ * is a query, and the answer section if this is a
+ * response. Unless it's a Win2000 client.
+ *
+ * Its class is ignored.
+ */
+ dns_section_t tkeysection;
+
+ if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
+ tkeysection = DNS_SECTION_ADDITIONAL;
+ else
+ tkeysection = DNS_SECTION_ANSWER;
+ if (sectionid != tkeysection &&
+ sectionid != DNS_SECTION_ANSWER)
+ DO_FORMERR;
+ }
+
+ /*
+ * ... now get ttl and rdatalen, and check buffer.
+ */
+ ttl = isc_buffer_getuint32(source);
+ rdatalen = isc_buffer_getuint16(source);
+ r.length -= (2 + 2 + 4 + 2);
+ if (r.length < rdatalen) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto cleanup;
+ }
+
+ /*
+ * Read the rdata from the wire format. Interpret the
+ * rdata according to its actual class, even if it had a
+ * DynDNS meta-class in the packet (unless this is a TSIG).
+ * Then put the meta-class back into the finished rdata.
+ */
+ rdata = newrdata(msg);
+ if (rdata == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ if (msg->opcode == dns_opcode_update &&
+ update(sectionid, rdclass)) {
+ if (rdatalen != 0) {
+ result = DNS_R_FORMERR;
+ goto cleanup;
+ }
+ /*
+ * When the rdata is empty, the data pointer is
+ * never dereferenced, but it must still be non-NULL.
+ * Casting 1 rather than "" avoids warnings about
+ * discarding the const attribute of a string,
+ * for compilers that would warn about such things.
+ */
+ rdata->data = (unsigned char *)1;
+ rdata->length = 0;
+ rdata->rdclass = rdclass;
+ rdata->type = rdtype;
+ rdata->flags = DNS_RDATA_UPDATE;
+ result = ISC_R_SUCCESS;
+ } else if (rdclass == dns_rdataclass_none &&
+ msg->opcode == dns_opcode_update &&
+ sectionid == DNS_SECTION_UPDATE) {
+ result = getrdata(source, msg, dctx, msg->rdclass,
+ rdtype, rdatalen, rdata);
+ } else
+ result = getrdata(source, msg, dctx, rdclass,
+ rdtype, rdatalen, rdata);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ rdata->rdclass = rdclass;
+ issigzero = ISC_FALSE;
+ if (rdtype == dns_rdatatype_rrsig &&
+ rdata->flags == 0) {
+ covers = dns_rdata_covers(rdata);
+ if (covers == 0)
+ DO_FORMERR;
+ } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
+ rdata->flags == 0) {
+ covers = dns_rdata_covers(rdata);
+ if (covers == 0) {
+ if (sectionid != DNS_SECTION_ADDITIONAL ||
+ count != msg->counts[sectionid] - 1)
+ DO_FORMERR;
+ msg->sigstart = recstart;
+ skip_name_search = ISC_TRUE;
+ skip_type_search = ISC_TRUE;
+ issigzero = ISC_TRUE;
+ }
+ } else
+ covers = 0;
+
+ /*
+ * If we are doing a dynamic update or this is a meta-type,
+ * don't bother searching for a name, just append this one
+ * to the end of the message.
+ */
+ if (preserve_order || msg->opcode == dns_opcode_update ||
+ skip_name_search) {
+ if (rdtype != dns_rdatatype_opt &&
+ rdtype != dns_rdatatype_tsig &&
+ !issigzero)
+ {
+ ISC_LIST_APPEND(*section, name, link);
+ free_name = ISC_FALSE;
+ }
+ } else {
+ /*
+ * Run through the section, looking to see if this name
+ * is already there. If it is found, put back the
+ * allocated name since we no longer need it, and set
+ * our name pointer to point to the name we found.
+ */
+ result = findname(&name2, name, section);
+
+ /*
+ * If it is a new name, append to the section.
+ */
+ if (result == ISC_R_SUCCESS) {
+ isc_mempool_put(msg->namepool, name);
+ name = name2;
+ } else {
+ ISC_LIST_APPEND(*section, name, link);
+ }
+ free_name = ISC_FALSE;
+ }
+
+ /*
+ * Search name for the particular type and class.
+ * Skip this stage if in update mode or this is a meta-type.
+ */
+ if (preserve_order || msg->opcode == dns_opcode_update ||
+ skip_type_search)
+ result = ISC_R_NOTFOUND;
+ else {
+ /*
+ * If this is a type that can only occur in
+ * the question section, fail.
+ */
+ if (dns_rdatatype_questiononly(rdtype))
+ DO_FORMERR;
+
+ rdataset = NULL;
+ result = dns_message_find(name, rdclass, rdtype,
+ covers, &rdataset);
+ }
+
+ /*
+ * If we found an rdataset that matches, we need to
+ * append this rdata to that set. If we did not, we need
+ * to create a new rdatalist, store the important bits there,
+ * convert it to an rdataset, and link the latter to the name.
+ * Yuck. When appending, make certain that the type isn't
+ * a singleton type, such as SOA or CNAME.
+ *
+ * Note that this check will be bypassed when preserving order,
+ * the opcode is an update, or the type search is skipped.
+ */
+ if (result == ISC_R_SUCCESS) {
+ if (dns_rdatatype_issingleton(rdtype))
+ DO_FORMERR;
+ }
+
+ if (result == ISC_R_NOTFOUND) {
+ rdataset = isc_mempool_get(msg->rdspool);
+ if (rdataset == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ free_rdataset = ISC_TRUE;
+
+ rdatalist = newrdatalist(msg);
+ if (rdatalist == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ rdatalist->type = rdtype;
+ rdatalist->covers = covers;
+ rdatalist->rdclass = rdclass;
+ rdatalist->ttl = ttl;
+ ISC_LIST_INIT(rdatalist->rdata);
+
+ dns_rdataset_init(rdataset);
+ RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
+ rdataset)
+ == ISC_R_SUCCESS);
+
+ if (rdtype != dns_rdatatype_opt &&
+ rdtype != dns_rdatatype_tsig &&
+ !issigzero)
+ {
+ ISC_LIST_APPEND(name->list, rdataset, link);
+ free_rdataset = ISC_FALSE;
+ }
+ }
+
+ /*
+ * Minimize TTLs.
+ *
+ * Section 5.2 of RFC2181 says we should drop
+ * nonauthoritative rrsets where the TTLs differ, but we
+ * currently treat them the as if they were authoritative and
+ * minimize them.
+ */
+ if (ttl != rdataset->ttl) {
+ rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
+ if (ttl < rdataset->ttl)
+ rdataset->ttl = ttl;
+ }
+
+ /*
+ * XXXMLG Perform a totally ugly hack here to pull
+ * the rdatalist out of the private field in the rdataset,
+ * and append this rdata to the rdatalist's linked list
+ * of rdata.
+ */
+ rdatalist = (dns_rdatalist_t *)(rdataset->private1);
+
+ ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
+
+ /*
+ * If this is an OPT record, remember it. Also, set
+ * the extended rcode. Note that msg->opt will only be set
+ * if best-effort parsing is enabled.
+ */
+ if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
+ dns_rcode_t ercode;
+
+ msg->opt = rdataset;
+ rdataset = NULL;
+ free_rdataset = ISC_FALSE;
+ ercode = (dns_rcode_t)
+ ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
+ >> 20);
+ msg->rcode |= ercode;
+ isc_mempool_put(msg->namepool, name);
+ free_name = ISC_FALSE;
+ }
+
+ /*
+ * If this is an SIG(0) or TSIG record, remember it. Note
+ * that msg->sig0 or msg->tsig will only be set if best-effort
+ * parsing is enabled.
+ */
+ if (issigzero && msg->sig0 == NULL) {
+ msg->sig0 = rdataset;
+ msg->sig0name = name;
+ rdataset = NULL;
+ free_rdataset = ISC_FALSE;
+ free_name = ISC_FALSE;
+ } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
+ msg->tsig = rdataset;
+ msg->tsigname = name;
+ rdataset = NULL;
+ free_rdataset = ISC_FALSE;
+ free_name = ISC_FALSE;
+ }
+
+ if (seen_problem) {
+ if (free_name)
+ isc_mempool_put(msg->namepool, name);
+ if (free_rdataset)
+ isc_mempool_put(msg->rdspool, rdataset);
+ free_name = free_rdataset = ISC_FALSE;
+ }
+ INSIST(free_name == ISC_FALSE);
+ INSIST(free_rdataset == ISC_FALSE);
+ }
+
+ if (seen_problem)
+ return (DNS_R_RECOVERABLE);
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (free_name)
+ isc_mempool_put(msg->namepool, name);
+ if (free_rdataset)
+ isc_mempool_put(msg->rdspool, rdataset);
+
+ return (result);
+}
+
+isc_result_t
+dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
+ unsigned int options)
+{
+ isc_region_t r;
+ dns_decompress_t dctx;
+ isc_result_t ret;
+ isc_uint16_t tmpflags;
+ isc_buffer_t origsource;
+ isc_boolean_t seen_problem;
+ isc_boolean_t ignore_tc;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(source != NULL);
+ REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
+
+ seen_problem = ISC_FALSE;
+ ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
+
+ origsource = *source;
+
+ msg->header_ok = 0;
+ msg->question_ok = 0;
+
+ isc_buffer_remainingregion(source, &r);
+ if (r.length < DNS_MESSAGE_HEADERLEN)
+ return (ISC_R_UNEXPECTEDEND);
+
+ msg->id = isc_buffer_getuint16(source);
+ tmpflags = isc_buffer_getuint16(source);
+ msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
+ >> DNS_MESSAGE_OPCODE_SHIFT);
+ msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
+ msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
+ msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
+ msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
+ msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
+ msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
+
+ msg->header_ok = 1;
+
+ /*
+ * -1 means no EDNS.
+ */
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
+
+ dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
+
+ ret = getquestions(source, msg, &dctx, options);
+ if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
+ goto truncated;
+ if (ret == DNS_R_RECOVERABLE) {
+ seen_problem = ISC_TRUE;
+ ret = ISC_R_SUCCESS;
+ }
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ msg->question_ok = 1;
+
+ ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
+ if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
+ goto truncated;
+ if (ret == DNS_R_RECOVERABLE) {
+ seen_problem = ISC_TRUE;
+ ret = ISC_R_SUCCESS;
+ }
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
+ if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
+ goto truncated;
+ if (ret == DNS_R_RECOVERABLE) {
+ seen_problem = ISC_TRUE;
+ ret = ISC_R_SUCCESS;
+ }
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
+ if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
+ goto truncated;
+ if (ret == DNS_R_RECOVERABLE) {
+ seen_problem = ISC_TRUE;
+ ret = ISC_R_SUCCESS;
+ }
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ isc_buffer_remainingregion(source, &r);
+ if (r.length != 0) {
+ isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
+ "message has %u byte(s) of trailing garbage",
+ r.length);
+ }
+
+ truncated:
+ if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
+ isc_buffer_usedregion(&origsource, &msg->saved);
+ else {
+ msg->saved.length = isc_buffer_usedlength(&origsource);
+ msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
+ if (msg->saved.base == NULL)
+ return (ISC_R_NOMEMORY);
+ memcpy(msg->saved.base, isc_buffer_base(&origsource),
+ msg->saved.length);
+ msg->free_saved = 1;
+ }
+
+ if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
+ return (DNS_R_RECOVERABLE);
+ if (seen_problem == ISC_TRUE)
+ return (DNS_R_RECOVERABLE);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
+ isc_buffer_t *buffer)
+{
+ isc_region_t r;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(buffer != NULL);
+ REQUIRE(msg->buffer == NULL);
+ REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
+
+ msg->cctx = cctx;
+
+ /*
+ * Erase the contents of this buffer.
+ */
+ isc_buffer_clear(buffer);
+
+ /*
+ * Make certain there is enough for at least the header in this
+ * buffer.
+ */
+ isc_buffer_availableregion(buffer, &r);
+ if (r.length < DNS_MESSAGE_HEADERLEN)
+ return (ISC_R_NOSPACE);
+
+ if (r.length < msg->reserved)
+ return (ISC_R_NOSPACE);
+
+ /*
+ * Reserve enough space for the header in this buffer.
+ */
+ isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
+
+ msg->buffer = buffer;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
+ isc_region_t r, rn;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(buffer != NULL);
+ REQUIRE(msg->buffer != NULL);
+
+ /*
+ * Ensure that the new buffer is empty, and has enough space to
+ * hold the current contents.
+ */
+ isc_buffer_clear(buffer);
+
+ isc_buffer_availableregion(buffer, &rn);
+ isc_buffer_usedregion(msg->buffer, &r);
+ REQUIRE(rn.length > r.length);
+
+ /*
+ * Copy the contents from the old to the new buffer.
+ */
+ isc_buffer_add(buffer, r.length);
+ memcpy(rn.base, r.base, r.length);
+
+ msg->buffer = buffer;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(space <= msg->reserved);
+
+ msg->reserved -= space;
+}
+
+isc_result_t
+dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
+ isc_region_t r;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+
+ if (msg->buffer != NULL) {
+ isc_buffer_availableregion(msg->buffer, &r);
+ if (r.length < (space + msg->reserved))
+ return (ISC_R_NOSPACE);
+ }
+
+ msg->reserved += space;
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_boolean_t
+wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
+ int pass_needed;
+
+ /*
+ * If we are not rendering class IN, this ordering is bogus.
+ */
+ if (rds->rdclass != dns_rdataclass_in)
+ return (ISC_FALSE);
+
+ switch (rds->type) {
+ case dns_rdatatype_a:
+ case dns_rdatatype_aaaa:
+ if (preferred_glue == rds->type)
+ pass_needed = 4;
+ else
+ pass_needed = 3;
+ break;
+ case dns_rdatatype_rrsig:
+ case dns_rdatatype_dnskey:
+ pass_needed = 2;
+ break;
+ default:
+ pass_needed = 1;
+ }
+
+ if (pass_needed >= pass)
+ return (ISC_FALSE);
+
+ return (ISC_TRUE);
+}
+
+isc_result_t
+dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
+ unsigned int options)
+{
+ dns_namelist_t *section;
+ dns_name_t *name, *next_name;
+ dns_rdataset_t *rdataset, *next_rdataset;
+ unsigned int count, total;
+ isc_result_t result;
+ isc_buffer_t st; /* for rollbacks */
+ int pass;
+ isc_boolean_t partial = ISC_FALSE;
+ unsigned int rd_options;
+ dns_rdatatype_t preferred_glue = 0;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(msg->buffer != NULL);
+ REQUIRE(VALID_NAMED_SECTION(sectionid));
+
+ section = &msg->sections[sectionid];
+
+ if ((sectionid == DNS_SECTION_ADDITIONAL)
+ && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
+ if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
+ preferred_glue = dns_rdatatype_a;
+ pass = 4;
+ } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
+ preferred_glue = dns_rdatatype_aaaa;
+ pass = 4;
+ } else
+ pass = 3;
+ } else
+ pass = 1;
+
+ if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
+ rd_options = 0;
+ else
+ rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
+
+ /*
+ * Shrink the space in the buffer by the reserved amount.
+ */
+ msg->buffer->length -= msg->reserved;
+
+ total = 0;
+ if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
+ partial = ISC_TRUE;
+
+ /*
+ * Render required glue first. Set TC if it won't fit.
+ */
+ name = ISC_LIST_HEAD(*section);
+ if (name != NULL) {
+ rdataset = ISC_LIST_HEAD(name->list);
+ if (rdataset != NULL &&
+ (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
+ (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
+ const void *order_arg = msg->order_arg;
+ st = *(msg->buffer);
+ count = 0;
+ if (partial)
+ result = dns_rdataset_towirepartial(rdataset,
+ name,
+ msg->cctx,
+ msg->buffer,
+ msg->order,
+ order_arg,
+ rd_options,
+ &count,
+ NULL);
+ else
+ result = dns_rdataset_towiresorted(rdataset,
+ name,
+ msg->cctx,
+ msg->buffer,
+ msg->order,
+ order_arg,
+ rd_options,
+ &count);
+ total += count;
+ if (partial && result == ISC_R_NOSPACE) {
+ msg->flags |= DNS_MESSAGEFLAG_TC;
+ msg->buffer->length += msg->reserved;
+ msg->counts[sectionid] += total;
+ return (result);
+ }
+ if (result != ISC_R_SUCCESS) {
+ INSIST(st.used < 65536);
+ dns_compress_rollback(msg->cctx,
+ (isc_uint16_t)st.used);
+ *(msg->buffer) = st; /* rollback */
+ msg->buffer->length += msg->reserved;
+ msg->counts[sectionid] += total;
+ return (result);
+ }
+ rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
+ }
+ }
+
+ do {
+ name = ISC_LIST_HEAD(*section);
+ if (name == NULL) {
+ msg->buffer->length += msg->reserved;
+ msg->counts[sectionid] += total;
+ return (ISC_R_SUCCESS);
+ }
+
+ while (name != NULL) {
+ next_name = ISC_LIST_NEXT(name, link);
+
+ rdataset = ISC_LIST_HEAD(name->list);
+ while (rdataset != NULL) {
+ next_rdataset = ISC_LIST_NEXT(rdataset, link);
+
+ if ((rdataset->attributes &
+ DNS_RDATASETATTR_RENDERED) != 0)
+ goto next;
+
+ if (((options & DNS_MESSAGERENDER_ORDERED)
+ == 0)
+ && (sectionid == DNS_SECTION_ADDITIONAL)
+ && wrong_priority(rdataset, pass,
+ preferred_glue))
+ goto next;
+
+ st = *(msg->buffer);
+
+ count = 0;
+ if (partial)
+ result = dns_rdataset_towirepartial(
+ rdataset,
+ name,
+ msg->cctx,
+ msg->buffer,
+ msg->order,
+ msg->order_arg,
+ rd_options,
+ &count,
+ NULL);
+ else
+ result = dns_rdataset_towiresorted(
+ rdataset,
+ name,
+ msg->cctx,
+ msg->buffer,
+ msg->order,
+ msg->order_arg,
+ rd_options,
+ &count);
+
+ total += count;
+
+ /*
+ * If out of space, record stats on what we
+ * rendered so far, and return that status.
+ *
+ * XXXMLG Need to change this when
+ * dns_rdataset_towire() can render partial
+ * sets starting at some arbitary point in the
+ * set. This will include setting a bit in the
+ * rdataset to indicate that a partial
+ * rendering was done, and some state saved
+ * somewhere (probably in the message struct)
+ * to indicate where to continue from.
+ */
+ if (partial && result == ISC_R_NOSPACE) {
+ msg->buffer->length += msg->reserved;
+ msg->counts[sectionid] += total;
+ return (result);
+ }
+ if (result != ISC_R_SUCCESS) {
+ INSIST(st.used < 65536);
+ dns_compress_rollback(msg->cctx,
+ (isc_uint16_t)st.used);
+ *(msg->buffer) = st; /* rollback */
+ msg->buffer->length += msg->reserved;
+ msg->counts[sectionid] += total;
+ return (result);
+ }
+
+ /*
+ * If we have rendered non-validated data,
+ * ensure that the AD bit is not set.
+ */
+ if (rdataset->trust != dns_trust_secure &&
+ (sectionid == DNS_SECTION_ANSWER ||
+ sectionid == DNS_SECTION_AUTHORITY))
+ msg->flags &= ~DNS_MESSAGEFLAG_AD;
+
+ rdataset->attributes |=
+ DNS_RDATASETATTR_RENDERED;
+
+ next:
+ rdataset = next_rdataset;
+ }
+
+ name = next_name;
+ }
+ } while (--pass != 0);
+
+ msg->buffer->length += msg->reserved;
+ msg->counts[sectionid] += total;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
+ isc_uint16_t tmp;
+ isc_region_t r;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(target != NULL);
+
+ isc_buffer_availableregion(target, &r);
+ REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
+
+ isc_buffer_putuint16(target, msg->id);
+
+ tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
+ & DNS_MESSAGE_OPCODE_MASK);
+ tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
+ tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
+
+ INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
+ msg->counts[DNS_SECTION_ANSWER] < 65536 &&
+ msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
+ msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
+
+ isc_buffer_putuint16(target, tmp);
+ isc_buffer_putuint16(target,
+ (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
+ isc_buffer_putuint16(target,
+ (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
+ isc_buffer_putuint16(target,
+ (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
+ isc_buffer_putuint16(target,
+ (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
+}
+
+isc_result_t
+dns_message_renderend(dns_message_t *msg) {
+ isc_buffer_t tmpbuf;
+ isc_region_t r;
+ int result;
+ unsigned int count;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(msg->buffer != NULL);
+
+ if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
+ /*
+ * We have an extended rcode but are not using EDNS.
+ */
+ return (DNS_R_FORMERR);
+ }
+
+ /*
+ * If we've got an OPT record, render it.
+ */
+ if (msg->opt != NULL) {
+ dns_message_renderrelease(msg, msg->opt_reserved);
+ msg->opt_reserved = 0;
+ /*
+ * Set the extended rcode.
+ */
+ msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
+ msg->opt->ttl |= ((msg->rcode << 20) &
+ DNS_MESSAGE_EDNSRCODE_MASK);
+ /*
+ * Render.
+ */
+ count = 0;
+ result = dns_rdataset_towire(msg->opt, dns_rootname,
+ msg->cctx, msg->buffer, 0,
+ &count);
+ msg->counts[DNS_SECTION_ADDITIONAL] += count;
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ /*
+ * If we're adding a TSIG or SIG(0) to a truncated message,
+ * clear all rdatasets from the message except for the question
+ * before adding the TSIG or SIG(0). If the question doesn't fit,
+ * don't include it.
+ */
+ if ((msg->tsigkey != NULL || msg->sig0key != NULL) &&
+ (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
+ {
+ isc_buffer_t *buf;
+
+ msgresetnames(msg, DNS_SECTION_ANSWER);
+ buf = msg->buffer;
+ dns_message_renderreset(msg);
+ msg->buffer = buf;
+ isc_buffer_clear(msg->buffer);
+ isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
+ dns_compress_rollback(msg->cctx, 0);
+ result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
+ 0);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
+ return (result);
+ }
+
+ /*
+ * If we're adding a TSIG record, generate and render it.
+ */
+ if (msg->tsigkey != NULL) {
+ dns_message_renderrelease(msg, msg->sig_reserved);
+ msg->sig_reserved = 0;
+ result = dns_tsig_sign(msg);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ count = 0;
+ result = dns_rdataset_towire(msg->tsig, msg->tsigname,
+ msg->cctx, msg->buffer, 0,
+ &count);
+ msg->counts[DNS_SECTION_ADDITIONAL] += count;
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ /*
+ * If we're adding a SIG(0) record, generate and render it.
+ */
+ if (msg->sig0key != NULL) {
+ dns_message_renderrelease(msg, msg->sig_reserved);
+ msg->sig_reserved = 0;
+ result = dns_dnssec_signmessage(msg, msg->sig0key);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ count = 0;
+ /*
+ * Note: dns_rootname is used here, not msg->sig0name, since
+ * the owner name of a SIG(0) is irrelevant, and will not
+ * be set in a message being rendered.
+ */
+ result = dns_rdataset_towire(msg->sig0, dns_rootname,
+ msg->cctx, msg->buffer, 0,
+ &count);
+ msg->counts[DNS_SECTION_ADDITIONAL] += count;
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ isc_buffer_usedregion(msg->buffer, &r);
+ isc_buffer_init(&tmpbuf, r.base, r.length);
+
+ dns_message_renderheader(msg, &tmpbuf);
+
+ msg->buffer = NULL; /* forget about this buffer only on success XXX */
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_message_renderreset(dns_message_t *msg) {
+ unsigned int i;
+ dns_name_t *name;
+ dns_rdataset_t *rds;
+
+ /*
+ * Reset the message so that it may be rendered again.
+ */
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
+
+ msg->buffer = NULL;
+
+ for (i = 0; i < DNS_SECTION_MAX; i++) {
+ msg->cursors[i] = NULL;
+ msg->counts[i] = 0;
+ for (name = ISC_LIST_HEAD(msg->sections[i]);
+ name != NULL;
+ name = ISC_LIST_NEXT(name, link)) {
+ for (rds = ISC_LIST_HEAD(name->list);
+ rds != NULL;
+ rds = ISC_LIST_NEXT(rds, link)) {
+ rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
+ }
+ }
+ }
+ if (msg->tsigname != NULL)
+ dns_message_puttempname(msg, &msg->tsigname);
+ if (msg->tsig != NULL) {
+ dns_rdataset_disassociate(msg->tsig);
+ dns_message_puttemprdataset(msg, &msg->tsig);
+ }
+ if (msg->sig0 != NULL) {
+ dns_rdataset_disassociate(msg->sig0);
+ dns_message_puttemprdataset(msg, &msg->sig0);
+ }
+}
+
+isc_result_t
+dns_message_firstname(dns_message_t *msg, dns_section_t section) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(VALID_NAMED_SECTION(section));
+
+ msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
+
+ if (msg->cursors[section] == NULL)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_message_nextname(dns_message_t *msg, dns_section_t section) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(VALID_NAMED_SECTION(section));
+ REQUIRE(msg->cursors[section] != NULL);
+
+ msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
+
+ if (msg->cursors[section] == NULL)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_message_currentname(dns_message_t *msg, dns_section_t section,
+ dns_name_t **name)
+{
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(VALID_NAMED_SECTION(section));
+ REQUIRE(name != NULL && *name == NULL);
+ REQUIRE(msg->cursors[section] != NULL);
+
+ *name = msg->cursors[section];
+}
+
+isc_result_t
+dns_message_findname(dns_message_t *msg, dns_section_t section,
+ dns_name_t *target, dns_rdatatype_t type,
+ dns_rdatatype_t covers, dns_name_t **name,
+ dns_rdataset_t **rdataset)
+{
+ dns_name_t *foundname;
+ isc_result_t result;
+
+ /*
+ * XXX These requirements are probably too intensive, especially
+ * where things can be NULL, but as they are they ensure that if
+ * something is NON-NULL, indicating that the caller expects it
+ * to be filled in, that we can in fact fill it in.
+ */
+ REQUIRE(msg != NULL);
+ REQUIRE(VALID_SECTION(section));
+ REQUIRE(target != NULL);
+ if (name != NULL)
+ REQUIRE(*name == NULL);
+ if (type == dns_rdatatype_any) {
+ REQUIRE(rdataset == NULL);
+ } else {
+ if (rdataset != NULL)
+ REQUIRE(*rdataset == NULL);
+ }
+
+ result = findname(&foundname, target,
+ &msg->sections[section]);
+
+ if (result == ISC_R_NOTFOUND)
+ return (DNS_R_NXDOMAIN);
+ else if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (name != NULL)
+ *name = foundname;
+
+ /*
+ * And now look for the type.
+ */
+ if (type == dns_rdatatype_any)
+ return (ISC_R_SUCCESS);
+
+ result = dns_message_findtype(foundname, type, covers, rdataset);
+ if (result == ISC_R_NOTFOUND)
+ return (DNS_R_NXRRSET);
+
+ return (result);
+}
+
+void
+dns_message_movename(dns_message_t *msg, dns_name_t *name,
+ dns_section_t fromsection,
+ dns_section_t tosection)
+{
+ REQUIRE(msg != NULL);
+ REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
+ REQUIRE(name != NULL);
+ REQUIRE(VALID_NAMED_SECTION(fromsection));
+ REQUIRE(VALID_NAMED_SECTION(tosection));
+
+ /*
+ * Unlink the name from the old section
+ */
+ ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
+ ISC_LIST_APPEND(msg->sections[tosection], name, link);
+}
+
+void
+dns_message_addname(dns_message_t *msg, dns_name_t *name,
+ dns_section_t section)
+{
+ REQUIRE(msg != NULL);
+ REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
+ REQUIRE(name != NULL);
+ REQUIRE(VALID_NAMED_SECTION(section));
+
+ ISC_LIST_APPEND(msg->sections[section], name, link);
+}
+
+void
+dns_message_removename(dns_message_t *msg, dns_name_t *name,
+ dns_section_t section)
+{
+ REQUIRE(msg != NULL);
+ REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
+ REQUIRE(name != NULL);
+ REQUIRE(VALID_NAMED_SECTION(section));
+
+ ISC_LIST_UNLINK(msg->sections[section], name, link);
+}
+
+isc_result_t
+dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(item != NULL && *item == NULL);
+
+ *item = isc_mempool_get(msg->namepool);
+ if (*item == NULL)
+ return (ISC_R_NOMEMORY);
+ dns_name_init(*item, NULL);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(item != NULL && *item == NULL);
+
+ *item = newoffsets(msg);
+ if (*item == NULL)
+ return (ISC_R_NOMEMORY);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(item != NULL && *item == NULL);
+
+ *item = newrdata(msg);
+ if (*item == NULL)
+ return (ISC_R_NOMEMORY);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(item != NULL && *item == NULL);
+
+ *item = isc_mempool_get(msg->rdspool);
+ if (*item == NULL)
+ return (ISC_R_NOMEMORY);
+
+ dns_rdataset_init(*item);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(item != NULL && *item == NULL);
+
+ *item = newrdatalist(msg);
+ if (*item == NULL)
+ return (ISC_R_NOMEMORY);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(item != NULL && *item != NULL);
+
+ if (dns_name_dynamic(*item))
+ dns_name_free(*item, msg->mctx);
+ isc_mempool_put(msg->namepool, *item);
+ *item = NULL;
+}
+
+void
+dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(item != NULL && *item != NULL);
+
+ releaserdata(msg, *item);
+ *item = NULL;
+}
+
+void
+dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(item != NULL && *item != NULL);
+
+ REQUIRE(!dns_rdataset_isassociated(*item));
+ isc_mempool_put(msg->rdspool, *item);
+ *item = NULL;
+}
+
+void
+dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(item != NULL && *item != NULL);
+
+ releaserdatalist(msg, *item);
+ *item = NULL;
+}
+
+isc_result_t
+dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
+ unsigned int *flagsp)
+{
+ isc_region_t r;
+ isc_buffer_t buffer;
+ dns_messageid_t id;
+ unsigned int flags;
+
+ REQUIRE(source != NULL);
+
+ buffer = *source;
+
+ isc_buffer_remainingregion(&buffer, &r);
+ if (r.length < DNS_MESSAGE_HEADERLEN)
+ return (ISC_R_UNEXPECTEDEND);
+
+ id = isc_buffer_getuint16(&buffer);
+ flags = isc_buffer_getuint16(&buffer);
+ flags &= DNS_MESSAGE_FLAG_MASK;
+
+ if (flagsp != NULL)
+ *flagsp = flags;
+ if (idp != NULL)
+ *idp = id;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
+ unsigned int first_section;
+ isc_result_t result;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
+
+ if (!msg->header_ok)
+ return (DNS_R_FORMERR);
+ if (msg->opcode != dns_opcode_query &&
+ msg->opcode != dns_opcode_notify)
+ want_question_section = ISC_FALSE;
+ if (want_question_section) {
+ if (!msg->question_ok)
+ return (DNS_R_FORMERR);
+ first_section = DNS_SECTION_ANSWER;
+ } else
+ first_section = DNS_SECTION_QUESTION;
+ msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
+ msgresetnames(msg, first_section);
+ msgresetopt(msg);
+ msgresetsigs(msg, ISC_TRUE);
+ msginitprivate(msg);
+ /*
+ * We now clear most flags and then set QR, ensuring that the
+ * reply's flags will be in a reasonable state.
+ */
+ msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
+ msg->flags |= DNS_MESSAGEFLAG_QR;
+
+ /*
+ * This saves the query TSIG status, if the query was signed, and
+ * reserves space in the reply for the TSIG.
+ */
+ if (msg->tsigkey != NULL) {
+ unsigned int otherlen = 0;
+ msg->querytsigstatus = msg->tsigstatus;
+ msg->tsigstatus = dns_rcode_noerror;
+ if (msg->querytsigstatus == dns_tsigerror_badtime)
+ otherlen = 6;
+ msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
+ result = dns_message_renderreserve(msg, msg->sig_reserved);
+ if (result != ISC_R_SUCCESS) {
+ msg->sig_reserved = 0;
+ return (result);
+ }
+ }
+ if (msg->saved.base != NULL) {
+ msg->query.base = msg->saved.base;
+ msg->query.length = msg->saved.length;
+ msg->free_query = msg->free_saved;
+ msg->saved.base = NULL;
+ msg->saved.length = 0;
+ msg->free_saved = 0;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+dns_rdataset_t *
+dns_message_getopt(dns_message_t *msg) {
+
+ /*
+ * Get the OPT record for 'msg'.
+ */
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+
+ return (msg->opt);
+}
+
+isc_result_t
+dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ /*
+ * Set the OPT record for 'msg'.
+ */
+
+ /*
+ * The space required for an OPT record is:
+ *
+ * 1 byte for the name
+ * 2 bytes for the type
+ * 2 bytes for the class
+ * 4 bytes for the ttl
+ * 2 bytes for the rdata length
+ * ---------------------------------
+ * 11 bytes
+ *
+ * plus the length of the rdata.
+ */
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(opt->type == dns_rdatatype_opt);
+ REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
+ REQUIRE(msg->state == DNS_SECTION_ANY);
+
+ msgresetopt(msg);
+
+ result = dns_rdataset_first(opt);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ dns_rdataset_current(opt, &rdata);
+ msg->opt_reserved = 11 + rdata.length;
+ result = dns_message_renderreserve(msg, msg->opt_reserved);
+ if (result != ISC_R_SUCCESS) {
+ msg->opt_reserved = 0;
+ goto cleanup;
+ }
+
+ msg->opt = opt;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ dns_message_puttemprdataset(msg, &opt);
+ return (result);
+
+}
+
+dns_rdataset_t *
+dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
+
+ /*
+ * Get the TSIG record and owner for 'msg'.
+ */
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(owner == NULL || *owner == NULL);
+
+ if (owner != NULL)
+ *owner = msg->tsigname;
+ return (msg->tsig);
+}
+
+isc_result_t
+dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
+ isc_result_t result;
+
+ /*
+ * Set the TSIG key for 'msg'
+ */
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(msg->state == DNS_SECTION_ANY);
+
+ if (key == NULL && msg->tsigkey != NULL) {
+ if (msg->sig_reserved != 0) {
+ dns_message_renderrelease(msg, msg->sig_reserved);
+ msg->sig_reserved = 0;
+ }
+ dns_tsigkey_detach(&msg->tsigkey);
+ }
+ if (key != NULL) {
+ REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
+ dns_tsigkey_attach(key, &msg->tsigkey);
+ if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
+ msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
+ result = dns_message_renderreserve(msg,
+ msg->sig_reserved);
+ if (result != ISC_R_SUCCESS) {
+ dns_tsigkey_detach(&msg->tsigkey);
+ msg->sig_reserved = 0;
+ return (result);
+ }
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+dns_tsigkey_t *
+dns_message_gettsigkey(dns_message_t *msg) {
+
+ /*
+ * Get the TSIG key for 'msg'
+ */
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+
+ return (msg->tsigkey);
+}
+
+isc_result_t
+dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
+ dns_rdata_t *rdata = NULL;
+ dns_rdatalist_t *list = NULL;
+ dns_rdataset_t *set = NULL;
+ isc_buffer_t *buf = NULL;
+ isc_region_t r;
+ isc_result_t result;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(msg->querytsig == NULL);
+
+ if (querytsig == NULL)
+ return (ISC_R_SUCCESS);
+
+ result = dns_message_gettemprdata(msg, &rdata);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = dns_message_gettemprdatalist(msg, &list);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_message_gettemprdataset(msg, &set);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ isc_buffer_usedregion(querytsig, &r);
+ result = isc_buffer_allocate(msg->mctx, &buf, r.length);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ isc_buffer_putmem(buf, r.base, r.length);
+ isc_buffer_usedregion(buf, &r);
+ dns_rdata_init(rdata);
+ dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
+ dns_message_takebuffer(msg, &buf);
+ ISC_LIST_INIT(list->rdata);
+ ISC_LIST_APPEND(list->rdata, rdata, link);
+ result = dns_rdatalist_tordataset(list, set);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ msg->querytsig = set;
+
+ return (result);
+
+ cleanup:
+ if (rdata != NULL)
+ dns_message_puttemprdata(msg, &rdata);
+ if (list != NULL)
+ dns_message_puttemprdatalist(msg, &list);
+ if (set != NULL)
+ dns_message_puttemprdataset(msg, &set);
+ return (ISC_R_NOMEMORY);
+}
+
+isc_result_t
+dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
+ isc_buffer_t **querytsig) {
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_region_t r;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(mctx != NULL);
+ REQUIRE(querytsig != NULL && *querytsig == NULL);
+
+ if (msg->tsig == NULL)
+ return (ISC_R_SUCCESS);
+
+ result = dns_rdataset_first(msg->tsig);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_rdataset_current(msg->tsig, &rdata);
+ dns_rdata_toregion(&rdata, &r);
+
+ result = isc_buffer_allocate(mctx, querytsig, r.length);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_putmem(*querytsig, r.base, r.length);
+ return (ISC_R_SUCCESS);
+}
+
+dns_rdataset_t *
+dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
+
+ /*
+ * Get the SIG(0) record for 'msg'.
+ */
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(owner == NULL || *owner == NULL);
+
+ if (msg->sig0 != NULL && owner != NULL) {
+ /* If dns_message_getsig0 is called on a rendered message
+ * after the SIG(0) has been applied, we need to return the
+ * root name, not NULL.
+ */
+ if (msg->sig0name == NULL)
+ *owner = dns_rootname;
+ else
+ *owner = msg->sig0name;
+ }
+ return (msg->sig0);
+}
+
+isc_result_t
+dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
+ isc_region_t r;
+ unsigned int x;
+ isc_result_t result;
+
+ /*
+ * Set the SIG(0) key for 'msg'
+ */
+
+ /*
+ * The space required for an SIG(0) record is:
+ *
+ * 1 byte for the name
+ * 2 bytes for the type
+ * 2 bytes for the class
+ * 4 bytes for the ttl
+ * 2 bytes for the type covered
+ * 1 byte for the algorithm
+ * 1 bytes for the labels
+ * 4 bytes for the original ttl
+ * 4 bytes for the signature expiration
+ * 4 bytes for the signature inception
+ * 2 bytes for the key tag
+ * n bytes for the signer's name
+ * x bytes for the signature
+ * ---------------------------------
+ * 27 + n + x bytes
+ */
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
+ REQUIRE(msg->state == DNS_SECTION_ANY);
+
+ if (key != NULL) {
+ REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
+ dns_name_toregion(dst_key_name(key), &r);
+ result = dst_key_sigsize(key, &x);
+ if (result != ISC_R_SUCCESS) {
+ msg->sig_reserved = 0;
+ return (result);
+ }
+ msg->sig_reserved = 27 + r.length + x;
+ result = dns_message_renderreserve(msg, msg->sig_reserved);
+ if (result != ISC_R_SUCCESS) {
+ msg->sig_reserved = 0;
+ return (result);
+ }
+ msg->sig0key = key;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+dst_key_t *
+dns_message_getsig0key(dns_message_t *msg) {
+
+ /*
+ * Get the SIG(0) key for 'msg'
+ */
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+
+ return (msg->sig0key);
+}
+
+void
+dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(buffer != NULL);
+ REQUIRE(ISC_BUFFER_VALID(*buffer));
+
+ ISC_LIST_APPEND(msg->cleanup, *buffer, link);
+ *buffer = NULL;
+}
+
+isc_result_t
+dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(signer != NULL);
+ REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
+
+ if (msg->tsig == NULL && msg->sig0 == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (msg->verify_attempted == 0)
+ return (DNS_R_NOTVERIFIEDYET);
+
+ if (!dns_name_hasbuffer(signer)) {
+ isc_buffer_t *dynbuf = NULL;
+ result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_name_setbuffer(signer, dynbuf);
+ dns_message_takebuffer(msg, &dynbuf);
+ }
+
+ if (msg->sig0 != NULL) {
+ dns_rdata_sig_t sig;
+
+ result = dns_rdataset_first(msg->sig0);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_rdataset_current(msg->sig0, &rdata);
+
+ result = dns_rdata_tostruct(&rdata, &sig, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
+ result = ISC_R_SUCCESS;
+ else
+ result = DNS_R_SIGINVALID;
+ dns_name_clone(&sig.signer, signer);
+ dns_rdata_freestruct(&sig);
+ } else {
+ dns_name_t *identity;
+ dns_rdata_any_tsig_t tsig;
+
+ result = dns_rdataset_first(msg->tsig);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_rdataset_current(msg->tsig, &rdata);
+
+ result = dns_rdata_tostruct(&rdata, &tsig, NULL);
+ if (msg->tsigstatus != dns_rcode_noerror)
+ result = DNS_R_TSIGVERIFYFAILURE;
+ else if (tsig.error != dns_rcode_noerror)
+ result = DNS_R_TSIGERRORSET;
+ else
+ result = ISC_R_SUCCESS;
+ dns_rdata_freestruct(&tsig);
+
+ if (msg->tsigkey == NULL) {
+ /*
+ * If msg->tsigstatus & tsig.error are both
+ * dns_rcode_noerror, the message must have been
+ * verified, which means msg->tsigkey will be
+ * non-NULL.
+ */
+ INSIST(result != ISC_R_SUCCESS);
+ } else {
+ identity = dns_tsigkey_identity(msg->tsigkey);
+ if (identity == NULL) {
+ if (result == ISC_R_SUCCESS)
+ result = DNS_R_NOIDENTITY;
+ identity = &msg->tsigkey->name;
+ }
+ dns_name_clone(identity, signer);
+ }
+ }
+
+ return (result);
+}
+
+void
+dns_message_resetsig(dns_message_t *msg) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ msg->verified_sig = 0;
+ msg->verify_attempted = 0;
+ msg->tsigstatus = dns_rcode_noerror;
+ msg->sig0status = dns_rcode_noerror;
+ msg->timeadjust = 0;
+ if (msg->tsigkey != NULL) {
+ dns_tsigkey_detach(&msg->tsigkey);
+ msg->tsigkey = NULL;
+ }
+}
+
+isc_result_t
+dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
+ dns_message_resetsig(msg);
+ return (dns_message_checksig(msg, view));
+}
+
+isc_result_t
+dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
+ isc_buffer_t b, msgb;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+
+ if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
+ return (ISC_R_SUCCESS);
+ INSIST(msg->saved.base != NULL);
+ isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
+ isc_buffer_add(&msgb, msg->saved.length);
+ if (msg->tsigkey != NULL || msg->tsig != NULL) {
+ if (view != NULL)
+ return (dns_view_checksig(view, &msgb, msg));
+ else
+ return (dns_tsig_verify(&msgb, msg, NULL, NULL));
+ } else {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_sig_t sig;
+ dns_rdataset_t keyset;
+ isc_result_t result;
+
+ result = dns_rdataset_first(msg->sig0);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_rdataset_current(msg->sig0, &rdata);
+
+ /*
+ * This can occur when the message is a dynamic update, since
+ * the rdata length checking is relaxed. This should not
+ * happen in a well-formed message, since the SIG(0) is only
+ * looked for in the additional section, and the dynamic update
+ * meta-records are in the prerequisite and update sections.
+ */
+ if (rdata.length == 0)
+ return (ISC_R_UNEXPECTEDEND);
+
+ result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ dns_rdataset_init(&keyset);
+ if (view == NULL)
+ return (DNS_R_KEYUNAUTHORIZED);
+ result = dns_view_simplefind(view, &sig.signer,
+ dns_rdatatype_key /* SIG(0) */,
+ 0, 0, ISC_FALSE, &keyset, NULL);
+
+ if (result != ISC_R_SUCCESS) {
+ /* XXXBEW Should possibly create a fetch here */
+ result = DNS_R_KEYUNAUTHORIZED;
+ goto freesig;
+ } else if (keyset.trust < dns_trust_secure) {
+ /* XXXBEW Should call a validator here */
+ result = DNS_R_KEYUNAUTHORIZED;
+ goto freesig;
+ }
+ result = dns_rdataset_first(&keyset);
+ INSIST(result == ISC_R_SUCCESS);
+ for (;
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&keyset))
+ {
+ dst_key_t *key = NULL;
+
+ dns_rdataset_current(&keyset, &rdata);
+ isc_buffer_init(&b, rdata.data, rdata.length);
+ isc_buffer_add(&b, rdata.length);
+
+ result = dst_key_fromdns(&sig.signer, rdata.rdclass,
+ &b, view->mctx, &key);
+ if (result != ISC_R_SUCCESS)
+ continue;
+ if (dst_key_alg(key) != sig.algorithm ||
+ dst_key_id(key) != sig.keyid ||
+ !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
+ dst_key_proto(key) == DNS_KEYPROTO_ANY))
+ {
+ dst_key_free(&key);
+ continue;
+ }
+ result = dns_dnssec_verifymessage(&msgb, msg, key);
+ dst_key_free(&key);
+ if (result == ISC_R_SUCCESS)
+ break;
+ }
+ if (result == ISC_R_NOMORE)
+ result = DNS_R_KEYUNAUTHORIZED;
+
+ freesig:
+ if (dns_rdataset_isassociated(&keyset))
+ dns_rdataset_disassociate(&keyset);
+ dns_rdata_freestruct(&sig);
+ return (result);
+ }
+}
+
+isc_result_t
+dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
+ const dns_master_style_t *style,
+ dns_messagetextflag_t flags,
+ isc_buffer_t *target) {
+ dns_name_t *name, empty_name;
+ dns_rdataset_t *rdataset;
+ isc_result_t result;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(target != NULL);
+ REQUIRE(VALID_SECTION(section));
+
+ if (ISC_LIST_EMPTY(msg->sections[section]))
+ return (ISC_R_SUCCESS);
+
+ if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
+ ADD_STRING(target, ";; ");
+ if (msg->opcode != dns_opcode_update) {
+ ADD_STRING(target, sectiontext[section]);
+ } else {
+ ADD_STRING(target, updsectiontext[section]);
+ }
+ ADD_STRING(target, " SECTION:\n");
+ }
+
+ dns_name_init(&empty_name, NULL);
+ result = dns_message_firstname(msg, section);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+ do {
+ 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) {
+ ADD_STRING(target, ";");
+ result = dns_master_questiontotext(name,
+ rdataset,
+ style,
+ target);
+ } else {
+ result = dns_master_rdatasettotext(name,
+ rdataset,
+ style,
+ target);
+ }
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ result = dns_message_nextname(msg, section);
+ } while (result == ISC_R_SUCCESS);
+ if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
+ (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
+ ADD_STRING(target, "\n");
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ return (result);
+}
+
+isc_result_t
+dns_message_pseudosectiontotext(dns_message_t *msg,
+ dns_pseudosection_t section,
+ const dns_master_style_t *style,
+ dns_messagetextflag_t flags,
+ isc_buffer_t *target) {
+ dns_rdataset_t *ps = NULL;
+ dns_name_t *name = NULL;
+ isc_result_t result;
+ char buf[sizeof("1234567890")];
+ isc_uint32_t mbz;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(target != NULL);
+ REQUIRE(VALID_PSEUDOSECTION(section));
+
+ switch (section) {
+ case DNS_PSEUDOSECTION_OPT:
+ ps = dns_message_getopt(msg);
+ if (ps == NULL)
+ return (ISC_R_SUCCESS);
+ if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
+ ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
+ ADD_STRING(target, "; EDNS: version: ");
+ snprintf(buf, sizeof(buf), "%u",
+ (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
+ ADD_STRING(target, buf);
+ ADD_STRING(target, ", flags:");
+ if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
+ ADD_STRING(target, " do");
+ mbz = ps->ttl & ~DNS_MESSAGEEXTFLAG_DO & 0xffff;
+ if (mbz != 0) {
+ ADD_STRING(target, "; MBZ: ");
+ snprintf(buf, sizeof(buf), "%.4x ", mbz);
+ ADD_STRING(target, buf);
+ ADD_STRING(target, ", udp: ");
+ } else
+ ADD_STRING(target, "; udp: ");
+ snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
+ ADD_STRING(target, buf);
+ return (ISC_R_SUCCESS);
+ case DNS_PSEUDOSECTION_TSIG:
+ ps = dns_message_gettsig(msg, &name);
+ if (ps == NULL)
+ return (ISC_R_SUCCESS);
+ if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
+ ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
+ result = dns_master_rdatasettotext(name, ps, style, target);
+ if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
+ (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
+ ADD_STRING(target, "\n");
+ return (result);
+ case DNS_PSEUDOSECTION_SIG0:
+ ps = dns_message_getsig0(msg, &name);
+ if (ps == NULL)
+ return (ISC_R_SUCCESS);
+ if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
+ ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
+ result = dns_master_rdatasettotext(name, ps, style, target);
+ if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
+ (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
+ ADD_STRING(target, "\n");
+ return (result);
+ }
+ return (ISC_R_UNEXPECTED);
+}
+
+isc_result_t
+dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
+ dns_messagetextflag_t flags, isc_buffer_t *target) {
+ char buf[sizeof("1234567890")];
+ isc_result_t result;
+
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ REQUIRE(target != NULL);
+
+ if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
+ ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
+ ADD_STRING(target, opcodetext[msg->opcode]);
+ ADD_STRING(target, ", status: ");
+ if (msg->rcode < (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
+ ADD_STRING(target, rcodetext[msg->rcode]);
+ } else {
+ snprintf(buf, sizeof(buf), "%4u", msg->rcode);
+ ADD_STRING(target, buf);
+ }
+ ADD_STRING(target, ", id: ");
+ snprintf(buf, sizeof(buf), "%6u", msg->id);
+ ADD_STRING(target, buf);
+ ADD_STRING(target, "\n;; flags: ");
+ if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
+ ADD_STRING(target, "qr ");
+ if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
+ ADD_STRING(target, "aa ");
+ if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
+ ADD_STRING(target, "tc ");
+ if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
+ ADD_STRING(target, "rd ");
+ if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
+ ADD_STRING(target, "ra ");
+ if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
+ ADD_STRING(target, "ad ");
+ if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
+ ADD_STRING(target, "cd ");
+ if (msg->opcode != dns_opcode_update) {
+ ADD_STRING(target, "; QUESTION: ");
+ } else {
+ ADD_STRING(target, "; ZONE: ");
+ }
+ snprintf(buf, sizeof(buf), "%1u",
+ msg->counts[DNS_SECTION_QUESTION]);
+ ADD_STRING(target, buf);
+ if (msg->opcode != dns_opcode_update) {
+ ADD_STRING(target, ", ANSWER: ");
+ } else {
+ ADD_STRING(target, ", PREREQ: ");
+ }
+ snprintf(buf, sizeof(buf), "%1u",
+ msg->counts[DNS_SECTION_ANSWER]);
+ ADD_STRING(target, buf);
+ if (msg->opcode != dns_opcode_update) {
+ ADD_STRING(target, ", AUTHORITY: ");
+ } else {
+ ADD_STRING(target, ", UPDATE: ");
+ }
+ snprintf(buf, sizeof(buf), "%1u",
+ msg->counts[DNS_SECTION_AUTHORITY]);
+ ADD_STRING(target, buf);
+ ADD_STRING(target, ", ADDITIONAL: ");
+ snprintf(buf, sizeof(buf), "%1u",
+ msg->counts[DNS_SECTION_ADDITIONAL]);
+ ADD_STRING(target, buf);
+ ADD_STRING(target, "\n");
+ }
+ result = dns_message_pseudosectiontotext(msg,
+ DNS_PSEUDOSECTION_OPT,
+ style, flags, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
+ style, flags, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
+ style, flags, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
+ style, flags, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
+ style, flags, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_message_pseudosectiontotext(msg,
+ DNS_PSEUDOSECTION_TSIG,
+ style, flags, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_message_pseudosectiontotext(msg,
+ DNS_PSEUDOSECTION_SIG0,
+ style, flags, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_region_t *
+dns_message_getrawmessage(dns_message_t *msg) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ return (&msg->saved);
+}
+
+void
+dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
+ const void *order_arg)
+{
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ msg->order = order;
+ msg->order_arg = order_arg;
+}
+
+void
+dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ msg->timeadjust = timeadjust;
+}
+
+int
+dns_message_gettimeadjust(dns_message_t *msg) {
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ return (msg->timeadjust);
+}
+
+isc_result_t
+dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
+
+ REQUIRE(opcode < 16);
+
+ if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
+ return (ISC_R_NOSPACE);
+ isc_buffer_putstr(target, opcodetext[opcode]);
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/dns/name.c b/lib/dns/name.c
new file mode 100644
index 0000000..7f5d4e9
--- /dev/null
+++ b/lib/dns/name.c
@@ -0,0 +1,2406 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: name.c,v 1.144.18.16 2006/12/07 07:03:10 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/hash.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include <dns/compress.h>
+#include <dns/name.h>
+#include <dns/result.h>
+
+#define VALID_NAME(n) ISC_MAGIC_VALID(n, DNS_NAME_MAGIC)
+
+typedef enum {
+ ft_init = 0,
+ ft_start,
+ ft_ordinary,
+ ft_initialescape,
+ ft_escape,
+ ft_escdecimal,
+ ft_at
+} ft_state;
+
+typedef enum {
+ fw_start = 0,
+ fw_ordinary,
+ fw_copy,
+ fw_newcurrent
+} fw_state;
+
+static 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*/
+};
+
+static unsigned char maptolower[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+#define CONVERTTOASCII(c)
+#define CONVERTFROMASCII(c)
+
+#define INIT_OFFSETS(name, var, default) \
+ if (name->offsets != NULL) \
+ var = name->offsets; \
+ else \
+ var = default;
+
+#define SETUP_OFFSETS(name, var, default) \
+ if (name->offsets != NULL) \
+ var = name->offsets; \
+ else { \
+ var = default; \
+ set_offsets(name, var, NULL); \
+ }
+
+/*%
+ * Note: If additional attributes are added that should not be set for
+ * empty names, MAKE_EMPTY() must be changed so it clears them.
+ */
+#define MAKE_EMPTY(name) \
+do { \
+ name->ndata = NULL; \
+ name->length = 0; \
+ name->labels = 0; \
+ name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \
+} while (0);
+
+/*%
+ * A name is "bindable" if it can be set to point to a new value, i.e.
+ * name->ndata and name->length may be changed.
+ */
+#define BINDABLE(name) \
+ ((name->attributes & (DNS_NAMEATTR_READONLY|DNS_NAMEATTR_DYNAMIC)) \
+ == 0)
+
+/*%
+ * Note that the name data must be a char array, not a string
+ * literal, to avoid compiler warnings about discarding
+ * the const attribute of a string.
+ */
+static unsigned char root_ndata[] = { '\0' };
+static unsigned char root_offsets[] = { 0 };
+
+static dns_name_t root =
+{
+ DNS_NAME_MAGIC,
+ root_ndata, 1, 1,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ root_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+/* XXXDCL make const? */
+LIBDNS_EXTERNAL_DATA dns_name_t *dns_rootname = &root;
+
+static unsigned char wild_ndata[] = { '\001', '*' };
+static unsigned char wild_offsets[] = { 0 };
+
+static dns_name_t wild =
+{
+ DNS_NAME_MAGIC,
+ wild_ndata, 2, 1,
+ DNS_NAMEATTR_READONLY,
+ wild_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+/* XXXDCL make const? */
+LIBDNS_EXTERNAL_DATA dns_name_t *dns_wildcardname = &wild;
+
+unsigned int
+dns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive);
+
+/*
+ * dns_name_t to text post-conversion procedure.
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+static int thread_key_initialized = 0;
+static isc_mutex_t thread_key_mutex;
+static isc_mem_t *thread_key_mctx = NULL;
+static isc_thread_key_t totext_filter_proc_key;
+static isc_once_t once = ISC_ONCE_INIT;
+#else
+static dns_name_totextfilter_t totext_filter_proc = NULL;
+#endif
+
+static void
+set_offsets(const dns_name_t *name, unsigned char *offsets,
+ dns_name_t *set_name);
+
+void
+dns_name_init(dns_name_t *name, unsigned char *offsets) {
+ /*
+ * Initialize 'name'.
+ */
+ DNS_NAME_INIT(name, offsets);
+}
+
+void
+dns_name_reset(dns_name_t *name) {
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(BINDABLE(name));
+
+ DNS_NAME_RESET(name);
+}
+
+void
+dns_name_invalidate(dns_name_t *name) {
+ /*
+ * Make 'name' invalid.
+ */
+
+ REQUIRE(VALID_NAME(name));
+
+ name->magic = 0;
+ name->ndata = NULL;
+ name->length = 0;
+ name->labels = 0;
+ name->attributes = 0;
+ name->offsets = NULL;
+ name->buffer = NULL;
+ ISC_LINK_INIT(name, link);
+}
+
+void
+dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) {
+ /*
+ * Dedicate a buffer for use with 'name'.
+ */
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE((buffer != NULL && name->buffer == NULL) ||
+ (buffer == NULL));
+
+ name->buffer = buffer;
+}
+
+isc_boolean_t
+dns_name_hasbuffer(const dns_name_t *name) {
+ /*
+ * Does 'name' have a dedicated buffer?
+ */
+
+ REQUIRE(VALID_NAME(name));
+
+ if (name->buffer != NULL)
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_name_isabsolute(const dns_name_t *name) {
+
+ /*
+ * Does 'name' end in the root label?
+ */
+
+ REQUIRE(VALID_NAME(name));
+
+ if ((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+#define hyphenchar(c) ((c) == 0x2d)
+#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)
+
+isc_boolean_t
+dns_name_ismailbox(const dns_name_t *name) {
+ unsigned char *ndata, ch;
+ unsigned int n;
+ isc_boolean_t first;
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(name->labels > 0);
+ REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
+
+ /*
+ * Root label.
+ */
+ if (name->length == 1)
+ return (ISC_TRUE);
+
+ ndata = name->ndata;
+ n = *ndata++;
+ INSIST(n <= 63);
+ while (n--) {
+ ch = *ndata++;
+ if (!domainchar(ch))
+ return (ISC_FALSE);
+ }
+
+ if (ndata == name->ndata + name->length)
+ return (ISC_FALSE);
+
+ /*
+ * RFC292/RFC1123 hostname.
+ */
+ while (ndata < (name->ndata + name->length)) {
+ n = *ndata++;
+ INSIST(n <= 63);
+ first = ISC_TRUE;
+ while (n--) {
+ ch = *ndata++;
+ if (first || n == 0) {
+ if (!borderchar(ch))
+ return (ISC_FALSE);
+ } else {
+ if (!middlechar(ch))
+ return (ISC_FALSE);
+ }
+ first = ISC_FALSE;
+ }
+ }
+ return (ISC_TRUE);
+}
+
+isc_boolean_t
+dns_name_ishostname(const dns_name_t *name, isc_boolean_t wildcard) {
+ unsigned char *ndata, ch;
+ unsigned int n;
+ isc_boolean_t first;
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(name->labels > 0);
+ REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
+
+ /*
+ * Root label.
+ */
+ if (name->length == 1)
+ return (ISC_TRUE);
+
+ /*
+ * Skip wildcard if this is a ownername.
+ */
+ ndata = name->ndata;
+ if (wildcard && ndata[0] == 1 && ndata[1] == '*')
+ ndata += 2;
+
+ /*
+ * RFC292/RFC1123 hostname.
+ */
+ while (ndata < (name->ndata + name->length)) {
+ n = *ndata++;
+ INSIST(n <= 63);
+ first = ISC_TRUE;
+ while (n--) {
+ ch = *ndata++;
+ if (first || n == 0) {
+ if (!borderchar(ch))
+ return (ISC_FALSE);
+ } else {
+ if (!middlechar(ch))
+ return (ISC_FALSE);
+ }
+ first = ISC_FALSE;
+ }
+ }
+ return (ISC_TRUE);
+}
+
+isc_boolean_t
+dns_name_iswildcard(const dns_name_t *name) {
+ unsigned char *ndata;
+
+ /*
+ * Is 'name' a wildcard name?
+ */
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(name->labels > 0);
+
+ if (name->length >= 2) {
+ ndata = name->ndata;
+ if (ndata[0] == 1 && ndata[1] == '*')
+ return (ISC_TRUE);
+ }
+
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_name_internalwildcard(const dns_name_t *name) {
+ unsigned char *ndata;
+ unsigned int count;
+ unsigned int label;
+
+ /*
+ * Does 'name' contain a internal wildcard?
+ */
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(name->labels > 0);
+
+ /*
+ * Skip first label.
+ */
+ ndata = name->ndata;
+ count = *ndata++;
+ INSIST(count <= 63);
+ ndata += count;
+ label = 1;
+ /*
+ * Check all but the last of the remaining labels.
+ */
+ while (label + 1 < name->labels) {
+ count = *ndata++;
+ INSIST(count <= 63);
+ if (count == 1 && *ndata == '*')
+ return (ISC_TRUE);
+ ndata += count;
+ label++;
+ }
+ return (ISC_FALSE);
+}
+
+static inline unsigned int
+name_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
+ unsigned int length;
+ const unsigned char *s;
+ unsigned int h = 0;
+ unsigned char c;
+
+ length = name->length;
+ if (length > 16)
+ length = 16;
+
+ /*
+ * This hash function is similar to the one Ousterhout
+ * uses in Tcl.
+ */
+ s = name->ndata;
+ if (case_sensitive) {
+ while (length > 0) {
+ h += ( h << 3 ) + *s;
+ s++;
+ length--;
+ }
+ } else {
+ while (length > 0) {
+ c = maptolower[*s];
+ h += ( h << 3 ) + c;
+ s++;
+ length--;
+ }
+ }
+
+ return (h);
+}
+
+unsigned int
+dns_name_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
+ /*
+ * Provide a hash value for 'name'.
+ */
+ REQUIRE(VALID_NAME(name));
+
+ if (name->labels == 0)
+ return (0);
+
+ return (name_hash(name, case_sensitive));
+}
+
+unsigned int
+dns_name_fullhash(dns_name_t *name, isc_boolean_t case_sensitive) {
+ /*
+ * Provide a hash value for 'name'.
+ */
+ REQUIRE(VALID_NAME(name));
+
+ if (name->labels == 0)
+ return (0);
+
+ return (isc_hash_calc((const unsigned char *)name->ndata,
+ name->length, case_sensitive));
+}
+
+unsigned int
+dns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
+ /*
+ * This function was deprecated due to the breakage of the name space
+ * convention. We only keep this internally to provide binary backward
+ * compatibility.
+ */
+ REQUIRE(VALID_NAME(name));
+
+ return (dns_name_fullhash(name, case_sensitive));
+}
+
+unsigned int
+dns_name_hashbylabel(dns_name_t *name, isc_boolean_t case_sensitive) {
+ unsigned char *offsets;
+ dns_offsets_t odata;
+ dns_name_t tname;
+ unsigned int h = 0;
+ unsigned int i;
+
+ /*
+ * Provide a hash value for 'name'.
+ */
+ REQUIRE(VALID_NAME(name));
+
+ if (name->labels == 0)
+ return (0);
+ else if (name->labels == 1)
+ return (name_hash(name, case_sensitive));
+
+ SETUP_OFFSETS(name, offsets, odata);
+ DNS_NAME_INIT(&tname, NULL);
+ tname.labels = 1;
+ h = 0;
+ for (i = 0; i < name->labels; i++) {
+ tname.ndata = name->ndata + offsets[i];
+ if (i == name->labels - 1)
+ tname.length = name->length - offsets[i];
+ else
+ tname.length = offsets[i + 1] - offsets[i];
+ h += name_hash(&tname, case_sensitive);
+ }
+
+ return (h);
+}
+
+dns_namereln_t
+dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
+ int *orderp, unsigned int *nlabelsp)
+{
+ unsigned int l1, l2, l, count1, count2, count, nlabels;
+ int cdiff, ldiff, chdiff;
+ unsigned char *label1, *label2;
+ unsigned char *offsets1, *offsets2;
+ dns_offsets_t odata1, odata2;
+ dns_namereln_t namereln = dns_namereln_none;
+
+ /*
+ * Determine the relative ordering under the DNSSEC order relation of
+ * 'name1' and 'name2', and also determine the hierarchical
+ * relationship of the names.
+ *
+ * Note: It makes no sense for one of the names to be relative and the
+ * other absolute. If both names are relative, then to be meaningfully
+ * compared the caller must ensure that they are both relative to the
+ * same domain.
+ */
+
+ REQUIRE(VALID_NAME(name1));
+ REQUIRE(VALID_NAME(name2));
+ REQUIRE(orderp != NULL);
+ REQUIRE(nlabelsp != NULL);
+ /*
+ * Either name1 is absolute and name2 is absolute, or neither is.
+ */
+ REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
+ (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
+
+ SETUP_OFFSETS(name1, offsets1, odata1);
+ SETUP_OFFSETS(name2, offsets2, odata2);
+
+ nlabels = 0;
+ l1 = name1->labels;
+ l2 = name2->labels;
+ ldiff = (int)l1 - (int)l2;
+ if (ldiff < 0)
+ l = l1;
+ else
+ l = l2;
+
+ while (l > 0) {
+ l--;
+ l1--;
+ l2--;
+ label1 = &name1->ndata[offsets1[l1]];
+ label2 = &name2->ndata[offsets2[l2]];
+ count1 = *label1++;
+ count2 = *label2++;
+
+ /*
+ * We dropped bitstring labels, and we don't support any
+ * other extended label types.
+ */
+ INSIST(count1 <= 63 && count2 <= 63);
+
+ cdiff = (int)count1 - (int)count2;
+ if (cdiff < 0)
+ count = count1;
+ else
+ count = count2;
+
+ while (count > 0) {
+ chdiff = (int)maptolower[*label1] -
+ (int)maptolower[*label2];
+ if (chdiff != 0) {
+ *orderp = chdiff;
+ goto done;
+ }
+ count--;
+ label1++;
+ label2++;
+ }
+ if (cdiff != 0) {
+ *orderp = cdiff;
+ goto done;
+ }
+ nlabels++;
+ }
+
+ *orderp = ldiff;
+ if (ldiff < 0)
+ namereln = dns_namereln_contains;
+ else if (ldiff > 0)
+ namereln = dns_namereln_subdomain;
+ else
+ namereln = dns_namereln_equal;
+
+ done:
+ *nlabelsp = nlabels;
+
+ if (nlabels > 0 && namereln == dns_namereln_none)
+ namereln = dns_namereln_commonancestor;
+
+ return (namereln);
+}
+
+int
+dns_name_compare(const dns_name_t *name1, const dns_name_t *name2) {
+ int order;
+ unsigned int nlabels;
+
+ /*
+ * Determine the relative ordering under the DNSSEC order relation of
+ * 'name1' and 'name2'.
+ *
+ * Note: It makes no sense for one of the names to be relative and the
+ * other absolute. If both names are relative, then to be meaningfully
+ * compared the caller must ensure that they are both relative to the
+ * same domain.
+ */
+
+ (void)dns_name_fullcompare(name1, name2, &order, &nlabels);
+
+ return (order);
+}
+
+isc_boolean_t
+dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) {
+ unsigned int l, count;
+ unsigned char c;
+ unsigned char *label1, *label2;
+
+ /*
+ * Are 'name1' and 'name2' equal?
+ *
+ * Note: It makes no sense for one of the names to be relative and the
+ * other absolute. If both names are relative, then to be meaningfully
+ * compared the caller must ensure that they are both relative to the
+ * same domain.
+ */
+
+ REQUIRE(VALID_NAME(name1));
+ REQUIRE(VALID_NAME(name2));
+ /*
+ * Either name1 is absolute and name2 is absolute, or neither is.
+ */
+ REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
+ (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
+
+ if (name1->length != name2->length)
+ return (ISC_FALSE);
+
+ l = name1->labels;
+
+ if (l != name2->labels)
+ return (ISC_FALSE);
+
+ label1 = name1->ndata;
+ label2 = name2->ndata;
+ while (l > 0) {
+ l--;
+ count = *label1++;
+ if (count != *label2++)
+ return (ISC_FALSE);
+
+ INSIST(count <= 63); /* no bitstring support */
+
+ while (count > 0) {
+ count--;
+ c = maptolower[*label1++];
+ if (c != maptolower[*label2++])
+ return (ISC_FALSE);
+ }
+ }
+
+ return (ISC_TRUE);
+}
+
+isc_boolean_t
+dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) {
+
+ /*
+ * Are 'name1' and 'name2' equal?
+ *
+ * Note: It makes no sense for one of the names to be relative and the
+ * other absolute. If both names are relative, then to be meaningfully
+ * compared the caller must ensure that they are both relative to the
+ * same domain.
+ */
+
+ REQUIRE(VALID_NAME(name1));
+ REQUIRE(VALID_NAME(name2));
+ /*
+ * Either name1 is absolute and name2 is absolute, or neither is.
+ */
+ REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
+ (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
+
+ if (name1->length != name2->length)
+ return (ISC_FALSE);
+
+ if (memcmp(name1->ndata, name2->ndata, name1->length) != 0)
+ return (ISC_FALSE);
+
+ return (ISC_TRUE);
+}
+
+int
+dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) {
+ unsigned int l1, l2, l, count1, count2, count;
+ unsigned char c1, c2;
+ unsigned char *label1, *label2;
+
+ /*
+ * Compare two absolute names as rdata.
+ */
+
+ REQUIRE(VALID_NAME(name1));
+ REQUIRE(name1->labels > 0);
+ REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
+ REQUIRE(VALID_NAME(name2));
+ REQUIRE(name2->labels > 0);
+ REQUIRE((name2->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
+
+ l1 = name1->labels;
+ l2 = name2->labels;
+
+ l = (l1 < l2) ? l1 : l2;
+
+ label1 = name1->ndata;
+ label2 = name2->ndata;
+ while (l > 0) {
+ l--;
+ count1 = *label1++;
+ count2 = *label2++;
+
+ /* no bitstring support */
+ INSIST(count1 <= 63 && count2 <= 63);
+
+ if (count1 != count2)
+ return ((count1 < count2) ? -1 : 1);
+ count = count1;
+ while (count > 0) {
+ count--;
+ c1 = maptolower[*label1++];
+ c2 = maptolower[*label2++];
+ if (c1 < c2)
+ return (-1);
+ else if (c1 > c2)
+ return (1);
+ }
+ }
+
+ /*
+ * If one name had more labels than the other, their common
+ * prefix must have been different because the shorter name
+ * ended with the root label and the longer one can't have
+ * a root label in the middle of it. Therefore, if we get
+ * to this point, the lengths must be equal.
+ */
+ INSIST(l1 == l2);
+
+ return (0);
+}
+
+isc_boolean_t
+dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) {
+ int order;
+ unsigned int nlabels;
+ dns_namereln_t namereln;
+
+ /*
+ * Is 'name1' a subdomain of 'name2'?
+ *
+ * Note: It makes no sense for one of the names to be relative and the
+ * other absolute. If both names are relative, then to be meaningfully
+ * compared the caller must ensure that they are both relative to the
+ * same domain.
+ */
+
+ namereln = dns_name_fullcompare(name1, name2, &order, &nlabels);
+ if (namereln == dns_namereln_subdomain ||
+ namereln == dns_namereln_equal)
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) {
+ int order;
+ unsigned int nlabels, labels;
+ dns_name_t tname;
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(name->labels > 0);
+ REQUIRE(VALID_NAME(wname));
+ labels = wname->labels;
+ REQUIRE(labels > 0);
+ REQUIRE(dns_name_iswildcard(wname));
+
+ DNS_NAME_INIT(&tname, NULL);
+ dns_name_getlabelsequence(wname, 1, labels - 1, &tname);
+ if (dns_name_fullcompare(name, &tname, &order, &nlabels) ==
+ dns_namereln_subdomain)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+unsigned int
+dns_name_countlabels(const dns_name_t *name) {
+ /*
+ * How many labels does 'name' have?
+ */
+
+ REQUIRE(VALID_NAME(name));
+
+ ENSURE(name->labels <= 128);
+
+ return (name->labels);
+}
+
+void
+dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) {
+ unsigned char *offsets;
+ dns_offsets_t odata;
+
+ /*
+ * Make 'label' refer to the 'n'th least significant label of 'name'.
+ */
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(name->labels > 0);
+ REQUIRE(n < name->labels);
+ REQUIRE(label != NULL);
+
+ SETUP_OFFSETS(name, offsets, odata);
+
+ label->base = &name->ndata[offsets[n]];
+ if (n == name->labels - 1)
+ label->length = name->length - offsets[n];
+ else
+ label->length = offsets[n + 1] - offsets[n];
+}
+
+void
+dns_name_getlabelsequence(const dns_name_t *source,
+ unsigned int first, unsigned int n,
+ dns_name_t *target)
+{
+ unsigned char *offsets;
+ dns_offsets_t odata;
+ unsigned int firstoffset, endoffset;
+
+ /*
+ * Make 'target' refer to the 'n' labels including and following
+ * 'first' in 'source'.
+ */
+
+ REQUIRE(VALID_NAME(source));
+ REQUIRE(VALID_NAME(target));
+ REQUIRE(first <= source->labels);
+ REQUIRE(first + n <= source->labels);
+ REQUIRE(BINDABLE(target));
+
+ SETUP_OFFSETS(source, offsets, odata);
+
+ if (first == source->labels)
+ firstoffset = source->length;
+ else
+ firstoffset = offsets[first];
+
+ if (first + n == source->labels)
+ endoffset = source->length;
+ else
+ endoffset = offsets[first + n];
+
+ target->ndata = &source->ndata[firstoffset];
+ target->length = endoffset - firstoffset;
+
+ if (first + n == source->labels && n > 0 &&
+ (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
+ target->attributes |= DNS_NAMEATTR_ABSOLUTE;
+ else
+ target->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
+
+ target->labels = n;
+
+ /*
+ * If source and target are the same, and we're making target
+ * a prefix of source, the offsets table is correct already
+ * so we don't need to call set_offsets().
+ */
+ if (target->offsets != NULL &&
+ (target != source || first != 0))
+ set_offsets(target, target->offsets, NULL);
+}
+
+void
+dns_name_clone(const dns_name_t *source, dns_name_t *target) {
+
+ /*
+ * Make 'target' refer to the same name as 'source'.
+ */
+
+ REQUIRE(VALID_NAME(source));
+ REQUIRE(VALID_NAME(target));
+ REQUIRE(BINDABLE(target));
+
+ target->ndata = source->ndata;
+ target->length = source->length;
+ target->labels = source->labels;
+ target->attributes = source->attributes &
+ (unsigned int)~(DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC |
+ DNS_NAMEATTR_DYNOFFSETS);
+ if (target->offsets != NULL && source->labels > 0) {
+ if (source->offsets != NULL)
+ memcpy(target->offsets, source->offsets,
+ source->labels);
+ else
+ set_offsets(target, target->offsets, NULL);
+ }
+}
+
+void
+dns_name_fromregion(dns_name_t *name, const isc_region_t *r) {
+ unsigned char *offsets;
+ dns_offsets_t odata;
+ unsigned int len;
+ isc_region_t r2;
+
+ /*
+ * Make 'name' refer to region 'r'.
+ */
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(r != NULL);
+ REQUIRE(BINDABLE(name));
+
+ INIT_OFFSETS(name, offsets, odata);
+
+ if (name->buffer != NULL) {
+ isc_buffer_clear(name->buffer);
+ isc_buffer_availableregion(name->buffer, &r2);
+ len = (r->length < r2.length) ? r->length : r2.length;
+ if (len > DNS_NAME_MAXWIRE)
+ len = DNS_NAME_MAXWIRE;
+ memcpy(r2.base, r->base, len);
+ name->ndata = r2.base;
+ name->length = len;
+ } else {
+ name->ndata = r->base;
+ name->length = (r->length <= DNS_NAME_MAXWIRE) ?
+ r->length : DNS_NAME_MAXWIRE;
+ }
+
+ if (r->length > 0)
+ set_offsets(name, offsets, name);
+ else {
+ name->labels = 0;
+ name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
+ }
+
+ if (name->buffer != NULL)
+ isc_buffer_add(name->buffer, name->length);
+}
+
+void
+dns_name_toregion(dns_name_t *name, isc_region_t *r) {
+ /*
+ * Make 'r' refer to 'name'.
+ */
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(r != NULL);
+
+ DNS_NAME_TOREGION(name, r);
+}
+
+
+isc_result_t
+dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
+ dns_name_t *origin, unsigned int options,
+ isc_buffer_t *target)
+{
+ unsigned char *ndata, *label;
+ char *tdata;
+ char c;
+ ft_state state;
+ unsigned int value, count;
+ unsigned int n1, n2, tlen, nrem, nused, digits, labels, tused;
+ isc_boolean_t done;
+ unsigned char *offsets;
+ dns_offsets_t odata;
+ isc_boolean_t downcase;
+
+ /*
+ * Convert the textual representation of a DNS name at source
+ * into uncompressed wire form stored in target.
+ *
+ * Notes:
+ * Relative domain names will have 'origin' appended to them
+ * unless 'origin' is NULL, in which case relative domain names
+ * will remain relative.
+ */
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(ISC_BUFFER_VALID(source));
+ REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
+ (target == NULL && ISC_BUFFER_VALID(name->buffer)));
+
+ downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0);
+
+ if (target == NULL && name->buffer != NULL) {
+ target = name->buffer;
+ isc_buffer_clear(target);
+ }
+
+ REQUIRE(BINDABLE(name));
+
+ INIT_OFFSETS(name, offsets, odata);
+ offsets[0] = 0;
+
+ /*
+ * Initialize things to make the compiler happy; they're not required.
+ */
+ n1 = 0;
+ n2 = 0;
+ label = NULL;
+ digits = 0;
+ value = 0;
+ count = 0;
+
+ /*
+ * Make 'name' empty in case of failure.
+ */
+ MAKE_EMPTY(name);
+
+ /*
+ * Set up the state machine.
+ */
+ tdata = (char *)source->base + source->current;
+ tlen = isc_buffer_remaininglength(source);
+ tused = 0;
+ ndata = isc_buffer_used(target);
+ nrem = isc_buffer_availablelength(target);
+ if (nrem > 255)
+ nrem = 255;
+ nused = 0;
+ labels = 0;
+ done = ISC_FALSE;
+ state = ft_init;
+
+ while (nrem > 0 && tlen > 0 && !done) {
+ c = *tdata++;
+ tlen--;
+ tused++;
+
+ switch (state) {
+ case ft_init:
+ /*
+ * Is this the root name?
+ */
+ if (c == '.') {
+ if (tlen != 0)
+ return (DNS_R_EMPTYLABEL);
+ labels++;
+ *ndata++ = 0;
+ nrem--;
+ nused++;
+ done = ISC_TRUE;
+ break;
+ }
+ if (c == '@' && tlen == 0) {
+ state = ft_at;
+ break;
+ }
+
+ /* FALLTHROUGH */
+ case ft_start:
+ label = ndata;
+ ndata++;
+ nrem--;
+ nused++;
+ count = 0;
+ if (c == '\\') {
+ state = ft_initialescape;
+ break;
+ }
+ state = ft_ordinary;
+ if (nrem == 0)
+ return (ISC_R_NOSPACE);
+ /* FALLTHROUGH */
+ case ft_ordinary:
+ if (c == '.') {
+ if (count == 0)
+ return (DNS_R_EMPTYLABEL);
+ *label = count;
+ labels++;
+ INSIST(labels <= 127);
+ offsets[labels] = nused;
+ if (tlen == 0) {
+ labels++;
+ *ndata++ = 0;
+ nrem--;
+ nused++;
+ done = ISC_TRUE;
+ }
+ state = ft_start;
+ } else if (c == '\\') {
+ state = ft_escape;
+ } else {
+ if (count >= 63)
+ return (DNS_R_LABELTOOLONG);
+ count++;
+ CONVERTTOASCII(c);
+ if (downcase)
+ c = maptolower[(int)c];
+ *ndata++ = c;
+ nrem--;
+ nused++;
+ }
+ break;
+ case ft_initialescape:
+ if (c == '[') {
+ /*
+ * This looks like a bitstring label, which
+ * was deprecated. Intentionally drop it.
+ */
+ return (DNS_R_BADLABELTYPE);
+ }
+ state = ft_escape;
+ /* FALLTHROUGH */
+ case ft_escape:
+ if (!isdigit(c & 0xff)) {
+ if (count >= 63)
+ return (DNS_R_LABELTOOLONG);
+ count++;
+ CONVERTTOASCII(c);
+ if (downcase)
+ c = maptolower[(int)c];
+ *ndata++ = c;
+ nrem--;
+ nused++;
+ state = ft_ordinary;
+ break;
+ }
+ digits = 0;
+ value = 0;
+ state = ft_escdecimal;
+ /* FALLTHROUGH */
+ case ft_escdecimal:
+ if (!isdigit(c & 0xff))
+ return (DNS_R_BADESCAPE);
+ value *= 10;
+ value += digitvalue[(int)c];
+ digits++;
+ if (digits == 3) {
+ if (value > 255)
+ return (DNS_R_BADESCAPE);
+ if (count >= 63)
+ return (DNS_R_LABELTOOLONG);
+ count++;
+ if (downcase)
+ value = maptolower[value];
+ *ndata++ = value;
+ nrem--;
+ nused++;
+ state = ft_ordinary;
+ }
+ break;
+ default:
+ FATAL_ERROR(__FILE__, __LINE__,
+ "Unexpected state %d", state);
+ /* Does not return. */
+ }
+ }
+
+ if (!done) {
+ if (nrem == 0)
+ return (ISC_R_NOSPACE);
+ INSIST(tlen == 0);
+ if (state != ft_ordinary && state != ft_at)
+ return (ISC_R_UNEXPECTEDEND);
+ if (state == ft_ordinary) {
+ INSIST(count != 0);
+ *label = count;
+ labels++;
+ INSIST(labels <= 127);
+ offsets[labels] = nused;
+ }
+ if (origin != NULL) {
+ if (nrem < origin->length)
+ return (ISC_R_NOSPACE);
+ label = origin->ndata;
+ n1 = origin->length;
+ nrem -= n1;
+ while (n1 > 0) {
+ n2 = *label++;
+ INSIST(n2 <= 63); /* no bitstring support */
+ *ndata++ = n2;
+ n1 -= n2 + 1;
+ nused += n2 + 1;
+ while (n2 > 0) {
+ c = *label++;
+ if (downcase)
+ c = maptolower[(int)c];
+ *ndata++ = c;
+ n2--;
+ }
+ labels++;
+ if (n1 > 0) {
+ INSIST(labels <= 127);
+ offsets[labels] = nused;
+ }
+ }
+ if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
+ name->attributes |= DNS_NAMEATTR_ABSOLUTE;
+ }
+ } else
+ name->attributes |= DNS_NAMEATTR_ABSOLUTE;
+
+ name->ndata = (unsigned char *)target->base + target->used;
+ name->labels = labels;
+ name->length = nused;
+
+ isc_buffer_forward(source, tused);
+ isc_buffer_add(target, name->length);
+
+ return (ISC_R_SUCCESS);
+}
+
+#ifdef ISC_PLATFORM_USETHREADS
+static void
+free_specific(void *arg) {
+ dns_name_totextfilter_t *mem = arg;
+ isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
+ /* Stop use being called again. */
+ (void)isc_thread_key_setspecific(totext_filter_proc_key, NULL);
+}
+
+static void
+thread_key_mutex_init(void) {
+ RUNTIME_CHECK(isc_mutex_init(&thread_key_mutex) == ISC_R_SUCCESS);
+}
+
+static isc_result_t
+totext_filter_proc_key_init(void) {
+ isc_result_t result;
+
+ /*
+ * We need the call to isc_once_do() to support profiled mutex
+ * otherwise thread_key_mutex could be initialized at compile time.
+ */
+ result = isc_once_do(&once, thread_key_mutex_init);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (!thread_key_initialized) {
+ LOCK(&thread_key_mutex);
+ if (thread_key_mctx == NULL)
+ result = isc_mem_create2(0, 0, &thread_key_mctx, 0);
+ if (result != ISC_R_SUCCESS)
+ goto unlock;
+ isc_mem_setdestroycheck(thread_key_mctx, ISC_FALSE);
+
+ if (!thread_key_initialized &&
+ isc_thread_key_create(&totext_filter_proc_key,
+ free_specific) != 0) {
+ result = ISC_R_FAILURE;
+ isc_mem_detach(&thread_key_mctx);
+ } else
+ thread_key_initialized = 1;
+ unlock:
+ UNLOCK(&thread_key_mutex);
+ }
+ return (result);
+}
+#endif
+
+isc_result_t
+dns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot,
+ isc_buffer_t *target)
+{
+ unsigned char *ndata;
+ char *tdata;
+ unsigned int nlen, tlen;
+ unsigned char c;
+ unsigned int trem, count;
+ unsigned int labels;
+ isc_boolean_t saw_root = ISC_FALSE;
+ unsigned int oused = target->used;
+#ifdef ISC_PLATFORM_USETHREADS
+ dns_name_totextfilter_t *mem;
+ dns_name_totextfilter_t totext_filter_proc = NULL;
+ isc_result_t result;
+#endif
+
+ /*
+ * This function assumes the name is in proper uncompressed
+ * wire format.
+ */
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(ISC_BUFFER_VALID(target));
+
+#ifdef ISC_PLATFORM_USETHREADS
+ result = totext_filter_proc_key_init();
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#endif
+ ndata = name->ndata;
+ nlen = name->length;
+ labels = name->labels;
+ tdata = isc_buffer_used(target);
+ tlen = isc_buffer_availablelength(target);
+
+ trem = tlen;
+
+ if (labels == 0 && nlen == 0) {
+ /*
+ * Special handling for an empty name.
+ */
+ if (trem == 0)
+ return (ISC_R_NOSPACE);
+
+ /*
+ * The names of these booleans are misleading in this case.
+ * This empty name is not necessarily from the root node of
+ * the DNS root zone, nor is a final dot going to be included.
+ * They need to be set this way, though, to keep the "@"
+ * from being trounced.
+ */
+ saw_root = ISC_TRUE;
+ omit_final_dot = ISC_FALSE;
+ *tdata++ = '@';
+ trem--;
+
+ /*
+ * Skip the while() loop.
+ */
+ nlen = 0;
+ } else if (nlen == 1 && labels == 1 && *ndata == '\0') {
+ /*
+ * Special handling for the root label.
+ */
+ if (trem == 0)
+ return (ISC_R_NOSPACE);
+
+ saw_root = ISC_TRUE;
+ omit_final_dot = ISC_FALSE;
+ *tdata++ = '.';
+ trem--;
+
+ /*
+ * Skip the while() loop.
+ */
+ nlen = 0;
+ }
+
+ while (labels > 0 && nlen > 0 && trem > 0) {
+ labels--;
+ count = *ndata++;
+ nlen--;
+ if (count == 0) {
+ saw_root = ISC_TRUE;
+ break;
+ }
+ if (count < 64) {
+ INSIST(nlen >= count);
+ while (count > 0) {
+ c = *ndata;
+ switch (c) {
+ case 0x22: /* '"' */
+ case 0x28: /* '(' */
+ case 0x29: /* ')' */
+ case 0x2E: /* '.' */
+ case 0x3B: /* ';' */
+ case 0x5C: /* '\\' */
+ /* Special modifiers in zone files. */
+ case 0x40: /* '@' */
+ case 0x24: /* '$' */
+ if (trem < 2)
+ return (ISC_R_NOSPACE);
+ *tdata++ = '\\';
+ CONVERTFROMASCII(c);
+ *tdata++ = c;
+ ndata++;
+ trem -= 2;
+ nlen--;
+ break;
+ default:
+ if (c > 0x20 && c < 0x7f) {
+ if (trem == 0)
+ return (ISC_R_NOSPACE);
+ CONVERTFROMASCII(c);
+ *tdata++ = c;
+ ndata++;
+ trem--;
+ nlen--;
+ } else {
+ if (trem < 4)
+ return (ISC_R_NOSPACE);
+ *tdata++ = 0x5c;
+ *tdata++ = 0x30 +
+ ((c / 100) % 10);
+ *tdata++ = 0x30 +
+ ((c / 10) % 10);
+ *tdata++ = 0x30 + (c % 10);
+ trem -= 4;
+ ndata++;
+ nlen--;
+ }
+ }
+ count--;
+ }
+ } else {
+ FATAL_ERROR(__FILE__, __LINE__,
+ "Unexpected label type %02x", count);
+ /* NOTREACHED */
+ }
+
+ /*
+ * The following assumes names are absolute. If not, we
+ * fix things up later. Note that this means that in some
+ * cases one more byte of text buffer is required than is
+ * needed in the final output.
+ */
+ if (trem == 0)
+ return (ISC_R_NOSPACE);
+ *tdata++ = '.';
+ trem--;
+ }
+
+ if (nlen != 0 && trem == 0)
+ return (ISC_R_NOSPACE);
+
+ if (!saw_root || omit_final_dot)
+ trem++;
+
+ isc_buffer_add(target, tlen - trem);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ mem = isc_thread_key_getspecific(totext_filter_proc_key);
+ if (mem != NULL)
+ totext_filter_proc = *mem;
+#endif
+ if (totext_filter_proc != NULL)
+ return ((*totext_filter_proc)(target, oused, saw_root));
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_name_tofilenametext(dns_name_t *name, isc_boolean_t omit_final_dot,
+ isc_buffer_t *target)
+{
+ unsigned char *ndata;
+ char *tdata;
+ unsigned int nlen, tlen;
+ unsigned char c;
+ unsigned int trem, count;
+ unsigned int labels;
+
+ /*
+ * This function assumes the name is in proper uncompressed
+ * wire format.
+ */
+ REQUIRE(VALID_NAME(name));
+ REQUIRE((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
+ REQUIRE(ISC_BUFFER_VALID(target));
+
+ ndata = name->ndata;
+ nlen = name->length;
+ labels = name->labels;
+ tdata = isc_buffer_used(target);
+ tlen = isc_buffer_availablelength(target);
+
+ trem = tlen;
+
+ if (nlen == 1 && labels == 1 && *ndata == '\0') {
+ /*
+ * Special handling for the root label.
+ */
+ if (trem == 0)
+ return (ISC_R_NOSPACE);
+
+ omit_final_dot = ISC_FALSE;
+ *tdata++ = '.';
+ trem--;
+
+ /*
+ * Skip the while() loop.
+ */
+ nlen = 0;
+ }
+
+ while (labels > 0 && nlen > 0 && trem > 0) {
+ labels--;
+ count = *ndata++;
+ nlen--;
+ if (count == 0)
+ break;
+ if (count < 64) {
+ INSIST(nlen >= count);
+ while (count > 0) {
+ c = *ndata;
+ if ((c >= 0x30 && c <= 0x39) || /* digit */
+ (c >= 0x41 && c <= 0x5A) || /* uppercase */
+ (c >= 0x61 && c <= 0x7A) || /* lowercase */
+ c == 0x2D || /* hyphen */
+ c == 0x5F) /* underscore */
+ {
+ if (trem == 0)
+ return (ISC_R_NOSPACE);
+ /* downcase */
+ if (c >= 0x41 && c <= 0x5A)
+ c += 0x20;
+ CONVERTFROMASCII(c);
+ *tdata++ = c;
+ ndata++;
+ trem--;
+ nlen--;
+ } else {
+ if (trem < 3)
+ return (ISC_R_NOSPACE);
+ sprintf(tdata, "%%%02X", c);
+ tdata += 3;
+ trem -= 3;
+ ndata++;
+ nlen--;
+ }
+ count--;
+ }
+ } else {
+ FATAL_ERROR(__FILE__, __LINE__,
+ "Unexpected label type %02x", count);
+ /* NOTREACHED */
+ }
+
+ /*
+ * The following assumes names are absolute. If not, we
+ * fix things up later. Note that this means that in some
+ * cases one more byte of text buffer is required than is
+ * needed in the final output.
+ */
+ if (trem == 0)
+ return (ISC_R_NOSPACE);
+ *tdata++ = '.';
+ trem--;
+ }
+
+ if (nlen != 0 && trem == 0)
+ return (ISC_R_NOSPACE);
+
+ if (omit_final_dot)
+ trem++;
+
+ isc_buffer_add(target, tlen - trem);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_name_downcase(dns_name_t *source, dns_name_t *name, isc_buffer_t *target) {
+ unsigned char *sndata, *ndata;
+ unsigned int nlen, count, labels;
+ isc_buffer_t buffer;
+
+ /*
+ * Downcase 'source'.
+ */
+
+ REQUIRE(VALID_NAME(source));
+ REQUIRE(VALID_NAME(name));
+ if (source == name) {
+ REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0);
+ isc_buffer_init(&buffer, source->ndata, source->length);
+ target = &buffer;
+ ndata = source->ndata;
+ } else {
+ REQUIRE(BINDABLE(name));
+ REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
+ (target == NULL && ISC_BUFFER_VALID(name->buffer)));
+ if (target == NULL) {
+ target = name->buffer;
+ isc_buffer_clear(name->buffer);
+ }
+ ndata = (unsigned char *)target->base + target->used;
+ name->ndata = ndata;
+ }
+
+ sndata = source->ndata;
+ nlen = source->length;
+ labels = source->labels;
+
+ if (nlen > (target->length - target->used)) {
+ MAKE_EMPTY(name);
+ return (ISC_R_NOSPACE);
+ }
+
+ while (labels > 0 && nlen > 0) {
+ labels--;
+ count = *sndata++;
+ *ndata++ = count;
+ nlen--;
+ if (count < 64) {
+ INSIST(nlen >= count);
+ while (count > 0) {
+ *ndata++ = maptolower[(*sndata++)];
+ nlen--;
+ count--;
+ }
+ } else {
+ FATAL_ERROR(__FILE__, __LINE__,
+ "Unexpected label type %02x", count);
+ /* Does not return. */
+ }
+ }
+
+ if (source != name) {
+ name->labels = source->labels;
+ name->length = source->length;
+ if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
+ name->attributes = DNS_NAMEATTR_ABSOLUTE;
+ else
+ name->attributes = 0;
+ if (name->labels > 0 && name->offsets != NULL)
+ set_offsets(name, name->offsets, NULL);
+ }
+
+ isc_buffer_add(target, name->length);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+set_offsets(const dns_name_t *name, unsigned char *offsets,
+ dns_name_t *set_name)
+{
+ unsigned int offset, count, length, nlabels;
+ unsigned char *ndata;
+ isc_boolean_t absolute;
+
+ ndata = name->ndata;
+ length = name->length;
+ offset = 0;
+ nlabels = 0;
+ absolute = ISC_FALSE;
+ while (offset != length) {
+ INSIST(nlabels < 128);
+ offsets[nlabels++] = offset;
+ count = *ndata++;
+ offset++;
+ INSIST(count <= 63);
+ offset += count;
+ ndata += count;
+ INSIST(offset <= length);
+ if (count == 0) {
+ absolute = ISC_TRUE;
+ break;
+ }
+ }
+ if (set_name != NULL) {
+ INSIST(set_name == name);
+
+ set_name->labels = nlabels;
+ set_name->length = offset;
+ if (absolute)
+ set_name->attributes |= DNS_NAMEATTR_ABSOLUTE;
+ else
+ set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
+ }
+ INSIST(nlabels == name->labels);
+ INSIST(offset == name->length);
+}
+
+isc_result_t
+dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
+ dns_decompress_t *dctx, unsigned int options,
+ isc_buffer_t *target)
+{
+ unsigned char *cdata, *ndata;
+ unsigned int cused; /* Bytes of compressed name data used */
+ unsigned int nused, labels, n, nmax;
+ unsigned int current, new_current, biggest_pointer;
+ isc_boolean_t done;
+ fw_state state = fw_start;
+ unsigned int c;
+ unsigned char *offsets;
+ dns_offsets_t odata;
+ isc_boolean_t downcase;
+ isc_boolean_t seen_pointer;
+
+ /*
+ * Copy the possibly-compressed name at source into target,
+ * decompressing it. Loop prevention is performed by checking
+ * the new pointer against biggest_pointer.
+ */
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
+ (target == NULL && ISC_BUFFER_VALID(name->buffer)));
+
+ downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0);
+
+ if (target == NULL && name->buffer != NULL) {
+ target = name->buffer;
+ isc_buffer_clear(target);
+ }
+
+ REQUIRE(dctx != NULL);
+ REQUIRE(BINDABLE(name));
+
+ INIT_OFFSETS(name, offsets, odata);
+
+ /*
+ * Make 'name' empty in case of failure.
+ */
+ MAKE_EMPTY(name);
+
+ /*
+ * Initialize things to make the compiler happy; they're not required.
+ */
+ n = 0;
+ new_current = 0;
+
+ /*
+ * Set up.
+ */
+ labels = 0;
+ done = ISC_FALSE;
+
+ ndata = isc_buffer_used(target);
+ nused = 0;
+ seen_pointer = ISC_FALSE;
+
+ /*
+ * Find the maximum number of uncompressed target name
+ * bytes we are willing to generate. This is the smaller
+ * of the available target buffer length and the
+ * maximum legal domain name length (255).
+ */
+ nmax = isc_buffer_availablelength(target);
+ if (nmax > DNS_NAME_MAXWIRE)
+ nmax = DNS_NAME_MAXWIRE;
+
+ cdata = isc_buffer_current(source);
+ cused = 0;
+
+ current = source->current;
+ biggest_pointer = current;
+
+ /*
+ * Note: The following code is not optimized for speed, but
+ * rather for correctness. Speed will be addressed in the future.
+ */
+
+ while (current < source->active && !done) {
+ c = *cdata++;
+ current++;
+ if (!seen_pointer)
+ cused++;
+
+ switch (state) {
+ case fw_start:
+ if (c < 64) {
+ offsets[labels] = nused;
+ labels++;
+ if (nused + c + 1 > nmax)
+ goto full;
+ nused += c + 1;
+ *ndata++ = c;
+ if (c == 0)
+ done = ISC_TRUE;
+ n = c;
+ state = fw_ordinary;
+ } else if (c >= 128 && c < 192) {
+ /*
+ * 14 bit local compression pointer.
+ * Local compression is no longer an
+ * IETF draft.
+ */
+ return (DNS_R_BADLABELTYPE);
+ } else if (c >= 192) {
+ /*
+ * Ordinary 14-bit pointer.
+ */
+ if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) ==
+ 0)
+ return (DNS_R_DISALLOWED);
+ new_current = c & 0x3F;
+ n = 1;
+ state = fw_newcurrent;
+ } else
+ return (DNS_R_BADLABELTYPE);
+ break;
+ case fw_ordinary:
+ if (downcase)
+ c = maptolower[c];
+ /* FALLTHROUGH */
+ case fw_copy:
+ *ndata++ = c;
+ n--;
+ if (n == 0)
+ state = fw_start;
+ break;
+ case fw_newcurrent:
+ new_current *= 256;
+ new_current += c;
+ n--;
+ if (n != 0)
+ break;
+ if (new_current >= biggest_pointer)
+ return (DNS_R_BADPOINTER);
+ biggest_pointer = new_current;
+ current = new_current;
+ cdata = (unsigned char *)source->base + current;
+ seen_pointer = ISC_TRUE;
+ state = fw_start;
+ break;
+ default:
+ FATAL_ERROR(__FILE__, __LINE__,
+ "Unknown state %d", state);
+ /* Does not return. */
+ }
+ }
+
+ if (!done)
+ return (ISC_R_UNEXPECTEDEND);
+
+ name->ndata = (unsigned char *)target->base + target->used;
+ name->labels = labels;
+ name->length = nused;
+ name->attributes |= DNS_NAMEATTR_ABSOLUTE;
+
+ isc_buffer_forward(source, cused);
+ isc_buffer_add(target, name->length);
+
+ return (ISC_R_SUCCESS);
+
+ full:
+ if (nmax == DNS_NAME_MAXWIRE)
+ /*
+ * The name did not fit even though we had a buffer
+ * big enough to fit a maximum-length name.
+ */
+ return (DNS_R_NAMETOOLONG);
+ else
+ /*
+ * The name might fit if only the caller could give us a
+ * big enough buffer.
+ */
+ return (ISC_R_NOSPACE);
+}
+
+isc_result_t
+dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
+ isc_buffer_t *target)
+{
+ unsigned int methods;
+ isc_uint16_t offset;
+ dns_name_t gp; /* Global compression prefix */
+ isc_boolean_t gf; /* Global compression target found */
+ isc_uint16_t go; /* Global compression offset */
+ dns_offsets_t clo;
+ dns_name_t clname;
+
+ /*
+ * Convert 'name' into wire format, compressing it as specified by the
+ * compression context 'cctx', and storing the result in 'target'.
+ */
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(cctx != NULL);
+ REQUIRE(ISC_BUFFER_VALID(target));
+
+ /*
+ * If 'name' doesn't have an offsets table, make a clone which
+ * has one.
+ */
+ if (name->offsets == NULL) {
+ DNS_NAME_INIT(&clname, clo);
+ dns_name_clone(name, &clname);
+ name = &clname;
+ }
+ DNS_NAME_INIT(&gp, NULL);
+
+ offset = target->used; /*XXX*/
+
+ methods = dns_compress_getmethods(cctx);
+
+ if ((methods & DNS_COMPRESS_GLOBAL14) != 0)
+ gf = dns_compress_findglobal(cctx, name, &gp, &go);
+ else
+ gf = ISC_FALSE;
+
+ /*
+ * If the offset is too high for 14 bit global compression, we're
+ * out of luck.
+ */
+ if (gf && go >= 0x4000)
+ gf = ISC_FALSE;
+
+ /*
+ * Will the compression pointer reduce the message size?
+ */
+ if (gf && (gp.length + 2) >= name->length)
+ gf = ISC_FALSE;
+
+ if (gf) {
+ if (target->length - target->used < gp.length)
+ return (ISC_R_NOSPACE);
+ (void)memcpy((unsigned char *)target->base + target->used,
+ gp.ndata, (size_t)gp.length);
+ isc_buffer_add(target, gp.length);
+ go |= 0xc000;
+ if (target->length - target->used < 2)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint16(target, go);
+ if (gp.length != 0)
+ dns_compress_add(cctx, name, &gp, offset);
+ } else {
+ if (target->length - target->used < name->length)
+ return (ISC_R_NOSPACE);
+ (void)memcpy((unsigned char *)target->base + target->used,
+ name->ndata, (size_t)name->length);
+ isc_buffer_add(target, name->length);
+ dns_compress_add(cctx, name, name, offset);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name,
+ isc_buffer_t *target)
+{
+ unsigned char *ndata, *offsets;
+ unsigned int nrem, labels, prefix_length, length;
+ isc_boolean_t copy_prefix = ISC_TRUE;
+ isc_boolean_t copy_suffix = ISC_TRUE;
+ isc_boolean_t absolute = ISC_FALSE;
+ dns_name_t tmp_name;
+ dns_offsets_t odata;
+
+ /*
+ * Concatenate 'prefix' and 'suffix'.
+ */
+
+ REQUIRE(prefix == NULL || VALID_NAME(prefix));
+ REQUIRE(suffix == NULL || VALID_NAME(suffix));
+ REQUIRE(name == NULL || VALID_NAME(name));
+ REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
+ (target == NULL && name != NULL && ISC_BUFFER_VALID(name->buffer)));
+ if (prefix == NULL || prefix->labels == 0)
+ copy_prefix = ISC_FALSE;
+ if (suffix == NULL || suffix->labels == 0)
+ copy_suffix = ISC_FALSE;
+ if (copy_prefix &&
+ (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
+ absolute = ISC_TRUE;
+ REQUIRE(!copy_suffix);
+ }
+ if (name == NULL) {
+ DNS_NAME_INIT(&tmp_name, odata);
+ name = &tmp_name;
+ }
+ if (target == NULL) {
+ INSIST(name->buffer != NULL);
+ target = name->buffer;
+ isc_buffer_clear(name->buffer);
+ }
+
+ REQUIRE(BINDABLE(name));
+
+ /*
+ * Set up.
+ */
+ nrem = target->length - target->used;
+ ndata = (unsigned char *)target->base + target->used;
+ if (nrem > DNS_NAME_MAXWIRE)
+ nrem = DNS_NAME_MAXWIRE;
+ length = 0;
+ prefix_length = 0;
+ labels = 0;
+ if (copy_prefix) {
+ prefix_length = prefix->length;
+ length += prefix_length;
+ labels += prefix->labels;
+ }
+ if (copy_suffix) {
+ length += suffix->length;
+ labels += suffix->labels;
+ }
+ if (length > DNS_NAME_MAXWIRE) {
+ MAKE_EMPTY(name);
+ return (DNS_R_NAMETOOLONG);
+ }
+ if (length > nrem) {
+ MAKE_EMPTY(name);
+ return (ISC_R_NOSPACE);
+ }
+
+ if (copy_suffix) {
+ if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
+ absolute = ISC_TRUE;
+ if (suffix == name && suffix->buffer == target)
+ memmove(ndata + prefix_length, suffix->ndata,
+ suffix->length);
+ else
+ memcpy(ndata + prefix_length, suffix->ndata,
+ suffix->length);
+ }
+
+ /*
+ * If 'prefix' and 'name' are the same object, and the object has
+ * a dedicated buffer, and we're using it, then we don't have to
+ * copy anything.
+ */
+ if (copy_prefix && (prefix != name || prefix->buffer != target))
+ memcpy(ndata, prefix->ndata, prefix_length);
+
+ name->ndata = ndata;
+ name->labels = labels;
+ name->length = length;
+ if (absolute)
+ name->attributes = DNS_NAMEATTR_ABSOLUTE;
+ else
+ name->attributes = 0;
+
+ if (name->labels > 0 && name->offsets != NULL) {
+ INIT_OFFSETS(name, offsets, odata);
+ set_offsets(name, offsets, NULL);
+ }
+
+ isc_buffer_add(target, name->length);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_name_split(dns_name_t *name, unsigned int suffixlabels,
+ dns_name_t *prefix, dns_name_t *suffix)
+
+{
+ unsigned int splitlabel;
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(suffixlabels > 0);
+ REQUIRE(suffixlabels < name->labels);
+ REQUIRE(prefix != NULL || suffix != NULL);
+ REQUIRE(prefix == NULL ||
+ (VALID_NAME(prefix) &&
+ prefix->buffer != NULL &&
+ BINDABLE(prefix)));
+ REQUIRE(suffix == NULL ||
+ (VALID_NAME(suffix) &&
+ suffix->buffer != NULL &&
+ BINDABLE(suffix)));
+
+ splitlabel = name->labels - suffixlabels;
+
+ if (prefix != NULL)
+ dns_name_getlabelsequence(name, 0, splitlabel, prefix);
+
+ if (suffix != NULL)
+ dns_name_getlabelsequence(name, splitlabel,
+ suffixlabels, suffix);
+
+ return;
+}
+
+isc_result_t
+dns_name_dup(const dns_name_t *source, isc_mem_t *mctx,
+ dns_name_t *target)
+{
+ /*
+ * Make 'target' a dynamically allocated copy of 'source'.
+ */
+
+ REQUIRE(VALID_NAME(source));
+ REQUIRE(source->length > 0);
+ REQUIRE(VALID_NAME(target));
+ REQUIRE(BINDABLE(target));
+
+ /*
+ * Make 'target' empty in case of failure.
+ */
+ MAKE_EMPTY(target);
+
+ target->ndata = isc_mem_get(mctx, source->length);
+ if (target->ndata == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memcpy(target->ndata, source->ndata, source->length);
+
+ target->length = source->length;
+ target->labels = source->labels;
+ target->attributes = DNS_NAMEATTR_DYNAMIC;
+ if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
+ target->attributes |= DNS_NAMEATTR_ABSOLUTE;
+ if (target->offsets != NULL) {
+ if (source->offsets != NULL)
+ memcpy(target->offsets, source->offsets,
+ source->labels);
+ else
+ set_offsets(target, target->offsets, NULL);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_name_dupwithoffsets(dns_name_t *source, isc_mem_t *mctx,
+ dns_name_t *target)
+{
+ /*
+ * Make 'target' a read-only dynamically allocated copy of 'source'.
+ * 'target' will also have a dynamically allocated offsets table.
+ */
+
+ REQUIRE(VALID_NAME(source));
+ REQUIRE(source->length > 0);
+ REQUIRE(VALID_NAME(target));
+ REQUIRE(BINDABLE(target));
+ REQUIRE(target->offsets == NULL);
+
+ /*
+ * Make 'target' empty in case of failure.
+ */
+ MAKE_EMPTY(target);
+
+ target->ndata = isc_mem_get(mctx, source->length + source->labels);
+ if (target->ndata == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memcpy(target->ndata, source->ndata, source->length);
+
+ target->length = source->length;
+ target->labels = source->labels;
+ target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS |
+ DNS_NAMEATTR_READONLY;
+ if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
+ target->attributes |= DNS_NAMEATTR_ABSOLUTE;
+ target->offsets = target->ndata + source->length;
+ if (source->offsets != NULL)
+ memcpy(target->offsets, source->offsets, source->labels);
+ else
+ set_offsets(target, target->offsets, NULL);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_name_free(dns_name_t *name, isc_mem_t *mctx) {
+ size_t size;
+
+ /*
+ * Free 'name'.
+ */
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0);
+
+ size = name->length;
+ if ((name->attributes & DNS_NAMEATTR_DYNOFFSETS) != 0)
+ size += name->labels;
+ isc_mem_put(mctx, name->ndata, size);
+ dns_name_invalidate(name);
+}
+
+isc_result_t
+dns_name_digest(dns_name_t *name, dns_digestfunc_t digest, void *arg) {
+ dns_name_t downname;
+ unsigned char data[256];
+ isc_buffer_t buffer;
+ isc_result_t result;
+ isc_region_t r;
+
+ /*
+ * Send 'name' in DNSSEC canonical form to 'digest'.
+ */
+
+ REQUIRE(VALID_NAME(name));
+ REQUIRE(digest != NULL);
+
+ DNS_NAME_INIT(&downname, NULL);
+ isc_buffer_init(&buffer, data, sizeof(data));
+
+ result = dns_name_downcase(name, &downname, &buffer);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ isc_buffer_usedregion(&buffer, &r);
+
+ return ((digest)(arg, &r));
+}
+
+isc_boolean_t
+dns_name_dynamic(dns_name_t *name) {
+ REQUIRE(VALID_NAME(name));
+
+ /*
+ * Returns whether there is dynamic memory associated with this name.
+ */
+
+ return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ?
+ ISC_TRUE : ISC_FALSE);
+}
+
+isc_result_t
+dns_name_print(dns_name_t *name, FILE *stream) {
+ isc_result_t result;
+ isc_buffer_t b;
+ isc_region_t r;
+ char t[1024];
+
+ /*
+ * Print 'name' on 'stream'.
+ */
+
+ REQUIRE(VALID_NAME(name));
+
+ isc_buffer_init(&b, t, sizeof(t));
+ result = dns_name_totext(name, ISC_FALSE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_usedregion(&b, &r);
+ fprintf(stream, "%.*s", (int)r.length, (char *)r.base);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_name_settotextfilter(dns_name_totextfilter_t proc) {
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_result_t result;
+ dns_name_totextfilter_t *mem;
+ int res;
+
+ result = totext_filter_proc_key_init();
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * If we already have been here set / clear as appropriate.
+ * Otherwise allocate memory.
+ */
+ mem = isc_thread_key_getspecific(totext_filter_proc_key);
+ if (mem != NULL && proc != NULL) {
+ *mem = proc;
+ return (ISC_R_SUCCESS);
+ }
+ if (proc == NULL) {
+ isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
+ res = isc_thread_key_setspecific(totext_filter_proc_key, NULL);
+ if (res != 0)
+ result = ISC_R_UNEXPECTED;
+ return (result);
+ }
+
+ mem = isc_mem_get(thread_key_mctx, sizeof(*mem));
+ if (mem == NULL)
+ return (ISC_R_NOMEMORY);
+ *mem = proc;
+ if (isc_thread_key_setspecific(totext_filter_proc_key, mem) != 0) {
+ isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
+ result = ISC_R_UNEXPECTED;
+ }
+ return (result);
+#else
+ totext_filter_proc = proc;
+ return (ISC_R_SUCCESS);
+#endif
+}
+
+void
+dns_name_format(dns_name_t *name, char *cp, unsigned int size) {
+ isc_result_t result;
+ isc_buffer_t buf;
+
+ REQUIRE(size > 0);
+
+ /*
+ * Leave room for null termination after buffer.
+ */
+ isc_buffer_init(&buf, cp, size - 1);
+ result = dns_name_totext(name, ISC_TRUE, &buf);
+ if (result == ISC_R_SUCCESS) {
+ /*
+ * Null terminate.
+ */
+ isc_region_t r;
+ isc_buffer_usedregion(&buf, &r);
+ ((char *) r.base)[r.length] = '\0';
+
+ } else
+ snprintf(cp, size, "<unknown>");
+}
+
+isc_result_t
+dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
+ unsigned char *ndata;
+
+ /*
+ * Make dest a copy of source.
+ */
+
+ REQUIRE(VALID_NAME(source));
+ REQUIRE(VALID_NAME(dest));
+ REQUIRE(target != NULL || dest->buffer != NULL);
+
+ if (target == NULL) {
+ target = dest->buffer;
+ isc_buffer_clear(dest->buffer);
+ }
+
+ REQUIRE(BINDABLE(dest));
+
+ /*
+ * Set up.
+ */
+ if (target->length - target->used < source->length)
+ return (ISC_R_NOSPACE);
+
+ ndata = (unsigned char *)target->base + target->used;
+ dest->ndata = target->base;
+
+ memcpy(ndata, source->ndata, source->length);
+
+ dest->ndata = ndata;
+ dest->labels = source->labels;
+ dest->length = source->length;
+ if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
+ dest->attributes = DNS_NAMEATTR_ABSOLUTE;
+ else
+ dest->attributes = 0;
+
+ if (dest->labels > 0 && dest->offsets != NULL) {
+ if (source->offsets != NULL)
+ memcpy(dest->offsets, source->offsets, source->labels);
+ else
+ set_offsets(dest, dest->offsets, NULL);
+ }
+
+ isc_buffer_add(target, dest->length);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_name_destroy(void) {
+#ifdef ISC_PLATFORM_USETHREADS
+ RUNTIME_CHECK(isc_once_do(&once, thread_key_mutex_init)
+ == ISC_R_SUCCESS);
+
+ LOCK(&thread_key_mutex);
+ if (thread_key_initialized) {
+ isc_mem_detach(&thread_key_mctx);
+ isc_thread_key_delete(totext_filter_proc_key);
+ thread_key_initialized = 0;
+ }
+ UNLOCK(&thread_key_mutex);
+
+#endif
+}
diff --git a/lib/dns/ncache.c b/lib/dns/ncache.c
new file mode 100644
index 0000000..1fdc5c8
--- /dev/null
+++ b/lib/dns/ncache.c
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) 2004, 2005 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: ncache.c,v 1.36.18.3 2005/04/29 00:15:59 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/buffer.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/message.h>
+#include <dns/ncache.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+
+/*
+ * The format of an ncache rdata is a sequence of one or more records of
+ * the following format:
+ *
+ * owner name
+ * type
+ * rdata count
+ * rdata length These two occur 'rdata count'
+ * rdata times.
+ *
+ */
+
+static inline isc_result_t
+copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
+ isc_result_t result;
+ unsigned int count;
+ isc_region_t ar, r;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ /*
+ * Copy the rdataset count to the buffer.
+ */
+ isc_buffer_availableregion(buffer, &ar);
+ if (ar.length < 2)
+ return (ISC_R_NOSPACE);
+ count = dns_rdataset_count(rdataset);
+ INSIST(count <= 65535);
+ isc_buffer_putuint16(buffer, (isc_uint16_t)count);
+
+ result = dns_rdataset_first(rdataset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(rdataset, &rdata);
+ dns_rdata_toregion(&rdata, &r);
+ INSIST(r.length <= 65535);
+ isc_buffer_availableregion(buffer, &ar);
+ if (ar.length < 2)
+ return (ISC_R_NOSPACE);
+ /*
+ * Copy the rdata length to the buffer.
+ */
+ isc_buffer_putuint16(buffer, (isc_uint16_t)r.length);
+ /*
+ * Copy the rdata to the buffer.
+ */
+ result = isc_buffer_copyregion(buffer, &r);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(rdataset);
+ }
+ if (result != ISC_R_NOMORE)
+ return (result);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
+ dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
+ dns_rdataset_t *addedrdataset)
+{
+ isc_result_t result;
+ isc_buffer_t buffer;
+ isc_region_t r;
+ dns_rdataset_t *rdataset;
+ dns_rdatatype_t type;
+ dns_name_t *name;
+ dns_ttl_t ttl;
+ dns_trust_t trust;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t ncrdataset;
+ dns_rdatalist_t ncrdatalist;
+ unsigned char data[4096];
+
+ /*
+ * Convert the authority data from 'message' into a negative cache
+ * rdataset, and store it in 'cache' at 'node'.
+ */
+
+ REQUIRE(message != NULL);
+
+ /*
+ * We assume that all data in the authority section has been
+ * validated by the caller.
+ */
+
+ /*
+ * First, build an ncache rdata in buffer.
+ */
+ ttl = maxttl;
+ trust = 0xffff;
+ isc_buffer_init(&buffer, data, sizeof(data));
+ if (message->counts[DNS_SECTION_AUTHORITY])
+ result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+ else
+ result = ISC_R_NOMORE;
+ while (result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_AUTHORITY,
+ &name);
+ if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ if ((rdataset->attributes &
+ DNS_RDATASETATTR_NCACHE) == 0)
+ continue;
+ type = rdataset->type;
+ if (type == dns_rdatatype_rrsig)
+ type = rdataset->covers;
+ if (type == dns_rdatatype_soa ||
+ type == dns_rdatatype_nsec) {
+ if (ttl > rdataset->ttl)
+ ttl = rdataset->ttl;
+ if (trust > rdataset->trust)
+ trust = rdataset->trust;
+ /*
+ * Copy the owner name to the buffer.
+ */
+ dns_name_toregion(name, &r);
+ result = isc_buffer_copyregion(&buffer,
+ &r);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ /*
+ * Copy the type to the buffer.
+ */
+ isc_buffer_availableregion(&buffer,
+ &r);
+ if (r.length < 2)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint16(&buffer,
+ rdataset->type);
+ /*
+ * Copy the rdataset into the buffer.
+ */
+ result = copy_rdataset(rdataset,
+ &buffer);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ }
+ }
+ result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
+ }
+ if (result != ISC_R_NOMORE)
+ return (result);
+
+ if (trust == 0xffff) {
+ /*
+ * We didn't find any authority data from which to create a
+ * negative cache rdataset. In particular, we have no SOA.
+ *
+ * We trust that the caller wants negative caching, so this
+ * means we have a "type 3 nxdomain" or "type 3 nodata"
+ * response (see RFC2308 for details).
+ *
+ * We will now build a suitable negative cache rdataset that
+ * will cause zero bytes to be emitted when converted to
+ * wire format.
+ */
+
+ /*
+ * The ownername must exist, but it doesn't matter what value
+ * it has. We use the root name.
+ */
+ dns_name_toregion(dns_rootname, &r);
+ result = isc_buffer_copyregion(&buffer, &r);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ /*
+ * Copy the type and a zero rdata count to the buffer.
+ */
+ isc_buffer_availableregion(&buffer, &r);
+ if (r.length < 4)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint16(&buffer, 0);
+ isc_buffer_putuint16(&buffer, 0);
+ /*
+ * RFC2308, section 5, says that negative answers without
+ * SOAs should not be cached.
+ */
+ ttl = 0;
+ /*
+ * Set trust.
+ */
+ if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
+ message->counts[DNS_SECTION_ANSWER] == 0) {
+ /*
+ * The response has aa set and we haven't followed
+ * any CNAME or DNAME chains.
+ */
+ trust = dns_trust_authauthority;
+ } else
+ trust = dns_trust_additional;
+ }
+
+ /*
+ * Now add it to the cache.
+ */
+ INSIST(trust != 0xffff);
+ isc_buffer_usedregion(&buffer, &r);
+ rdata.data = r.base;
+ rdata.length = r.length;
+ rdata.rdclass = dns_db_class(cache);
+ rdata.type = 0;
+ rdata.flags = 0;
+
+ ncrdatalist.rdclass = rdata.rdclass;
+ ncrdatalist.type = 0;
+ ncrdatalist.covers = covers;
+ ncrdatalist.ttl = ttl;
+ ISC_LIST_INIT(ncrdatalist.rdata);
+ ISC_LINK_INIT(&ncrdatalist, link);
+
+ ISC_LIST_APPEND(ncrdatalist.rdata, &rdata, link);
+
+ dns_rdataset_init(&ncrdataset);
+ RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
+ == ISC_R_SUCCESS);
+ ncrdataset.trust = trust;
+ if (message->rcode == dns_rcode_nxdomain)
+ ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
+
+ return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
+ 0, addedrdataset));
+}
+
+isc_result_t
+dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
+ isc_buffer_t *target, unsigned int options,
+ unsigned int *countp)
+{
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_result_t result;
+ isc_region_t remaining, tavailable;
+ isc_buffer_t source, savedbuffer, rdlen;
+ dns_name_t name;
+ dns_rdatatype_t type;
+ unsigned int i, rcount, count;
+
+ /*
+ * Convert the negative caching rdataset 'rdataset' to wire format,
+ * compressing names as specified in 'cctx', and storing the result in
+ * 'target'.
+ */
+
+ REQUIRE(rdataset != NULL);
+ REQUIRE(rdataset->type == 0);
+
+ result = dns_rdataset_first(rdataset);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_rdataset_current(rdataset, &rdata);
+ INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
+ isc_buffer_init(&source, rdata.data, rdata.length);
+ isc_buffer_add(&source, rdata.length);
+
+ savedbuffer = *target;
+
+ count = 0;
+ do {
+ dns_name_init(&name, NULL);
+ isc_buffer_remainingregion(&source, &remaining);
+ dns_name_fromregion(&name, &remaining);
+ INSIST(remaining.length >= name.length);
+ isc_buffer_forward(&source, name.length);
+ remaining.length -= name.length;
+
+ INSIST(remaining.length >= 4);
+ type = isc_buffer_getuint16(&source);
+ rcount = isc_buffer_getuint16(&source);
+
+ for (i = 0; i < rcount; i++) {
+ /*
+ * Get the length of this rdata and set up an
+ * rdata structure for it.
+ */
+ isc_buffer_remainingregion(&source, &remaining);
+ INSIST(remaining.length >= 2);
+ dns_rdata_reset(&rdata);
+ rdata.length = isc_buffer_getuint16(&source);
+ isc_buffer_remainingregion(&source, &remaining);
+ rdata.data = remaining.base;
+ rdata.type = type;
+ rdata.rdclass = rdataset->rdclass;
+ INSIST(remaining.length >= rdata.length);
+ isc_buffer_forward(&source, rdata.length);
+
+ if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
+ dns_rdatatype_isdnssec(type))
+ continue;
+
+ /*
+ * Write the name.
+ */
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+ result = dns_name_towire(&name, cctx, target);
+ if (result != ISC_R_SUCCESS)
+ goto rollback;
+
+ /*
+ * See if we have space for type, class, ttl, and
+ * rdata length. Write the type, class, and ttl.
+ */
+ isc_buffer_availableregion(target, &tavailable);
+ if (tavailable.length < 10) {
+ result = ISC_R_NOSPACE;
+ goto rollback;
+ }
+ isc_buffer_putuint16(target, type);
+ isc_buffer_putuint16(target, rdataset->rdclass);
+ isc_buffer_putuint32(target, rdataset->ttl);
+
+ /*
+ * Save space for rdata length.
+ */
+ rdlen = *target;
+ isc_buffer_add(target, 2);
+
+ /*
+ * Write the rdata.
+ */
+ result = dns_rdata_towire(&rdata, cctx, target);
+ if (result != ISC_R_SUCCESS)
+ goto rollback;
+
+ /*
+ * Set the rdata length field to the compressed
+ * length.
+ */
+ INSIST((target->used >= rdlen.used + 2) &&
+ (target->used - rdlen.used - 2 < 65536));
+ isc_buffer_putuint16(&rdlen,
+ (isc_uint16_t)(target->used -
+ rdlen.used - 2));
+
+ count++;
+ }
+ isc_buffer_remainingregion(&source, &remaining);
+ } while (remaining.length > 0);
+
+ *countp = count;
+
+ return (ISC_R_SUCCESS);
+
+ rollback:
+ INSIST(savedbuffer.used < 65536);
+ dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
+ *countp = 0;
+ *target = savedbuffer;
+
+ return (result);
+}
+
+static void
+rdataset_disassociate(dns_rdataset_t *rdataset) {
+ UNUSED(rdataset);
+}
+
+static isc_result_t
+rdataset_first(dns_rdataset_t *rdataset) {
+ unsigned char *raw = rdataset->private3;
+ unsigned int count;
+
+ count = raw[0] * 256 + raw[1];
+ if (count == 0) {
+ rdataset->private5 = NULL;
+ return (ISC_R_NOMORE);
+ }
+ raw += 2;
+ /*
+ * The privateuint4 field is the number of rdata beyond the cursor
+ * position, so we decrement the total count by one before storing
+ * it.
+ */
+ count--;
+ rdataset->privateuint4 = count;
+ rdataset->private5 = raw;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+rdataset_next(dns_rdataset_t *rdataset) {
+ unsigned int count;
+ unsigned int length;
+ unsigned char *raw;
+
+ count = rdataset->privateuint4;
+ if (count == 0)
+ return (ISC_R_NOMORE);
+ count--;
+ rdataset->privateuint4 = count;
+ raw = rdataset->private5;
+ length = raw[0] * 256 + raw[1];
+ raw += length + 2;
+ rdataset->private5 = raw;
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
+ unsigned char *raw = rdataset->private5;
+ isc_region_t r;
+
+ REQUIRE(raw != NULL);
+
+ r.length = raw[0] * 256 + raw[1];
+ raw += 2;
+ r.base = raw;
+ dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
+}
+
+static void
+rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
+ *target = *source;
+
+ /*
+ * Reset iterator state.
+ */
+ target->privateuint4 = 0;
+ target->private5 = NULL;
+}
+
+static unsigned int
+rdataset_count(dns_rdataset_t *rdataset) {
+ unsigned char *raw = rdataset->private3;
+ unsigned int count;
+
+ count = raw[0] * 256 + raw[1];
+
+ return (count);
+}
+
+static dns_rdatasetmethods_t rdataset_methods = {
+ rdataset_disassociate,
+ rdataset_first,
+ rdataset_next,
+ rdataset_current,
+ rdataset_clone,
+ rdataset_count,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+isc_result_t
+dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
+ dns_rdatatype_t type, dns_rdataset_t *rdataset)
+{
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_region_t remaining;
+ isc_buffer_t source;
+ dns_name_t tname;
+ dns_rdatatype_t ttype;
+ unsigned int i, rcount;
+ isc_uint16_t length;
+
+ REQUIRE(ncacherdataset != NULL);
+ REQUIRE(ncacherdataset->type == 0);
+ REQUIRE(name != NULL);
+ REQUIRE(!dns_rdataset_isassociated(rdataset));
+ REQUIRE(type != dns_rdatatype_rrsig);
+
+ result = dns_rdataset_first(ncacherdataset);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_rdataset_current(ncacherdataset, &rdata);
+ INSIST(dns_rdataset_next(ncacherdataset) == ISC_R_NOMORE);
+ isc_buffer_init(&source, rdata.data, rdata.length);
+ isc_buffer_add(&source, rdata.length);
+
+ do {
+ dns_name_init(&tname, NULL);
+ isc_buffer_remainingregion(&source, &remaining);
+ dns_name_fromregion(&tname, &remaining);
+ INSIST(remaining.length >= tname.length);
+ isc_buffer_forward(&source, tname.length);
+ remaining.length -= tname.length;
+
+ INSIST(remaining.length >= 4);
+ ttype = isc_buffer_getuint16(&source);
+
+ if (ttype == type && dns_name_equal(&tname, name)) {
+ isc_buffer_remainingregion(&source, &remaining);
+ break;
+ }
+
+ rcount = isc_buffer_getuint16(&source);
+ for (i = 0; i < rcount; i++) {
+ isc_buffer_remainingregion(&source, &remaining);
+ INSIST(remaining.length >= 2);
+ length = isc_buffer_getuint16(&source);
+ isc_buffer_remainingregion(&source, &remaining);
+ INSIST(remaining.length >= length);
+ isc_buffer_forward(&source, length);
+ }
+ isc_buffer_remainingregion(&source, &remaining);
+ } while (remaining.length > 0);
+
+ if (remaining.length == 0)
+ return (ISC_R_NOTFOUND);
+
+ rdataset->methods = &rdataset_methods;
+ rdataset->rdclass = ncacherdataset->rdclass;
+ rdataset->type = type;
+ rdataset->covers = 0;
+ rdataset->ttl = ncacherdataset->ttl;
+ rdataset->trust = ncacherdataset->trust;
+ rdataset->private1 = NULL;
+ rdataset->private2 = NULL;
+
+ rdataset->private3 = remaining.base;
+
+ /*
+ * Reset iterator state.
+ */
+ rdataset->privateuint4 = 0;
+ rdataset->private5 = NULL;
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/dns/nsec.c b/lib/dns/nsec.c
new file mode 100644
index 0000000..c1de67e
--- /dev/null
+++ b/lib/dns/nsec.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2004, 2005 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: nsec.c,v 1.5.20.2 2005/04/29 00:15:59 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/nsec.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/rdatastruct.h>
+#include <dns/result.h>
+
+#define RETERR(x) do { \
+ result = (x); \
+ if (result != ISC_R_SUCCESS) \
+ goto failure; \
+ } while (0)
+
+static 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 unsigned int
+bit_isset(unsigned char *array, unsigned int index) {
+ unsigned int byte, shift, mask;
+
+ byte = array[index / 8];
+ shift = 7 - (index % 8);
+ mask = 1 << shift;
+
+ return ((byte & mask) != 0);
+}
+
+isc_result_t
+dns_nsec_buildrdata(dns_db_t *db, dns_dbversion_t *version,
+ dns_dbnode_t *node, dns_name_t *target,
+ unsigned char *buffer, dns_rdata_t *rdata)
+{
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+ isc_region_t r;
+ unsigned int i, window;
+ int octet;
+
+ unsigned char *nsec_bits, *bm;
+ unsigned int max_type;
+ dns_rdatasetiter_t *rdsiter;
+
+ memset(buffer, 0, DNS_NSEC_BUFFERSIZE);
+ dns_name_toregion(target, &r);
+ memcpy(buffer, r.base, r.length);
+ r.base = buffer;
+ /*
+ * Use the end of the space for a raw bitmap leaving enough
+ * space for the window identifiers and length octets.
+ */
+ bm = r.base + r.length + 512;
+ nsec_bits = r.base + r.length;
+ set_bit(bm, dns_rdatatype_nsec, 1);
+ max_type = dns_rdatatype_nsec;
+ dns_rdataset_init(&rdataset);
+ rdsiter = NULL;
+ result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ for (result = dns_rdatasetiter_first(rdsiter);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(rdsiter))
+ {
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+ if (rdataset.type != dns_rdatatype_nsec) {
+ if (rdataset.type > max_type)
+ max_type = rdataset.type;
+ set_bit(bm, rdataset.type, 1);
+ }
+ dns_rdataset_disassociate(&rdataset);
+ }
+
+ /*
+ * At zone cuts, deny the existence of glue in the parent zone.
+ */
+ if (bit_isset(bm, dns_rdatatype_ns) &&
+ ! bit_isset(bm, dns_rdatatype_soa)) {
+ for (i = 0; i <= max_type; i++) {
+ if (bit_isset(bm, i) &&
+ ! dns_rdatatype_iszonecutauth((dns_rdatatype_t)i))
+ set_bit(bm, i, 0);
+ }
+ }
+
+ dns_rdatasetiter_destroy(&rdsiter);
+ if (result != ISC_R_NOMORE)
+ return (result);
+
+ for (window = 0; window < 256; window++) {
+ if (window * 256 > max_type)
+ break;
+ for (octet = 31; octet >= 0; octet--)
+ if (bm[window * 32 + octet] != 0)
+ break;
+ if (octet < 0)
+ continue;
+ nsec_bits[0] = window;
+ nsec_bits[1] = octet + 1;
+ /*
+ * Note: potential overlapping move.
+ */
+ memmove(&nsec_bits[2], &bm[window * 32], octet + 1);
+ nsec_bits += 3 + octet;
+ }
+ r.length = nsec_bits - r.base;
+ INSIST(r.length <= DNS_NSEC_BUFFERSIZE);
+ dns_rdata_fromregion(rdata,
+ dns_db_class(db),
+ dns_rdatatype_nsec,
+ &r);
+
+ return (ISC_R_SUCCESS);
+}
+
+
+isc_result_t
+dns_nsec_build(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
+ dns_name_t *target, dns_ttl_t ttl)
+{
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned char data[DNS_NSEC_BUFFERSIZE];
+ dns_rdatalist_t rdatalist;
+ dns_rdataset_t rdataset;
+
+ dns_rdataset_init(&rdataset);
+ dns_rdata_init(&rdata);
+
+ RETERR(dns_nsec_buildrdata(db, version, node, target, data, &rdata));
+
+ rdatalist.rdclass = dns_db_class(db);
+ rdatalist.type = dns_rdatatype_nsec;
+ rdatalist.covers = 0;
+ rdatalist.ttl = ttl;
+ ISC_LIST_INIT(rdatalist.rdata);
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
+ RETERR(dns_rdatalist_tordataset(&rdatalist, &rdataset));
+ result = dns_db_addrdataset(db, node, version, 0, &rdataset,
+ 0, NULL);
+ if (result == DNS_R_UNCHANGED)
+ result = ISC_R_SUCCESS;
+ RETERR(result);
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ return (result);
+}
+
+isc_boolean_t
+dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type) {
+ dns_rdata_nsec_t nsecstruct;
+ isc_result_t result;
+ isc_boolean_t present;
+ unsigned int i, len, window;
+
+ REQUIRE(nsec != NULL);
+ REQUIRE(nsec->type == dns_rdatatype_nsec);
+
+ /* This should never fail */
+ result = dns_rdata_tostruct(nsec, &nsecstruct, NULL);
+ INSIST(result == ISC_R_SUCCESS);
+
+ present = ISC_FALSE;
+ for (i = 0; i < nsecstruct.len; i += len) {
+ INSIST(i + 2 <= nsecstruct.len);
+ window = nsecstruct.typebits[i];
+ len = nsecstruct.typebits[i + 1];
+ INSIST(len > 0 && len <= 32);
+ i += 2;
+ INSIST(i + len <= nsecstruct.len);
+ if (window * 256 > type)
+ break;
+ if ((window + 1) * 256 <= type)
+ continue;
+ if (type < (window * 256) + len * 8)
+ present = ISC_TF(bit_isset(&nsecstruct.typebits[i],
+ type % 256));
+ break;
+ }
+ dns_rdata_freestruct(&nsec);
+ return (present);
+}
diff --git a/lib/dns/openssl_link.c b/lib/dns/openssl_link.c
new file mode 100644
index 0000000..bb76e0e
--- /dev/null
+++ b/lib/dns/openssl_link.c
@@ -0,0 +1,261 @@
+/*
+ * Portions Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1999-2003 Internet Software Consortium.
+ * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
+ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Principal Author: Brian Wellington
+ * $Id: openssl_link.c,v 1.1.6.12 2007/08/28 07:20:04 tbox Exp $
+ */
+#ifdef OPENSSL
+
+#include <config.h>
+
+#include <isc/entropy.h>
+#include <isc/mem.h>
+#include <isc/mutex.h>
+#include <isc/mutexblock.h>
+#include <isc/string.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include "dst_internal.h"
+#include "dst_openssl.h"
+
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#include <openssl/conf.h>
+#include <openssl/crypto.h>
+
+#if defined(CRYPTO_LOCK_ENGINE) && (OPENSSL_VERSION_NUMBER != 0x00907000L)
+#define USE_ENGINE 1
+#endif
+
+#ifdef USE_ENGINE
+#include <openssl/engine.h>
+#endif
+
+static RAND_METHOD *rm = NULL;
+static isc_mutex_t *locks = NULL;
+static int nlocks;
+
+#ifdef USE_ENGINE
+static ENGINE *e;
+#endif
+
+
+static int
+entropy_get(unsigned char *buf, int num) {
+ isc_result_t result;
+ if (num < 0)
+ return (-1);
+ result = dst__entropy_getdata(buf, (unsigned int) num, ISC_FALSE);
+ return (result == ISC_R_SUCCESS ? num : -1);
+}
+
+static int
+entropy_getpseudo(unsigned char *buf, int num) {
+ isc_result_t result;
+ if (num < 0)
+ return (-1);
+ result = dst__entropy_getdata(buf, (unsigned int) num, ISC_TRUE);
+ return (result == ISC_R_SUCCESS ? num : -1);
+}
+
+static void
+entropy_add(const void *buf, int num, double entropy) {
+ /*
+ * Do nothing. The only call to this provides no useful data anyway.
+ */
+ UNUSED(buf);
+ UNUSED(num);
+ UNUSED(entropy);
+}
+
+static void
+lock_callback(int mode, int type, const char *file, int line) {
+ UNUSED(file);
+ UNUSED(line);
+ if ((mode & CRYPTO_LOCK) != 0)
+ LOCK(&locks[type]);
+ else
+ UNLOCK(&locks[type]);
+}
+
+static unsigned long
+id_callback(void) {
+ return ((unsigned long)isc_thread_self());
+}
+
+static void *
+mem_alloc(size_t size) {
+ INSIST(dst__memory_pool != NULL);
+ return (isc_mem_allocate(dst__memory_pool, size));
+}
+
+static void
+mem_free(void *ptr) {
+ INSIST(dst__memory_pool != NULL);
+ if (ptr != NULL)
+ isc_mem_free(dst__memory_pool, ptr);
+}
+
+static void *
+mem_realloc(void *ptr, size_t size) {
+ void *p;
+
+ INSIST(dst__memory_pool != NULL);
+ p = NULL;
+ if (size > 0U) {
+ p = mem_alloc(size);
+ if (p != NULL && ptr != NULL)
+ memcpy(p, ptr, size);
+ }
+ if (ptr != NULL)
+ mem_free(ptr);
+ return (p);
+}
+
+isc_result_t
+dst__openssl_init() {
+ isc_result_t result;
+
+#ifdef DNS_CRYPTO_LEAKS
+ CRYPTO_malloc_debug_init();
+ CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
+ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+#endif
+ CRYPTO_set_mem_functions(mem_alloc, mem_realloc, mem_free);
+ nlocks = CRYPTO_num_locks();
+ locks = mem_alloc(sizeof(isc_mutex_t) * nlocks);
+ if (locks == NULL)
+ return (ISC_R_NOMEMORY);
+ result = isc_mutexblock_init(locks, nlocks);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_mutexalloc;
+ CRYPTO_set_locking_callback(lock_callback);
+ CRYPTO_set_id_callback(id_callback);
+ rm = mem_alloc(sizeof(RAND_METHOD));
+ if (rm == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_mutexinit;
+ }
+ rm->seed = NULL;
+ rm->bytes = entropy_get;
+ rm->cleanup = NULL;
+ rm->add = entropy_add;
+ rm->pseudorand = entropy_getpseudo;
+ rm->status = NULL;
+#ifdef USE_ENGINE
+ e = ENGINE_new();
+ if (e == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_rm;
+ }
+ ENGINE_set_RAND(e, rm);
+ RAND_set_rand_method(rm);
+#else
+ RAND_set_rand_method(rm);
+#endif
+ return (ISC_R_SUCCESS);
+
+#ifdef USE_ENGINE
+ cleanup_rm:
+ mem_free(rm);
+#endif
+ cleanup_mutexinit:
+ CRYPTO_set_locking_callback(NULL);
+ DESTROYMUTEXBLOCK(locks, nlocks);
+ cleanup_mutexalloc:
+ mem_free(locks);
+ return (result);
+}
+
+void
+dst__openssl_destroy() {
+
+ /*
+ * Sequence taken from apps_shutdown() in <apps/apps.h>.
+ */
+#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+ CONF_modules_unload(1);
+#endif
+ EVP_cleanup();
+#if defined(USE_ENGINE) && OPENSSL_VERSION_NUMBER >= 0x00907000L
+ ENGINE_cleanup();
+#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+ CRYPTO_cleanup_all_ex_data();
+#endif
+ ERR_clear_error();
+ ERR_free_strings();
+ ERR_remove_state(0);
+
+#ifdef DNS_CRYPTO_LEAKS
+ CRYPTO_mem_leaks_fp(stderr);
+#endif
+
+#if 0
+ /*
+ * The old error sequence that leaked. Remove for 9.4.1 if
+ * there are no issues by then.
+ */
+ ERR_clear_error();
+#ifdef USE_ENGINE
+ if (e != NULL) {
+ ENGINE_free(e);
+ e = NULL;
+ }
+#endif
+#endif
+ if (rm != NULL) {
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+ RAND_cleanup();
+#endif
+ mem_free(rm);
+ }
+ if (locks != NULL) {
+ CRYPTO_set_locking_callback(NULL);
+ DESTROYMUTEXBLOCK(locks, nlocks);
+ mem_free(locks);
+ }
+}
+
+isc_result_t
+dst__openssl_toresult(isc_result_t fallback) {
+ isc_result_t result = fallback;
+ int err = ERR_get_error();
+
+ switch (ERR_GET_REASON(err)) {
+ case ERR_R_MALLOC_FAILURE:
+ result = ISC_R_NOMEMORY;
+ break;
+ default:
+ break;
+ }
+ ERR_clear_error();
+ return (result);
+}
+
+#else /* OPENSSL */
+
+#include <isc/util.h>
+
+EMPTY_TRANSLATION_UNIT
+
+#endif /* OPENSSL */
+/*! \file */
diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c
new file mode 100644
index 0000000..8f47482
--- /dev/null
+++ b/lib/dns/openssldh_link.c
@@ -0,0 +1,626 @@
+/*
+ * Portions Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1999-2002 Internet Software Consortium.
+ * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
+ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Principal Author: Brian Wellington
+ * $Id: openssldh_link.c,v 1.1.6.10 2007/08/28 07:20:04 tbox Exp $
+ */
+
+#ifdef OPENSSL
+
+#include <config.h>
+
+#include <ctype.h>
+
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dst/result.h>
+
+#include "dst_internal.h"
+#include "dst_openssl.h"
+#include "dst_parse.h"
+
+#include <openssl/dh.h>
+
+#define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
+ "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
+ "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
+
+#define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \
+ "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \
+ "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \
+ "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
+
+#define PRIME1536 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
+ "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
+
+
+static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data);
+
+static BIGNUM bn2, bn768, bn1024, bn1536;
+
+static isc_result_t
+openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv,
+ isc_buffer_t *secret)
+{
+ DH *dhpub, *dhpriv;
+ int ret;
+ isc_region_t r;
+ unsigned int len;
+
+ REQUIRE(pub->opaque != NULL);
+ REQUIRE(priv->opaque != NULL);
+
+ dhpub = (DH *) pub->opaque;
+ dhpriv = (DH *) priv->opaque;
+
+ len = DH_size(dhpriv);
+ isc_buffer_availableregion(secret, &r);
+ if (r.length < len)
+ return (ISC_R_NOSPACE);
+ ret = DH_compute_key(r.base, dhpub->pub_key, dhpriv);
+ if (ret == 0)
+ return (dst__openssl_toresult(DST_R_COMPUTESECRETFAILURE));
+ isc_buffer_add(secret, len);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_boolean_t
+openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ int status;
+ DH *dh1, *dh2;
+
+ dh1 = (DH *) key1->opaque;
+ dh2 = (DH *) key2->opaque;
+
+ if (dh1 == NULL && dh2 == NULL)
+ return (ISC_TRUE);
+ else if (dh1 == NULL || dh2 == NULL)
+ return (ISC_FALSE);
+
+ status = BN_cmp(dh1->p, dh2->p) ||
+ BN_cmp(dh1->g, dh2->g) ||
+ BN_cmp(dh1->pub_key, dh2->pub_key);
+
+ if (status != 0)
+ return (ISC_FALSE);
+
+ if (dh1->priv_key != NULL || dh2->priv_key != NULL) {
+ if (dh1->priv_key == NULL || dh2->priv_key == NULL)
+ return (ISC_FALSE);
+ if (BN_cmp(dh1->priv_key, dh2->priv_key) != 0)
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+static isc_boolean_t
+openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
+ int status;
+ DH *dh1, *dh2;
+
+ dh1 = (DH *) key1->opaque;
+ dh2 = (DH *) key2->opaque;
+
+ if (dh1 == NULL && dh2 == NULL)
+ return (ISC_TRUE);
+ else if (dh1 == NULL || dh2 == NULL)
+ return (ISC_FALSE);
+
+ status = BN_cmp(dh1->p, dh2->p) ||
+ BN_cmp(dh1->g, dh2->g);
+
+ if (status != 0)
+ return (ISC_FALSE);
+ return (ISC_TRUE);
+}
+
+static isc_result_t
+openssldh_generate(dst_key_t *key, int generator) {
+#if OPENSSL_VERSION_NUMBER > 0x00908000L
+ BN_GENCB cb;
+#endif
+ DH *dh = NULL;
+
+ if (generator == 0) {
+ if (key->key_size == 768 ||
+ key->key_size == 1024 ||
+ key->key_size == 1536)
+ {
+ dh = DH_new();
+ if (dh == NULL)
+ return (dst__openssl_toresult(ISC_R_NOMEMORY));
+ if (key->key_size == 768)
+ dh->p = &bn768;
+ else if (key->key_size == 1024)
+ dh->p = &bn1024;
+ else
+ dh->p = &bn1536;
+ dh->g = &bn2;
+ } else
+ generator = 2;
+ }
+
+ if (generator != 0) {
+#if OPENSSL_VERSION_NUMBER > 0x00908000L
+ dh = DH_new();
+ if (dh == NULL)
+ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+
+ BN_GENCB_set_old(&cb, NULL, NULL);
+
+ if (!DH_generate_parameters_ex(dh, key->key_size, generator,
+ &cb)) {
+ DH_free(dh);
+ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+ }
+#else
+ dh = DH_generate_parameters(key->key_size, generator,
+ NULL, NULL);
+#endif
+ }
+
+ if (dh == NULL)
+ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+
+ if (DH_generate_key(dh) == 0) {
+ DH_free(dh);
+ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+ }
+ dh->flags &= ~DH_FLAG_CACHE_MONT_P;
+
+ key->opaque = dh;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_boolean_t
+openssldh_isprivate(const dst_key_t *key) {
+ DH *dh = (DH *) key->opaque;
+ return (ISC_TF(dh != NULL && dh->priv_key != NULL));
+}
+
+static void
+openssldh_destroy(dst_key_t *key) {
+ DH *dh = key->opaque;
+
+ if (dh == NULL)
+ return;
+
+ if (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536)
+ dh->p = NULL;
+ if (dh->g == &bn2)
+ dh->g = NULL;
+ DH_free(dh);
+ key->opaque = NULL;
+}
+
+static void
+uint16_toregion(isc_uint16_t val, isc_region_t *region) {
+ *region->base++ = (val & 0xff00) >> 8;
+ *region->base++ = (val & 0x00ff);
+}
+
+static isc_uint16_t
+uint16_fromregion(isc_region_t *region) {
+ isc_uint16_t val;
+ unsigned char *cp = region->base;
+
+ val = ((unsigned int)(cp[0])) << 8;
+ val |= ((unsigned int)(cp[1]));
+
+ region->base += 2;
+ return (val);
+}
+
+static isc_result_t
+openssldh_todns(const dst_key_t *key, isc_buffer_t *data) {
+ DH *dh;
+ isc_region_t r;
+ isc_uint16_t dnslen, plen, glen, publen;
+
+ REQUIRE(key->opaque != NULL);
+
+ dh = (DH *) key->opaque;
+
+ isc_buffer_availableregion(data, &r);
+
+ if (dh->g == &bn2 &&
+ (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536)) {
+ plen = 1;
+ glen = 0;
+ }
+ else {
+ plen = BN_num_bytes(dh->p);
+ glen = BN_num_bytes(dh->g);
+ }
+ publen = BN_num_bytes(dh->pub_key);
+ dnslen = plen + glen + publen + 6;
+ if (r.length < (unsigned int) dnslen)
+ return (ISC_R_NOSPACE);
+
+ uint16_toregion(plen, &r);
+ if (plen == 1) {
+ if (dh->p == &bn768)
+ *r.base = 1;
+ else if (dh->p == &bn1024)
+ *r.base = 2;
+ else
+ *r.base = 3;
+ }
+ else
+ BN_bn2bin(dh->p, r.base);
+ r.base += plen;
+
+ uint16_toregion(glen, &r);
+ if (glen > 0)
+ BN_bn2bin(dh->g, r.base);
+ r.base += glen;
+
+ uint16_toregion(publen, &r);
+ BN_bn2bin(dh->pub_key, r.base);
+ r.base += publen;
+
+ isc_buffer_add(data, dnslen);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ DH *dh;
+ isc_region_t r;
+ isc_uint16_t plen, glen, publen;
+ int special = 0;
+
+ isc_buffer_remainingregion(data, &r);
+ if (r.length == 0)
+ return (ISC_R_SUCCESS);
+
+ dh = DH_new();
+ if (dh == NULL)
+ return (dst__openssl_toresult(ISC_R_NOMEMORY));
+ dh->flags &= ~DH_FLAG_CACHE_MONT_P;
+
+ /*
+ * Read the prime length. 1 & 2 are table entries, > 16 means a
+ * prime follows, otherwise an error.
+ */
+ if (r.length < 2) {
+ DH_free(dh);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ plen = uint16_fromregion(&r);
+ if (plen < 16 && plen != 1 && plen != 2) {
+ DH_free(dh);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ if (r.length < plen) {
+ DH_free(dh);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ if (plen == 1 || plen == 2) {
+ if (plen == 1)
+ special = *r.base++;
+ else
+ special = uint16_fromregion(&r);
+ switch (special) {
+ case 1:
+ dh->p = &bn768;
+ break;
+ case 2:
+ dh->p = &bn1024;
+ break;
+ case 3:
+ dh->p = &bn1536;
+ break;
+ default:
+ DH_free(dh);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ }
+ else {
+ dh->p = BN_bin2bn(r.base, plen, NULL);
+ r.base += plen;
+ }
+
+ /*
+ * Read the generator length. This should be 0 if the prime was
+ * special, but it might not be. If it's 0 and the prime is not
+ * special, we have a problem.
+ */
+ if (r.length < 2) {
+ DH_free(dh);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ glen = uint16_fromregion(&r);
+ if (r.length < glen) {
+ DH_free(dh);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ if (special != 0) {
+ if (glen == 0)
+ dh->g = &bn2;
+ else {
+ dh->g = BN_bin2bn(r.base, glen, NULL);
+ if (BN_cmp(dh->g, &bn2) == 0) {
+ BN_free(dh->g);
+ dh->g = &bn2;
+ }
+ else {
+ DH_free(dh);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ }
+ }
+ else {
+ if (glen == 0) {
+ DH_free(dh);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ dh->g = BN_bin2bn(r.base, glen, NULL);
+ }
+ r.base += glen;
+
+ if (r.length < 2) {
+ DH_free(dh);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ publen = uint16_fromregion(&r);
+ if (r.length < publen) {
+ DH_free(dh);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ dh->pub_key = BN_bin2bn(r.base, publen, NULL);
+ r.base += publen;
+
+ key->key_size = BN_num_bits(dh->p);
+
+ isc_buffer_forward(data, plen + glen + publen + 6);
+
+ key->opaque = (void *) dh;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+openssldh_tofile(const dst_key_t *key, const char *directory) {
+ int i;
+ DH *dh;
+ dst_private_t priv;
+ unsigned char *bufs[4];
+ isc_result_t result;
+
+ if (key->opaque == NULL)
+ return (DST_R_NULLKEY);
+
+ dh = (DH *) key->opaque;
+
+ for (i = 0; i < 4; i++) {
+ bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(dh->p));
+ if (bufs[i] == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto fail;
+ }
+ }
+
+ i = 0;
+
+ priv.elements[i].tag = TAG_DH_PRIME;
+ priv.elements[i].length = BN_num_bytes(dh->p);
+ BN_bn2bin(dh->p, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.elements[i].tag = TAG_DH_GENERATOR;
+ priv.elements[i].length = BN_num_bytes(dh->g);
+ BN_bn2bin(dh->g, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.elements[i].tag = TAG_DH_PRIVATE;
+ priv.elements[i].length = BN_num_bytes(dh->priv_key);
+ BN_bn2bin(dh->priv_key, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.elements[i].tag = TAG_DH_PUBLIC;
+ priv.elements[i].length = BN_num_bytes(dh->pub_key);
+ BN_bn2bin(dh->pub_key, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.nelements = i;
+ result = dst__privstruct_writefile(key, &priv, directory);
+ fail:
+ for (i = 0; i < 4; i++) {
+ if (bufs[i] == NULL)
+ break;
+ isc_mem_put(key->mctx, bufs[i], BN_num_bytes(dh->p));
+ }
+ return (result);
+}
+
+static isc_result_t
+openssldh_parse(dst_key_t *key, isc_lex_t *lexer) {
+ dst_private_t priv;
+ isc_result_t ret;
+ int i;
+ DH *dh = NULL;
+ isc_mem_t *mctx;
+#define DST_RET(a) {ret = a; goto err;}
+
+ mctx = key->mctx;
+
+ /* read private key file */
+ ret = dst__privstruct_parse(key, DST_ALG_DH, lexer, mctx, &priv);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ dh = DH_new();
+ if (dh == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ dh->flags &= ~DH_FLAG_CACHE_MONT_P;
+ key->opaque = dh;
+
+ for (i = 0; i < priv.nelements; i++) {
+ BIGNUM *bn;
+ bn = BN_bin2bn(priv.elements[i].data,
+ priv.elements[i].length, NULL);
+ if (bn == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+
+ switch (priv.elements[i].tag) {
+ case TAG_DH_PRIME:
+ dh->p = bn;
+ break;
+ case TAG_DH_GENERATOR:
+ dh->g = bn;
+ break;
+ case TAG_DH_PRIVATE:
+ dh->priv_key = bn;
+ break;
+ case TAG_DH_PUBLIC:
+ dh->pub_key = bn;
+ break;
+ }
+ }
+ dst__privstruct_free(&priv, mctx);
+
+ key->key_size = BN_num_bits(dh->p);
+
+ if ((key->key_size == 768 ||
+ key->key_size == 1024 ||
+ key->key_size == 1536) &&
+ BN_cmp(dh->g, &bn2) == 0)
+ {
+ if (key->key_size == 768 && BN_cmp(dh->p, &bn768) == 0) {
+ BN_free(dh->p);
+ BN_free(dh->g);
+ dh->p = &bn768;
+ dh->g = &bn2;
+ } else if (key->key_size == 1024 &&
+ BN_cmp(dh->p, &bn1024) == 0) {
+ BN_free(dh->p);
+ BN_free(dh->g);
+ dh->p = &bn1024;
+ dh->g = &bn2;
+ } else if (key->key_size == 1536 &&
+ BN_cmp(dh->p, &bn1536) == 0) {
+ BN_free(dh->p);
+ BN_free(dh->g);
+ dh->p = &bn1536;
+ dh->g = &bn2;
+ }
+ }
+
+ return (ISC_R_SUCCESS);
+
+ err:
+ openssldh_destroy(key);
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (ret);
+}
+
+static void
+BN_fromhex(BIGNUM *b, const char *str) {
+ static const char hexdigits[] = "0123456789abcdef";
+ unsigned char data[512];
+ unsigned int i;
+ BIGNUM *out;
+
+ RUNTIME_CHECK(strlen(str) < 1024U && strlen(str) % 2 == 0U);
+ for (i = 0; i < strlen(str); i += 2) {
+ char *s;
+ unsigned int high, low;
+
+ s = strchr(hexdigits, tolower((unsigned char)str[i]));
+ RUNTIME_CHECK(s != NULL);
+ high = s - hexdigits;
+
+ s = strchr(hexdigits, tolower((unsigned char)str[i + 1]));
+ RUNTIME_CHECK(s != NULL);
+ low = s - hexdigits;
+
+ data[i/2] = (unsigned char)((high << 4) + low);
+ }
+ out = BN_bin2bn(data, strlen(str)/2, b);
+ RUNTIME_CHECK(out != NULL);
+}
+
+static void
+openssldh_cleanup(void) {
+ BN_free(&bn2);
+ BN_free(&bn768);
+ BN_free(&bn1024);
+ BN_free(&bn1536);
+}
+
+static dst_func_t openssldh_functions = {
+ NULL, /*%< createctx */
+ NULL, /*%< destroyctx */
+ NULL, /*%< adddata */
+ NULL, /*%< openssldh_sign */
+ NULL, /*%< openssldh_verify */
+ openssldh_computesecret,
+ openssldh_compare,
+ openssldh_paramcompare,
+ openssldh_generate,
+ openssldh_isprivate,
+ openssldh_destroy,
+ openssldh_todns,
+ openssldh_fromdns,
+ openssldh_tofile,
+ openssldh_parse,
+ openssldh_cleanup,
+};
+
+isc_result_t
+dst__openssldh_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL) {
+ BN_init(&bn2);
+ BN_init(&bn768);
+ BN_init(&bn1024);
+ BN_init(&bn1536);
+ BN_set_word(&bn2, 2);
+ BN_fromhex(&bn768, PRIME768);
+ BN_fromhex(&bn1024, PRIME1024);
+ BN_fromhex(&bn1536, PRIME1536);
+ *funcp = &openssldh_functions;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+#else /* OPENSSL */
+
+#include <isc/util.h>
+
+EMPTY_TRANSLATION_UNIT
+
+#endif /* OPENSSL */
+/*! \file */
diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c
new file mode 100644
index 0000000..d2b0833
--- /dev/null
+++ b/lib/dns/openssldsa_link.c
@@ -0,0 +1,462 @@
+/*
+ * Portions Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1999-2002 Internet Software Consortium.
+ * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
+ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: openssldsa_link.c,v 1.1.6.9 2007/08/28 07:20:04 tbox Exp $ */
+
+#ifdef OPENSSL
+
+#include <config.h>
+
+#include <string.h>
+
+#include <isc/entropy.h>
+#include <isc/mem.h>
+#include <isc/sha1.h>
+#include <isc/util.h>
+
+#include <dst/result.h>
+
+#include "dst_internal.h"
+#include "dst_openssl.h"
+#include "dst_parse.h"
+
+#include <openssl/dsa.h>
+
+static isc_result_t openssldsa_todns(const dst_key_t *key, isc_buffer_t *data);
+
+static isc_result_t
+openssldsa_createctx(dst_key_t *key, dst_context_t *dctx) {
+ isc_sha1_t *sha1ctx;
+
+ UNUSED(key);
+
+ sha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_sha1_t));
+ isc_sha1_init(sha1ctx);
+ dctx->opaque = sha1ctx;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+openssldsa_destroyctx(dst_context_t *dctx) {
+ isc_sha1_t *sha1ctx = dctx->opaque;
+
+ if (sha1ctx != NULL) {
+ isc_sha1_invalidate(sha1ctx);
+ isc_mem_put(dctx->mctx, sha1ctx, sizeof(isc_sha1_t));
+ dctx->opaque = NULL;
+ }
+}
+
+static isc_result_t
+openssldsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ isc_sha1_t *sha1ctx = dctx->opaque;
+
+ isc_sha1_update(sha1ctx, data->base, data->length);
+ return (ISC_R_SUCCESS);
+}
+
+static int
+BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) {
+ int bytes = size - BN_num_bytes(bn);
+ while (bytes-- > 0)
+ *buf++ = 0;
+ BN_bn2bin(bn, buf);
+ return (size);
+}
+
+static isc_result_t
+openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ isc_sha1_t *sha1ctx = dctx->opaque;
+ dst_key_t *key = dctx->key;
+ DSA *dsa = key->opaque;
+ DSA_SIG *dsasig;
+ isc_region_t r;
+ unsigned char digest[ISC_SHA1_DIGESTLENGTH];
+
+ isc_buffer_availableregion(sig, &r);
+ if (r.length < ISC_SHA1_DIGESTLENGTH * 2 + 1)
+ return (ISC_R_NOSPACE);
+
+ isc_sha1_final(sha1ctx, digest);
+
+ dsasig = DSA_do_sign(digest, ISC_SHA1_DIGESTLENGTH, dsa);
+ if (dsasig == NULL)
+ return (dst__openssl_toresult(DST_R_SIGNFAILURE));
+
+ *r.base++ = (key->key_size - 512)/64;
+ BN_bn2bin_fixed(dsasig->r, r.base, ISC_SHA1_DIGESTLENGTH);
+ r.base += ISC_SHA1_DIGESTLENGTH;
+ BN_bn2bin_fixed(dsasig->s, r.base, ISC_SHA1_DIGESTLENGTH);
+ r.base += ISC_SHA1_DIGESTLENGTH;
+ DSA_SIG_free(dsasig);
+ isc_buffer_add(sig, ISC_SHA1_DIGESTLENGTH * 2 + 1);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+openssldsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
+ isc_sha1_t *sha1ctx = dctx->opaque;
+ dst_key_t *key = dctx->key;
+ DSA *dsa = key->opaque;
+ DSA_SIG *dsasig;
+ int status = 0;
+ unsigned char digest[ISC_SHA1_DIGESTLENGTH];
+ unsigned char *cp = sig->base;
+
+ isc_sha1_final(sha1ctx, digest);
+
+ if (sig->length < 2 * ISC_SHA1_DIGESTLENGTH + 1)
+ return (DST_R_VERIFYFAILURE);
+
+ cp++; /*%< Skip T */
+ dsasig = DSA_SIG_new();
+ dsasig->r = BN_bin2bn(cp, ISC_SHA1_DIGESTLENGTH, NULL);
+ cp += ISC_SHA1_DIGESTLENGTH;
+ dsasig->s = BN_bin2bn(cp, ISC_SHA1_DIGESTLENGTH, NULL);
+ cp += ISC_SHA1_DIGESTLENGTH;
+
+ status = DSA_do_verify(digest, ISC_SHA1_DIGESTLENGTH, dsasig, dsa);
+ DSA_SIG_free(dsasig);
+ if (status == 0)
+ return (dst__openssl_toresult(DST_R_VERIFYFAILURE));
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_boolean_t
+openssldsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ int status;
+ DSA *dsa1, *dsa2;
+
+ dsa1 = (DSA *) key1->opaque;
+ dsa2 = (DSA *) key2->opaque;
+
+ if (dsa1 == NULL && dsa2 == NULL)
+ return (ISC_TRUE);
+ else if (dsa1 == NULL || dsa2 == NULL)
+ return (ISC_FALSE);
+
+ status = BN_cmp(dsa1->p, dsa2->p) ||
+ BN_cmp(dsa1->q, dsa2->q) ||
+ BN_cmp(dsa1->g, dsa2->g) ||
+ BN_cmp(dsa1->pub_key, dsa2->pub_key);
+
+ if (status != 0)
+ return (ISC_FALSE);
+
+ if (dsa1->priv_key != NULL || dsa2->priv_key != NULL) {
+ if (dsa1->priv_key == NULL || dsa2->priv_key == NULL)
+ return (ISC_FALSE);
+ if (BN_cmp(dsa1->priv_key, dsa2->priv_key))
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+static isc_result_t
+openssldsa_generate(dst_key_t *key, int unused) {
+#if OPENSSL_VERSION_NUMBER > 0x00908000L
+ BN_GENCB cb;
+#endif
+ DSA *dsa;
+ unsigned char rand_array[ISC_SHA1_DIGESTLENGTH];
+ isc_result_t result;
+
+ UNUSED(unused);
+
+ result = dst__entropy_getdata(rand_array, sizeof(rand_array),
+ ISC_FALSE);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+#if OPENSSL_VERSION_NUMBER > 0x00908000L
+ dsa = DSA_new();
+ if (dsa == NULL)
+ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+
+ BN_GENCB_set_old(&cb, NULL, NULL);
+
+ if (!DSA_generate_parameters_ex(dsa, key->key_size, rand_array,
+ ISC_SHA1_DIGESTLENGTH, NULL, NULL,
+ &cb))
+ {
+ DSA_free(dsa);
+ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+ }
+#else
+ dsa = DSA_generate_parameters(key->key_size, rand_array,
+ ISC_SHA1_DIGESTLENGTH, NULL, NULL,
+ NULL, NULL);
+ if (dsa == NULL)
+ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+#endif
+
+ if (DSA_generate_key(dsa) == 0) {
+ DSA_free(dsa);
+ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+ }
+ dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
+
+ key->opaque = dsa;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_boolean_t
+openssldsa_isprivate(const dst_key_t *key) {
+ DSA *dsa = (DSA *) key->opaque;
+ return (ISC_TF(dsa != NULL && dsa->priv_key != NULL));
+}
+
+static void
+openssldsa_destroy(dst_key_t *key) {
+ DSA *dsa = key->opaque;
+ DSA_free(dsa);
+ key->opaque = NULL;
+}
+
+
+static isc_result_t
+openssldsa_todns(const dst_key_t *key, isc_buffer_t *data) {
+ DSA *dsa;
+ isc_region_t r;
+ int dnslen;
+ unsigned int t, p_bytes;
+
+ REQUIRE(key->opaque != NULL);
+
+ dsa = (DSA *) key->opaque;
+
+ isc_buffer_availableregion(data, &r);
+
+ t = (BN_num_bytes(dsa->p) - 64) / 8;
+ if (t > 8)
+ return (DST_R_INVALIDPUBLICKEY);
+ p_bytes = 64 + 8 * t;
+
+ dnslen = 1 + (key->key_size * 3)/8 + ISC_SHA1_DIGESTLENGTH;
+ if (r.length < (unsigned int) dnslen)
+ return (ISC_R_NOSPACE);
+
+ *r.base++ = t;
+ BN_bn2bin_fixed(dsa->q, r.base, ISC_SHA1_DIGESTLENGTH);
+ r.base += ISC_SHA1_DIGESTLENGTH;
+ BN_bn2bin_fixed(dsa->p, r.base, key->key_size/8);
+ r.base += p_bytes;
+ BN_bn2bin_fixed(dsa->g, r.base, key->key_size/8);
+ r.base += p_bytes;
+ BN_bn2bin_fixed(dsa->pub_key, r.base, key->key_size/8);
+ r.base += p_bytes;
+
+ isc_buffer_add(data, dnslen);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+openssldsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ DSA *dsa;
+ isc_region_t r;
+ unsigned int t, p_bytes;
+ isc_mem_t *mctx = key->mctx;
+
+ UNUSED(mctx);
+
+ isc_buffer_remainingregion(data, &r);
+ if (r.length == 0)
+ return (ISC_R_SUCCESS);
+
+ dsa = DSA_new();
+ if (dsa == NULL)
+ return (ISC_R_NOMEMORY);
+ dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
+
+ t = (unsigned int) *r.base++;
+ if (t > 8) {
+ DSA_free(dsa);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ p_bytes = 64 + 8 * t;
+
+ if (r.length < 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) {
+ DSA_free(dsa);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+
+ dsa->q = BN_bin2bn(r.base, ISC_SHA1_DIGESTLENGTH, NULL);
+ r.base += ISC_SHA1_DIGESTLENGTH;
+
+ dsa->p = BN_bin2bn(r.base, p_bytes, NULL);
+ r.base += p_bytes;
+
+ dsa->g = BN_bin2bn(r.base, p_bytes, NULL);
+ r.base += p_bytes;
+
+ dsa->pub_key = BN_bin2bn(r.base, p_bytes, NULL);
+ r.base += p_bytes;
+
+ key->key_size = p_bytes * 8;
+
+ isc_buffer_forward(data, 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes);
+
+ key->opaque = (void *) dsa;
+
+ return (ISC_R_SUCCESS);
+}
+
+
+static isc_result_t
+openssldsa_tofile(const dst_key_t *key, const char *directory) {
+ int cnt = 0;
+ DSA *dsa;
+ dst_private_t priv;
+ unsigned char bufs[5][128];
+
+ if (key->opaque == NULL)
+ return (DST_R_NULLKEY);
+
+ dsa = (DSA *) key->opaque;
+
+ priv.elements[cnt].tag = TAG_DSA_PRIME;
+ priv.elements[cnt].length = BN_num_bytes(dsa->p);
+ BN_bn2bin(dsa->p, bufs[cnt]);
+ priv.elements[cnt].data = bufs[cnt];
+ cnt++;
+
+ priv.elements[cnt].tag = TAG_DSA_SUBPRIME;
+ priv.elements[cnt].length = BN_num_bytes(dsa->q);
+ BN_bn2bin(dsa->q, bufs[cnt]);
+ priv.elements[cnt].data = bufs[cnt];
+ cnt++;
+
+ priv.elements[cnt].tag = TAG_DSA_BASE;
+ priv.elements[cnt].length = BN_num_bytes(dsa->g);
+ BN_bn2bin(dsa->g, bufs[cnt]);
+ priv.elements[cnt].data = bufs[cnt];
+ cnt++;
+
+ priv.elements[cnt].tag = TAG_DSA_PRIVATE;
+ priv.elements[cnt].length = BN_num_bytes(dsa->priv_key);
+ BN_bn2bin(dsa->priv_key, bufs[cnt]);
+ priv.elements[cnt].data = bufs[cnt];
+ cnt++;
+
+ priv.elements[cnt].tag = TAG_DSA_PUBLIC;
+ priv.elements[cnt].length = BN_num_bytes(dsa->pub_key);
+ BN_bn2bin(dsa->pub_key, bufs[cnt]);
+ priv.elements[cnt].data = bufs[cnt];
+ cnt++;
+
+ priv.nelements = cnt;
+ return (dst__privstruct_writefile(key, &priv, directory));
+}
+
+static isc_result_t
+openssldsa_parse(dst_key_t *key, isc_lex_t *lexer) {
+ dst_private_t priv;
+ isc_result_t ret;
+ int i;
+ DSA *dsa = NULL;
+ isc_mem_t *mctx = key->mctx;
+#define DST_RET(a) {ret = a; goto err;}
+
+ /* read private key file */
+ ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ dsa = DSA_new();
+ if (dsa == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
+ key->opaque = dsa;
+
+ for (i=0; i < priv.nelements; i++) {
+ BIGNUM *bn;
+ bn = BN_bin2bn(priv.elements[i].data,
+ priv.elements[i].length, NULL);
+ if (bn == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+
+ switch (priv.elements[i].tag) {
+ case TAG_DSA_PRIME:
+ dsa->p = bn;
+ break;
+ case TAG_DSA_SUBPRIME:
+ dsa->q = bn;
+ break;
+ case TAG_DSA_BASE:
+ dsa->g = bn;
+ break;
+ case TAG_DSA_PRIVATE:
+ dsa->priv_key = bn;
+ break;
+ case TAG_DSA_PUBLIC:
+ dsa->pub_key = bn;
+ break;
+ }
+ }
+ dst__privstruct_free(&priv, mctx);
+
+ key->key_size = BN_num_bits(dsa->p);
+
+ return (ISC_R_SUCCESS);
+
+ err:
+ openssldsa_destroy(key);
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (ret);
+}
+
+static dst_func_t openssldsa_functions = {
+ openssldsa_createctx,
+ openssldsa_destroyctx,
+ openssldsa_adddata,
+ openssldsa_sign,
+ openssldsa_verify,
+ NULL, /*%< computesecret */
+ openssldsa_compare,
+ NULL, /*%< paramcompare */
+ openssldsa_generate,
+ openssldsa_isprivate,
+ openssldsa_destroy,
+ openssldsa_todns,
+ openssldsa_fromdns,
+ openssldsa_tofile,
+ openssldsa_parse,
+ NULL, /*%< cleanup */
+};
+
+isc_result_t
+dst__openssldsa_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL)
+ *funcp = &openssldsa_functions;
+ return (ISC_R_SUCCESS);
+}
+
+#else /* OPENSSL */
+
+#include <isc/util.h>
+
+EMPTY_TRANSLATION_UNIT
+
+#endif /* OPENSSL */
+/*! \file */
diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c
new file mode 100644
index 0000000..2609df6
--- /dev/null
+++ b/lib/dns/opensslrsa_link.c
@@ -0,0 +1,629 @@
+/*
+ * Copyright (C) 2004-2006 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.
+ */
+
+/*
+ * Principal Author: Brian Wellington
+ * $Id: opensslrsa_link.c,v 1.1.6.11 2006/11/07 21:28:49 marka Exp $
+ */
+#ifdef OPENSSL
+
+#include <config.h>
+
+#include <isc/entropy.h>
+#include <isc/md5.h>
+#include <isc/sha1.h>
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dst/result.h>
+
+#include "dst_internal.h"
+#include "dst_openssl.h"
+#include "dst_parse.h"
+
+#include <openssl/err.h>
+#include <openssl/objects.h>
+#include <openssl/rsa.h>
+#if OPENSSL_VERSION_NUMBER > 0x00908000L
+#include <openssl/bn.h>
+#endif
+
+/*
+ * We don't use configure for windows so enforce the OpenSSL version
+ * here. Unlike with configure we don't support overriding this test.
+ */
+#ifdef WIN32
+#if !((OPENSSL_VERSION_NUMBER >= 0x009070cfL && \
+ OPENSSL_VERSION_NUMBER < 0x00908000L) || \
+ OPENSSL_VERSION_NUMBER >= 0x0090804fL)
+#error Please upgrade OpenSSL to 0.9.8d/0.9.7l or greater.
+#endif
+#endif
+
+
+ /*
+ * XXXMPA Temporarially disable RSA_BLINDING as it requires
+ * good quality random data that cannot currently be guarenteed.
+ * XXXMPA Find which versions of openssl use pseudo random data
+ * and set RSA_FLAG_BLINDING for those.
+ */
+
+#if 0
+#if OPENSSL_VERSION_NUMBER < 0x0090601fL
+#define SET_FLAGS(rsa) \
+ do { \
+ (rsa)->flags &= ~(RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE); \
+ (rsa)->flags |= RSA_FLAG_BLINDING; \
+ } while (0)
+#else
+#define SET_FLAGS(rsa) \
+ do { \
+ (rsa)->flags |= RSA_FLAG_BLINDING; \
+ } while (0)
+#endif
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x0090601fL
+#define SET_FLAGS(rsa) \
+ do { \
+ (rsa)->flags &= ~(RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE); \
+ (rsa)->flags &= ~RSA_FLAG_BLINDING; \
+ } while (0)
+#elif defined(RSA_FLAG_NO_BLINDING)
+#define SET_FLAGS(rsa) \
+ do { \
+ (rsa)->flags &= ~RSA_FLAG_BLINDING; \
+ (rsa)->flags |= RSA_FLAG_NO_BLINDING; \
+ } while (0)
+#else
+#define SET_FLAGS(rsa) \
+ do { \
+ (rsa)->flags &= ~RSA_FLAG_BLINDING; \
+ } while (0)
+#endif
+
+static isc_result_t opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data);
+
+static isc_result_t
+opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) {
+ UNUSED(key);
+ REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 ||
+ dctx->key->key_alg == DST_ALG_RSASHA1);
+
+ if (dctx->key->key_alg == DST_ALG_RSAMD5) {
+ isc_md5_t *md5ctx;
+
+ md5ctx = isc_mem_get(dctx->mctx, sizeof(isc_md5_t));
+ if (md5ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_md5_init(md5ctx);
+ dctx->opaque = md5ctx;
+ } else {
+ isc_sha1_t *sha1ctx;
+
+ sha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_sha1_t));
+ if (sha1ctx == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_sha1_init(sha1ctx);
+ dctx->opaque = sha1ctx;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+opensslrsa_destroyctx(dst_context_t *dctx) {
+ REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 ||
+ dctx->key->key_alg == DST_ALG_RSASHA1);
+
+ if (dctx->key->key_alg == DST_ALG_RSAMD5) {
+ isc_md5_t *md5ctx = dctx->opaque;
+
+ if (md5ctx != NULL) {
+ isc_md5_invalidate(md5ctx);
+ isc_mem_put(dctx->mctx, md5ctx, sizeof(isc_md5_t));
+ }
+ } else {
+ isc_sha1_t *sha1ctx = dctx->opaque;
+
+ if (sha1ctx != NULL) {
+ isc_sha1_invalidate(sha1ctx);
+ isc_mem_put(dctx->mctx, sha1ctx, sizeof(isc_sha1_t));
+ }
+ }
+ dctx->opaque = NULL;
+}
+
+static isc_result_t
+opensslrsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
+ REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 ||
+ dctx->key->key_alg == DST_ALG_RSASHA1);
+
+ if (dctx->key->key_alg == DST_ALG_RSAMD5) {
+ isc_md5_t *md5ctx = dctx->opaque;
+ isc_md5_update(md5ctx, data->base, data->length);
+ } else {
+ isc_sha1_t *sha1ctx = dctx->opaque;
+ isc_sha1_update(sha1ctx, data->base, data->length);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ dst_key_t *key = dctx->key;
+ RSA *rsa = key->opaque;
+ isc_region_t r;
+ /* note: ISC_SHA1_DIGESTLENGTH > ISC_MD5_DIGESTLENGTH */
+ unsigned char digest[ISC_SHA1_DIGESTLENGTH];
+ unsigned int siglen = 0;
+ int status;
+ int type;
+ unsigned int digestlen;
+ char *message;
+ unsigned long err;
+ const char* file;
+ int line;
+
+ REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 ||
+ dctx->key->key_alg == DST_ALG_RSASHA1);
+
+ isc_buffer_availableregion(sig, &r);
+
+ if (r.length < (unsigned int) RSA_size(rsa))
+ return (ISC_R_NOSPACE);
+
+ if (dctx->key->key_alg == DST_ALG_RSAMD5) {
+ isc_md5_t *md5ctx = dctx->opaque;
+ isc_md5_final(md5ctx, digest);
+ type = NID_md5;
+ digestlen = ISC_MD5_DIGESTLENGTH;
+ } else {
+ isc_sha1_t *sha1ctx = dctx->opaque;
+ isc_sha1_final(sha1ctx, digest);
+ type = NID_sha1;
+ digestlen = ISC_SHA1_DIGESTLENGTH;
+ }
+
+ status = RSA_sign(type, digest, digestlen, r.base, &siglen, rsa);
+ if (status == 0) {
+ err = ERR_peek_error_line(&file, &line);
+ if (err != 0U) {
+ message = ERR_error_string(err, NULL);
+ fprintf(stderr, "%s:%s:%d\n", message,
+ file ? file : "", line);
+ }
+ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+ }
+
+ isc_buffer_add(sig, siglen);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
+ dst_key_t *key = dctx->key;
+ RSA *rsa = key->opaque;
+ /* note: ISC_SHA1_DIGESTLENGTH > ISC_MD5_DIGESTLENGTH */
+ unsigned char digest[ISC_SHA1_DIGESTLENGTH];
+ int status = 0;
+ int type;
+ unsigned int digestlen;
+
+ REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 ||
+ dctx->key->key_alg == DST_ALG_RSASHA1);
+
+ if (dctx->key->key_alg == DST_ALG_RSAMD5) {
+ isc_md5_t *md5ctx = dctx->opaque;
+ isc_md5_final(md5ctx, digest);
+ type = NID_md5;
+ digestlen = ISC_MD5_DIGESTLENGTH;
+ } else {
+ isc_sha1_t *sha1ctx = dctx->opaque;
+ isc_sha1_final(sha1ctx, digest);
+ type = NID_sha1;
+ digestlen = ISC_SHA1_DIGESTLENGTH;
+ }
+
+ if (sig->length < (unsigned int) RSA_size(rsa))
+ return (DST_R_VERIFYFAILURE);
+
+ status = RSA_verify(type, digest, digestlen, sig->base,
+ RSA_size(rsa), rsa);
+ if (status == 0)
+ return (dst__openssl_toresult(DST_R_VERIFYFAILURE));
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_boolean_t
+opensslrsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ int status;
+ RSA *rsa1, *rsa2;
+
+ rsa1 = (RSA *) key1->opaque;
+ rsa2 = (RSA *) key2->opaque;
+
+ if (rsa1 == NULL && rsa2 == NULL)
+ return (ISC_TRUE);
+ else if (rsa1 == NULL || rsa2 == NULL)
+ return (ISC_FALSE);
+
+ status = BN_cmp(rsa1->n, rsa2->n) ||
+ BN_cmp(rsa1->e, rsa2->e);
+
+ if (status != 0)
+ return (ISC_FALSE);
+
+ if (rsa1->d != NULL || rsa2->d != NULL) {
+ if (rsa1->d == NULL || rsa2->d == NULL)
+ return (ISC_FALSE);
+ status = BN_cmp(rsa1->d, rsa2->d) ||
+ BN_cmp(rsa1->p, rsa2->p) ||
+ BN_cmp(rsa1->q, rsa2->q);
+
+ if (status != 0)
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+static isc_result_t
+opensslrsa_generate(dst_key_t *key, int exp) {
+#if OPENSSL_VERSION_NUMBER > 0x00908000L
+ BN_GENCB cb;
+ RSA *rsa = RSA_new();
+ BIGNUM *e = BN_new();
+
+ if (rsa == NULL || e == NULL)
+ goto err;
+
+ if (exp == 0) {
+ /* RSA_F4 0x10001 */
+ BN_set_bit(e, 0);
+ BN_set_bit(e, 16);
+ } else {
+ /* F5 0x100000001 */
+ BN_set_bit(e, 0);
+ BN_set_bit(e, 32);
+ }
+
+ BN_GENCB_set_old(&cb, NULL, NULL);
+
+ if (RSA_generate_key_ex(rsa, key->key_size, e, &cb)) {
+ BN_free(e);
+ SET_FLAGS(rsa);
+ key->opaque = rsa;
+ return (ISC_R_SUCCESS);
+ }
+
+err:
+ if (e != NULL)
+ BN_free(e);
+ if (rsa != NULL)
+ RSA_free(rsa);
+ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+#else
+ RSA *rsa;
+ unsigned long e;
+
+ if (exp == 0)
+ e = RSA_F4;
+ else
+ e = 0x40000003;
+ rsa = RSA_generate_key(key->key_size, e, NULL, NULL);
+ if (rsa == NULL)
+ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+ SET_FLAGS(rsa);
+ key->opaque = rsa;
+
+ return (ISC_R_SUCCESS);
+#endif
+}
+
+static isc_boolean_t
+opensslrsa_isprivate(const dst_key_t *key) {
+ RSA *rsa = (RSA *) key->opaque;
+ return (ISC_TF(rsa != NULL && rsa->d != NULL));
+}
+
+static void
+opensslrsa_destroy(dst_key_t *key) {
+ RSA *rsa = key->opaque;
+ RSA_free(rsa);
+ key->opaque = NULL;
+}
+
+
+static isc_result_t
+opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) {
+ RSA *rsa;
+ isc_region_t r;
+ unsigned int e_bytes;
+ unsigned int mod_bytes;
+
+ REQUIRE(key->opaque != NULL);
+
+ rsa = (RSA *) key->opaque;
+
+ isc_buffer_availableregion(data, &r);
+
+ e_bytes = BN_num_bytes(rsa->e);
+ mod_bytes = BN_num_bytes(rsa->n);
+
+ if (e_bytes < 256) { /*%< key exponent is <= 2040 bits */
+ if (r.length < 1)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint8(data, (isc_uint8_t) e_bytes);
+ } else {
+ if (r.length < 3)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint8(data, 0);
+ isc_buffer_putuint16(data, (isc_uint16_t) e_bytes);
+ }
+
+ if (r.length < e_bytes + mod_bytes)
+ return (ISC_R_NOSPACE);
+ isc_buffer_availableregion(data, &r);
+
+ BN_bn2bin(rsa->e, r.base);
+ r.base += e_bytes;
+ BN_bn2bin(rsa->n, r.base);
+
+ isc_buffer_add(data, e_bytes + mod_bytes);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ RSA *rsa;
+ isc_region_t r;
+ unsigned int e_bytes;
+
+ isc_buffer_remainingregion(data, &r);
+ if (r.length == 0)
+ return (ISC_R_SUCCESS);
+
+ rsa = RSA_new();
+ if (rsa == NULL)
+ return (dst__openssl_toresult(ISC_R_NOMEMORY));
+ SET_FLAGS(rsa);
+
+ if (r.length < 1) {
+ RSA_free(rsa);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ e_bytes = *r.base++;
+ r.length--;
+
+ if (e_bytes == 0) {
+ if (r.length < 2) {
+ RSA_free(rsa);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ e_bytes = ((*r.base++) << 8);
+ e_bytes += *r.base++;
+ r.length -= 2;
+ }
+
+ if (r.length < e_bytes) {
+ RSA_free(rsa);
+ return (DST_R_INVALIDPUBLICKEY);
+ }
+ rsa->e = BN_bin2bn(r.base, e_bytes, NULL);
+ r.base += e_bytes;
+ r.length -= e_bytes;
+
+ rsa->n = BN_bin2bn(r.base, r.length, NULL);
+
+ key->key_size = BN_num_bits(rsa->n);
+
+ isc_buffer_forward(data, r.length);
+
+ key->opaque = (void *) rsa;
+
+ return (ISC_R_SUCCESS);
+}
+
+
+static isc_result_t
+opensslrsa_tofile(const dst_key_t *key, const char *directory) {
+ int i;
+ RSA *rsa;
+ dst_private_t priv;
+ unsigned char *bufs[8];
+ isc_result_t result;
+
+ if (key->opaque == NULL)
+ return (DST_R_NULLKEY);
+
+ rsa = (RSA *) key->opaque;
+
+ for (i = 0; i < 8; i++) {
+ bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(rsa->n));
+ if (bufs[i] == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto fail;
+ }
+ }
+
+ i = 0;
+
+ priv.elements[i].tag = TAG_RSA_MODULUS;
+ priv.elements[i].length = BN_num_bytes(rsa->n);
+ BN_bn2bin(rsa->n, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.elements[i].tag = TAG_RSA_PUBLICEXPONENT;
+ priv.elements[i].length = BN_num_bytes(rsa->e);
+ BN_bn2bin(rsa->e, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.elements[i].tag = TAG_RSA_PRIVATEEXPONENT;
+ priv.elements[i].length = BN_num_bytes(rsa->d);
+ BN_bn2bin(rsa->d, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.elements[i].tag = TAG_RSA_PRIME1;
+ priv.elements[i].length = BN_num_bytes(rsa->p);
+ BN_bn2bin(rsa->p, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.elements[i].tag = TAG_RSA_PRIME2;
+ priv.elements[i].length = BN_num_bytes(rsa->q);
+ BN_bn2bin(rsa->q, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.elements[i].tag = TAG_RSA_EXPONENT1;
+ priv.elements[i].length = BN_num_bytes(rsa->dmp1);
+ BN_bn2bin(rsa->dmp1, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.elements[i].tag = TAG_RSA_EXPONENT2;
+ priv.elements[i].length = BN_num_bytes(rsa->dmq1);
+ BN_bn2bin(rsa->dmq1, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.elements[i].tag = TAG_RSA_COEFFICIENT;
+ priv.elements[i].length = BN_num_bytes(rsa->iqmp);
+ BN_bn2bin(rsa->iqmp, bufs[i]);
+ priv.elements[i].data = bufs[i];
+ i++;
+
+ priv.nelements = i;
+ result = dst__privstruct_writefile(key, &priv, directory);
+ fail:
+ for (i = 0; i < 8; i++) {
+ if (bufs[i] == NULL)
+ break;
+ isc_mem_put(key->mctx, bufs[i], BN_num_bytes(rsa->n));
+ }
+ return (result);
+}
+
+static isc_result_t
+opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) {
+ dst_private_t priv;
+ isc_result_t ret;
+ int i;
+ RSA *rsa = NULL;
+ isc_mem_t *mctx = key->mctx;
+#define DST_RET(a) {ret = a; goto err;}
+
+ /* read private key file */
+ ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ rsa = RSA_new();
+ if (rsa == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+ SET_FLAGS(rsa);
+ key->opaque = rsa;
+
+ for (i = 0; i < priv.nelements; i++) {
+ BIGNUM *bn;
+ bn = BN_bin2bn(priv.elements[i].data,
+ priv.elements[i].length, NULL);
+ if (bn == NULL)
+ DST_RET(ISC_R_NOMEMORY);
+
+ switch (priv.elements[i].tag) {
+ case TAG_RSA_MODULUS:
+ rsa->n = bn;
+ break;
+ case TAG_RSA_PUBLICEXPONENT:
+ rsa->e = bn;
+ break;
+ case TAG_RSA_PRIVATEEXPONENT:
+ rsa->d = bn;
+ break;
+ case TAG_RSA_PRIME1:
+ rsa->p = bn;
+ break;
+ case TAG_RSA_PRIME2:
+ rsa->q = bn;
+ break;
+ case TAG_RSA_EXPONENT1:
+ rsa->dmp1 = bn;
+ break;
+ case TAG_RSA_EXPONENT2:
+ rsa->dmq1 = bn;
+ break;
+ case TAG_RSA_COEFFICIENT:
+ rsa->iqmp = bn;
+ break;
+ }
+ }
+ dst__privstruct_free(&priv, mctx);
+
+ key->key_size = BN_num_bits(rsa->n);
+
+ return (ISC_R_SUCCESS);
+
+ err:
+ opensslrsa_destroy(key);
+ dst__privstruct_free(&priv, mctx);
+ memset(&priv, 0, sizeof(priv));
+ return (ret);
+}
+
+static dst_func_t opensslrsa_functions = {
+ opensslrsa_createctx,
+ opensslrsa_destroyctx,
+ opensslrsa_adddata,
+ opensslrsa_sign,
+ opensslrsa_verify,
+ NULL, /*%< computesecret */
+ opensslrsa_compare,
+ NULL, /*%< paramcompare */
+ opensslrsa_generate,
+ opensslrsa_isprivate,
+ opensslrsa_destroy,
+ opensslrsa_todns,
+ opensslrsa_fromdns,
+ opensslrsa_tofile,
+ opensslrsa_parse,
+ NULL, /*%< cleanup */
+};
+
+isc_result_t
+dst__opensslrsa_init(dst_func_t **funcp) {
+ REQUIRE(funcp != NULL);
+ if (*funcp == NULL)
+ *funcp = &opensslrsa_functions;
+ return (ISC_R_SUCCESS);
+}
+
+#else /* OPENSSL */
+
+#include <isc/util.h>
+
+EMPTY_TRANSLATION_UNIT
+
+#endif /* OPENSSL */
+/*! \file */
diff --git a/lib/dns/order.c b/lib/dns/order.c
new file mode 100644
index 0000000..1d216b7
--- /dev/null
+++ b/lib/dns/order.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: order.c,v 1.5.18.3 2005/07/12 01:22:21 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/types.h>
+#include <isc/util.h>
+#include <isc/refcount.h>
+
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/order.h>
+#include <dns/rdataset.h>
+#include <dns/types.h>
+
+typedef struct dns_order_ent dns_order_ent_t;
+struct dns_order_ent {
+ dns_fixedname_t name;
+ dns_rdataclass_t rdclass;
+ dns_rdatatype_t rdtype;
+ unsigned int mode;
+ ISC_LINK(dns_order_ent_t) link;
+};
+
+struct dns_order {
+ unsigned int magic;
+ isc_refcount_t references;
+ ISC_LIST(dns_order_ent_t) ents;
+ isc_mem_t *mctx;
+};
+
+#define DNS_ORDER_MAGIC ISC_MAGIC('O','r','d','r')
+#define DNS_ORDER_VALID(order) ISC_MAGIC_VALID(order, DNS_ORDER_MAGIC)
+
+isc_result_t
+dns_order_create(isc_mem_t *mctx, dns_order_t **orderp) {
+ dns_order_t *order;
+ isc_result_t result;
+
+ REQUIRE(orderp != NULL && *orderp == NULL);
+
+ order = isc_mem_get(mctx, sizeof(*order));
+ if (order == NULL)
+ return (ISC_R_NOMEMORY);
+
+ ISC_LIST_INIT(order->ents);
+
+ /* Implicit attach. */
+ result = isc_refcount_init(&order->references, 1);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, order, sizeof(*order));
+ return (result);
+ }
+
+ order->mctx = NULL;
+ isc_mem_attach(mctx, &order->mctx);
+ order->magic = DNS_ORDER_MAGIC;
+ *orderp = order;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_order_add(dns_order_t *order, dns_name_t *name,
+ dns_rdatatype_t rdtype, dns_rdataclass_t rdclass,
+ unsigned int mode)
+{
+ dns_order_ent_t *ent;
+
+ REQUIRE(DNS_ORDER_VALID(order));
+ REQUIRE(mode == DNS_RDATASETATTR_RANDOMIZE ||
+ mode == DNS_RDATASETATTR_FIXEDORDER ||
+ mode == 0 /* DNS_RDATASETATTR_CYCLIC */ );
+
+ ent = isc_mem_get(order->mctx, sizeof(*ent));
+ if (ent == NULL)
+ return (ISC_R_NOMEMORY);
+
+ dns_fixedname_init(&ent->name);
+ RUNTIME_CHECK(dns_name_copy(name, dns_fixedname_name(&ent->name), NULL)
+ == ISC_R_SUCCESS);
+ ent->rdtype = rdtype;
+ ent->rdclass = rdclass;
+ ent->mode = mode;
+ ISC_LINK_INIT(ent, link);
+ ISC_LIST_INITANDAPPEND(order->ents, ent, link);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_boolean_t
+match(dns_name_t *name1, dns_name_t *name2) {
+
+ if (dns_name_iswildcard(name2))
+ return(dns_name_matcheswildcard(name1, name2));
+ return (dns_name_equal(name1, name2));
+}
+
+unsigned int
+dns_order_find(dns_order_t *order, dns_name_t *name,
+ dns_rdatatype_t rdtype, dns_rdataclass_t rdclass)
+{
+ dns_order_ent_t *ent;
+ REQUIRE(DNS_ORDER_VALID(order));
+
+ for (ent = ISC_LIST_HEAD(order->ents);
+ ent != NULL;
+ ent = ISC_LIST_NEXT(ent, link)) {
+ if (ent->rdtype != rdtype && ent->rdtype != dns_rdatatype_any)
+ continue;
+ if (ent->rdclass != rdclass &&
+ ent->rdclass != dns_rdataclass_any)
+ continue;
+ if (match(name, dns_fixedname_name(&ent->name)))
+ return (ent->mode);
+ }
+ return (0);
+}
+
+void
+dns_order_attach(dns_order_t *source, dns_order_t **target) {
+ REQUIRE(DNS_ORDER_VALID(source));
+ REQUIRE(target != NULL && *target == NULL);
+ isc_refcount_increment(&source->references, NULL);
+ *target = source;
+}
+
+void
+dns_order_detach(dns_order_t **orderp) {
+ dns_order_t *order;
+ dns_order_ent_t *ent;
+ unsigned int references;
+
+ REQUIRE(orderp != NULL);
+ order = *orderp;
+ REQUIRE(DNS_ORDER_VALID(order));
+ isc_refcount_decrement(&order->references, &references);
+ *orderp = NULL;
+ if (references != 0)
+ return;
+
+ order->magic = 0;
+ while ((ent = ISC_LIST_HEAD(order->ents)) != NULL) {
+ ISC_LIST_UNLINK(order->ents, ent, link);
+ isc_mem_put(order->mctx, ent, sizeof(*ent));
+ }
+ isc_refcount_destroy(&order->references);
+ isc_mem_putanddetach(&order->mctx, order, sizeof(*order));
+}
diff --git a/lib/dns/peer.c b/lib/dns/peer.c
new file mode 100644
index 0000000..7d878b5
--- /dev/null
+++ b/lib/dns/peer.c
@@ -0,0 +1,685 @@
+/*
+ * Copyright (C) 2004-2006 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: peer.c,v 1.19.18.8 2006/02/28 03:10:48 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/util.h>
+#include <isc/sockaddr.h>
+
+#include <dns/bit.h>
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/peer.h>
+
+/*%
+ * Bit positions in the dns_peer_t structure flags field
+ */
+#define BOGUS_BIT 0
+#define SERVER_TRANSFER_FORMAT_BIT 1
+#define TRANSFERS_BIT 2
+#define PROVIDE_IXFR_BIT 3
+#define REQUEST_IXFR_BIT 4
+#define SUPPORT_EDNS_BIT 5
+#define SERVER_UDPSIZE_BIT 6
+#define SERVER_MAXUDP_BIT 7
+
+static void
+peerlist_delete(dns_peerlist_t **list);
+
+static void
+peer_delete(dns_peer_t **peer);
+
+isc_result_t
+dns_peerlist_new(isc_mem_t *mem, dns_peerlist_t **list) {
+ dns_peerlist_t *l;
+
+ REQUIRE(list != NULL);
+
+ l = isc_mem_get(mem, sizeof(*l));
+ if (l == NULL)
+ return (ISC_R_NOMEMORY);
+
+ ISC_LIST_INIT(l->elements);
+ l->mem = mem;
+ l->refs = 1;
+ l->magic = DNS_PEERLIST_MAGIC;
+
+ *list = l;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_peerlist_attach(dns_peerlist_t *source, dns_peerlist_t **target) {
+ REQUIRE(DNS_PEERLIST_VALID(source));
+ REQUIRE(target != NULL);
+ REQUIRE(*target == NULL);
+
+ source->refs++;
+
+ ENSURE(source->refs != 0xffffffffU);
+
+ *target = source;
+}
+
+void
+dns_peerlist_detach(dns_peerlist_t **list) {
+ dns_peerlist_t *plist;
+
+ REQUIRE(list != NULL);
+ REQUIRE(*list != NULL);
+ REQUIRE(DNS_PEERLIST_VALID(*list));
+
+ plist = *list;
+ *list = NULL;
+
+ REQUIRE(plist->refs > 0);
+
+ plist->refs--;
+
+ if (plist->refs == 0)
+ peerlist_delete(&plist);
+}
+
+static void
+peerlist_delete(dns_peerlist_t **list) {
+ dns_peerlist_t *l;
+ dns_peer_t *server, *stmp;
+
+ REQUIRE(list != NULL);
+ REQUIRE(DNS_PEERLIST_VALID(*list));
+
+ l = *list;
+
+ REQUIRE(l->refs == 0);
+
+ server = ISC_LIST_HEAD(l->elements);
+ while (server != NULL) {
+ stmp = ISC_LIST_NEXT(server, next);
+ ISC_LIST_UNLINK(l->elements, server, next);
+ dns_peer_detach(&server);
+ server = stmp;
+ }
+
+ l->magic = 0;
+ isc_mem_put(l->mem, l, sizeof(*l));
+
+ *list = NULL;
+}
+
+void
+dns_peerlist_addpeer(dns_peerlist_t *peers, dns_peer_t *peer) {
+ dns_peer_t *p = NULL;
+
+ dns_peer_attach(peer, &p);
+
+ /*
+ * More specifics to front of list.
+ */
+ for (p = ISC_LIST_HEAD(peers->elements);
+ p != NULL;
+ p = ISC_LIST_NEXT(p, next))
+ if (p->prefixlen < peer->prefixlen)
+ break;
+
+ if (p != NULL)
+ ISC_LIST_INSERTBEFORE(peers->elements, p, peer, next);
+ else
+ ISC_LIST_APPEND(peers->elements, peer, next);
+
+}
+
+isc_result_t
+dns_peerlist_peerbyaddr(dns_peerlist_t *servers,
+ isc_netaddr_t *addr, dns_peer_t **retval)
+{
+ dns_peer_t *server;
+ isc_result_t res;
+
+ REQUIRE(retval != NULL);
+ REQUIRE(DNS_PEERLIST_VALID(servers));
+
+ server = ISC_LIST_HEAD(servers->elements);
+ while (server != NULL) {
+ if (isc_netaddr_eqprefix(addr, &server->address,
+ server->prefixlen))
+ break;
+
+ server = ISC_LIST_NEXT(server, next);
+ }
+
+ if (server != NULL) {
+ *retval = server;
+ res = ISC_R_SUCCESS;
+ } else {
+ res = ISC_R_NOTFOUND;
+ }
+
+ return (res);
+}
+
+
+
+isc_result_t
+dns_peerlist_currpeer(dns_peerlist_t *peers, dns_peer_t **retval) {
+ dns_peer_t *p = NULL;
+
+ p = ISC_LIST_TAIL(peers->elements);
+
+ dns_peer_attach(p, retval);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_new(isc_mem_t *mem, isc_netaddr_t *addr, dns_peer_t **peerptr) {
+ unsigned int prefixlen = 0;
+
+ REQUIRE(peerptr != NULL);
+ switch(addr->family) {
+ case AF_INET:
+ prefixlen = 32;
+ break;
+ case AF_INET6:
+ prefixlen = 128;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ return (dns_peer_newprefix(mem, addr, prefixlen, peerptr));
+}
+
+isc_result_t
+dns_peer_newprefix(isc_mem_t *mem, isc_netaddr_t *addr, unsigned int prefixlen,
+ dns_peer_t **peerptr)
+{
+ dns_peer_t *peer;
+
+ REQUIRE(peerptr != NULL);
+
+ peer = isc_mem_get(mem, sizeof(*peer));
+ if (peer == NULL)
+ return (ISC_R_NOMEMORY);
+
+ peer->magic = DNS_PEER_MAGIC;
+ peer->address = *addr;
+ peer->prefixlen = prefixlen;
+ peer->mem = mem;
+ peer->bogus = ISC_FALSE;
+ peer->transfer_format = dns_one_answer;
+ peer->transfers = 0;
+ peer->request_ixfr = ISC_FALSE;
+ peer->provide_ixfr = ISC_FALSE;
+ peer->key = NULL;
+ peer->refs = 1;
+ peer->transfer_source = NULL;
+ peer->notify_source = NULL;
+ peer->query_source = NULL;
+
+ memset(&peer->bitflags, 0x0, sizeof(peer->bitflags));
+
+ ISC_LINK_INIT(peer, next);
+
+ *peerptr = peer;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_peer_attach(dns_peer_t *source, dns_peer_t **target) {
+ REQUIRE(DNS_PEER_VALID(source));
+ REQUIRE(target != NULL);
+ REQUIRE(*target == NULL);
+
+ source->refs++;
+
+ ENSURE(source->refs != 0xffffffffU);
+
+ *target = source;
+}
+
+void
+dns_peer_detach(dns_peer_t **peer) {
+ dns_peer_t *p;
+
+ REQUIRE(peer != NULL);
+ REQUIRE(*peer != NULL);
+ REQUIRE(DNS_PEER_VALID(*peer));
+
+ p = *peer;
+
+ REQUIRE(p->refs > 0);
+
+ *peer = NULL;
+ p->refs--;
+
+ if (p->refs == 0)
+ peer_delete(&p);
+}
+
+static void
+peer_delete(dns_peer_t **peer) {
+ dns_peer_t *p;
+ isc_mem_t *mem;
+
+ REQUIRE(peer != NULL);
+ REQUIRE(DNS_PEER_VALID(*peer));
+
+ p = *peer;
+
+ REQUIRE(p->refs == 0);
+
+ mem = p->mem;
+ p->mem = NULL;
+ p->magic = 0;
+
+ if (p->key != NULL) {
+ dns_name_free(p->key, mem);
+ isc_mem_put(mem, p->key, sizeof(dns_name_t));
+ }
+
+ if (p->transfer_source != NULL) {
+ isc_mem_put(mem, p->transfer_source,
+ sizeof(*p->transfer_source));
+ }
+
+ isc_mem_put(mem, p, sizeof(*p));
+
+ *peer = NULL;
+}
+
+isc_result_t
+dns_peer_setbogus(dns_peer_t *peer, isc_boolean_t newval) {
+ isc_boolean_t existed;
+
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ existed = DNS_BIT_CHECK(BOGUS_BIT, &peer->bitflags);
+
+ peer->bogus = newval;
+ DNS_BIT_SET(BOGUS_BIT, &peer->bitflags);
+
+ return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_getbogus(dns_peer_t *peer, isc_boolean_t *retval) {
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(retval != NULL);
+
+ if (DNS_BIT_CHECK(BOGUS_BIT, &peer->bitflags)) {
+ *retval = peer->bogus;
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_NOTFOUND);
+}
+
+
+isc_result_t
+dns_peer_setprovideixfr(dns_peer_t *peer, isc_boolean_t newval) {
+ isc_boolean_t existed;
+
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ existed = DNS_BIT_CHECK(PROVIDE_IXFR_BIT, &peer->bitflags);
+
+ peer->provide_ixfr = newval;
+ DNS_BIT_SET(PROVIDE_IXFR_BIT, &peer->bitflags);
+
+ return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_getprovideixfr(dns_peer_t *peer, isc_boolean_t *retval) {
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(retval != NULL);
+
+ if (DNS_BIT_CHECK(PROVIDE_IXFR_BIT, &peer->bitflags)) {
+ *retval = peer->provide_ixfr;
+ return (ISC_R_SUCCESS);
+ } else {
+ return (ISC_R_NOTFOUND);
+ }
+}
+
+isc_result_t
+dns_peer_setrequestixfr(dns_peer_t *peer, isc_boolean_t newval) {
+ isc_boolean_t existed;
+
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ existed = DNS_BIT_CHECK(REQUEST_IXFR_BIT, &peer->bitflags);
+
+ peer->request_ixfr = newval;
+ DNS_BIT_SET(REQUEST_IXFR_BIT, &peer->bitflags);
+
+ return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_getrequestixfr(dns_peer_t *peer, isc_boolean_t *retval) {
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(retval != NULL);
+
+ if (DNS_BIT_CHECK(REQUEST_IXFR_BIT, &peer->bitflags)) {
+ *retval = peer->request_ixfr;
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_NOTFOUND);
+}
+
+isc_result_t
+dns_peer_setsupportedns(dns_peer_t *peer, isc_boolean_t newval) {
+ isc_boolean_t existed;
+
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ existed = DNS_BIT_CHECK(SUPPORT_EDNS_BIT, &peer->bitflags);
+
+ peer->support_edns = newval;
+ DNS_BIT_SET(SUPPORT_EDNS_BIT, &peer->bitflags);
+
+ return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_getsupportedns(dns_peer_t *peer, isc_boolean_t *retval) {
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(retval != NULL);
+
+ if (DNS_BIT_CHECK(SUPPORT_EDNS_BIT, &peer->bitflags)) {
+ *retval = peer->support_edns;
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_NOTFOUND);
+}
+
+isc_result_t
+dns_peer_settransfers(dns_peer_t *peer, isc_uint32_t newval) {
+ isc_boolean_t existed;
+
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ existed = DNS_BIT_CHECK(TRANSFERS_BIT, &peer->bitflags);
+
+ peer->transfers = newval;
+ DNS_BIT_SET(TRANSFERS_BIT, &peer->bitflags);
+
+ return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_gettransfers(dns_peer_t *peer, isc_uint32_t *retval) {
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(retval != NULL);
+
+ if (DNS_BIT_CHECK(TRANSFERS_BIT, &peer->bitflags)) {
+ *retval = peer->transfers;
+ return (ISC_R_SUCCESS);
+ } else {
+ return (ISC_R_NOTFOUND);
+ }
+}
+
+isc_result_t
+dns_peer_settransferformat(dns_peer_t *peer, dns_transfer_format_t newval) {
+ isc_boolean_t existed;
+
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ existed = DNS_BIT_CHECK(SERVER_TRANSFER_FORMAT_BIT,
+ &peer->bitflags);
+
+ peer->transfer_format = newval;
+ DNS_BIT_SET(SERVER_TRANSFER_FORMAT_BIT, &peer->bitflags);
+
+ return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_gettransferformat(dns_peer_t *peer, dns_transfer_format_t *retval) {
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(retval != NULL);
+
+ if (DNS_BIT_CHECK(SERVER_TRANSFER_FORMAT_BIT, &peer->bitflags)) {
+ *retval = peer->transfer_format;
+ return (ISC_R_SUCCESS);
+ } else {
+ return (ISC_R_NOTFOUND);
+ }
+}
+
+isc_result_t
+dns_peer_getkey(dns_peer_t *peer, dns_name_t **retval) {
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(retval != NULL);
+
+ if (peer->key != NULL) {
+ *retval = peer->key;
+ }
+
+ return (peer->key == NULL ? ISC_R_NOTFOUND : ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_setkey(dns_peer_t *peer, dns_name_t **keyval) {
+ isc_boolean_t exists = ISC_FALSE;
+
+ if (peer->key != NULL) {
+ dns_name_free(peer->key, peer->mem);
+ isc_mem_put(peer->mem, peer->key, sizeof(dns_name_t));
+ exists = ISC_TRUE;
+ }
+
+ peer->key = *keyval;
+ *keyval = NULL;
+
+ return (exists ? ISC_R_EXISTS : ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_setkeybycharp(dns_peer_t *peer, const char *keyval) {
+ isc_buffer_t b;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ isc_result_t result;
+
+ dns_fixedname_init(&fname);
+ isc_buffer_init(&b, keyval, strlen(keyval));
+ isc_buffer_add(&b, strlen(keyval));
+ result = dns_name_fromtext(dns_fixedname_name(&fname), &b,
+ dns_rootname, ISC_FALSE, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ name = isc_mem_get(peer->mem, sizeof(dns_name_t));
+ if (name == NULL)
+ return (ISC_R_NOMEMORY);
+
+ dns_name_init(name, NULL);
+ result = dns_name_dup(dns_fixedname_name(&fname), peer->mem, name);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(peer->mem, name, sizeof(dns_name_t));
+ return (result);
+ }
+
+ result = dns_peer_setkey(peer, &name);
+ if (result != ISC_R_SUCCESS)
+ isc_mem_put(peer->mem, name, sizeof(dns_name_t));
+
+ return (result);
+}
+
+isc_result_t
+dns_peer_settransfersource(dns_peer_t *peer,
+ const isc_sockaddr_t *transfer_source)
+{
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ if (peer->transfer_source != NULL) {
+ isc_mem_put(peer->mem, peer->transfer_source,
+ sizeof(*peer->transfer_source));
+ peer->transfer_source = NULL;
+ }
+ if (transfer_source != NULL) {
+ peer->transfer_source = isc_mem_get(peer->mem,
+ sizeof(*peer->transfer_source));
+ if (peer->transfer_source == NULL)
+ return (ISC_R_NOMEMORY);
+
+ *peer->transfer_source = *transfer_source;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_gettransfersource(dns_peer_t *peer, isc_sockaddr_t *transfer_source) {
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(transfer_source != NULL);
+
+ if (peer->transfer_source == NULL)
+ return (ISC_R_NOTFOUND);
+ *transfer_source = *peer->transfer_source;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_setnotifysource(dns_peer_t *peer,
+ const isc_sockaddr_t *notify_source)
+{
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ if (peer->notify_source != NULL) {
+ isc_mem_put(peer->mem, peer->notify_source,
+ sizeof(*peer->notify_source));
+ peer->notify_source = NULL;
+ }
+ if (notify_source != NULL) {
+ peer->notify_source = isc_mem_get(peer->mem,
+ sizeof(*peer->notify_source));
+ if (peer->notify_source == NULL)
+ return (ISC_R_NOMEMORY);
+
+ *peer->notify_source = *notify_source;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_getnotifysource(dns_peer_t *peer, isc_sockaddr_t *notify_source) {
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(notify_source != NULL);
+
+ if (peer->notify_source == NULL)
+ return (ISC_R_NOTFOUND);
+ *notify_source = *peer->notify_source;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_setquerysource(dns_peer_t *peer, const isc_sockaddr_t *query_source) {
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ if (peer->query_source != NULL) {
+ isc_mem_put(peer->mem, peer->query_source,
+ sizeof(*peer->query_source));
+ peer->query_source = NULL;
+ }
+ if (query_source != NULL) {
+ peer->query_source = isc_mem_get(peer->mem,
+ sizeof(*peer->query_source));
+ if (peer->query_source == NULL)
+ return (ISC_R_NOMEMORY);
+
+ *peer->query_source = *query_source;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_getquerysource(dns_peer_t *peer, isc_sockaddr_t *query_source) {
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(query_source != NULL);
+
+ if (peer->query_source == NULL)
+ return (ISC_R_NOTFOUND);
+ *query_source = *peer->query_source;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_setudpsize(dns_peer_t *peer, isc_uint16_t udpsize) {
+ isc_boolean_t existed;
+
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ existed = DNS_BIT_CHECK(SERVER_UDPSIZE_BIT, &peer->bitflags);
+
+ peer->udpsize = udpsize;
+ DNS_BIT_SET(SERVER_UDPSIZE_BIT, &peer->bitflags);
+
+ return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_getudpsize(dns_peer_t *peer, isc_uint16_t *udpsize) {
+
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(udpsize != NULL);
+
+ if (DNS_BIT_CHECK(SERVER_UDPSIZE_BIT, &peer->bitflags)) {
+ *udpsize = peer->udpsize;
+ return (ISC_R_SUCCESS);
+ } else {
+ return (ISC_R_NOTFOUND);
+ }
+}
+
+isc_result_t
+dns_peer_setmaxudp(dns_peer_t *peer, isc_uint16_t maxudp) {
+ isc_boolean_t existed;
+
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ existed = DNS_BIT_CHECK(SERVER_MAXUDP_BIT, &peer->bitflags);
+
+ peer->maxudp = maxudp;
+ DNS_BIT_SET(SERVER_MAXUDP_BIT, &peer->bitflags);
+
+ return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_getmaxudp(dns_peer_t *peer, isc_uint16_t *maxudp) {
+
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(maxudp != NULL);
+
+ if (DNS_BIT_CHECK(SERVER_MAXUDP_BIT, &peer->bitflags)) {
+ *maxudp = peer->maxudp;
+ return (ISC_R_SUCCESS);
+ } else {
+ return (ISC_R_NOTFOUND);
+ }
+}
diff --git a/lib/dns/portlist.c b/lib/dns/portlist.c
new file mode 100644
index 0000000..7e76171
--- /dev/null
+++ b/lib/dns/portlist.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: portlist.c,v 1.6.18.5 2006/08/25 05:25:51 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/refcount.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <dns/types.h>
+#include <dns/portlist.h>
+
+#define DNS_PORTLIST_MAGIC ISC_MAGIC('P','L','S','T')
+#define DNS_VALID_PORTLIST(p) ISC_MAGIC_VALID(p, DNS_PORTLIST_MAGIC)
+
+typedef struct dns_element {
+ in_port_t port;
+ isc_uint16_t flags;
+} dns_element_t;
+
+struct dns_portlist {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_refcount_t refcount;
+ isc_mutex_t lock;
+ dns_element_t *list;
+ unsigned int allocated;
+ unsigned int active;
+};
+
+#define DNS_PL_INET 0x0001
+#define DNS_PL_INET6 0x0002
+#define DNS_PL_ALLOCATE 16
+
+static int
+compare(const void *arg1, const void *arg2) {
+ const dns_element_t *e1 = (const dns_element_t *)arg1;
+ const dns_element_t *e2 = (const dns_element_t *)arg2;
+
+ if (e1->port < e2->port)
+ return (-1);
+ if (e1->port > e2->port)
+ return (1);
+ return (0);
+}
+
+isc_result_t
+dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) {
+ dns_portlist_t *portlist;
+ isc_result_t result;
+
+ REQUIRE(portlistp != NULL && *portlistp == NULL);
+
+ portlist = isc_mem_get(mctx, sizeof(*portlist));
+ if (portlist == NULL)
+ return (ISC_R_NOMEMORY);
+ result = isc_mutex_init(&portlist->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, portlist, sizeof(*portlist));
+ return (result);
+ }
+ result = isc_refcount_init(&portlist->refcount, 1);
+ if (result != ISC_R_SUCCESS) {
+ DESTROYLOCK(&portlist->lock);
+ isc_mem_put(mctx, portlist, sizeof(*portlist));
+ return (result);
+ }
+ portlist->list = NULL;
+ portlist->allocated = 0;
+ portlist->active = 0;
+ portlist->mctx = NULL;
+ isc_mem_attach(mctx, &portlist->mctx);
+ portlist->magic = DNS_PORTLIST_MAGIC;
+ *portlistp = portlist;
+ return (ISC_R_SUCCESS);
+}
+
+static dns_element_t *
+find_port(dns_element_t *list, unsigned int len, in_port_t port) {
+ unsigned int xtry = len / 2;
+ unsigned int min = 0;
+ unsigned int max = len - 1;
+ unsigned int last = len;
+
+ for (;;) {
+ if (list[xtry].port == port)
+ return (&list[xtry]);
+ if (port > list[xtry].port) {
+ if (xtry == max)
+ break;
+ min = xtry;
+ xtry = xtry + (max - xtry + 1) / 2;
+ INSIST(xtry <= max);
+ if (xtry == last)
+ break;
+ last = min;
+ } else {
+ if (xtry == min)
+ break;
+ max = xtry;
+ xtry = xtry - (xtry - min + 1) / 2;
+ INSIST(xtry >= min);
+ if (xtry == last)
+ break;
+ last = max;
+ }
+ }
+ return (NULL);
+}
+
+isc_result_t
+dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) {
+ dns_element_t *el;
+ isc_result_t result;
+
+ REQUIRE(DNS_VALID_PORTLIST(portlist));
+ REQUIRE(af == AF_INET || af == AF_INET6);
+
+ LOCK(&portlist->lock);
+ if (portlist->active != 0) {
+ el = find_port(portlist->list, portlist->active, port);
+ if (el != NULL) {
+ if (af == AF_INET)
+ el->flags |= DNS_PL_INET;
+ else
+ el->flags |= DNS_PL_INET6;
+ result = ISC_R_SUCCESS;
+ goto unlock;
+ }
+ }
+
+ if (portlist->allocated <= portlist->active) {
+ unsigned int allocated;
+ allocated = portlist->allocated + DNS_PL_ALLOCATE;
+ el = isc_mem_get(portlist->mctx, sizeof(*el) * allocated);
+ if (el == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto unlock;
+ }
+ if (portlist->list != NULL) {
+ memcpy(el, portlist->list,
+ portlist->allocated * sizeof(*el));
+ isc_mem_put(portlist->mctx, portlist->list,
+ portlist->allocated * sizeof(*el));
+ }
+ portlist->list = el;
+ portlist->allocated = allocated;
+ }
+ portlist->list[portlist->active].port = port;
+ if (af == AF_INET)
+ portlist->list[portlist->active].flags = DNS_PL_INET;
+ else
+ portlist->list[portlist->active].flags = DNS_PL_INET6;
+ portlist->active++;
+ qsort(portlist->list, portlist->active, sizeof(*el), compare);
+ result = ISC_R_SUCCESS;
+ unlock:
+ UNLOCK(&portlist->lock);
+ return (result);
+}
+
+void
+dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port) {
+ dns_element_t *el;
+
+ REQUIRE(DNS_VALID_PORTLIST(portlist));
+ REQUIRE(af == AF_INET || af == AF_INET6);
+
+ LOCK(&portlist->lock);
+ if (portlist->active != 0) {
+ el = find_port(portlist->list, portlist->active, port);
+ if (el != NULL) {
+ if (af == AF_INET)
+ el->flags &= ~DNS_PL_INET;
+ else
+ el->flags &= ~DNS_PL_INET6;
+ if (el->flags == 0) {
+ *el = portlist->list[portlist->active];
+ portlist->active--;
+ qsort(portlist->list, portlist->active,
+ sizeof(*el), compare);
+ }
+ }
+ }
+ UNLOCK(&portlist->lock);
+}
+
+isc_boolean_t
+dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) {
+ dns_element_t *el;
+ isc_boolean_t result = ISC_FALSE;
+
+ REQUIRE(DNS_VALID_PORTLIST(portlist));
+ REQUIRE(af == AF_INET || af == AF_INET6);
+ LOCK(&portlist->lock);
+ if (portlist->active != 0) {
+ el = find_port(portlist->list, portlist->active, port);
+ if (el != NULL) {
+ if (af == AF_INET && (el->flags & DNS_PL_INET) != 0)
+ result = ISC_TRUE;
+ if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0)
+ result = ISC_TRUE;
+ }
+ }
+ UNLOCK(&portlist->lock);
+ return (result);
+}
+
+void
+dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp) {
+
+ REQUIRE(DNS_VALID_PORTLIST(portlist));
+ REQUIRE(portlistp != NULL && *portlistp == NULL);
+
+ isc_refcount_increment(&portlist->refcount, NULL);
+ *portlistp = portlist;
+}
+
+void
+dns_portlist_detach(dns_portlist_t **portlistp) {
+ dns_portlist_t *portlist;
+ unsigned int count;
+
+ REQUIRE(portlistp != NULL);
+ portlist = *portlistp;
+ REQUIRE(DNS_VALID_PORTLIST(portlist));
+ *portlistp = NULL;
+ isc_refcount_decrement(&portlist->refcount, &count);
+ if (count == 0) {
+ portlist->magic = 0;
+ isc_refcount_destroy(&portlist->refcount);
+ if (portlist->list != NULL)
+ isc_mem_put(portlist->mctx, portlist->list,
+ portlist->allocated *
+ sizeof(*portlist->list));
+ DESTROYLOCK(&portlist->lock);
+ isc_mem_putanddetach(&portlist->mctx, portlist,
+ sizeof(*portlist));
+ }
+}
diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c
new file mode 100644
index 0000000..b8db99a
--- /dev/null
+++ b/lib/dns/rbt.c
@@ -0,0 +1,2544 @@
+/*
+ * Copyright (C) 2004, 2005 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: rbt.c,v 1.128.18.7 2005/10/13 01:26:06 marka Exp $ */
+
+/*! \file */
+
+/* Principal Authors: DCL */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/refcount.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/*%
+ * This define is so dns/name.h (included by dns/fixedname.h) uses more
+ * efficient macro calls instead of functions for a few operations.
+ */
+#define DNS_NAME_USEINLINE 1
+
+#include <dns/fixedname.h>
+#include <dns/rbt.h>
+#include <dns/result.h>
+
+#define RBT_MAGIC ISC_MAGIC('R', 'B', 'T', '+')
+#define VALID_RBT(rbt) ISC_MAGIC_VALID(rbt, RBT_MAGIC)
+
+/*
+ * XXXDCL Since parent pointers were added in again, I could remove all of the
+ * chain junk, and replace with dns_rbt_firstnode, _previousnode, _nextnode,
+ * _lastnode. This would involve pretty major change to the API.
+ */
+#define CHAIN_MAGIC ISC_MAGIC('0', '-', '0', '-')
+#define VALID_CHAIN(chain) ISC_MAGIC_VALID(chain, CHAIN_MAGIC)
+
+#define RBT_HASH_SIZE 64
+
+#ifdef RBT_MEM_TEST
+#undef RBT_HASH_SIZE
+#define RBT_HASH_SIZE 2 /*%< To give the reallocation code a workout. */
+#endif
+
+struct dns_rbt {
+ unsigned int magic;
+ isc_mem_t * mctx;
+ dns_rbtnode_t * root;
+ void (*data_deleter)(void *, void *);
+ void * deleter_arg;
+ unsigned int nodecount;
+ unsigned int hashsize;
+ dns_rbtnode_t ** hashtable;
+};
+
+#define RED 0
+#define BLACK 1
+
+/*%
+ * Elements of the rbtnode structure.
+ */
+#define PARENT(node) ((node)->parent)
+#define LEFT(node) ((node)->left)
+#define RIGHT(node) ((node)->right)
+#define DOWN(node) ((node)->down)
+#define DATA(node) ((node)->data)
+#define HASHNEXT(node) ((node)->hashnext)
+#define HASHVAL(node) ((node)->hashval)
+#define COLOR(node) ((node)->color)
+#define NAMELEN(node) ((node)->namelen)
+#define OFFSETLEN(node) ((node)->offsetlen)
+#define ATTRS(node) ((node)->attributes)
+#define PADBYTES(node) ((node)->padbytes)
+#define IS_ROOT(node) ISC_TF((node)->is_root == 1)
+#define FINDCALLBACK(node) ISC_TF((node)->find_callback == 1)
+
+/*%
+ * Structure elements from the rbtdb.c, not
+ * used as part of the rbt.c algorithms.
+ */
+#define DIRTY(node) ((node)->dirty)
+#define WILD(node) ((node)->wild)
+#define LOCKNUM(node) ((node)->locknum)
+
+/*%
+ * The variable length stuff stored after the node.
+ */
+#define NAME(node) ((unsigned char *)((node) + 1))
+#define OFFSETS(node) (NAME(node) + NAMELEN(node))
+
+#define NODE_SIZE(node) (sizeof(*node) + \
+ NAMELEN(node) + OFFSETLEN(node) + PADBYTES(node))
+
+/*%
+ * Color management.
+ */
+#define IS_RED(node) ((node) != NULL && (node)->color == RED)
+#define IS_BLACK(node) ((node) == NULL || (node)->color == BLACK)
+#define MAKE_RED(node) ((node)->color = RED)
+#define MAKE_BLACK(node) ((node)->color = BLACK)
+
+/*%
+ * Chain management.
+ *
+ * The "ancestors" member of chains were removed, with their job now
+ * being wholy handled by parent pointers (which didn't exist, because
+ * of memory concerns, when chains were first implemented).
+ */
+#define ADD_LEVEL(chain, node) \
+ (chain)->levels[(chain)->level_count++] = (node)
+
+/*%
+ * The following macros directly access normally private name variables.
+ * These macros are used to avoid a lot of function calls in the critical
+ * path of the tree traversal code.
+ */
+
+#define NODENAME(node, name) \
+do { \
+ (name)->length = NAMELEN(node); \
+ (name)->labels = OFFSETLEN(node); \
+ (name)->ndata = NAME(node); \
+ (name)->offsets = OFFSETS(node); \
+ (name)->attributes = ATTRS(node); \
+ (name)->attributes |= DNS_NAMEATTR_READONLY; \
+} while (0)
+
+#ifdef DNS_RBT_USEHASH
+static isc_result_t
+inithash(dns_rbt_t *rbt);
+#endif
+
+#ifdef DEBUG
+#define inline
+/*
+ * A little something to help out in GDB.
+ */
+dns_name_t Name(dns_rbtnode_t *node);
+dns_name_t
+Name(dns_rbtnode_t *node) {
+ dns_name_t name;
+
+ dns_name_init(&name, NULL);
+ if (node != NULL)
+ NODENAME(node, &name);
+
+ return (name);
+}
+
+static void dns_rbt_printnodename(dns_rbtnode_t *node);
+#endif
+
+static inline dns_rbtnode_t *
+find_up(dns_rbtnode_t *node) {
+ dns_rbtnode_t *root;
+
+ /*
+ * Return the node in the level above the argument node that points
+ * to the level the argument node is in. If the argument node is in
+ * the top level, the return value is NULL.
+ */
+ for (root = node; ! IS_ROOT(root); root = PARENT(root))
+ ; /* Nothing. */
+
+ return (PARENT(root));
+}
+
+/*
+ * Forward declarations.
+ */
+static isc_result_t
+create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep);
+
+#ifdef DNS_RBT_USEHASH
+static inline void
+hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name);
+static inline void
+unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node);
+#else
+#define hash_node(rbt, node, name) (ISC_R_SUCCESS)
+#define unhash_node(rbt, node)
+#endif
+
+static inline void
+rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
+static inline void
+rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
+
+static void
+dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
+ dns_rbtnode_t **rootp);
+
+static void
+dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp);
+
+static isc_result_t
+dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node);
+
+static void
+dns_rbt_deletetreeflat(dns_rbt_t *rbt, unsigned int quantum,
+ dns_rbtnode_t **nodep);
+
+/*
+ * Initialize a red/black tree of trees.
+ */
+isc_result_t
+dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
+ void *deleter_arg, dns_rbt_t **rbtp)
+{
+#ifdef DNS_RBT_USEHASH
+ isc_result_t result;
+#endif
+ dns_rbt_t *rbt;
+
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(rbtp != NULL && *rbtp == NULL);
+ REQUIRE(deleter == NULL ? deleter_arg == NULL : 1);
+
+ rbt = (dns_rbt_t *)isc_mem_get(mctx, sizeof(*rbt));
+ if (rbt == NULL)
+ return (ISC_R_NOMEMORY);
+
+ rbt->mctx = mctx;
+ rbt->data_deleter = deleter;
+ rbt->deleter_arg = deleter_arg;
+ rbt->root = NULL;
+ rbt->nodecount = 0;
+ rbt->hashtable = NULL;
+ rbt->hashsize = 0;
+#ifdef DNS_RBT_USEHASH
+ result = inithash(rbt);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, rbt, sizeof(*rbt));
+ return (result);
+ }
+#endif
+ rbt->magic = RBT_MAGIC;
+
+ *rbtp = rbt;
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Deallocate a red/black tree of trees.
+ */
+void
+dns_rbt_destroy(dns_rbt_t **rbtp) {
+ RUNTIME_CHECK(dns_rbt_destroy2(rbtp, 0) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) {
+ dns_rbt_t *rbt;
+
+ REQUIRE(rbtp != NULL && VALID_RBT(*rbtp));
+
+ rbt = *rbtp;
+
+ dns_rbt_deletetreeflat(rbt, quantum, &rbt->root);
+ if (rbt->root != NULL)
+ return (ISC_R_QUOTA);
+
+ INSIST(rbt->nodecount == 0);
+
+ if (rbt->hashtable != NULL)
+ isc_mem_put(rbt->mctx, rbt->hashtable,
+ rbt->hashsize * sizeof(dns_rbtnode_t *));
+
+ rbt->magic = 0;
+
+ isc_mem_put(rbt->mctx, rbt, sizeof(*rbt));
+ *rbtp = NULL;
+ return (ISC_R_SUCCESS);
+}
+
+unsigned int
+dns_rbt_nodecount(dns_rbt_t *rbt) {
+ REQUIRE(VALID_RBT(rbt));
+ return (rbt->nodecount);
+}
+
+static inline isc_result_t
+chain_name(dns_rbtnodechain_t *chain, dns_name_t *name,
+ isc_boolean_t include_chain_end)
+{
+ dns_name_t nodename;
+ isc_result_t result = ISC_R_SUCCESS;
+ int i;
+
+ dns_name_init(&nodename, NULL);
+
+ if (include_chain_end && chain->end != NULL) {
+ NODENAME(chain->end, &nodename);
+ result = dns_name_copy(&nodename, name, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else
+ dns_name_reset(name);
+
+ for (i = (int)chain->level_count - 1; i >= 0; i--) {
+ NODENAME(chain->levels[i], &nodename);
+ result = dns_name_concatenate(name, &nodename, name, NULL);
+
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ return (result);
+}
+
+static inline isc_result_t
+move_chain_to_last(dns_rbtnodechain_t *chain, dns_rbtnode_t *node) {
+ do {
+ /*
+ * Go as far right and then down as much as possible,
+ * as long as the rightmost node has a down pointer.
+ */
+ while (RIGHT(node) != NULL)
+ node = RIGHT(node);
+
+ if (DOWN(node) == NULL)
+ break;
+
+ ADD_LEVEL(chain, node);
+ node = DOWN(node);
+ } while (1);
+
+ chain->end = node;
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Add 'name' to tree, initializing its data pointer with 'data'.
+ */
+
+isc_result_t
+dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) {
+ /*
+ * Does this thing have too many variables or what?
+ */
+ dns_rbtnode_t **root, *parent, *child, *current, *new_current;
+ dns_name_t *add_name, *new_name, current_name, *prefix, *suffix;
+ dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix, fnewname;
+ dns_offsets_t current_offsets;
+ dns_namereln_t compared;
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_rbtnodechain_t chain;
+ unsigned int common_labels;
+ unsigned int nlabels, hlabels;
+ int order;
+
+ REQUIRE(VALID_RBT(rbt));
+ REQUIRE(dns_name_isabsolute(name));
+ REQUIRE(nodep != NULL && *nodep == NULL);
+
+ /*
+ * Create a copy of the name so the original name structure is
+ * not modified.
+ */
+ dns_fixedname_init(&fixedcopy);
+ add_name = dns_fixedname_name(&fixedcopy);
+ dns_name_clone(name, add_name);
+
+ if (rbt->root == NULL) {
+ result = create_node(rbt->mctx, add_name, &new_current);
+ if (result == ISC_R_SUCCESS) {
+ rbt->nodecount++;
+ new_current->is_root = 1;
+ rbt->root = new_current;
+ *nodep = new_current;
+ hash_node(rbt, new_current, name);
+ }
+ return (result);
+ }
+
+ dns_rbtnodechain_init(&chain, rbt->mctx);
+
+ dns_fixedname_init(&fixedprefix);
+ dns_fixedname_init(&fixedsuffix);
+ prefix = dns_fixedname_name(&fixedprefix);
+ suffix = dns_fixedname_name(&fixedsuffix);
+
+ root = &rbt->root;
+ INSIST(IS_ROOT(*root));
+ parent = NULL;
+ current = NULL;
+ child = *root;
+ dns_name_init(&current_name, current_offsets);
+ dns_fixedname_init(&fnewname);
+ new_name = dns_fixedname_name(&fnewname);
+ nlabels = dns_name_countlabels(name);
+ hlabels = 0;
+
+ do {
+ current = child;
+
+ NODENAME(current, &current_name);
+ compared = dns_name_fullcompare(add_name, &current_name,
+ &order, &common_labels);
+
+ if (compared == dns_namereln_equal) {
+ *nodep = current;
+ result = ISC_R_EXISTS;
+ break;
+
+ }
+
+ if (compared == dns_namereln_none) {
+
+ if (order < 0) {
+ parent = current;
+ child = LEFT(current);
+
+ } else if (order > 0) {
+ parent = current;
+ child = RIGHT(current);
+
+ }
+
+ } else {
+ /*
+ * This name has some suffix in common with the
+ * name at the current node. If the name at
+ * the current node is shorter, that means the
+ * new name should be in a subtree. If the
+ * name at the current node is longer, that means
+ * the down pointer to this tree should point
+ * to a new tree that has the common suffix, and
+ * the non-common parts of these two names should
+ * start a new tree.
+ */
+ hlabels += common_labels;
+ if (compared == dns_namereln_subdomain) {
+ /*
+ * All of the existing labels are in common,
+ * so the new name is in a subtree.
+ * Whack off the common labels for the
+ * not-in-common part to be searched for
+ * in the next level.
+ */
+ dns_name_split(add_name, common_labels,
+ add_name, NULL);
+
+ /*
+ * Follow the down pointer (possibly NULL).
+ */
+ root = &DOWN(current);
+
+ INSIST(*root == NULL ||
+ (IS_ROOT(*root) &&
+ PARENT(*root) == current));
+
+ parent = NULL;
+ child = DOWN(current);
+ ADD_LEVEL(&chain, current);
+
+ } else {
+ /*
+ * The number of labels in common is fewer
+ * than the number of labels at the current
+ * node, so the current node must be adjusted
+ * to have just the common suffix, and a down
+ * pointer made to a new tree.
+ */
+
+ INSIST(compared == dns_namereln_commonancestor
+ || compared == dns_namereln_contains);
+
+ /*
+ * Ensure the number of levels in the tree
+ * does not exceed the number of logical
+ * levels allowed by DNSSEC.
+ *
+ * XXXDCL need a better error result?
+ *
+ * XXXDCL Since chain ancestors were removed,
+ * no longer used by dns_rbt_addonlevel(),
+ * this is the only real use of chains in the
+ * function. It could be done instead with
+ * a simple integer variable, but I am pressed
+ * for time.
+ */
+ if (chain.level_count ==
+ (sizeof(chain.levels) /
+ sizeof(*chain.levels))) {
+ result = ISC_R_NOSPACE;
+ break;
+ }
+
+ /*
+ * Split the name into two parts, a prefix
+ * which is the not-in-common parts of the
+ * two names and a suffix that is the common
+ * parts of them.
+ */
+ dns_name_split(&current_name, common_labels,
+ prefix, suffix);
+ result = create_node(rbt->mctx, suffix,
+ &new_current);
+
+ if (result != ISC_R_SUCCESS)
+ break;
+
+ /*
+ * Reproduce the tree attributes of the
+ * current node.
+ */
+ new_current->is_root = current->is_root;
+ PARENT(new_current) = PARENT(current);
+ LEFT(new_current) = LEFT(current);
+ RIGHT(new_current) = RIGHT(current);
+ COLOR(new_current) = COLOR(current);
+
+ /*
+ * Fix pointers that were to the current node.
+ */
+ if (parent != NULL) {
+ if (LEFT(parent) == current)
+ LEFT(parent) = new_current;
+ else
+ RIGHT(parent) = new_current;
+ }
+ if (LEFT(new_current) != NULL)
+ PARENT(LEFT(new_current)) =
+ new_current;
+ if (RIGHT(new_current) != NULL)
+ PARENT(RIGHT(new_current)) =
+ new_current;
+ if (*root == current)
+ *root = new_current;
+
+ NAMELEN(current) = prefix->length;
+ OFFSETLEN(current) = prefix->labels;
+ memcpy(OFFSETS(current), prefix->offsets,
+ prefix->labels);
+ PADBYTES(current) +=
+ (current_name.length - prefix->length) +
+ (current_name.labels - prefix->labels);
+
+ /*
+ * Set up the new root of the next level.
+ * By definition it will not be the top
+ * level tree, so clear DNS_NAMEATTR_ABSOLUTE.
+ */
+ current->is_root = 1;
+ PARENT(current) = new_current;
+ DOWN(new_current) = current;
+ root = &DOWN(new_current);
+
+ ADD_LEVEL(&chain, new_current);
+
+ LEFT(current) = NULL;
+ RIGHT(current) = NULL;
+
+ MAKE_BLACK(current);
+ ATTRS(current) &= ~DNS_NAMEATTR_ABSOLUTE;
+
+ rbt->nodecount++;
+ dns_name_getlabelsequence(name,
+ nlabels - hlabels,
+ hlabels, new_name);
+ hash_node(rbt, new_current, new_name);
+
+ if (common_labels ==
+ dns_name_countlabels(add_name)) {
+ /*
+ * The name has been added by pushing
+ * the not-in-common parts down to
+ * a new level.
+ */
+ *nodep = new_current;
+ return (ISC_R_SUCCESS);
+
+ } else {
+ /*
+ * The current node has no data,
+ * because it is just a placeholder.
+ * Its data pointer is already NULL
+ * from create_node()), so there's
+ * nothing more to do to it.
+ */
+
+ /*
+ * The not-in-common parts of the new
+ * name will be inserted into the new
+ * level following this loop (unless
+ * result != ISC_R_SUCCESS, which
+ * is tested after the loop ends).
+ */
+ dns_name_split(add_name, common_labels,
+ add_name, NULL);
+
+ break;
+ }
+
+ }
+
+ }
+
+ } while (child != NULL);
+
+ if (result == ISC_R_SUCCESS)
+ result = create_node(rbt->mctx, add_name, &new_current);
+
+ if (result == ISC_R_SUCCESS) {
+ dns_rbt_addonlevel(new_current, current, order, root);
+ rbt->nodecount++;
+ *nodep = new_current;
+ hash_node(rbt, new_current, name);
+ }
+
+ return (result);
+}
+
+/*
+ * Add a name to the tree of trees, associating it with some data.
+ */
+isc_result_t
+dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data) {
+ isc_result_t result;
+ dns_rbtnode_t *node;
+
+ REQUIRE(VALID_RBT(rbt));
+ REQUIRE(dns_name_isabsolute(name));
+
+ node = NULL;
+
+ result = dns_rbt_addnode(rbt, name, &node);
+
+ /*
+ * dns_rbt_addnode will report the node exists even when
+ * it does not have data associated with it, but the
+ * dns_rbt_*name functions all behave depending on whether
+ * there is data associated with a node.
+ */
+ if (result == ISC_R_SUCCESS ||
+ (result == ISC_R_EXISTS && DATA(node) == NULL)) {
+ DATA(node) = data;
+ result = ISC_R_SUCCESS;
+ }
+
+ return (result);
+}
+
+/*
+ * Find the node for "name" in the tree of trees.
+ */
+isc_result_t
+dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
+ dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
+ unsigned int options, dns_rbtfindcallback_t callback,
+ void *callback_arg)
+{
+ dns_rbtnode_t *current, *last_compared, *current_root;
+ dns_rbtnodechain_t localchain;
+ dns_name_t *search_name, current_name, *callback_name;
+ dns_fixedname_t fixedcallbackname, fixedsearchname;
+ dns_namereln_t compared;
+ isc_result_t result, saved_result;
+ unsigned int common_labels;
+ unsigned int hlabels = 0;
+ int order;
+
+ REQUIRE(VALID_RBT(rbt));
+ REQUIRE(dns_name_isabsolute(name));
+ REQUIRE(node != NULL && *node == NULL);
+ REQUIRE((options & (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR))
+ != (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR));
+
+ /*
+ * If there is a chain it needs to appear to be in a sane state,
+ * otherwise a chain is still needed to generate foundname and
+ * callback_name.
+ */
+ if (chain == NULL) {
+ options |= DNS_RBTFIND_NOPREDECESSOR;
+ chain = &localchain;
+ dns_rbtnodechain_init(chain, rbt->mctx);
+ } else
+ dns_rbtnodechain_reset(chain);
+
+ if (rbt->root == NULL)
+ return (ISC_R_NOTFOUND);
+ else {
+ /*
+ * Appease GCC about variables it incorrectly thinks are
+ * possibly used uninitialized.
+ */
+ compared = dns_namereln_none;
+ last_compared = NULL;
+ }
+
+ dns_fixedname_init(&fixedcallbackname);
+ callback_name = dns_fixedname_name(&fixedcallbackname);
+
+ /*
+ * search_name is the name segment being sought in each tree level.
+ * By using a fixedname, the search_name will definitely have offsets
+ * for use by any splitting.
+ * By using dns_name_clone, no name data should be copied thanks to
+ * the lack of bitstring labels.
+ */
+ dns_fixedname_init(&fixedsearchname);
+ search_name = dns_fixedname_name(&fixedsearchname);
+ dns_name_clone(name, search_name);
+
+ dns_name_init(&current_name, NULL);
+
+ saved_result = ISC_R_SUCCESS;
+ current = rbt->root;
+ current_root = rbt->root;
+
+ while (current != NULL) {
+ NODENAME(current, &current_name);
+ compared = dns_name_fullcompare(search_name, &current_name,
+ &order, &common_labels);
+ last_compared = current;
+
+ if (compared == dns_namereln_equal)
+ break;
+
+ if (compared == dns_namereln_none) {
+#ifdef DNS_RBT_USEHASH
+ dns_name_t hash_name;
+ dns_rbtnode_t *hnode;
+ dns_rbtnode_t *up_current;
+ unsigned int nlabels;
+ unsigned int tlabels = 1;
+ unsigned int hash;
+
+ /*
+ * If there is no hash table, hashing can't be done.
+ */
+ if (rbt->hashtable == NULL)
+ goto nohash;
+
+ /*
+ * The case of current != current_root, that
+ * means a left or right pointer was followed,
+ * only happens when the algorithm fell through to
+ * the traditional binary search because of a
+ * bitstring label. Since we dropped the bitstring
+ * support, this should not happen.
+ */
+ INSIST(current == current_root);
+
+ nlabels = dns_name_countlabels(search_name);
+
+ /*
+ * current_root is the root of the current level, so
+ * it's parent is the same as it's "up" pointer.
+ */
+ up_current = PARENT(current_root);
+ dns_name_init(&hash_name, NULL);
+
+ hashagain:
+ /*
+ * Hash includes tail.
+ */
+ dns_name_getlabelsequence(name,
+ nlabels - tlabels,
+ hlabels + tlabels,
+ &hash_name);
+ hash = dns_name_fullhash(&hash_name, ISC_FALSE);
+ dns_name_getlabelsequence(search_name,
+ nlabels - tlabels,
+ tlabels, &hash_name);
+
+ for (hnode = rbt->hashtable[hash % rbt->hashsize];
+ hnode != NULL;
+ hnode = hnode->hashnext)
+ {
+ dns_name_t hnode_name;
+
+ if (hash != HASHVAL(hnode))
+ continue;
+ if (find_up(hnode) != up_current)
+ continue;
+ dns_name_init(&hnode_name, NULL);
+ NODENAME(hnode, &hnode_name);
+ if (dns_name_equal(&hnode_name, &hash_name))
+ break;
+ }
+
+ if (hnode != NULL) {
+ current = hnode;
+ /*
+ * This is an optimization. If hashing found
+ * the right node, the next call to
+ * dns_name_fullcompare() would obviously
+ * return _equal or _subdomain. Determine
+ * which of those would be the case by
+ * checking if the full name was hashed. Then
+ * make it look like dns_name_fullcompare
+ * was called and jump to the right place.
+ */
+ if (tlabels == nlabels) {
+ compared = dns_namereln_equal;
+ break;
+ } else {
+ common_labels = tlabels;
+ compared = dns_namereln_subdomain;
+ goto subdomain;
+ }
+ }
+
+ if (tlabels++ < nlabels)
+ goto hashagain;
+
+ /*
+ * All of the labels have been tried against the hash
+ * table. Since we dropped the support of bitstring
+ * labels, the name isn't in the table.
+ */
+ current = NULL;
+ continue;
+
+ nohash:
+#endif /* DNS_RBT_USEHASH */
+ /*
+ * Standard binary search tree movement.
+ */
+ if (order < 0)
+ current = LEFT(current);
+ else
+ current = RIGHT(current);
+
+ } else {
+ /*
+ * The names have some common suffix labels.
+ *
+ * If the number in common are equal in length to
+ * the current node's name length, then follow the
+ * down pointer and search in the new tree.
+ */
+ if (compared == dns_namereln_subdomain) {
+ subdomain:
+ /*
+ * Whack off the current node's common parts
+ * for the name to search in the next level.
+ */
+ dns_name_split(search_name, common_labels,
+ search_name, NULL);
+ hlabels += common_labels;
+ /*
+ * This might be the closest enclosing name.
+ */
+ if (DATA(current) != NULL ||
+ (options & DNS_RBTFIND_EMPTYDATA) != 0)
+ *node = current;
+
+ /*
+ * Point the chain to the next level. This
+ * needs to be done before 'current' is pointed
+ * there because the callback in the next
+ * block of code needs the current 'current',
+ * but in the event the callback requests that
+ * the search be stopped then the
+ * DNS_R_PARTIALMATCH code at the end of this
+ * function needs the chain pointed to the
+ * next level.
+ */
+ ADD_LEVEL(chain, current);
+
+ /*
+ * The caller may want to interrupt the
+ * downward search when certain special nodes
+ * are traversed. If this is a special node,
+ * the callback is used to learn what the
+ * caller wants to do.
+ */
+ if (callback != NULL &&
+ FINDCALLBACK(current)) {
+ result = chain_name(chain,
+ callback_name,
+ ISC_FALSE);
+ if (result != ISC_R_SUCCESS) {
+ dns_rbtnodechain_reset(chain);
+ return (result);
+ }
+
+ result = (callback)(current,
+ callback_name,
+ callback_arg);
+ if (result != DNS_R_CONTINUE) {
+ saved_result = result;
+ /*
+ * Treat this node as if it
+ * had no down pointer.
+ */
+ current = NULL;
+ break;
+ }
+ }
+
+ /*
+ * Finally, head to the next tree level.
+ */
+ current = DOWN(current);
+ current_root = current;
+
+ } else {
+ /*
+ * Though there are labels in common, the
+ * entire name at this node is not common
+ * with the search name so the search
+ * name does not exist in the tree.
+ */
+ INSIST(compared == dns_namereln_commonancestor
+ || compared == dns_namereln_contains);
+
+ current = NULL;
+ }
+ }
+ }
+
+ /*
+ * If current is not NULL, NOEXACT is not disallowing exact matches,
+ * and either the node has data or an empty node is ok, return
+ * ISC_R_SUCCESS to indicate an exact match.
+ */
+ if (current != NULL && (options & DNS_RBTFIND_NOEXACT) == 0 &&
+ (DATA(current) != NULL ||
+ (options & DNS_RBTFIND_EMPTYDATA) != 0)) {
+ /*
+ * Found an exact match.
+ */
+ chain->end = current;
+ chain->level_matches = chain->level_count;
+
+ if (foundname != NULL)
+ result = chain_name(chain, foundname, ISC_TRUE);
+ else
+ result = ISC_R_SUCCESS;
+
+ if (result == ISC_R_SUCCESS) {
+ *node = current;
+ result = saved_result;
+ } else
+ *node = NULL;
+ } else {
+ /*
+ * Did not find an exact match (or did not want one).
+ */
+ if (*node != NULL) {
+ /*
+ * ... but found a partially matching superdomain.
+ * Unwind the chain to the partial match node
+ * to set level_matches to the level above the node,
+ * and then to derive the name.
+ *
+ * chain->level_count is guaranteed to be at least 1
+ * here because by definition of finding a superdomain,
+ * the chain is pointed to at least the first subtree.
+ */
+ chain->level_matches = chain->level_count - 1;
+
+ while (chain->levels[chain->level_matches] != *node) {
+ INSIST(chain->level_matches > 0);
+ chain->level_matches--;
+ }
+
+ if (foundname != NULL) {
+ unsigned int saved_count = chain->level_count;
+
+ chain->level_count = chain->level_matches + 1;
+
+ result = chain_name(chain, foundname,
+ ISC_FALSE);
+
+ chain->level_count = saved_count;
+ } else
+ result = ISC_R_SUCCESS;
+
+ if (result == ISC_R_SUCCESS)
+ result = DNS_R_PARTIALMATCH;
+
+ } else
+ result = ISC_R_NOTFOUND;
+
+ if (current != NULL) {
+ /*
+ * There was an exact match but either
+ * DNS_RBTFIND_NOEXACT was set, or
+ * DNS_RBTFIND_EMPTYDATA was set and the node had no
+ * data. A policy decision was made to set the
+ * chain to the exact match, but this is subject
+ * to change if it becomes apparent that something
+ * else would be more useful. It is important that
+ * this case is handled here, because the predecessor
+ * setting code below assumes the match was not exact.
+ */
+ INSIST(((options & DNS_RBTFIND_NOEXACT) != 0) ||
+ ((options & DNS_RBTFIND_EMPTYDATA) == 0 &&
+ DATA(current) == NULL));
+ chain->end = current;
+
+ } else if ((options & DNS_RBTFIND_NOPREDECESSOR) != 0) {
+ /*
+ * Ensure the chain points nowhere.
+ */
+ chain->end = NULL;
+
+ } else {
+ /*
+ * Since there was no exact match, the chain argument
+ * needs to be pointed at the DNSSEC predecessor of
+ * the search name.
+ */
+ if (compared == dns_namereln_subdomain) {
+ /*
+ * Attempted to follow a down pointer that was
+ * NULL, which means the searched for name was
+ * a subdomain of a terminal name in the tree.
+ * Since there are no existing subdomains to
+ * order against, the terminal name is the
+ * predecessor.
+ */
+ INSIST(chain->level_count > 0);
+ INSIST(chain->level_matches <
+ chain->level_count);
+ chain->end =
+ chain->levels[--chain->level_count];
+
+ } else {
+ isc_result_t result2;
+
+ /*
+ * Point current to the node that stopped
+ * the search.
+ *
+ * With the hashing modification that has been
+ * added to the algorithm, the stop node of a
+ * standard binary search is not known. So it
+ * has to be found. There is probably a more
+ * clever way of doing this.
+ *
+ * The assignment of current to NULL when
+ * the relationship is *not* dns_namereln_none,
+ * even though it later gets set to the same
+ * last_compared anyway, is simply to not push
+ * the while loop in one more level of
+ * indentation.
+ */
+ if (compared == dns_namereln_none)
+ current = last_compared;
+ else
+ current = NULL;
+
+ while (current != NULL) {
+ NODENAME(current, &current_name);
+ compared = dns_name_fullcompare(
+ search_name,
+ &current_name,
+ &order,
+ &common_labels);
+
+ last_compared = current;
+
+ /*
+ * Standard binary search movement.
+ */
+ if (order < 0)
+ current = LEFT(current);
+ else
+ current = RIGHT(current);
+
+ }
+
+ current = last_compared;
+
+ /*
+ * Reached a point within a level tree that
+ * positively indicates the name is not
+ * present, but the stop node could be either
+ * less than the desired name (order > 0) or
+ * greater than the desired name (order < 0).
+ *
+ * If the stop node is less, it is not
+ * necessarily the predecessor. If the stop
+ * node has a down pointer, then the real
+ * predecessor is at the end of a level below
+ * (not necessarily the next level).
+ * Move down levels until the rightmost node
+ * does not have a down pointer.
+ *
+ * When the stop node is greater, it is
+ * the successor. All the logic for finding
+ * the predecessor is handily encapsulated
+ * in dns_rbtnodechain_prev. In the event
+ * that the search name is less than anything
+ * else in the tree, the chain is reset.
+ * XXX DCL What is the best way for the caller
+ * to know that the search name has
+ * no predecessor?
+ */
+
+
+ if (order > 0) {
+ if (DOWN(current) != NULL) {
+ ADD_LEVEL(chain, current);
+
+ result2 =
+ move_chain_to_last(chain,
+ DOWN(current));
+
+ if (result2 != ISC_R_SUCCESS)
+ result = result2;
+ } else
+ /*
+ * Ah, the pure and simple
+ * case. The stop node is the
+ * predecessor.
+ */
+ chain->end = current;
+
+ } else {
+ INSIST(order < 0);
+
+ chain->end = current;
+
+ result2 = dns_rbtnodechain_prev(chain,
+ NULL,
+ NULL);
+ if (result2 == ISC_R_SUCCESS ||
+ result2 == DNS_R_NEWORIGIN)
+ ; /* Nothing. */
+ else if (result2 == ISC_R_NOMORE)
+ /*
+ * There is no predecessor.
+ */
+ dns_rbtnodechain_reset(chain);
+ else
+ result = result2;
+ }
+
+ }
+ }
+ }
+
+ ENSURE(*node == NULL || DNS_RBTNODE_VALID(*node));
+
+ return (result);
+}
+
+/*
+ * Get the data pointer associated with 'name'.
+ */
+isc_result_t
+dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
+ dns_name_t *foundname, void **data) {
+ dns_rbtnode_t *node = NULL;
+ isc_result_t result;
+
+ REQUIRE(data != NULL && *data == NULL);
+
+ result = dns_rbt_findnode(rbt, name, foundname, &node, NULL,
+ options, NULL, NULL);
+
+ if (node != NULL &&
+ (DATA(node) != NULL || (options & DNS_RBTFIND_EMPTYDATA) != 0))
+ *data = DATA(node);
+ else
+ result = ISC_R_NOTFOUND;
+
+ return (result);
+}
+
+/*
+ * Delete a name from the tree of trees.
+ */
+isc_result_t
+dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse) {
+ dns_rbtnode_t *node = NULL;
+ isc_result_t result;
+
+ REQUIRE(VALID_RBT(rbt));
+ REQUIRE(dns_name_isabsolute(name));
+
+ /*
+ * First, find the node.
+ *
+ * When searching, the name might not have an exact match:
+ * consider a.b.a.com, b.b.a.com and c.b.a.com as the only
+ * elements of a tree, which would make layer 1 a single
+ * node tree of "b.a.com" and layer 2 a three node tree of
+ * a, b, and c. Deleting a.com would find only a partial depth
+ * match in the first layer. Should it be a requirement that
+ * that the name to be deleted have data? For now, it is.
+ *
+ * ->dirty, ->locknum and ->references are ignored; they are
+ * solely the province of rbtdb.c.
+ */
+ result = dns_rbt_findnode(rbt, name, NULL, &node, NULL,
+ DNS_RBTFIND_NOOPTIONS, NULL, NULL);
+
+ if (result == ISC_R_SUCCESS) {
+ if (DATA(node) != NULL)
+ result = dns_rbt_deletenode(rbt, node, recurse);
+ else
+ result = ISC_R_NOTFOUND;
+
+ } else if (result == DNS_R_PARTIALMATCH)
+ result = ISC_R_NOTFOUND;
+
+ return (result);
+}
+
+/*
+ * Remove a node from the tree of trees.
+ *
+ * NOTE WELL: deletion is *not* symmetric with addition; that is, reversing
+ * a sequence of additions to be deletions will not generally get the
+ * tree back to the state it started in. For example, if the addition
+ * of "b.c" caused the node "a.b.c" to be split, pushing "a" to its own level,
+ * then the subsequent deletion of "b.c" will not cause "a" to be pulled up,
+ * restoring "a.b.c". The RBT *used* to do this kind of rejoining, but it
+ * turned out to be a bad idea because it could corrupt an active nodechain
+ * that had "b.c" as one of its levels -- and the RBT has no idea what
+ * nodechains are in use by callers, so it can't even *try* to helpfully
+ * fix them up (which would probably be doomed to failure anyway).
+ *
+ * Similarly, it is possible to leave the tree in a state where a supposedly
+ * deleted node still exists. The first case of this is obvious; take
+ * the tree which has "b.c" on one level, pointing to "a". Now deleted "b.c".
+ * It was just established in the previous paragraph why we can't pull "a"
+ * back up to its parent level. But what happens when "a" then gets deleted?
+ * "b.c" is left hanging around without data or children. This condition
+ * is actually pretty easy to detect, but ... should it really be removed?
+ * Is a chain pointing to it? An iterator? Who knows! (Note that the
+ * references structure member cannot be looked at because it is private to
+ * rbtdb.) This is ugly and makes me unhappy, but after hours of trying to
+ * make it more aesthetically proper and getting nowhere, this is the way it
+ * is going to stay until such time as it proves to be a *real* problem.
+ *
+ * Finally, for reference, note that the original routine that did node
+ * joining was called join_nodes(). It has been excised, living now only
+ * in the CVS history, but comments have been left behind that point to it just
+ * in case someone wants to muck with this some more.
+ *
+ * The one positive aspect of all of this is that joining used to have a
+ * case where it might fail. Without trying to join, now this function always
+ * succeeds. It still returns isc_result_t, though, so the API wouldn't change.
+ */
+isc_result_t
+dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse)
+{
+ dns_rbtnode_t *parent;
+
+ REQUIRE(VALID_RBT(rbt));
+ REQUIRE(DNS_RBTNODE_VALID(node));
+
+ if (DOWN(node) != NULL) {
+ if (recurse)
+ RUNTIME_CHECK(dns_rbt_deletetree(rbt, DOWN(node))
+ == ISC_R_SUCCESS);
+ else {
+ if (DATA(node) != NULL && rbt->data_deleter != NULL)
+ rbt->data_deleter(DATA(node),
+ rbt->deleter_arg);
+ DATA(node) = NULL;
+
+ /*
+ * Since there is at least one node below this one and
+ * no recursion was requested, the deletion is
+ * complete. The down node from this node might be all
+ * by itself on a single level, so join_nodes() could
+ * be used to collapse the tree (with all the caveats
+ * of the comment at the start of this function).
+ */
+ return (ISC_R_SUCCESS);
+ }
+ }
+
+ /*
+ * Note the node that points to the level of the node that is being
+ * deleted. If the deleted node is the top level, parent will be set
+ * to NULL.
+ */
+ parent = find_up(node);
+
+ /*
+ * This node now has no down pointer (either because it didn't
+ * have one to start, or because it was recursively removed).
+ * So now the node needs to be removed from this level.
+ */
+ dns_rbt_deletefromlevel(node, parent == NULL ? &rbt->root :
+ &DOWN(parent));
+
+ if (DATA(node) != NULL && rbt->data_deleter != NULL)
+ rbt->data_deleter(DATA(node), rbt->deleter_arg);
+
+ unhash_node(rbt, node);
+#if DNS_RBT_USEMAGIC
+ node->magic = 0;
+#endif
+ dns_rbtnode_refdestroy(node);
+ isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
+ rbt->nodecount--;
+
+ /*
+ * There are now two special cases that can exist that would
+ * not have existed if the tree had been created using only
+ * the names that now exist in it. (This is all related to
+ * join_nodes() as described in this function's introductory comment.)
+ * Both cases exist when the deleted node's parent (the node
+ * that pointed to the deleted node's level) is not null but
+ * it has no data: parent != NULL && DATA(parent) == NULL.
+ *
+ * The first case is that the deleted node was the last on its level:
+ * DOWN(parent) == NULL. This case can only exist if the parent was
+ * previously deleted -- and so now, apparently, the parent should go
+ * away. That can't be done though because there might be external
+ * references to it, such as through a nodechain.
+ *
+ * The other case also involves a parent with no data, but with the
+ * deleted node being the next-to-last node instead of the last:
+ * LEFT(DOWN(parent)) == NULL && RIGHT(DOWN(parent)) == NULL.
+ * Presumably now the remaining node on the level should be joined
+ * with the parent, but it's already been described why that can't be
+ * done.
+ */
+
+ /*
+ * This function never fails.
+ */
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name) {
+
+ REQUIRE(DNS_RBTNODE_VALID(node));
+ REQUIRE(name != NULL);
+ REQUIRE(name->offsets == NULL);
+
+ NODENAME(node, name);
+}
+
+isc_result_t
+dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name) {
+ dns_name_t current;
+ isc_result_t result;
+
+ REQUIRE(DNS_RBTNODE_VALID(node));
+ REQUIRE(name != NULL);
+ REQUIRE(name->buffer != NULL);
+
+ dns_name_init(&current, NULL);
+ dns_name_reset(name);
+
+ do {
+ INSIST(node != NULL);
+
+ NODENAME(node, &current);
+
+ result = dns_name_concatenate(name, &current, name, NULL);
+ if (result != ISC_R_SUCCESS)
+ break;
+
+ node = find_up(node);
+ } while (! dns_name_isabsolute(name));
+
+ return (result);
+}
+
+char *
+dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, unsigned int size)
+{
+ dns_fixedname_t fixedname;
+ dns_name_t *name;
+ isc_result_t result;
+
+ REQUIRE(DNS_RBTNODE_VALID(node));
+ REQUIRE(printname != NULL);
+
+ dns_fixedname_init(&fixedname);
+ name = dns_fixedname_name(&fixedname);
+ result = dns_rbt_fullnamefromnode(node, name);
+ if (result == ISC_R_SUCCESS)
+ dns_name_format(name, printname, size);
+ else
+ snprintf(printname, size, "<error building name: %s>",
+ dns_result_totext(result));
+
+ return (printname);
+}
+
+static isc_result_t
+create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) {
+ dns_rbtnode_t *node;
+ isc_region_t region;
+ unsigned int labels;
+
+ REQUIRE(name->offsets != NULL);
+
+ dns_name_toregion(name, &region);
+ labels = dns_name_countlabels(name);
+ ENSURE(labels > 0);
+
+ /*
+ * Allocate space for the node structure, the name, and the offsets.
+ */
+ node = (dns_rbtnode_t *)isc_mem_get(mctx, sizeof(*node) +
+ region.length + labels);
+
+ if (node == NULL)
+ return (ISC_R_NOMEMORY);
+
+ node->is_root = 0;
+ PARENT(node) = NULL;
+ RIGHT(node) = NULL;
+ LEFT(node) = NULL;
+ DOWN(node) = NULL;
+ DATA(node) = NULL;
+#ifdef DNS_RBT_USEHASH
+ HASHNEXT(node) = NULL;
+ HASHVAL(node) = 0;
+#endif
+
+ LOCKNUM(node) = 0;
+ WILD(node) = 0;
+ DIRTY(node) = 0;
+ dns_rbtnode_refinit(node, 0);
+ node->find_callback = 0;
+
+ MAKE_BLACK(node);
+
+ /*
+ * The following is stored to make reconstructing a name from the
+ * stored value in the node easy: the length of the name, the number
+ * of labels, whether the name is absolute or not, the name itself,
+ * and the name's offsets table.
+ *
+ * XXX RTH
+ * The offsets table could be made smaller by eliminating the
+ * first offset, which is always 0. This requires changes to
+ * lib/dns/name.c.
+ */
+ NAMELEN(node) = region.length;
+ PADBYTES(node) = 0;
+ OFFSETLEN(node) = labels;
+ ATTRS(node) = name->attributes;
+
+ memcpy(NAME(node), region.base, region.length);
+ memcpy(OFFSETS(node), name->offsets, labels);
+
+#if DNS_RBT_USEMAGIC
+ node->magic = DNS_RBTNODE_MAGIC;
+#endif
+ *nodep = node;
+
+ return (ISC_R_SUCCESS);
+}
+
+#ifdef DNS_RBT_USEHASH
+static inline void
+hash_add_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
+ unsigned int hash;
+
+ HASHVAL(node) = dns_name_fullhash(name, ISC_FALSE);
+
+ hash = HASHVAL(node) % rbt->hashsize;
+ HASHNEXT(node) = rbt->hashtable[hash];
+
+ rbt->hashtable[hash] = node;
+}
+
+static isc_result_t
+inithash(dns_rbt_t *rbt) {
+ unsigned int bytes;
+
+ rbt->hashsize = RBT_HASH_SIZE;
+ bytes = rbt->hashsize * sizeof(dns_rbtnode_t *);
+ rbt->hashtable = isc_mem_get(rbt->mctx, bytes);
+
+ if (rbt->hashtable == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(rbt->hashtable, 0, bytes);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+rehash(dns_rbt_t *rbt) {
+ unsigned int oldsize;
+ dns_rbtnode_t **oldtable;
+ dns_rbtnode_t *node;
+ unsigned int hash;
+ unsigned int i;
+
+ oldsize = rbt->hashsize;
+ oldtable = rbt->hashtable;
+ rbt->hashsize *= 2 + 1;
+ rbt->hashtable = isc_mem_get(rbt->mctx,
+ rbt->hashsize * sizeof(dns_rbtnode_t *));
+ if (rbt->hashtable == NULL) {
+ rbt->hashtable = oldtable;
+ rbt->hashsize = oldsize;
+ return;
+ }
+
+ for (i = 0; i < rbt->hashsize; i++)
+ rbt->hashtable[i] = NULL;
+
+ for (i = 0; i < oldsize; i++) {
+ node = oldtable[i];
+ while (node != NULL) {
+ hash = HASHVAL(node) % rbt->hashsize;
+ oldtable[i] = HASHNEXT(node);
+ HASHNEXT(node) = rbt->hashtable[hash];
+ rbt->hashtable[hash] = node;
+ node = oldtable[i];
+ }
+ }
+
+ isc_mem_put(rbt->mctx, oldtable, oldsize * sizeof(dns_rbtnode_t *));
+}
+
+static inline void
+hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
+
+ REQUIRE(DNS_RBTNODE_VALID(node));
+
+ if (rbt->nodecount >= (rbt->hashsize *3))
+ rehash(rbt);
+
+ hash_add_node(rbt, node, name);
+}
+
+static inline void
+unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) {
+ unsigned int bucket;
+ dns_rbtnode_t *bucket_node;
+
+ REQUIRE(DNS_RBTNODE_VALID(node));
+
+ if (rbt->hashtable != NULL) {
+ bucket = HASHVAL(node) % rbt->hashsize;
+ bucket_node = rbt->hashtable[bucket];
+
+ if (bucket_node == node)
+ rbt->hashtable[bucket] = HASHNEXT(node);
+ else {
+ while (HASHNEXT(bucket_node) != node) {
+ INSIST(HASHNEXT(bucket_node) != NULL);
+ bucket_node = HASHNEXT(bucket_node);
+ }
+ HASHNEXT(bucket_node) = HASHNEXT(node);
+ }
+ }
+}
+#endif /* DNS_RBT_USEHASH */
+
+static inline void
+rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
+ dns_rbtnode_t *child;
+
+ REQUIRE(DNS_RBTNODE_VALID(node));
+ REQUIRE(rootp != NULL);
+
+ child = RIGHT(node);
+ INSIST(child != NULL);
+
+ RIGHT(node) = LEFT(child);
+ if (LEFT(child) != NULL)
+ PARENT(LEFT(child)) = node;
+ LEFT(child) = node;
+
+ if (child != NULL)
+ PARENT(child) = PARENT(node);
+
+ if (IS_ROOT(node)) {
+ *rootp = child;
+ child->is_root = 1;
+ node->is_root = 0;
+
+ } else {
+ if (LEFT(PARENT(node)) == node)
+ LEFT(PARENT(node)) = child;
+ else
+ RIGHT(PARENT(node)) = child;
+ }
+
+ PARENT(node) = child;
+}
+
+static inline void
+rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
+ dns_rbtnode_t *child;
+
+ REQUIRE(DNS_RBTNODE_VALID(node));
+ REQUIRE(rootp != NULL);
+
+ child = LEFT(node);
+ INSIST(child != NULL);
+
+ LEFT(node) = RIGHT(child);
+ if (RIGHT(child) != NULL)
+ PARENT(RIGHT(child)) = node;
+ RIGHT(child) = node;
+
+ if (child != NULL)
+ PARENT(child) = PARENT(node);
+
+ if (IS_ROOT(node)) {
+ *rootp = child;
+ child->is_root = 1;
+ node->is_root = 0;
+
+ } else {
+ if (LEFT(PARENT(node)) == node)
+ LEFT(PARENT(node)) = child;
+ else
+ RIGHT(PARENT(node)) = child;
+ }
+
+ PARENT(node) = child;
+}
+
+/*
+ * This is the real workhorse of the insertion code, because it does the
+ * true red/black tree on a single level.
+ */
+static void
+dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
+ dns_rbtnode_t **rootp)
+{
+ dns_rbtnode_t *child, *root, *parent, *grandparent;
+ dns_name_t add_name, current_name;
+ dns_offsets_t add_offsets, current_offsets;
+
+ REQUIRE(rootp != NULL);
+ REQUIRE(DNS_RBTNODE_VALID(node) && LEFT(node) == NULL &&
+ RIGHT(node) == NULL);
+ REQUIRE(current != NULL);
+
+ root = *rootp;
+ if (root == NULL) {
+ /*
+ * First node of a level.
+ */
+ MAKE_BLACK(node);
+ node->is_root = 1;
+ PARENT(node) = current;
+ *rootp = node;
+ return;
+ }
+
+ child = root;
+
+ dns_name_init(&add_name, add_offsets);
+ NODENAME(node, &add_name);
+
+ dns_name_init(&current_name, current_offsets);
+ NODENAME(current, &current_name);
+
+ if (order < 0) {
+ INSIST(LEFT(current) == NULL);
+ LEFT(current) = node;
+ } else {
+ INSIST(RIGHT(current) == NULL);
+ RIGHT(current) = node;
+ }
+
+ INSIST(PARENT(node) == NULL);
+ PARENT(node) = current;
+
+ MAKE_RED(node);
+
+ while (node != root && IS_RED(PARENT(node))) {
+ /*
+ * XXXDCL could do away with separate parent and grandparent
+ * variables. They are vestiges of the days before parent
+ * pointers. However, they make the code a little clearer.
+ */
+
+ parent = PARENT(node);
+ grandparent = PARENT(parent);
+
+ if (parent == LEFT(grandparent)) {
+ child = RIGHT(grandparent);
+ if (child != NULL && IS_RED(child)) {
+ MAKE_BLACK(parent);
+ MAKE_BLACK(child);
+ MAKE_RED(grandparent);
+ node = grandparent;
+ } else {
+ if (node == RIGHT(parent)) {
+ rotate_left(parent, &root);
+ node = parent;
+ parent = PARENT(node);
+ grandparent = PARENT(parent);
+ }
+ MAKE_BLACK(parent);
+ MAKE_RED(grandparent);
+ rotate_right(grandparent, &root);
+ }
+ } else {
+ child = LEFT(grandparent);
+ if (child != NULL && IS_RED(child)) {
+ MAKE_BLACK(parent);
+ MAKE_BLACK(child);
+ MAKE_RED(grandparent);
+ node = grandparent;
+ } else {
+ if (node == LEFT(parent)) {
+ rotate_right(parent, &root);
+ node = parent;
+ parent = PARENT(node);
+ grandparent = PARENT(parent);
+ }
+ MAKE_BLACK(parent);
+ MAKE_RED(grandparent);
+ rotate_left(grandparent, &root);
+ }
+ }
+ }
+
+ MAKE_BLACK(root);
+ ENSURE(IS_ROOT(root));
+ *rootp = root;
+
+ return;
+}
+
+/*
+ * This is the real workhorse of the deletion code, because it does the
+ * true red/black tree on a single level.
+ */
+static void
+dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) {
+ dns_rbtnode_t *child, *sibling, *parent;
+ dns_rbtnode_t *successor;
+
+ REQUIRE(delete != NULL);
+
+ /*
+ * Verify that the parent history is (apparently) correct.
+ */
+ INSIST((IS_ROOT(delete) && *rootp == delete) ||
+ (! IS_ROOT(delete) &&
+ (LEFT(PARENT(delete)) == delete ||
+ RIGHT(PARENT(delete)) == delete)));
+
+ child = NULL;
+
+ if (LEFT(delete) == NULL) {
+ if (RIGHT(delete) == NULL) {
+ if (IS_ROOT(delete)) {
+ /*
+ * This is the only item in the tree.
+ */
+ *rootp = NULL;
+ return;
+ }
+ } else
+ /*
+ * This node has one child, on the right.
+ */
+ child = RIGHT(delete);
+
+ } else if (RIGHT(delete) == NULL)
+ /*
+ * This node has one child, on the left.
+ */
+ child = LEFT(delete);
+ else {
+ dns_rbtnode_t holder, *tmp = &holder;
+
+ /*
+ * This node has two children, so it cannot be directly
+ * deleted. Find its immediate in-order successor and
+ * move it to this location, then do the deletion at the
+ * old site of the successor.
+ */
+ successor = RIGHT(delete);
+ while (LEFT(successor) != NULL)
+ successor = LEFT(successor);
+
+ /*
+ * The successor cannot possibly have a left child;
+ * if there is any child, it is on the right.
+ */
+ if (RIGHT(successor) != NULL)
+ child = RIGHT(successor);
+
+ /*
+ * Swap the two nodes; it would be simpler to just replace
+ * the value being deleted with that of the successor,
+ * but this rigamarole is done so the caller has complete
+ * control over the pointers (and memory allocation) of
+ * all of nodes. If just the key value were removed from
+ * the tree, the pointer to the node would be unchanged.
+ */
+
+ /*
+ * First, put the successor in the tree location of the
+ * node to be deleted. Save its existing tree pointer
+ * information, which will be needed when linking up
+ * delete to the successor's old location.
+ */
+ memcpy(tmp, successor, sizeof(dns_rbtnode_t));
+
+ if (IS_ROOT(delete)) {
+ *rootp = successor;
+ successor->is_root = ISC_TRUE;
+ delete->is_root = ISC_FALSE;
+
+ } else
+ if (LEFT(PARENT(delete)) == delete)
+ LEFT(PARENT(delete)) = successor;
+ else
+ RIGHT(PARENT(delete)) = successor;
+
+ PARENT(successor) = PARENT(delete);
+ LEFT(successor) = LEFT(delete);
+ RIGHT(successor) = RIGHT(delete);
+ COLOR(successor) = COLOR(delete);
+
+ if (LEFT(successor) != NULL)
+ PARENT(LEFT(successor)) = successor;
+ if (RIGHT(successor) != successor)
+ PARENT(RIGHT(successor)) = successor;
+
+ /*
+ * Now relink the node to be deleted into the
+ * successor's previous tree location. PARENT(tmp)
+ * is the successor's original parent.
+ */
+ INSIST(! IS_ROOT(delete));
+
+ if (PARENT(tmp) == delete) {
+ /*
+ * Node being deleted was successor's parent.
+ */
+ RIGHT(successor) = delete;
+ PARENT(delete) = successor;
+
+ } else {
+ LEFT(PARENT(tmp)) = delete;
+ PARENT(delete) = PARENT(tmp);
+ }
+
+ /*
+ * Original location of successor node has no left.
+ */
+ LEFT(delete) = NULL;
+ RIGHT(delete) = RIGHT(tmp);
+ COLOR(delete) = COLOR(tmp);
+ }
+
+ /*
+ * Remove the node by removing the links from its parent.
+ */
+ if (! IS_ROOT(delete)) {
+ if (LEFT(PARENT(delete)) == delete)
+ LEFT(PARENT(delete)) = child;
+ else
+ RIGHT(PARENT(delete)) = child;
+
+ if (child != NULL)
+ PARENT(child) = PARENT(delete);
+
+ } else {
+ /*
+ * This is the root being deleted, and at this point
+ * it is known to have just one child.
+ */
+ *rootp = child;
+ child->is_root = 1;
+ PARENT(child) = PARENT(delete);
+ }
+
+ /*
+ * Fix color violations.
+ */
+ if (IS_BLACK(delete)) {
+ parent = PARENT(delete);
+
+ while (child != *rootp && IS_BLACK(child)) {
+ INSIST(child == NULL || ! IS_ROOT(child));
+
+ if (LEFT(parent) == child) {
+ sibling = RIGHT(parent);
+
+ if (IS_RED(sibling)) {
+ MAKE_BLACK(sibling);
+ MAKE_RED(parent);
+ rotate_left(parent, rootp);
+ sibling = RIGHT(parent);
+ }
+
+ if (IS_BLACK(LEFT(sibling)) &&
+ IS_BLACK(RIGHT(sibling))) {
+ MAKE_RED(sibling);
+ child = parent;
+
+ } else {
+
+ if (IS_BLACK(RIGHT(sibling))) {
+ MAKE_BLACK(LEFT(sibling));
+ MAKE_RED(sibling);
+ rotate_right(sibling, rootp);
+ sibling = RIGHT(parent);
+ }
+
+ COLOR(sibling) = COLOR(parent);
+ MAKE_BLACK(parent);
+ MAKE_BLACK(RIGHT(sibling));
+ rotate_left(parent, rootp);
+ child = *rootp;
+ }
+
+ } else {
+ /*
+ * Child is parent's right child.
+ * Everything is doen the same as above,
+ * except mirrored.
+ */
+ sibling = LEFT(parent);
+
+ if (IS_RED(sibling)) {
+ MAKE_BLACK(sibling);
+ MAKE_RED(parent);
+ rotate_right(parent, rootp);
+ sibling = LEFT(parent);
+ }
+
+ if (IS_BLACK(LEFT(sibling)) &&
+ IS_BLACK(RIGHT(sibling))) {
+ MAKE_RED(sibling);
+ child = parent;
+
+ } else {
+ if (IS_BLACK(LEFT(sibling))) {
+ MAKE_BLACK(RIGHT(sibling));
+ MAKE_RED(sibling);
+ rotate_left(sibling, rootp);
+ sibling = LEFT(parent);
+ }
+
+ COLOR(sibling) = COLOR(parent);
+ MAKE_BLACK(parent);
+ MAKE_BLACK(LEFT(sibling));
+ rotate_right(parent, rootp);
+ child = *rootp;
+ }
+ }
+
+ parent = PARENT(child);
+ }
+
+ if (IS_RED(child))
+ MAKE_BLACK(child);
+ }
+}
+
+/*
+ * This should only be used on the root of a tree, because no color fixup
+ * is done at all.
+ *
+ * NOTE: No root pointer maintenance is done, because the function is only
+ * used for two cases:
+ * + deleting everything DOWN from a node that is itself being deleted, and
+ * + deleting the entire tree of trees from dns_rbt_destroy.
+ * In each case, the root pointer is no longer relevant, so there
+ * is no need for a root parameter to this function.
+ *
+ * If the function is ever intended to be used to delete something where
+ * a pointer needs to be told that this tree no longer exists,
+ * this function would need to adjusted accordingly.
+ */
+static isc_result_t
+dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node) {
+ isc_result_t result = ISC_R_SUCCESS;
+ REQUIRE(VALID_RBT(rbt));
+
+ if (node == NULL)
+ return (result);
+
+ if (LEFT(node) != NULL) {
+ result = dns_rbt_deletetree(rbt, LEFT(node));
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ LEFT(node) = NULL;
+ }
+ if (RIGHT(node) != NULL) {
+ result = dns_rbt_deletetree(rbt, RIGHT(node));
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ RIGHT(node) = NULL;
+ }
+ if (DOWN(node) != NULL) {
+ result = dns_rbt_deletetree(rbt, DOWN(node));
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ DOWN(node) = NULL;
+ }
+ done:
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (DATA(node) != NULL && rbt->data_deleter != NULL)
+ rbt->data_deleter(DATA(node), rbt->deleter_arg);
+
+ unhash_node(rbt, node);
+#if DNS_RBT_USEMAGIC
+ node->magic = 0;
+#endif
+ isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
+ rbt->nodecount--;
+ return (result);
+}
+
+static void
+dns_rbt_deletetreeflat(dns_rbt_t *rbt, unsigned int quantum,
+ dns_rbtnode_t **nodep)
+{
+ dns_rbtnode_t *parent;
+ dns_rbtnode_t *node = *nodep;
+ REQUIRE(VALID_RBT(rbt));
+
+ again:
+ if (node == NULL) {
+ *nodep = NULL;
+ return;
+ }
+
+ traverse:
+ if (LEFT(node) != NULL) {
+ node = LEFT(node);
+ goto traverse;
+ }
+ if (RIGHT(node) != NULL) {
+ node = RIGHT(node);
+ goto traverse;
+ }
+ if (DOWN(node) != NULL) {
+ node = DOWN(node);
+ goto traverse;
+ }
+
+ if (DATA(node) != NULL && rbt->data_deleter != NULL)
+ rbt->data_deleter(DATA(node), rbt->deleter_arg);
+
+ /*
+ * Note: we don't call unhash_node() here as we are destroying
+ * the complete rbt tree.
+ */
+#if DNS_RBT_USEMAGIC
+ node->magic = 0;
+#endif
+ parent = PARENT(node);
+ if (parent != NULL) {
+ if (LEFT(parent) == node)
+ LEFT(parent) = NULL;
+ else if (DOWN(parent) == node)
+ DOWN(parent) = NULL;
+ else if (RIGHT(parent) == node)
+ RIGHT(parent) = NULL;
+ }
+ isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
+ rbt->nodecount--;
+ node = parent;
+ if (quantum != 0 && --quantum == 0) {
+ *nodep = node;
+ return;
+ }
+ goto again;
+}
+
+static void
+dns_rbt_indent(int depth) {
+ int i;
+
+ for (i = 0; i < depth; i++)
+ putchar('\t');
+}
+
+static void
+dns_rbt_printnodename(dns_rbtnode_t *node) {
+ isc_region_t r;
+ dns_name_t name;
+ char buffer[DNS_NAME_FORMATSIZE];
+ dns_offsets_t offsets;
+
+ r.length = NAMELEN(node);
+ r.base = NAME(node);
+
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &r);
+
+ dns_name_format(&name, buffer, sizeof(buffer));
+
+ printf("%s", buffer);
+}
+
+static void
+dns_rbt_printtree(dns_rbtnode_t *root, dns_rbtnode_t *parent, int depth) {
+ dns_rbt_indent(depth);
+
+ if (root != NULL) {
+ dns_rbt_printnodename(root);
+ printf(" (%s", IS_RED(root) ? "RED" : "black");
+ if (parent) {
+ printf(" from ");
+ dns_rbt_printnodename(parent);
+ }
+
+ if ((! IS_ROOT(root) && PARENT(root) != parent) ||
+ ( IS_ROOT(root) && depth > 0 &&
+ DOWN(PARENT(root)) != root)) {
+
+ printf(" (BAD parent pointer! -> ");
+ if (PARENT(root) != NULL)
+ dns_rbt_printnodename(PARENT(root));
+ else
+ printf("NULL");
+ printf(")");
+ }
+
+ printf(")\n");
+
+
+ depth++;
+
+ if (DOWN(root)) {
+ dns_rbt_indent(depth);
+ printf("++ BEG down from ");
+ dns_rbt_printnodename(root);
+ printf("\n");
+ dns_rbt_printtree(DOWN(root), NULL, depth);
+ dns_rbt_indent(depth);
+ printf("-- END down from ");
+ dns_rbt_printnodename(root);
+ printf("\n");
+ }
+
+ if (IS_RED(root) && IS_RED(LEFT(root)))
+ printf("** Red/Red color violation on left\n");
+ dns_rbt_printtree(LEFT(root), root, depth);
+
+ if (IS_RED(root) && IS_RED(RIGHT(root)))
+ printf("** Red/Red color violation on right\n");
+ dns_rbt_printtree(RIGHT(root), root, depth);
+
+ } else
+ printf("NULL\n");
+}
+
+void
+dns_rbt_printall(dns_rbt_t *rbt) {
+ REQUIRE(VALID_RBT(rbt));
+
+ dns_rbt_printtree(rbt->root, NULL, 0);
+}
+
+/*
+ * Chain Functions
+ */
+
+void
+dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx) {
+ /*
+ * Initialize 'chain'.
+ */
+
+ REQUIRE(chain != NULL);
+
+ chain->mctx = mctx;
+ chain->end = NULL;
+ chain->level_count = 0;
+ chain->level_matches = 0;
+
+ chain->magic = CHAIN_MAGIC;
+}
+
+isc_result_t
+dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
+ dns_name_t *origin, dns_rbtnode_t **node)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_CHAIN(chain));
+
+ if (node != NULL)
+ *node = chain->end;
+
+ if (chain->end == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (name != NULL) {
+ NODENAME(chain->end, name);
+
+ if (chain->level_count == 0) {
+ /*
+ * Names in the top level tree are all absolute.
+ * Always make 'name' relative.
+ */
+ INSIST(dns_name_isabsolute(name));
+
+ /*
+ * This is cheaper than dns_name_getlabelsequence().
+ */
+ name->labels--;
+ name->length--;
+ name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
+ }
+ }
+
+ if (origin != NULL) {
+ if (chain->level_count > 0)
+ result = chain_name(chain, origin, ISC_FALSE);
+ else
+ result = dns_name_copy(dns_rootname, origin, NULL);
+ }
+
+ return (result);
+}
+
+isc_result_t
+dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
+ dns_name_t *origin)
+{
+ dns_rbtnode_t *current, *previous, *predecessor;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_boolean_t new_origin = ISC_FALSE;
+
+ REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
+
+ predecessor = NULL;
+
+ current = chain->end;
+
+ if (LEFT(current) != NULL) {
+ /*
+ * Moving left one then right as far as possible is the
+ * previous node, at least for this level.
+ */
+ current = LEFT(current);
+
+ while (RIGHT(current) != NULL)
+ current = RIGHT(current);
+
+ predecessor = current;
+
+ } else {
+ /*
+ * No left links, so move toward the root. If at any point on
+ * the way there the link from parent to child is a right
+ * link, then the parent is the previous node, at least
+ * for this level.
+ */
+ while (! IS_ROOT(current)) {
+ previous = current;
+ current = PARENT(current);
+
+ if (RIGHT(current) == previous) {
+ predecessor = current;
+ break;
+ }
+ }
+ }
+
+ if (predecessor != NULL) {
+ /*
+ * Found a predecessor node in this level. It might not
+ * really be the predecessor, however.
+ */
+ if (DOWN(predecessor) != NULL) {
+ /*
+ * The predecessor is really down at least one level.
+ * Go down and as far right as possible, and repeat
+ * as long as the rightmost node has a down pointer.
+ */
+ do {
+ /*
+ * XXX DCL Need to do something about origins
+ * here. See whether to go down, and if so
+ * whether it is truly what Bob calls a
+ * new origin.
+ */
+ ADD_LEVEL(chain, predecessor);
+ predecessor = DOWN(predecessor);
+
+ /* XXX DCL duplicated from above; clever
+ * way to unduplicate? */
+
+ while (RIGHT(predecessor) != NULL)
+ predecessor = RIGHT(predecessor);
+ } while (DOWN(predecessor) != NULL);
+
+ /* XXX DCL probably needs work on the concept */
+ if (origin != NULL)
+ new_origin = ISC_TRUE;
+ }
+
+ } else if (chain->level_count > 0) {
+ /*
+ * Dang, didn't find a predecessor in this level.
+ * Got to the root of this level without having traversed
+ * any right links. Ascend the tree one level; the
+ * node that points to this tree is the predecessor.
+ */
+ INSIST(chain->level_count > 0 && IS_ROOT(current));
+ predecessor = chain->levels[--chain->level_count];
+
+ /* XXX DCL probably needs work on the concept */
+ /*
+ * Don't declare an origin change when the new origin is "."
+ * at the top level tree, because "." is declared as the origin
+ * for the second level tree.
+ */
+ if (origin != NULL &&
+ (chain->level_count > 0 || OFFSETLEN(predecessor) > 1))
+ new_origin = ISC_TRUE;
+ }
+
+ if (predecessor != NULL) {
+ chain->end = predecessor;
+
+ if (new_origin) {
+ result = dns_rbtnodechain_current(chain, name, origin,
+ NULL);
+ if (result == ISC_R_SUCCESS)
+ result = DNS_R_NEWORIGIN;
+
+ } else
+ result = dns_rbtnodechain_current(chain, name, NULL,
+ NULL);
+
+ } else
+ result = ISC_R_NOMORE;
+
+ return (result);
+}
+
+isc_result_t
+dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
+ dns_name_t *origin)
+{
+ dns_rbtnode_t *current, *previous, *successor;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_boolean_t new_origin = ISC_FALSE;
+
+ REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
+
+ successor = NULL;
+
+ current = chain->end;
+
+ /*
+ * If there is a level below this node, the next node is the leftmost
+ * node of the next level.
+ */
+ if (DOWN(current) != NULL) {
+ /*
+ * Don't declare an origin change when the new origin is "."
+ * at the second level tree, because "." is already declared
+ * as the origin for the top level tree.
+ */
+ if (chain->level_count > 0 ||
+ OFFSETLEN(current) > 1)
+ new_origin = ISC_TRUE;
+
+ ADD_LEVEL(chain, current);
+ current = DOWN(current);
+
+ while (LEFT(current) != NULL)
+ current = LEFT(current);
+
+ successor = current;
+
+ } else if (RIGHT(current) == NULL) {
+ /*
+ * The successor is up, either in this level or a previous one.
+ * Head back toward the root of the tree, looking for any path
+ * that was via a left link; the successor is the node that has
+ * that left link. In the event the root of the level is
+ * reached without having traversed any left links, ascend one
+ * level and look for either a right link off the point of
+ * ascent, or search for a left link upward again, repeating
+ * ascents until either case is true.
+ */
+ do {
+ while (! IS_ROOT(current)) {
+ previous = current;
+ current = PARENT(current);
+
+ if (LEFT(current) == previous) {
+ successor = current;
+ break;
+ }
+ }
+
+ if (successor == NULL) {
+ /*
+ * Reached the root without having traversed
+ * any left pointers, so this level is done.
+ */
+ if (chain->level_count == 0)
+ break;
+
+ current = chain->levels[--chain->level_count];
+ new_origin = ISC_TRUE;
+
+ if (RIGHT(current) != NULL)
+ break;
+ }
+ } while (successor == NULL);
+ }
+
+ if (successor == NULL && RIGHT(current) != NULL) {
+ current = RIGHT(current);
+
+ while (LEFT(current) != NULL)
+ current = LEFT(current);
+
+ successor = current;
+ }
+
+ if (successor != NULL) {
+ chain->end = successor;
+
+ /*
+ * It is not necessary to use dns_rbtnodechain_current like
+ * the other functions because this function will never
+ * find a node in the topmost level. This is because the
+ * root level will never be more than one name, and everything
+ * in the megatree is a successor to that node, down at
+ * the second level or below.
+ */
+
+ if (name != NULL)
+ NODENAME(chain->end, name);
+
+ if (new_origin) {
+ if (origin != NULL)
+ result = chain_name(chain, origin, ISC_FALSE);
+
+ if (result == ISC_R_SUCCESS)
+ result = DNS_R_NEWORIGIN;
+
+ } else
+ result = ISC_R_SUCCESS;
+
+ } else
+ result = ISC_R_NOMORE;
+
+ return (result);
+}
+
+isc_result_t
+dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
+ dns_name_t *name, dns_name_t *origin)
+
+{
+ isc_result_t result;
+
+ REQUIRE(VALID_RBT(rbt));
+ REQUIRE(VALID_CHAIN(chain));
+
+ dns_rbtnodechain_reset(chain);
+
+ chain->end = rbt->root;
+
+ result = dns_rbtnodechain_current(chain, name, origin, NULL);
+
+ if (result == ISC_R_SUCCESS)
+ result = DNS_R_NEWORIGIN;
+
+ return (result);
+}
+
+isc_result_t
+dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
+ dns_name_t *name, dns_name_t *origin)
+
+{
+ isc_result_t result;
+
+ REQUIRE(VALID_RBT(rbt));
+ REQUIRE(VALID_CHAIN(chain));
+
+ dns_rbtnodechain_reset(chain);
+
+ result = move_chain_to_last(chain, rbt->root);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_rbtnodechain_current(chain, name, origin, NULL);
+
+ if (result == ISC_R_SUCCESS)
+ result = DNS_R_NEWORIGIN;
+
+ return (result);
+}
+
+
+void
+dns_rbtnodechain_reset(dns_rbtnodechain_t *chain) {
+ /*
+ * Free any dynamic storage associated with 'chain', and then
+ * reinitialize 'chain'.
+ */
+
+ REQUIRE(VALID_CHAIN(chain));
+
+ chain->end = NULL;
+ chain->level_count = 0;
+ chain->level_matches = 0;
+}
+
+void
+dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain) {
+ /*
+ * Free any dynamic storage associated with 'chain', and then
+ * invalidate 'chain'.
+ */
+
+ dns_rbtnodechain_reset(chain);
+
+ chain->magic = 0;
+}
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
new file mode 100644
index 0000000..1d729d0
--- /dev/null
+++ b/lib/dns/rbtdb.c
@@ -0,0 +1,6760 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: rbtdb.c,v 1.196.18.48 2007/08/28 07:20:04 tbox Exp $ */
+
+/*! \file */
+
+/*
+ * Principal Author: Bob Halley
+ */
+
+#include <config.h>
+
+#include <isc/event.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/mutex.h>
+#include <isc/random.h>
+#include <isc/refcount.h>
+#include <isc/rwlock.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include <dns/acache.h>
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/events.h>
+#include <dns/fixedname.h>
+#include <dns/lib.h>
+#include <dns/log.h>
+#include <dns/masterdump.h>
+#include <dns/rbt.h>
+#include <dns/rdata.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/rdataslab.h>
+#include <dns/result.h>
+#include <dns/view.h>
+#include <dns/zone.h>
+#include <dns/zonekey.h>
+
+#ifdef DNS_RBTDB_VERSION64
+#include "rbtdb64.h"
+#else
+#include "rbtdb.h"
+#endif
+
+#ifdef DNS_RBTDB_VERSION64
+#define RBTDB_MAGIC ISC_MAGIC('R', 'B', 'D', '8')
+#else
+#define RBTDB_MAGIC ISC_MAGIC('R', 'B', 'D', '4')
+#endif
+
+/*%
+ * Note that "impmagic" is not the first four bytes of the struct, so
+ * ISC_MAGIC_VALID cannot be used.
+ */
+#define VALID_RBTDB(rbtdb) ((rbtdb) != NULL && \
+ (rbtdb)->common.impmagic == RBTDB_MAGIC)
+
+#ifdef DNS_RBTDB_VERSION64
+typedef isc_uint64_t rbtdb_serial_t;
+/*%
+ * Make casting easier in symbolic debuggers by using different names
+ * for the 64 bit version.
+ */
+#define dns_rbtdb_t dns_rbtdb64_t
+#define rdatasetheader_t rdatasetheader64_t
+#define rbtdb_version_t rbtdb_version64_t
+#else
+typedef isc_uint32_t rbtdb_serial_t;
+#endif
+
+typedef isc_uint32_t rbtdb_rdatatype_t;
+
+#define RBTDB_RDATATYPE_BASE(type) ((dns_rdatatype_t)((type) & 0xFFFF))
+#define RBTDB_RDATATYPE_EXT(type) ((dns_rdatatype_t)((type) >> 16))
+#define RBTDB_RDATATYPE_VALUE(b, e) (((e) << 16) | (b))
+
+#define RBTDB_RDATATYPE_SIGNSEC \
+ RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec)
+#define RBTDB_RDATATYPE_SIGNS \
+ RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ns)
+#define RBTDB_RDATATYPE_SIGCNAME \
+ RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_cname)
+#define RBTDB_RDATATYPE_SIGDNAME \
+ RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dname)
+#define RBTDB_RDATATYPE_NCACHEANY \
+ RBTDB_RDATATYPE_VALUE(0, dns_rdatatype_any)
+
+/*
+ * We use rwlock for DB lock only when ISC_RWLOCK_USEATOMIC is non 0.
+ * Using rwlock is effective with regard to lookup performance only when
+ * it is implemented in an efficient way.
+ * Otherwise, it is generally wise to stick to the simple locking since rwlock
+ * would require more memory or can even make lookups slower due to its own
+ * overhead (when it internally calls mutex locks).
+ */
+#ifdef ISC_RWLOCK_USEATOMIC
+#define DNS_RBTDB_USERWLOCK 1
+#else
+#define DNS_RBTDB_USERWLOCK 0
+#endif
+
+#if DNS_RBTDB_USERWLOCK
+#define RBTDB_INITLOCK(l) isc_rwlock_init((l), 0, 0)
+#define RBTDB_DESTROYLOCK(l) isc_rwlock_destroy(l)
+#define RBTDB_LOCK(l, t) RWLOCK((l), (t))
+#define RBTDB_UNLOCK(l, t) RWUNLOCK((l), (t))
+#else
+#define RBTDB_INITLOCK(l) isc_mutex_init(l)
+#define RBTDB_DESTROYLOCK(l) DESTROYLOCK(l)
+#define RBTDB_LOCK(l, t) LOCK(l)
+#define RBTDB_UNLOCK(l, t) UNLOCK(l)
+#endif
+
+/*
+ * Since node locking is sensitive to both performance and memory footprint,
+ * we need some trick here. If we have both high-performance rwlock and
+ * high performance and small-memory reference counters, we use rwlock for
+ * node lock and isc_refcount for node references. In this case, we don't have
+ * to protect the access to the counters by locks.
+ * Otherwise, we simply use ordinary mutex lock for node locking, and use
+ * simple integers as reference counters which is protected by the lock.
+ * In most cases, we can simply use wrapper macros such as NODE_LOCK and
+ * NODE_UNLOCK. In some other cases, however, we need to protect reference
+ * counters first and then protect other parts of a node as read-only data.
+ * Special additional macros, NODE_STRONGLOCK(), NODE_WEAKLOCK(), etc, are also
+ * provided for these special cases. When we can use the efficient backend
+ * routines, we should only protect the "other members" by NODE_WEAKLOCK(read).
+ * Otherwise, we should use NODE_STRONGLOCK() to protect the entire critical
+ * section including the access to the reference counter.
+ * Note that we cannot use NODE_LOCK()/NODE_UNLOCK() wherever the protected
+ * section is also protected by NODE_STRONGLOCK().
+ */
+#if defined(ISC_RWLOCK_USEATOMIC) && defined(DNS_RBT_USEISCREFCOUNT)
+typedef isc_rwlock_t nodelock_t;
+
+#define NODE_INITLOCK(l) isc_rwlock_init((l), 0, 0)
+#define NODE_DESTROYLOCK(l) isc_rwlock_destroy(l)
+#define NODE_LOCK(l, t) RWLOCK((l), (t))
+#define NODE_UNLOCK(l, t) RWUNLOCK((l), (t))
+#define NODE_TRYUPGRADE(l) isc_rwlock_tryupgrade(l)
+
+#define NODE_STRONGLOCK(l) ((void)0)
+#define NODE_STRONGUNLOCK(l) ((void)0)
+#define NODE_WEAKLOCK(l, t) NODE_LOCK(l, t)
+#define NODE_WEAKUNLOCK(l, t) NODE_UNLOCK(l, t)
+#define NODE_WEAKDOWNGRADE(l) isc_rwlock_downgrade(l)
+#else
+typedef isc_mutex_t nodelock_t;
+
+#define NODE_INITLOCK(l) isc_mutex_init(l)
+#define NODE_DESTROYLOCK(l) DESTROYLOCK(l)
+#define NODE_LOCK(l, t) LOCK(l)
+#define NODE_UNLOCK(l, t) UNLOCK(l)
+#define NODE_TRYUPGRADE(l) ISC_R_SUCCESS
+
+#define NODE_STRONGLOCK(l) LOCK(l)
+#define NODE_STRONGUNLOCK(l) UNLOCK(l)
+#define NODE_WEAKLOCK(l, t) ((void)0)
+#define NODE_WEAKUNLOCK(l, t) ((void)0)
+#define NODE_WEAKDOWNGRADE(l) ((void)0)
+#endif
+
+#ifndef DNS_RDATASET_FIXED
+#define DNS_RDATASET_FIXED 1
+#endif
+
+/*
+ * Allow clients with a virtual time of upto 5 minutes in the past to see
+ * records that would have otherwise have expired.
+ */
+#define RBTDB_VIRTUAL 300
+
+struct noqname {
+ dns_name_t name;
+ void * nsec;
+ void * nsecsig;
+};
+
+typedef struct acachectl acachectl_t;
+
+typedef struct rdatasetheader {
+ /*%
+ * Locked by the owning node's lock.
+ */
+ rbtdb_serial_t serial;
+ dns_ttl_t ttl;
+ rbtdb_rdatatype_t type;
+ isc_uint16_t attributes;
+ dns_trust_t trust;
+ struct noqname *noqname;
+ /*%<
+ * We don't use the LIST macros, because the LIST structure has
+ * both head and tail pointers, and is doubly linked.
+ */
+
+ struct rdatasetheader *next;
+ /*%<
+ * If this is the top header for an rdataset, 'next' points
+ * to the top header for the next rdataset (i.e., the next type).
+ * Otherwise, it points up to the header whose down pointer points
+ * at this header.
+ */
+
+ struct rdatasetheader *down;
+ /*%<
+ * Points to the header for the next older version of
+ * this rdataset.
+ */
+
+ isc_uint32_t count;
+ /*%<
+ * Monotonously increased every time this rdataset is bound so that
+ * it is used as the base of the starting point in DNS responses
+ * when the "cyclic" rrset-order is required. Since the ordering
+ * should not be so crucial, no lock is set for the counter for
+ * performance reasons.
+ */
+
+ acachectl_t *additional_auth;
+ acachectl_t *additional_glue;
+} rdatasetheader_t;
+
+#define RDATASET_ATTR_NONEXISTENT 0x0001
+#define RDATASET_ATTR_STALE 0x0002
+#define RDATASET_ATTR_IGNORE 0x0004
+#define RDATASET_ATTR_RETAIN 0x0008
+#define RDATASET_ATTR_NXDOMAIN 0x0010
+
+typedef struct acache_cbarg {
+ dns_rdatasetadditional_t type;
+ unsigned int count;
+ dns_db_t *db;
+ dns_dbnode_t *node;
+ rdatasetheader_t *header;
+} acache_cbarg_t;
+
+struct acachectl {
+ dns_acacheentry_t *entry;
+ acache_cbarg_t *cbarg;
+};
+
+/*
+ * XXX
+ * When the cache will pre-expire data (due to memory low or other
+ * situations) before the rdataset's TTL has expired, it MUST
+ * respect the RETAIN bit and not expire the data until its TTL is
+ * expired.
+ */
+
+#undef IGNORE /* WIN32 winbase.h defines this. */
+
+#define EXISTS(header) \
+ (((header)->attributes & RDATASET_ATTR_NONEXISTENT) == 0)
+#define NONEXISTENT(header) \
+ (((header)->attributes & RDATASET_ATTR_NONEXISTENT) != 0)
+#define IGNORE(header) \
+ (((header)->attributes & RDATASET_ATTR_IGNORE) != 0)
+#define RETAIN(header) \
+ (((header)->attributes & RDATASET_ATTR_RETAIN) != 0)
+#define NXDOMAIN(header) \
+ (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
+
+#define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */
+#define DEFAULT_CACHE_NODE_LOCK_COUNT 1009 /*%< Should be prime. */
+
+typedef struct {
+ nodelock_t lock;
+ /* Protected in the refcount routines. */
+ isc_refcount_t references;
+ /* Locked by lock. */
+ isc_boolean_t exiting;
+} rbtdb_nodelock_t;
+
+typedef struct rbtdb_changed {
+ dns_rbtnode_t * node;
+ isc_boolean_t dirty;
+ ISC_LINK(struct rbtdb_changed) link;
+} rbtdb_changed_t;
+
+typedef ISC_LIST(rbtdb_changed_t) rbtdb_changedlist_t;
+
+typedef struct rbtdb_version {
+ /* Not locked */
+ rbtdb_serial_t serial;
+ /*
+ * Protected in the refcount routines.
+ * XXXJT: should we change the lock policy based on the refcount
+ * performance?
+ */
+ isc_refcount_t references;
+ /* Locked by database lock. */
+ isc_boolean_t writer;
+ isc_boolean_t commit_ok;
+ rbtdb_changedlist_t changed_list;
+ ISC_LINK(struct rbtdb_version) link;
+} rbtdb_version_t;
+
+typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t;
+
+typedef struct {
+ /* Unlocked. */
+ dns_db_t common;
+#if DNS_RBTDB_USERWLOCK
+ isc_rwlock_t lock;
+#else
+ isc_mutex_t lock;
+#endif
+ isc_rwlock_t tree_lock;
+ unsigned int node_lock_count;
+ rbtdb_nodelock_t * node_locks;
+ dns_rbtnode_t * origin_node;
+ /* Locked by lock. */
+ unsigned int active;
+ isc_refcount_t references;
+ unsigned int attributes;
+ rbtdb_serial_t current_serial;
+ rbtdb_serial_t least_serial;
+ rbtdb_serial_t next_serial;
+ rbtdb_version_t * current_version;
+ rbtdb_version_t * future_version;
+ rbtdb_versionlist_t open_versions;
+ isc_boolean_t overmem;
+ isc_task_t * task;
+ dns_dbnode_t *soanode;
+ dns_dbnode_t *nsnode;
+ /* Locked by tree_lock. */
+ dns_rbt_t * tree;
+ isc_boolean_t secure;
+
+ /* Unlocked */
+ unsigned int quantum;
+} dns_rbtdb_t;
+
+#define RBTDB_ATTR_LOADED 0x01
+#define RBTDB_ATTR_LOADING 0x02
+
+/*%
+ * Search Context
+ */
+typedef struct {
+ dns_rbtdb_t * rbtdb;
+ rbtdb_version_t * rbtversion;
+ rbtdb_serial_t serial;
+ unsigned int options;
+ dns_rbtnodechain_t chain;
+ isc_boolean_t copy_name;
+ isc_boolean_t need_cleanup;
+ isc_boolean_t wild;
+ dns_rbtnode_t * zonecut;
+ rdatasetheader_t * zonecut_rdataset;
+ rdatasetheader_t * zonecut_sigrdataset;
+ dns_fixedname_t zonecut_name;
+ isc_stdtime_t now;
+} rbtdb_search_t;
+
+/*%
+ * Load Context
+ */
+typedef struct {
+ dns_rbtdb_t * rbtdb;
+ isc_stdtime_t now;
+} rbtdb_load_t;
+
+static void rdataset_disassociate(dns_rdataset_t *rdataset);
+static isc_result_t rdataset_first(dns_rdataset_t *rdataset);
+static isc_result_t rdataset_next(dns_rdataset_t *rdataset);
+static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
+static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
+static unsigned int rdataset_count(dns_rdataset_t *rdataset);
+static isc_result_t rdataset_getnoqname(dns_rdataset_t *rdataset,
+ dns_name_t *name,
+ dns_rdataset_t *nsec,
+ dns_rdataset_t *nsecsig);
+static isc_result_t rdataset_getadditional(dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype,
+ dns_acache_t *acache,
+ dns_zone_t **zonep,
+ dns_db_t **dbp,
+ dns_dbversion_t **versionp,
+ dns_dbnode_t **nodep,
+ dns_name_t *fname,
+ dns_message_t *msg,
+ isc_stdtime_t now);
+static isc_result_t rdataset_setadditional(dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype,
+ dns_acache_t *acache,
+ dns_zone_t *zone,
+ dns_db_t *db,
+ dns_dbversion_t *version,
+ dns_dbnode_t *node,
+ dns_name_t *fname);
+static isc_result_t rdataset_putadditional(dns_acache_t *acache,
+ dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype);
+
+static dns_rdatasetmethods_t rdataset_methods = {
+ rdataset_disassociate,
+ rdataset_first,
+ rdataset_next,
+ rdataset_current,
+ rdataset_clone,
+ rdataset_count,
+ NULL,
+ rdataset_getnoqname,
+ rdataset_getadditional,
+ rdataset_setadditional,
+ rdataset_putadditional
+};
+
+static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
+static isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator);
+static isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator);
+static void rdatasetiter_current(dns_rdatasetiter_t *iterator,
+ dns_rdataset_t *rdataset);
+
+static dns_rdatasetitermethods_t rdatasetiter_methods = {
+ rdatasetiter_destroy,
+ rdatasetiter_first,
+ rdatasetiter_next,
+ rdatasetiter_current
+};
+
+typedef struct rbtdb_rdatasetiter {
+ dns_rdatasetiter_t common;
+ rdatasetheader_t * current;
+} rbtdb_rdatasetiter_t;
+
+static void dbiterator_destroy(dns_dbiterator_t **iteratorp);
+static isc_result_t dbiterator_first(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_last(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_seek(dns_dbiterator_t *iterator,
+ dns_name_t *name);
+static isc_result_t dbiterator_prev(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_next(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_current(dns_dbiterator_t *iterator,
+ dns_dbnode_t **nodep,
+ dns_name_t *name);
+static isc_result_t dbiterator_pause(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_origin(dns_dbiterator_t *iterator,
+ dns_name_t *name);
+
+static dns_dbiteratormethods_t dbiterator_methods = {
+ dbiterator_destroy,
+ dbiterator_first,
+ dbiterator_last,
+ dbiterator_seek,
+ dbiterator_prev,
+ dbiterator_next,
+ dbiterator_current,
+ dbiterator_pause,
+ dbiterator_origin
+};
+
+#define DELETION_BATCH_MAX 64
+
+/*
+ * If 'paused' is ISC_TRUE, then the tree lock is not being held.
+ */
+typedef struct rbtdb_dbiterator {
+ dns_dbiterator_t common;
+ isc_boolean_t paused;
+ isc_boolean_t new_origin;
+ isc_rwlocktype_t tree_locked;
+ isc_result_t result;
+ dns_fixedname_t name;
+ dns_fixedname_t origin;
+ dns_rbtnodechain_t chain;
+ dns_rbtnode_t *node;
+ dns_rbtnode_t *deletions[DELETION_BATCH_MAX];
+ int delete;
+} rbtdb_dbiterator_t;
+
+
+#define IS_STUB(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_STUB) != 0)
+#define IS_CACHE(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_CACHE) != 0)
+
+static void free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log,
+ isc_event_t *event);
+
+/*%
+ * 'init_count' is used to initialize 'newheader->count' which inturn
+ * is used to determine where in the cycle rrset-order cyclic starts.
+ * We don't lock this as we don't care about simultanious updates.
+ *
+ * Note:
+ * Both init_count and header->count can be ISC_UINT32_MAX.
+ * The count on the returned rdataset however can't be as
+ * that indicates that the database does not implement cyclic
+ * processing.
+ */
+static unsigned int init_count;
+
+/*
+ * Locking
+ *
+ * If a routine is going to lock more than one lock in this module, then
+ * the locking must be done in the following order:
+ *
+ * Tree Lock
+ *
+ * Node Lock (Only one from the set may be locked at one time by
+ * any caller)
+ *
+ * Database Lock
+ *
+ * Failure to follow this hierarchy can result in deadlock.
+ */
+
+/*
+ * Deleting Nodes
+ *
+ * Currently there is no deletion of nodes from the database, except when
+ * the database is being destroyed.
+ *
+ * If node deletion is added in the future, then for zone databases the node
+ * for the origin of the zone MUST NOT be deleted.
+ */
+
+
+/*
+ * DB Routines
+ */
+
+static void
+attach(dns_db_t *source, dns_db_t **targetp) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)source;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ isc_refcount_increment(&rbtdb->references, NULL);
+
+ *targetp = source;
+}
+
+static void
+free_rbtdb_callback(isc_task_t *task, isc_event_t *event) {
+ dns_rbtdb_t *rbtdb = event->ev_arg;
+
+ UNUSED(task);
+
+ free_rbtdb(rbtdb, ISC_TRUE, event);
+}
+
+/*%
+ * Work out how many nodes can be deleted in the time between two
+ * requests to the nameserver. Smooth the resulting number and use it
+ * as a estimate for the number of nodes to be deleted in the next
+ * iteration.
+ */
+static unsigned int
+adjust_quantum(unsigned int old, isc_time_t *start) {
+ unsigned int pps = dns_pps; /* packets per second */
+ unsigned int interval;
+ isc_uint64_t usecs;
+ isc_time_t end;
+ unsigned int new;
+
+ if (pps < 100)
+ pps = 100;
+ isc_time_now(&end);
+
+ interval = 1000000 / pps; /* interval in usec */
+ if (interval == 0)
+ interval = 1;
+ usecs = isc_time_microdiff(&end, start);
+ if (usecs == 0) {
+ /*
+ * We were unable to measure the amount of time taken.
+ * Double the nodes deleted next time.
+ */
+ old *= 2;
+ if (old > 1000)
+ old = 1000;
+ return (old);
+ }
+ new = old * interval;
+ new /= (unsigned int)usecs;
+ if (new == 0)
+ new = 1;
+ else if (new > 1000)
+ new = 1000;
+
+ /* Smooth */
+ new = (new + old * 3) / 4;
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+ ISC_LOG_DEBUG(1), "adjust_quantum -> %d", new);
+
+ return (new);
+}
+
+static void
+free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
+ unsigned int i;
+ isc_ondestroy_t ondest;
+ isc_result_t result;
+ char buf[DNS_NAME_FORMATSIZE];
+ isc_time_t start;
+
+ REQUIRE(rbtdb->current_version != NULL || EMPTY(rbtdb->open_versions));
+ REQUIRE(rbtdb->future_version == NULL);
+
+ if (rbtdb->current_version != NULL) {
+ unsigned int refs;
+
+ isc_refcount_decrement(&rbtdb->current_version->references,
+ &refs);
+ INSIST(refs == 0);
+ UNLINK(rbtdb->open_versions, rbtdb->current_version, link);
+ isc_refcount_destroy(&rbtdb->current_version->references);
+ isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,
+ sizeof(rbtdb_version_t));
+ }
+ if (event == NULL)
+ rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0;
+ again:
+ if (rbtdb->tree != NULL) {
+ isc_time_now(&start);
+ result = dns_rbt_destroy2(&rbtdb->tree, rbtdb->quantum);
+ if (result == ISC_R_QUOTA) {
+ INSIST(rbtdb->task != NULL);
+ if (rbtdb->quantum != 0)
+ rbtdb->quantum = adjust_quantum(rbtdb->quantum,
+ &start);
+ if (event == NULL)
+ event = isc_event_allocate(rbtdb->common.mctx,
+ NULL,
+ DNS_EVENT_FREESTORAGE,
+ free_rbtdb_callback,
+ rbtdb,
+ sizeof(isc_event_t));
+ if (event == NULL)
+ goto again;
+ isc_task_send(rbtdb->task, &event);
+ return;
+ }
+ INSIST(result == ISC_R_SUCCESS && rbtdb->tree == NULL);
+ }
+ if (event != NULL)
+ isc_event_free(&event);
+ if (log) {
+ if (dns_name_dynamic(&rbtdb->common.origin))
+ dns_name_format(&rbtdb->common.origin, buf,
+ sizeof(buf));
+ else
+ strcpy(buf, "<UNKNOWN>");
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+ "done free_rbtdb(%s)", buf);
+ }
+ if (dns_name_dynamic(&rbtdb->common.origin))
+ dns_name_free(&rbtdb->common.origin, rbtdb->common.mctx);
+ for (i = 0; i < rbtdb->node_lock_count; i++) {
+ isc_refcount_destroy(&rbtdb->node_locks[i].references);
+ NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
+ }
+ isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks,
+ rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t));
+ isc_rwlock_destroy(&rbtdb->tree_lock);
+ isc_refcount_destroy(&rbtdb->references);
+ if (rbtdb->task != NULL)
+ isc_task_detach(&rbtdb->task);
+ RBTDB_DESTROYLOCK(&rbtdb->lock);
+ rbtdb->common.magic = 0;
+ rbtdb->common.impmagic = 0;
+ ondest = rbtdb->common.ondest;
+ isc_mem_putanddetach(&rbtdb->common.mctx, rbtdb, sizeof(*rbtdb));
+ isc_ondestroy_notify(&ondest, rbtdb);
+}
+
+static inline void
+maybe_free_rbtdb(dns_rbtdb_t *rbtdb) {
+ isc_boolean_t want_free = ISC_FALSE;
+ unsigned int i;
+ unsigned int inactive = 0;
+
+ /* XXX check for open versions here */
+
+ if (rbtdb->soanode != NULL)
+ dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->soanode);
+ if (rbtdb->nsnode != NULL)
+ dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->nsnode);
+
+ /*
+ * Even though there are no external direct references, there still
+ * may be nodes in use.
+ */
+ for (i = 0; i < rbtdb->node_lock_count; i++) {
+ NODE_LOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
+ rbtdb->node_locks[i].exiting = ISC_TRUE;
+ NODE_UNLOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
+ if (isc_refcount_current(&rbtdb->node_locks[i].references)
+ == 0) {
+ inactive++;
+ }
+ }
+
+ if (inactive != 0) {
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+ rbtdb->active -= inactive;
+ if (rbtdb->active == 0)
+ want_free = ISC_TRUE;
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+ if (want_free) {
+ char buf[DNS_NAME_FORMATSIZE];
+ if (dns_name_dynamic(&rbtdb->common.origin))
+ dns_name_format(&rbtdb->common.origin, buf,
+ sizeof(buf));
+ else
+ strcpy(buf, "<UNKNOWN>");
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+ "calling free_rbtdb(%s)", buf);
+ free_rbtdb(rbtdb, ISC_TRUE, NULL);
+ }
+ }
+}
+
+static void
+detach(dns_db_t **dbp) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(*dbp);
+ unsigned int refs;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ isc_refcount_decrement(&rbtdb->references, &refs);
+
+ if (refs == 0)
+ maybe_free_rbtdb(rbtdb);
+
+ *dbp = NULL;
+}
+
+static void
+currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ rbtdb_version_t *version;
+ unsigned int refs;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
+ version = rbtdb->current_version;
+ isc_refcount_increment(&version->references, &refs);
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
+
+ *versionp = (dns_dbversion_t *)version;
+}
+
+static inline rbtdb_version_t *
+allocate_version(isc_mem_t *mctx, rbtdb_serial_t serial,
+ unsigned int references, isc_boolean_t writer)
+{
+ isc_result_t result;
+ rbtdb_version_t *version;
+
+ version = isc_mem_get(mctx, sizeof(*version));
+ if (version == NULL)
+ return (NULL);
+ version->serial = serial;
+ result = isc_refcount_init(&version->references, references);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, version, sizeof(*version));
+ return (NULL);
+ }
+ version->writer = writer;
+ version->commit_ok = ISC_FALSE;
+ ISC_LIST_INIT(version->changed_list);
+ ISC_LINK_INIT(version, link);
+
+ return (version);
+}
+
+static isc_result_t
+newversion(dns_db_t *db, dns_dbversion_t **versionp) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ rbtdb_version_t *version;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+ REQUIRE(versionp != NULL && *versionp == NULL);
+ REQUIRE(rbtdb->future_version == NULL);
+
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+ RUNTIME_CHECK(rbtdb->next_serial != 0); /* XXX Error? */
+ version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1,
+ ISC_TRUE);
+ if (version != NULL) {
+ version->commit_ok = ISC_TRUE;
+ rbtdb->next_serial++;
+ rbtdb->future_version = version;
+ }
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+
+ if (version == NULL)
+ return (ISC_R_NOMEMORY);
+
+ *versionp = version;
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+attachversion(dns_db_t *db, dns_dbversion_t *source,
+ dns_dbversion_t **targetp)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ rbtdb_version_t *rbtversion = source;
+ unsigned int refs;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ isc_refcount_increment(&rbtversion->references, &refs);
+ INSIST(refs > 1);
+
+ *targetp = rbtversion;
+}
+
+static rbtdb_changed_t *
+add_changed(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
+ dns_rbtnode_t *node)
+{
+ rbtdb_changed_t *changed;
+ unsigned int refs;
+
+ /*
+ * Caller must be holding the node lock if its reference must be
+ * protected by the lock.
+ */
+
+ changed = isc_mem_get(rbtdb->common.mctx, sizeof(*changed));
+
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+
+ REQUIRE(version->writer);
+
+ if (changed != NULL) {
+ dns_rbtnode_refincrement(node, &refs);
+ INSIST(refs != 0);
+ changed->node = node;
+ changed->dirty = ISC_FALSE;
+ ISC_LIST_INITANDAPPEND(version->changed_list, changed, link);
+ } else
+ version->commit_ok = ISC_FALSE;
+
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+
+ return (changed);
+}
+
+static void
+free_acachearray(isc_mem_t *mctx, rdatasetheader_t *header,
+ acachectl_t *array)
+{
+ unsigned int count;
+ unsigned int i;
+ unsigned char *raw; /* RDATASLAB */
+
+ /*
+ * The caller must be holding the corresponding node lock.
+ */
+
+ if (array == NULL)
+ return;
+
+ raw = (unsigned char *)header + sizeof(*header);
+ count = raw[0] * 256 + raw[1];
+
+ /*
+ * Sanity check: since an additional cache entry has a reference to
+ * the original DB node (in the callback arg), there should be no
+ * acache entries when the node can be freed.
+ */
+ for (i = 0; i < count; i++)
+ INSIST(array[i].entry == NULL && array[i].cbarg == NULL);
+
+ isc_mem_put(mctx, array, count * sizeof(acachectl_t));
+}
+
+static inline void
+free_noqname(isc_mem_t *mctx, struct noqname **noqname) {
+
+ if (dns_name_dynamic(&(*noqname)->name))
+ dns_name_free(&(*noqname)->name, mctx);
+ if ((*noqname)->nsec != NULL)
+ isc_mem_put(mctx, (*noqname)->nsec,
+ dns_rdataslab_size((*noqname)->nsec, 0));
+ if ((*noqname)->nsecsig != NULL)
+ isc_mem_put(mctx, (*noqname)->nsecsig,
+ dns_rdataslab_size((*noqname)->nsecsig, 0));
+ isc_mem_put(mctx, *noqname, sizeof(**noqname));
+ *noqname = NULL;
+}
+
+static inline void
+free_rdataset(isc_mem_t *mctx, rdatasetheader_t *rdataset) {
+ unsigned int size;
+
+ if (rdataset->noqname != NULL)
+ free_noqname(mctx, &rdataset->noqname);
+
+ free_acachearray(mctx, rdataset, rdataset->additional_auth);
+ free_acachearray(mctx, rdataset, rdataset->additional_glue);
+
+ if ((rdataset->attributes & RDATASET_ATTR_NONEXISTENT) != 0)
+ size = sizeof(*rdataset);
+ else
+ size = dns_rdataslab_size((unsigned char *)rdataset,
+ sizeof(*rdataset));
+ isc_mem_put(mctx, rdataset, size);
+}
+
+static inline void
+rollback_node(dns_rbtnode_t *node, rbtdb_serial_t serial) {
+ rdatasetheader_t *header, *dcurrent;
+ isc_boolean_t make_dirty = ISC_FALSE;
+
+ /*
+ * Caller must hold the node lock.
+ */
+
+ /*
+ * We set the IGNORE attribute on rdatasets with serial number
+ * 'serial'. When the reference count goes to zero, these rdatasets
+ * will be cleaned up; until that time, they will be ignored.
+ */
+ for (header = node->data; header != NULL; header = header->next) {
+ if (header->serial == serial) {
+ header->attributes |= RDATASET_ATTR_IGNORE;
+ make_dirty = ISC_TRUE;
+ }
+ for (dcurrent = header->down;
+ dcurrent != NULL;
+ dcurrent = dcurrent->down) {
+ if (dcurrent->serial == serial) {
+ dcurrent->attributes |= RDATASET_ATTR_IGNORE;
+ make_dirty = ISC_TRUE;
+ }
+ }
+ }
+ if (make_dirty)
+ node->dirty = 1;
+}
+
+static inline void
+clean_stale_headers(isc_mem_t *mctx, rdatasetheader_t *top) {
+ rdatasetheader_t *d, *down_next;
+
+ for (d = top->down; d != NULL; d = down_next) {
+ down_next = d->down;
+ free_rdataset(mctx, d);
+ }
+ top->down = NULL;
+}
+
+static inline void
+clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
+ rdatasetheader_t *current, *top_prev, *top_next;
+ isc_mem_t *mctx = rbtdb->common.mctx;
+
+ /*
+ * Caller must be holding the node lock.
+ */
+
+ top_prev = NULL;
+ for (current = node->data; current != NULL; current = top_next) {
+ top_next = current->next;
+ clean_stale_headers(mctx, current);
+ /*
+ * If current is nonexistent or stale, we can clean it up.
+ */
+ if ((current->attributes &
+ (RDATASET_ATTR_NONEXISTENT|RDATASET_ATTR_STALE)) != 0) {
+ if (top_prev != NULL)
+ top_prev->next = current->next;
+ else
+ node->data = current->next;
+ free_rdataset(mctx, current);
+ } else
+ top_prev = current;
+ }
+ node->dirty = 0;
+}
+
+static inline void
+clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
+ rbtdb_serial_t least_serial)
+{
+ rdatasetheader_t *current, *dcurrent, *down_next, *dparent;
+ rdatasetheader_t *top_prev, *top_next;
+ isc_mem_t *mctx = rbtdb->common.mctx;
+ isc_boolean_t still_dirty = ISC_FALSE;
+
+ /*
+ * Caller must be holding the node lock.
+ */
+ REQUIRE(least_serial != 0);
+
+ top_prev = NULL;
+ for (current = node->data; current != NULL; current = top_next) {
+ top_next = current->next;
+
+ /*
+ * First, we clean up any instances of multiple rdatasets
+ * with the same serial number, or that have the IGNORE
+ * attribute.
+ */
+ dparent = current;
+ for (dcurrent = current->down;
+ dcurrent != NULL;
+ dcurrent = down_next) {
+ down_next = dcurrent->down;
+ INSIST(dcurrent->serial <= dparent->serial);
+ if (dcurrent->serial == dparent->serial ||
+ IGNORE(dcurrent)) {
+ if (down_next != NULL)
+ down_next->next = dparent;
+ dparent->down = down_next;
+ free_rdataset(mctx, dcurrent);
+ } else
+ dparent = dcurrent;
+ }
+
+ /*
+ * We've now eliminated all IGNORE datasets with the possible
+ * exception of current, which we now check.
+ */
+ if (IGNORE(current)) {
+ down_next = current->down;
+ if (down_next == NULL) {
+ if (top_prev != NULL)
+ top_prev->next = current->next;
+ else
+ node->data = current->next;
+ free_rdataset(mctx, current);
+ /*
+ * current no longer exists, so we can
+ * just continue with the loop.
+ */
+ continue;
+ } else {
+ /*
+ * Pull up current->down, making it the new
+ * current.
+ */
+ if (top_prev != NULL)
+ top_prev->next = down_next;
+ else
+ node->data = down_next;
+ down_next->next = top_next;
+ free_rdataset(mctx, current);
+ current = down_next;
+ }
+ }
+
+ /*
+ * We now try to find the first down node less than the
+ * least serial.
+ */
+ dparent = current;
+ for (dcurrent = current->down;
+ dcurrent != NULL;
+ dcurrent = down_next) {
+ down_next = dcurrent->down;
+ if (dcurrent->serial < least_serial)
+ break;
+ dparent = dcurrent;
+ }
+
+ /*
+ * If there is a such an rdataset, delete it and any older
+ * versions.
+ */
+ if (dcurrent != NULL) {
+ do {
+ down_next = dcurrent->down;
+ INSIST(dcurrent->serial <= least_serial);
+ free_rdataset(mctx, dcurrent);
+ dcurrent = down_next;
+ } while (dcurrent != NULL);
+ dparent->down = NULL;
+ }
+
+ /*
+ * Note. The serial number of 'current' might be less than
+ * least_serial too, but we cannot delete it because it is
+ * the most recent version, unless it is a NONEXISTENT
+ * rdataset.
+ */
+ if (current->down != NULL) {
+ still_dirty = ISC_TRUE;
+ top_prev = current;
+ } else {
+ /*
+ * If this is a NONEXISTENT rdataset, we can delete it.
+ */
+ if (NONEXISTENT(current)) {
+ if (top_prev != NULL)
+ top_prev->next = current->next;
+ else
+ node->data = current->next;
+ free_rdataset(mctx, current);
+ } else
+ top_prev = current;
+ }
+ }
+ if (!still_dirty)
+ node->dirty = 0;
+}
+
+/*
+ * Caller must be holding the node lock if its reference must be protected
+ * by the lock.
+ */
+static inline void
+new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
+ unsigned int lockrefs, noderefs;
+ isc_refcount_t *lockref;
+
+ dns_rbtnode_refincrement0(node, &noderefs);
+ if (noderefs == 1) { /* this is the first reference to the node */
+ lockref = &rbtdb->node_locks[node->locknum].references;
+ isc_refcount_increment0(lockref, &lockrefs);
+ INSIST(lockrefs != 0);
+ }
+ INSIST(noderefs != 0);
+}
+
+/*
+ * Caller must be holding the node lock; either the "strong", read or write
+ * lock. Note that the lock must be held even when node references are
+ * atomically modified; in that case the decrement operation itself does not
+ * have to be protected, but we must avoid a race condition where multiple
+ * threads are decreasing the reference to zero simultaneously and at least
+ * one of them is going to free the node.
+ * This function returns ISC_TRUE if and only if the node reference decreases
+ * to zero.
+ */
+static isc_boolean_t
+decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
+ rbtdb_serial_t least_serial,
+ isc_rwlocktype_t nlock, isc_rwlocktype_t tlock)
+{
+ isc_result_t result;
+ isc_boolean_t write_locked;
+ rbtdb_nodelock_t *nodelock;
+ unsigned int refs, nrefs;
+
+ nodelock = &rbtdb->node_locks[node->locknum];
+
+ /* Handle easy and typical case first. */
+ if (!node->dirty && (node->data != NULL || node->down != NULL)) {
+ dns_rbtnode_refdecrement(node, &nrefs);
+ INSIST((int)nrefs >= 0);
+ if (nrefs == 0) {
+ isc_refcount_decrement(&nodelock->references, &refs);
+ INSIST((int)refs >= 0);
+ }
+ return ((nrefs == 0) ? ISC_TRUE : ISC_FALSE);
+ }
+
+ /* Upgrade the lock? */
+ if (nlock == isc_rwlocktype_read) {
+ NODE_WEAKUNLOCK(&nodelock->lock, isc_rwlocktype_read);
+ NODE_WEAKLOCK(&nodelock->lock, isc_rwlocktype_write);
+ }
+ dns_rbtnode_refdecrement(node, &nrefs);
+ INSIST((int)nrefs >= 0);
+ if (nrefs > 0) {
+ /* Restore the lock? */
+ if (nlock == isc_rwlocktype_read)
+ NODE_WEAKDOWNGRADE(&nodelock->lock);
+ return (ISC_FALSE);
+ }
+
+ if (node->dirty && dns_rbtnode_refcurrent(node) == 0) {
+ if (IS_CACHE(rbtdb))
+ clean_cache_node(rbtdb, node);
+ else {
+ if (least_serial == 0) {
+ /*
+ * Caller doesn't know the least serial.
+ * Get it.
+ */
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
+ least_serial = rbtdb->least_serial;
+ RBTDB_UNLOCK(&rbtdb->lock,
+ isc_rwlocktype_read);
+ }
+ clean_zone_node(rbtdb, node, least_serial);
+ }
+ }
+
+ isc_refcount_decrement(&nodelock->references, &refs);
+ INSIST((int)refs >= 0);
+
+ /*
+ * XXXDCL should this only be done for cache zones?
+ */
+ if (node->data != NULL || node->down != NULL) {
+ /* Restore the lock? */
+ if (nlock == isc_rwlocktype_read)
+ NODE_WEAKDOWNGRADE(&nodelock->lock);
+ return (ISC_TRUE);
+ }
+
+ /*
+ * XXXDCL need to add a deferred delete method for ISC_R_LOCKBUSY.
+ */
+ if (tlock != isc_rwlocktype_write) {
+ /*
+ * Locking hierarchy notwithstanding, we don't need to free
+ * the node lock before acquiring the tree write lock because
+ * we only do a trylock.
+ */
+ if (tlock == isc_rwlocktype_read)
+ result = isc_rwlock_tryupgrade(&rbtdb->tree_lock);
+ else
+ result = isc_rwlock_trylock(&rbtdb->tree_lock,
+ isc_rwlocktype_write);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS ||
+ result == ISC_R_LOCKBUSY);
+
+ write_locked = ISC_TF(result == ISC_R_SUCCESS);
+ } else
+ write_locked = ISC_TRUE;
+
+ if (write_locked && dns_rbtnode_refcurrent(node) == 0) {
+ /*
+ * We can now delete the node if the reference counter is
+ * zero. This should be typically the case, but a different
+ * thread may still gain a (new) reference just before the
+ * current thread locks the tree (e.g., in findnode()).
+ */
+
+ if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
+ char printname[DNS_NAME_FORMATSIZE];
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+ "decrement_reference: "
+ "delete from rbt: %p %s",
+ node,
+ dns_rbt_formatnodename(node, printname,
+ sizeof(printname)));
+ }
+
+ result = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE);
+ if (result != ISC_R_SUCCESS)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
+ "decrement_reference: "
+ "dns_rbt_deletenode: %s",
+ isc_result_totext(result));
+ }
+
+ /* Restore the lock? */
+ if (nlock == isc_rwlocktype_read)
+ NODE_WEAKDOWNGRADE(&nodelock->lock);
+
+ /*
+ * Relock a read lock, or unlock the write lock if no lock was held.
+ */
+ if (tlock == isc_rwlocktype_none)
+ if (write_locked)
+ RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+
+ if (tlock == isc_rwlocktype_read)
+ if (write_locked)
+ isc_rwlock_downgrade(&rbtdb->tree_lock);
+
+ return (ISC_TRUE);
+}
+
+static inline void
+make_least_version(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
+ rbtdb_changedlist_t *cleanup_list)
+{
+ /*
+ * Caller must be holding the database lock.
+ */
+
+ rbtdb->least_serial = version->serial;
+ *cleanup_list = version->changed_list;
+ ISC_LIST_INIT(version->changed_list);
+}
+
+static inline void
+cleanup_nondirty(rbtdb_version_t *version, rbtdb_changedlist_t *cleanup_list) {
+ rbtdb_changed_t *changed, *next_changed;
+
+ /*
+ * If the changed record is dirty, then
+ * an update created multiple versions of
+ * a given rdataset. We keep this list
+ * until we're the least open version, at
+ * which point it's safe to get rid of any
+ * older versions.
+ *
+ * If the changed record isn't dirty, then
+ * we don't need it anymore since we're
+ * committing and not rolling back.
+ *
+ * The caller must be holding the database lock.
+ */
+ for (changed = HEAD(version->changed_list);
+ changed != NULL;
+ changed = next_changed) {
+ next_changed = NEXT(changed, link);
+ if (!changed->dirty) {
+ UNLINK(version->changed_list,
+ changed, link);
+ APPEND(*cleanup_list,
+ changed, link);
+ }
+ }
+}
+
+static isc_boolean_t
+iszonesecure(dns_db_t *db, dns_dbnode_t *origin) {
+ dns_rdataset_t keyset;
+ dns_rdataset_t nsecset, signsecset;
+ isc_boolean_t haszonekey = ISC_FALSE;
+ isc_boolean_t hasnsec = ISC_FALSE;
+ isc_result_t result;
+
+ dns_rdataset_init(&keyset);
+ result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_dnskey, 0,
+ 0, &keyset, NULL);
+ if (result == ISC_R_SUCCESS) {
+ dns_rdata_t keyrdata = DNS_RDATA_INIT;
+ result = dns_rdataset_first(&keyset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&keyset, &keyrdata);
+ if (dns_zonekey_iszonekey(&keyrdata)) {
+ haszonekey = ISC_TRUE;
+ break;
+ }
+ result = dns_rdataset_next(&keyset);
+ }
+ dns_rdataset_disassociate(&keyset);
+ }
+ if (!haszonekey)
+ return (ISC_FALSE);
+
+ dns_rdataset_init(&nsecset);
+ dns_rdataset_init(&signsecset);
+ result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_nsec, 0,
+ 0, &nsecset, &signsecset);
+ if (result == ISC_R_SUCCESS) {
+ if (dns_rdataset_isassociated(&signsecset)) {
+ hasnsec = ISC_TRUE;
+ dns_rdataset_disassociate(&signsecset);
+ }
+ dns_rdataset_disassociate(&nsecset);
+ }
+ return (hasnsec);
+}
+
+static void
+closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ rbtdb_version_t *version, *cleanup_version, *least_greater;
+ isc_boolean_t rollback = ISC_FALSE;
+ rbtdb_changedlist_t cleanup_list;
+ rbtdb_changed_t *changed, *next_changed;
+ rbtdb_serial_t serial, least_serial;
+ dns_rbtnode_t *rbtnode;
+ unsigned int refs;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+ version = (rbtdb_version_t *)*versionp;
+
+ cleanup_version = NULL;
+ ISC_LIST_INIT(cleanup_list);
+
+ isc_refcount_decrement(&version->references, &refs);
+ if (refs > 0) { /* typical and easy case first */
+ if (commit) {
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
+ INSIST(!version->writer);
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
+ }
+ goto end;
+ }
+
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+ serial = version->serial;
+ if (version->writer) {
+ if (commit) {
+ unsigned cur_ref;
+ rbtdb_version_t *cur_version;
+
+ INSIST(version->commit_ok);
+ INSIST(version == rbtdb->future_version);
+ /*
+ * The current version is going to be replaced.
+ * Release the (likely last) reference to it from the
+ * DB itself and unlink it from the open list.
+ */
+ cur_version = rbtdb->current_version;
+ isc_refcount_decrement(&cur_version->references,
+ &cur_ref);
+ if (cur_ref == 0) {
+ if (cur_version->serial == rbtdb->least_serial)
+ INSIST(EMPTY(cur_version->changed_list));
+ UNLINK(rbtdb->open_versions,
+ cur_version, link);
+ }
+ if (EMPTY(rbtdb->open_versions)) {
+ /*
+ * We're going to become the least open
+ * version.
+ */
+ make_least_version(rbtdb, version,
+ &cleanup_list);
+ } else {
+ /*
+ * Some other open version is the
+ * least version. We can't cleanup
+ * records that were changed in this
+ * version because the older versions
+ * may still be in use by an open
+ * version.
+ *
+ * We can, however, discard the
+ * changed records for things that
+ * we've added that didn't exist in
+ * prior versions.
+ */
+ cleanup_nondirty(version, &cleanup_list);
+ }
+ /*
+ * If the (soon to be former) current version
+ * isn't being used by anyone, we can clean
+ * it up.
+ */
+ if (cur_ref == 0) {
+ cleanup_version = cur_version;
+ APPENDLIST(version->changed_list,
+ cleanup_version->changed_list,
+ link);
+ }
+ /*
+ * Become the current version.
+ */
+ version->writer = ISC_FALSE;
+ rbtdb->current_version = version;
+ rbtdb->current_serial = version->serial;
+ rbtdb->future_version = NULL;
+
+ /*
+ * Keep the current version in the open list, and
+ * gain a reference for the DB itself (see the DB
+ * creation function below). This must be the only
+ * case where we need to increment the counter from
+ * zero and need to use isc_refcount_increment0().
+ */
+ isc_refcount_increment0(&version->references,
+ &cur_ref);
+ INSIST(cur_ref == 1);
+ PREPEND(rbtdb->open_versions,
+ rbtdb->current_version, link);
+ } else {
+ /*
+ * We're rolling back this transaction.
+ */
+ cleanup_list = version->changed_list;
+ ISC_LIST_INIT(version->changed_list);
+ rollback = ISC_TRUE;
+ cleanup_version = version;
+ rbtdb->future_version = NULL;
+ }
+ } else {
+ if (version != rbtdb->current_version) {
+ /*
+ * There are no external or internal references
+ * to this version and it can be cleaned up.
+ */
+ cleanup_version = version;
+
+ /*
+ * Find the version with the least serial
+ * number greater than ours.
+ */
+ least_greater = PREV(version, link);
+ if (least_greater == NULL)
+ least_greater = rbtdb->current_version;
+
+ INSIST(version->serial < least_greater->serial);
+ /*
+ * Is this the least open version?
+ */
+ if (version->serial == rbtdb->least_serial) {
+ /*
+ * Yes. Install the new least open
+ * version.
+ */
+ make_least_version(rbtdb,
+ least_greater,
+ &cleanup_list);
+ } else {
+ /*
+ * Add any unexecuted cleanups to
+ * those of the least greater version.
+ */
+ APPENDLIST(least_greater->changed_list,
+ version->changed_list,
+ link);
+ }
+ } else if (version->serial == rbtdb->least_serial)
+ INSIST(EMPTY(version->changed_list));
+ UNLINK(rbtdb->open_versions, version, link);
+ }
+ least_serial = rbtdb->least_serial;
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+
+ /*
+ * Update the zone's secure status.
+ */
+ if (version->writer && commit && !IS_CACHE(rbtdb))
+ rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+
+ if (cleanup_version != NULL) {
+ INSIST(EMPTY(cleanup_version->changed_list));
+ isc_mem_put(rbtdb->common.mctx, cleanup_version,
+ sizeof(*cleanup_version));
+ }
+
+ if (!EMPTY(cleanup_list)) {
+ for (changed = HEAD(cleanup_list);
+ changed != NULL;
+ changed = next_changed) {
+ nodelock_t *lock;
+
+ next_changed = NEXT(changed, link);
+ rbtnode = changed->node;
+ lock = &rbtdb->node_locks[rbtnode->locknum].lock;
+
+ NODE_LOCK(lock, isc_rwlocktype_write);
+ if (rollback)
+ rollback_node(rbtnode, serial);
+ decrement_reference(rbtdb, rbtnode, least_serial,
+ isc_rwlocktype_write,
+ isc_rwlocktype_none);
+ NODE_UNLOCK(lock, isc_rwlocktype_write);
+
+ isc_mem_put(rbtdb->common.mctx, changed,
+ sizeof(*changed));
+ }
+ }
+
+ end:
+ *versionp = NULL;
+}
+
+/*
+ * Add the necessary magic for the wildcard name 'name'
+ * to be found in 'rbtdb'.
+ *
+ * In order for wildcard matching to work correctly in
+ * zone_find(), we must ensure that a node for the wildcarding
+ * level exists in the database, and has its 'find_callback'
+ * and 'wild' bits set.
+ *
+ * E.g. if the wildcard name is "*.sub.example." then we
+ * must ensure that "sub.example." exists and is marked as
+ * a wildcard level.
+ */
+static isc_result_t
+add_wildcard_magic(dns_rbtdb_t *rbtdb, dns_name_t *name) {
+ isc_result_t result;
+ dns_name_t foundname;
+ dns_offsets_t offsets;
+ unsigned int n;
+ dns_rbtnode_t *node = NULL;
+
+ dns_name_init(&foundname, offsets);
+ n = dns_name_countlabels(name);
+ INSIST(n >= 2);
+ n--;
+ dns_name_getlabelsequence(name, 1, n, &foundname);
+ result = dns_rbt_addnode(rbtdb->tree, &foundname, &node);
+ if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
+ return (result);
+ node->find_callback = 1;
+ node->wild = 1;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+add_empty_wildcards(dns_rbtdb_t *rbtdb, dns_name_t *name) {
+ isc_result_t result;
+ dns_name_t foundname;
+ dns_offsets_t offsets;
+ unsigned int n, l, i;
+
+ dns_name_init(&foundname, offsets);
+ n = dns_name_countlabels(name);
+ l = dns_name_countlabels(&rbtdb->common.origin);
+ i = l + 1;
+ while (i < n) {
+ dns_rbtnode_t *node = NULL; /* dummy */
+ dns_name_getlabelsequence(name, n - i, i, &foundname);
+ if (dns_name_iswildcard(&foundname)) {
+ result = add_wildcard_magic(rbtdb, &foundname);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dns_rbt_addnode(rbtdb->tree, &foundname,
+ &node);
+ if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
+ return (result);
+ }
+ i++;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
+ dns_dbnode_t **nodep)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *node = NULL;
+ dns_name_t nodename;
+ isc_result_t result;
+ isc_rwlocktype_t locktype = isc_rwlocktype_read;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ dns_name_init(&nodename, NULL);
+ RWLOCK(&rbtdb->tree_lock, locktype);
+ result = dns_rbt_findnode(rbtdb->tree, name, NULL, &node, NULL,
+ DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+ if (result != ISC_R_SUCCESS) {
+ RWUNLOCK(&rbtdb->tree_lock, locktype);
+ if (!create) {
+ if (result == DNS_R_PARTIALMATCH)
+ result = ISC_R_NOTFOUND;
+ return (result);
+ }
+ /*
+ * It would be nice to try to upgrade the lock instead of
+ * unlocking then relocking.
+ */
+ locktype = isc_rwlocktype_write;
+ RWLOCK(&rbtdb->tree_lock, locktype);
+ node = NULL;
+ result = dns_rbt_addnode(rbtdb->tree, name, &node);
+ if (result == ISC_R_SUCCESS) {
+ dns_rbt_namefromnode(node, &nodename);
+#ifdef DNS_RBT_USEHASH
+ node->locknum = node->hashval % rbtdb->node_lock_count;
+#else
+ node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
+ rbtdb->node_lock_count;
+#endif
+ add_empty_wildcards(rbtdb, name);
+
+ if (dns_name_iswildcard(name)) {
+ result = add_wildcard_magic(rbtdb, name);
+ if (result != ISC_R_SUCCESS) {
+ RWUNLOCK(&rbtdb->tree_lock, locktype);
+ return (result);
+ }
+ }
+ } else if (result != ISC_R_EXISTS) {
+ RWUNLOCK(&rbtdb->tree_lock, locktype);
+ return (result);
+ }
+ }
+ NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
+ new_reference(rbtdb, node);
+ NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+ RWUNLOCK(&rbtdb->tree_lock, locktype);
+
+ *nodep = (dns_dbnode_t *)node;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
+ rbtdb_search_t *search = arg;
+ rdatasetheader_t *header, *header_next;
+ rdatasetheader_t *dname_header, *sigdname_header, *ns_header;
+ rdatasetheader_t *found;
+ isc_result_t result;
+ dns_rbtnode_t *onode;
+
+ /*
+ * We only want to remember the topmost zone cut, since it's the one
+ * that counts, so we'll just continue if we've already found a
+ * zonecut.
+ */
+ if (search->zonecut != NULL)
+ return (DNS_R_CONTINUE);
+
+ found = NULL;
+ result = DNS_R_CONTINUE;
+ onode = search->rbtdb->origin_node;
+
+ NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+
+ /*
+ * Look for an NS or DNAME rdataset active in our version.
+ */
+ ns_header = NULL;
+ dname_header = NULL;
+ sigdname_header = NULL;
+ for (header = node->data; header != NULL; header = header_next) {
+ header_next = header->next;
+ if (header->type == dns_rdatatype_ns ||
+ header->type == dns_rdatatype_dname ||
+ header->type == RBTDB_RDATATYPE_SIGDNAME) {
+ do {
+ if (header->serial <= search->serial &&
+ !IGNORE(header)) {
+ /*
+ * Is this a "this rdataset doesn't
+ * exist" record?
+ */
+ if (NONEXISTENT(header))
+ header = NULL;
+ break;
+ } else
+ header = header->down;
+ } while (header != NULL);
+ if (header != NULL) {
+ if (header->type == dns_rdatatype_dname)
+ dname_header = header;
+ else if (header->type ==
+ RBTDB_RDATATYPE_SIGDNAME)
+ sigdname_header = header;
+ else if (node != onode ||
+ IS_STUB(search->rbtdb)) {
+ /*
+ * We've found an NS rdataset that
+ * isn't at the origin node. We check
+ * that they're not at the origin node,
+ * because otherwise we'd erroneously
+ * treat the zone top as if it were
+ * a delegation.
+ */
+ ns_header = header;
+ }
+ }
+ }
+ }
+
+ /*
+ * Did we find anything?
+ */
+ if (dname_header != NULL) {
+ /*
+ * Note that DNAME has precedence over NS if both exist.
+ */
+ found = dname_header;
+ search->zonecut_sigrdataset = sigdname_header;
+ } else if (ns_header != NULL) {
+ found = ns_header;
+ search->zonecut_sigrdataset = NULL;
+ }
+
+ if (found != NULL) {
+ /*
+ * We increment the reference count on node to ensure that
+ * search->zonecut_rdataset will still be valid later.
+ */
+ new_reference(search->rbtdb, node);
+ search->zonecut = node;
+ search->zonecut_rdataset = found;
+ search->need_cleanup = ISC_TRUE;
+ /*
+ * Since we've found a zonecut, anything beneath it is
+ * glue and is not subject to wildcard matching, so we
+ * may clear search->wild.
+ */
+ search->wild = ISC_FALSE;
+ if ((search->options & DNS_DBFIND_GLUEOK) == 0) {
+ /*
+ * If the caller does not want to find glue, then
+ * this is the best answer and the search should
+ * stop now.
+ */
+ result = DNS_R_PARTIALMATCH;
+ } else {
+ dns_name_t *zcname;
+
+ /*
+ * The search will continue beneath the zone cut.
+ * This may or may not be the best match. In case it
+ * is, we need to remember the node name.
+ */
+ zcname = dns_fixedname_name(&search->zonecut_name);
+ RUNTIME_CHECK(dns_name_copy(name, zcname, NULL) ==
+ ISC_R_SUCCESS);
+ search->copy_name = ISC_TRUE;
+ }
+ } else {
+ /*
+ * There is no zonecut at this node which is active in this
+ * version.
+ *
+ * If this is a "wild" node and the caller hasn't disabled
+ * wildcard matching, remember that we've seen a wild node
+ * in case we need to go searching for wildcard matches
+ * later on.
+ */
+ if (node->wild && (search->options & DNS_DBFIND_NOWILD) == 0)
+ search->wild = ISC_TRUE;
+ }
+
+ NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+
+ return (result);
+}
+
+static inline void
+bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
+ rdatasetheader_t *header, isc_stdtime_t now,
+ dns_rdataset_t *rdataset)
+{
+ unsigned char *raw; /* RDATASLAB */
+
+ /*
+ * Caller must be holding the node reader lock.
+ * XXXJT: technically, we need a writer lock, since we'll increment
+ * the header count below. However, since the actual counter value
+ * doesn't matter, we prioritize performance here. (We may want to
+ * use atomic increment when available).
+ */
+
+ if (rdataset == NULL)
+ return;
+
+ new_reference(rbtdb, node);
+
+ INSIST(rdataset->methods == NULL); /* We must be disassociated. */
+
+ rdataset->methods = &rdataset_methods;
+ rdataset->rdclass = rbtdb->common.rdclass;
+ rdataset->type = RBTDB_RDATATYPE_BASE(header->type);
+ rdataset->covers = RBTDB_RDATATYPE_EXT(header->type);
+ rdataset->ttl = header->ttl - now;
+ rdataset->trust = header->trust;
+ if (NXDOMAIN(header))
+ rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
+ rdataset->private1 = rbtdb;
+ rdataset->private2 = node;
+ raw = (unsigned char *)header + sizeof(*header);
+ rdataset->private3 = raw;
+ rdataset->count = header->count++;
+ if (rdataset->count == ISC_UINT32_MAX)
+ rdataset->count = 0;
+
+ /*
+ * Reset iterator state.
+ */
+ rdataset->privateuint4 = 0;
+ rdataset->private5 = NULL;
+
+ /*
+ * Add noqname proof.
+ */
+ rdataset->private6 = header->noqname;
+ if (rdataset->private6 != NULL)
+ rdataset->attributes |= DNS_RDATASETATTR_NOQNAME;
+}
+
+static inline isc_result_t
+setup_delegation(rbtdb_search_t *search, dns_dbnode_t **nodep,
+ dns_name_t *foundname, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset)
+{
+ isc_result_t result;
+ dns_name_t *zcname;
+ rbtdb_rdatatype_t type;
+ dns_rbtnode_t *node;
+
+ /*
+ * The caller MUST NOT be holding any node locks.
+ */
+
+ node = search->zonecut;
+ type = search->zonecut_rdataset->type;
+
+ /*
+ * If we have to set foundname, we do it before anything else.
+ * If we were to set foundname after we had set nodep or bound the
+ * rdataset, then we'd have to undo that work if dns_name_copy()
+ * failed. By setting foundname first, there's nothing to undo if
+ * we have trouble.
+ */
+ if (foundname != NULL && search->copy_name) {
+ zcname = dns_fixedname_name(&search->zonecut_name);
+ result = dns_name_copy(zcname, foundname, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ if (nodep != NULL) {
+ /*
+ * Note that we don't have to increment the node's reference
+ * count here because we're going to use the reference we
+ * already have in the search block.
+ */
+ *nodep = node;
+ search->need_cleanup = ISC_FALSE;
+ }
+ if (rdataset != NULL) {
+ NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ bind_rdataset(search->rbtdb, node, search->zonecut_rdataset,
+ search->now, rdataset);
+ if (sigrdataset != NULL && search->zonecut_sigrdataset != NULL)
+ bind_rdataset(search->rbtdb, node,
+ search->zonecut_sigrdataset,
+ search->now, sigrdataset);
+ NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ }
+
+ if (type == dns_rdatatype_dname)
+ return (DNS_R_DNAME);
+ return (DNS_R_DELEGATION);
+}
+
+static inline isc_boolean_t
+valid_glue(rbtdb_search_t *search, dns_name_t *name, rbtdb_rdatatype_t type,
+ dns_rbtnode_t *node)
+{
+ unsigned char *raw; /* RDATASLAB */
+ unsigned int count, size;
+ dns_name_t ns_name;
+ isc_boolean_t valid = ISC_FALSE;
+ dns_offsets_t offsets;
+ isc_region_t region;
+ rdatasetheader_t *header;
+
+ /*
+ * No additional locking is required.
+ */
+
+ /*
+ * Valid glue types are A, AAAA, A6. NS is also a valid glue type
+ * if it occurs at a zone cut, but is not valid below it.
+ */
+ if (type == dns_rdatatype_ns) {
+ if (node != search->zonecut) {
+ return (ISC_FALSE);
+ }
+ } else if (type != dns_rdatatype_a &&
+ type != dns_rdatatype_aaaa &&
+ type != dns_rdatatype_a6) {
+ return (ISC_FALSE);
+ }
+
+ header = search->zonecut_rdataset;
+ raw = (unsigned char *)header + sizeof(*header);
+ count = raw[0] * 256 + raw[1];
+#if DNS_RDATASET_FIXED
+ raw += 2 + (4 * count);
+#else
+ raw += 2;
+#endif
+
+ while (count > 0) {
+ count--;
+ size = raw[0] * 256 + raw[1];
+#if DNS_RDATASET_FIXED
+ raw += 4;
+#else
+ raw += 2;
+#endif
+ region.base = raw;
+ region.length = size;
+ raw += size;
+ /*
+ * XXX Until we have rdata structures, we have no choice but
+ * to directly access the rdata format.
+ */
+ dns_name_init(&ns_name, offsets);
+ dns_name_fromregion(&ns_name, &region);
+ if (dns_name_compare(&ns_name, name) == 0) {
+ valid = ISC_TRUE;
+ break;
+ }
+ }
+
+ return (valid);
+}
+
+static inline isc_boolean_t
+activeempty(rbtdb_search_t *search, dns_rbtnodechain_t *chain,
+ dns_name_t *name)
+{
+ dns_fixedname_t fnext;
+ dns_fixedname_t forigin;
+ dns_name_t *next;
+ dns_name_t *origin;
+ dns_name_t prefix;
+ dns_rbtdb_t *rbtdb;
+ dns_rbtnode_t *node;
+ isc_result_t result;
+ isc_boolean_t answer = ISC_FALSE;
+ rdatasetheader_t *header;
+
+ rbtdb = search->rbtdb;
+
+ dns_name_init(&prefix, NULL);
+ dns_fixedname_init(&fnext);
+ next = dns_fixedname_name(&fnext);
+ dns_fixedname_init(&forigin);
+ origin = dns_fixedname_name(&forigin);
+
+ result = dns_rbtnodechain_next(chain, NULL, NULL);
+ while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
+ node = NULL;
+ result = dns_rbtnodechain_current(chain, &prefix,
+ origin, &node);
+ if (result != ISC_R_SUCCESS)
+ break;
+ NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ for (header = node->data;
+ header != NULL;
+ header = header->next) {
+ if (header->serial <= search->serial &&
+ !IGNORE(header) && EXISTS(header))
+ break;
+ }
+ NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ if (header != NULL)
+ break;
+ result = dns_rbtnodechain_next(chain, NULL, NULL);
+ }
+ if (result == ISC_R_SUCCESS)
+ result = dns_name_concatenate(&prefix, origin, next, NULL);
+ if (result == ISC_R_SUCCESS && dns_name_issubdomain(next, name))
+ answer = ISC_TRUE;
+ return (answer);
+}
+
+static inline isc_boolean_t
+activeemtpynode(rbtdb_search_t *search, dns_name_t *qname, dns_name_t *wname) {
+ dns_fixedname_t fnext;
+ dns_fixedname_t forigin;
+ dns_fixedname_t fprev;
+ dns_name_t *next;
+ dns_name_t *origin;
+ dns_name_t *prev;
+ dns_name_t name;
+ dns_name_t rname;
+ dns_name_t tname;
+ dns_rbtdb_t *rbtdb;
+ dns_rbtnode_t *node;
+ dns_rbtnodechain_t chain;
+ isc_boolean_t check_next = ISC_TRUE;
+ isc_boolean_t check_prev = ISC_TRUE;
+ isc_boolean_t answer = ISC_FALSE;
+ isc_result_t result;
+ rdatasetheader_t *header;
+ unsigned int n;
+
+ rbtdb = search->rbtdb;
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&tname, NULL);
+ dns_name_init(&rname, NULL);
+ dns_fixedname_init(&fnext);
+ next = dns_fixedname_name(&fnext);
+ dns_fixedname_init(&fprev);
+ prev = dns_fixedname_name(&fprev);
+ dns_fixedname_init(&forigin);
+ origin = dns_fixedname_name(&forigin);
+
+ /*
+ * Find if qname is at or below a empty node.
+ * Use our own copy of the chain.
+ */
+
+ chain = search->chain;
+ do {
+ node = NULL;
+ result = dns_rbtnodechain_current(&chain, &name,
+ origin, &node);
+ if (result != ISC_R_SUCCESS)
+ break;
+ NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ for (header = node->data;
+ header != NULL;
+ header = header->next) {
+ if (header->serial <= search->serial &&
+ !IGNORE(header) && EXISTS(header))
+ break;
+ }
+ NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ if (header != NULL)
+ break;
+ result = dns_rbtnodechain_prev(&chain, NULL, NULL);
+ } while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN);
+ if (result == ISC_R_SUCCESS)
+ result = dns_name_concatenate(&name, origin, prev, NULL);
+ if (result != ISC_R_SUCCESS)
+ check_prev = ISC_FALSE;
+
+ result = dns_rbtnodechain_next(&chain, NULL, NULL);
+ while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
+ node = NULL;
+ result = dns_rbtnodechain_current(&chain, &name,
+ origin, &node);
+ if (result != ISC_R_SUCCESS)
+ break;
+ NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ for (header = node->data;
+ header != NULL;
+ header = header->next) {
+ if (header->serial <= search->serial &&
+ !IGNORE(header) && EXISTS(header))
+ break;
+ }
+ NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ if (header != NULL)
+ break;
+ result = dns_rbtnodechain_next(&chain, NULL, NULL);
+ }
+ if (result == ISC_R_SUCCESS)
+ result = dns_name_concatenate(&name, origin, next, NULL);
+ if (result != ISC_R_SUCCESS)
+ check_next = ISC_FALSE;
+
+ dns_name_clone(qname, &rname);
+
+ /*
+ * Remove the wildcard label to find the terminal name.
+ */
+ n = dns_name_countlabels(wname);
+ dns_name_getlabelsequence(wname, 1, n - 1, &tname);
+
+ do {
+ if ((check_prev && dns_name_issubdomain(prev, &rname)) ||
+ (check_next && dns_name_issubdomain(next, &rname))) {
+ answer = ISC_TRUE;
+ break;
+ }
+ /*
+ * Remove the left hand label.
+ */
+ n = dns_name_countlabels(&rname);
+ dns_name_getlabelsequence(&rname, 1, n - 1, &rname);
+ } while (!dns_name_equal(&rname, &tname));
+ return (answer);
+}
+
+static inline isc_result_t
+find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep,
+ dns_name_t *qname)
+{
+ unsigned int i, j;
+ dns_rbtnode_t *node, *level_node, *wnode;
+ rdatasetheader_t *header;
+ isc_result_t result = ISC_R_NOTFOUND;
+ dns_name_t name;
+ dns_name_t *wname;
+ dns_fixedname_t fwname;
+ dns_rbtdb_t *rbtdb;
+ isc_boolean_t done, wild, active;
+ dns_rbtnodechain_t wchain;
+
+ /*
+ * Caller must be holding the tree lock and MUST NOT be holding
+ * any node locks.
+ */
+
+ /*
+ * Examine each ancestor level. If the level's wild bit
+ * is set, then construct the corresponding wildcard name and
+ * search for it. If the wildcard node exists, and is active in
+ * this version, we're done. If not, then we next check to see
+ * if the ancestor is active in this version. If so, then there
+ * can be no possible wildcard match and again we're done. If not,
+ * continue the search.
+ */
+
+ rbtdb = search->rbtdb;
+ i = search->chain.level_matches;
+ done = ISC_FALSE;
+ node = *nodep;
+ do {
+ NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+
+ /*
+ * First we try to figure out if this node is active in
+ * the search's version. We do this now, even though we
+ * may not need the information, because it simplifies the
+ * locking and code flow.
+ */
+ for (header = node->data;
+ header != NULL;
+ header = header->next) {
+ if (header->serial <= search->serial &&
+ !IGNORE(header) && EXISTS(header))
+ break;
+ }
+ if (header != NULL)
+ active = ISC_TRUE;
+ else
+ active = ISC_FALSE;
+
+ if (node->wild)
+ wild = ISC_TRUE;
+ else
+ wild = ISC_FALSE;
+
+ NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+
+ if (wild) {
+ /*
+ * Construct the wildcard name for this level.
+ */
+ dns_name_init(&name, NULL);
+ dns_rbt_namefromnode(node, &name);
+ dns_fixedname_init(&fwname);
+ wname = dns_fixedname_name(&fwname);
+ result = dns_name_concatenate(dns_wildcardname, &name,
+ wname, NULL);
+ j = i;
+ while (result == ISC_R_SUCCESS && j != 0) {
+ j--;
+ level_node = search->chain.levels[j];
+ dns_name_init(&name, NULL);
+ dns_rbt_namefromnode(level_node, &name);
+ result = dns_name_concatenate(wname,
+ &name,
+ wname,
+ NULL);
+ }
+ if (result != ISC_R_SUCCESS)
+ break;
+
+ wnode = NULL;
+ dns_rbtnodechain_init(&wchain, NULL);
+ result = dns_rbt_findnode(rbtdb->tree, wname,
+ NULL, &wnode, &wchain,
+ DNS_RBTFIND_EMPTYDATA,
+ NULL, NULL);
+ if (result == ISC_R_SUCCESS) {
+ nodelock_t *lock;
+
+ /*
+ * We have found the wildcard node. If it
+ * is active in the search's version, we're
+ * done.
+ */
+ lock = &rbtdb->node_locks[wnode->locknum].lock;
+ NODE_LOCK(lock, isc_rwlocktype_read);
+ for (header = wnode->data;
+ header != NULL;
+ header = header->next) {
+ if (header->serial <= search->serial &&
+ !IGNORE(header) && EXISTS(header))
+ break;
+ }
+ NODE_UNLOCK(lock, isc_rwlocktype_read);
+ if (header != NULL ||
+ activeempty(search, &wchain, wname)) {
+ if (activeemtpynode(search, qname,
+ wname)) {
+ return (ISC_R_NOTFOUND);
+ }
+ /*
+ * The wildcard node is active!
+ *
+ * Note: result is still ISC_R_SUCCESS
+ * so we don't have to set it.
+ */
+ *nodep = wnode;
+ break;
+ }
+ } else if (result != ISC_R_NOTFOUND &&
+ result != DNS_R_PARTIALMATCH) {
+ /*
+ * An error has occurred. Bail out.
+ */
+ break;
+ }
+ }
+
+ if (active) {
+ /*
+ * The level node is active. Any wildcarding
+ * present at higher levels has no
+ * effect and we're done.
+ */
+ result = ISC_R_NOTFOUND;
+ break;
+ }
+
+ if (i > 0) {
+ i--;
+ node = search->chain.levels[i];
+ } else
+ done = ISC_TRUE;
+ } while (!done);
+
+ return (result);
+}
+
+static inline isc_result_t
+find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
+ dns_name_t *foundname, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset, isc_boolean_t need_sig)
+{
+ dns_rbtnode_t *node;
+ rdatasetheader_t *header, *header_next, *found, *foundsig;
+ isc_boolean_t empty_node;
+ isc_result_t result;
+ dns_fixedname_t fname, forigin;
+ dns_name_t *name, *origin;
+
+ do {
+ node = NULL;
+ dns_fixedname_init(&fname);
+ name = dns_fixedname_name(&fname);
+ dns_fixedname_init(&forigin);
+ origin = dns_fixedname_name(&forigin);
+ result = dns_rbtnodechain_current(&search->chain, name,
+ origin, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ found = NULL;
+ foundsig = NULL;
+ empty_node = ISC_TRUE;
+ for (header = node->data;
+ header != NULL;
+ header = header_next) {
+ header_next = header->next;
+ /*
+ * Look for an active, extant NSEC or RRSIG NSEC.
+ */
+ do {
+ if (header->serial <= search->serial &&
+ !IGNORE(header)) {
+ /*
+ * Is this a "this rdataset doesn't
+ * exist" record?
+ */
+ if (NONEXISTENT(header))
+ header = NULL;
+ break;
+ } else
+ header = header->down;
+ } while (header != NULL);
+ if (header != NULL) {
+ /*
+ * We now know that there is at least one
+ * active rdataset at this node.
+ */
+ empty_node = ISC_FALSE;
+ if (header->type == dns_rdatatype_nsec) {
+ found = header;
+ if (foundsig != NULL)
+ break;
+ } else if (header->type ==
+ RBTDB_RDATATYPE_SIGNSEC) {
+ foundsig = header;
+ if (found != NULL)
+ break;
+ }
+ }
+ }
+ if (!empty_node) {
+ if (found != NULL &&
+ (foundsig != NULL || !need_sig))
+ {
+ /*
+ * We've found the right NSEC record.
+ *
+ * Note: for this to really be the right
+ * NSEC record, it's essential that the NSEC
+ * records of any nodes obscured by a zone
+ * cut have been removed; we assume this is
+ * the case.
+ */
+ result = dns_name_concatenate(name, origin,
+ foundname, NULL);
+ if (result == ISC_R_SUCCESS) {
+ if (nodep != NULL) {
+ new_reference(search->rbtdb,
+ node);
+ *nodep = node;
+ }
+ bind_rdataset(search->rbtdb, node,
+ found, search->now,
+ rdataset);
+ if (foundsig != NULL)
+ bind_rdataset(search->rbtdb,
+ node,
+ foundsig,
+ search->now,
+ sigrdataset);
+ }
+ } else if (found == NULL && foundsig == NULL) {
+ /*
+ * This node is active, but has no NSEC or
+ * RRSIG NSEC. That means it's glue or
+ * other obscured zone data that isn't
+ * relevant for our search. Treat the
+ * node as if it were empty and keep looking.
+ */
+ empty_node = ISC_TRUE;
+ result = dns_rbtnodechain_prev(&search->chain,
+ NULL, NULL);
+ } else {
+ /*
+ * We found an active node, but either the
+ * NSEC or the RRSIG NSEC is missing. This
+ * shouldn't happen.
+ */
+ result = DNS_R_BADDB;
+ }
+ } else {
+ /*
+ * This node isn't active. We've got to keep
+ * looking.
+ */
+ result = dns_rbtnodechain_prev(&search->chain, NULL,
+ NULL);
+ }
+ NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ } while (empty_node && result == ISC_R_SUCCESS);
+
+ /*
+ * If the result is ISC_R_NOMORE, then we got to the beginning of
+ * the database and didn't find a NSEC record. This shouldn't
+ * happen.
+ */
+ if (result == ISC_R_NOMORE)
+ result = DNS_R_BADDB;
+
+ return (result);
+}
+
+static isc_result_t
+zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
+ dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
+ dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ dns_rbtnode_t *node = NULL;
+ isc_result_t result;
+ rbtdb_search_t search;
+ isc_boolean_t cname_ok = ISC_TRUE;
+ isc_boolean_t close_version = ISC_FALSE;
+ isc_boolean_t maybe_zonecut = ISC_FALSE;
+ isc_boolean_t at_zonecut = ISC_FALSE;
+ isc_boolean_t wild;
+ isc_boolean_t empty_node;
+ rdatasetheader_t *header, *header_next, *found, *nsecheader;
+ rdatasetheader_t *foundsig, *cnamesig, *nsecsig;
+ rbtdb_rdatatype_t sigtype;
+ isc_boolean_t active;
+ dns_rbtnodechain_t chain;
+ nodelock_t *lock;
+
+
+ search.rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(search.rbtdb));
+
+ /*
+ * We don't care about 'now'.
+ */
+ UNUSED(now);
+
+ /*
+ * If the caller didn't supply a version, attach to the current
+ * version.
+ */
+ if (version == NULL) {
+ currentversion(db, &version);
+ close_version = ISC_TRUE;
+ }
+
+ search.rbtversion = version;
+ search.serial = search.rbtversion->serial;
+ search.options = options;
+ search.copy_name = ISC_FALSE;
+ search.need_cleanup = ISC_FALSE;
+ search.wild = ISC_FALSE;
+ search.zonecut = NULL;
+ dns_fixedname_init(&search.zonecut_name);
+ dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
+ search.now = 0;
+
+ /*
+ * 'wild' will be true iff. we've matched a wildcard.
+ */
+ wild = ISC_FALSE;
+
+ RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+
+ /*
+ * Search down from the root of the tree. If, while going down, we
+ * encounter a callback node, zone_zonecut_callback() will search the
+ * rdatasets at the zone cut for active DNAME or NS rdatasets.
+ */
+ result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
+ &search.chain, DNS_RBTFIND_EMPTYDATA,
+ zone_zonecut_callback, &search);
+
+ if (result == DNS_R_PARTIALMATCH) {
+ partial_match:
+ if (search.zonecut != NULL) {
+ result = setup_delegation(&search, nodep, foundname,
+ rdataset, sigrdataset);
+ goto tree_exit;
+ }
+
+ if (search.wild) {
+ /*
+ * At least one of the levels in the search chain
+ * potentially has a wildcard. For each such level,
+ * we must see if there's a matching wildcard active
+ * in the current version.
+ */
+ result = find_wildcard(&search, &node, name);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_name_copy(name, foundname, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto tree_exit;
+ wild = ISC_TRUE;
+ goto found;
+ }
+ else if (result != ISC_R_NOTFOUND)
+ goto tree_exit;
+ }
+
+ chain = search.chain;
+ active = activeempty(&search, &chain, name);
+
+ /*
+ * If we're here, then the name does not exist, is not
+ * beneath a zonecut, and there's no matching wildcard.
+ */
+ if (search.rbtdb->secure ||
+ (search.options & DNS_DBFIND_FORCENSEC) != 0)
+ {
+ result = find_closest_nsec(&search, nodep, foundname,
+ rdataset, sigrdataset,
+ search.rbtdb->secure);
+ if (result == ISC_R_SUCCESS)
+ result = active ? DNS_R_EMPTYNAME :
+ DNS_R_NXDOMAIN;
+ } else
+ result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN;
+ goto tree_exit;
+ } else if (result != ISC_R_SUCCESS)
+ goto tree_exit;
+
+ found:
+ /*
+ * We have found a node whose name is the desired name, or we
+ * have matched a wildcard.
+ */
+
+ if (search.zonecut != NULL) {
+ /*
+ * If we're beneath a zone cut, we don't want to look for
+ * CNAMEs because they're not legitimate zone glue.
+ */
+ cname_ok = ISC_FALSE;
+ } else {
+ /*
+ * The node may be a zone cut itself. If it might be one,
+ * make sure we check for it later.
+ */
+ if (node->find_callback &&
+ (node != search.rbtdb->origin_node ||
+ IS_STUB(search.rbtdb)) &&
+ !dns_rdatatype_atparent(type))
+ maybe_zonecut = ISC_TRUE;
+ }
+
+ /*
+ * Certain DNSSEC types are not subject to CNAME matching
+ * (RFC4035, section 2.5 and RFC3007).
+ *
+ * We don't check for RRSIG, because we don't store RRSIG records
+ * directly.
+ */
+ if (type == dns_rdatatype_key || type == dns_rdatatype_nsec)
+ cname_ok = ISC_FALSE;
+
+ /*
+ * We now go looking for rdata...
+ */
+
+ NODE_LOCK(&(search.rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+
+ found = NULL;
+ foundsig = NULL;
+ sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
+ nsecheader = NULL;
+ nsecsig = NULL;
+ cnamesig = NULL;
+ empty_node = ISC_TRUE;
+ for (header = node->data; header != NULL; header = header_next) {
+ header_next = header->next;
+ /*
+ * Look for an active, extant rdataset.
+ */
+ do {
+ if (header->serial <= search.serial &&
+ !IGNORE(header)) {
+ /*
+ * Is this a "this rdataset doesn't
+ * exist" record?
+ */
+ if (NONEXISTENT(header))
+ header = NULL;
+ break;
+ } else
+ header = header->down;
+ } while (header != NULL);
+ if (header != NULL) {
+ /*
+ * We now know that there is at least one active
+ * rdataset at this node.
+ */
+ empty_node = ISC_FALSE;
+
+ /*
+ * Do special zone cut handling, if requested.
+ */
+ if (maybe_zonecut &&
+ header->type == dns_rdatatype_ns) {
+ /*
+ * We increment the reference count on node to
+ * ensure that search->zonecut_rdataset will
+ * still be valid later.
+ */
+ new_reference(search.rbtdb, node);
+ search.zonecut = node;
+ search.zonecut_rdataset = header;
+ search.zonecut_sigrdataset = NULL;
+ search.need_cleanup = ISC_TRUE;
+ maybe_zonecut = ISC_FALSE;
+ at_zonecut = ISC_TRUE;
+ /*
+ * It is not clear if KEY should still be
+ * allowed at the parent side of the zone
+ * cut or not. It is needed for RFC3007
+ * validated updates.
+ */
+ if ((search.options & DNS_DBFIND_GLUEOK) == 0
+ && type != dns_rdatatype_nsec
+ && type != dns_rdatatype_key) {
+ /*
+ * Glue is not OK, but any answer we
+ * could return would be glue. Return
+ * the delegation.
+ */
+ found = NULL;
+ break;
+ }
+ if (found != NULL && foundsig != NULL)
+ break;
+ }
+
+ /*
+ * If we found a type we were looking for,
+ * remember it.
+ */
+ if (header->type == type ||
+ type == dns_rdatatype_any ||
+ (header->type == dns_rdatatype_cname &&
+ cname_ok)) {
+ /*
+ * We've found the answer!
+ */
+ found = header;
+ if (header->type == dns_rdatatype_cname &&
+ cname_ok) {
+ /*
+ * We may be finding a CNAME instead
+ * of the desired type.
+ *
+ * If we've already got the CNAME RRSIG,
+ * use it, otherwise change sigtype
+ * so that we find it.
+ */
+ if (cnamesig != NULL)
+ foundsig = cnamesig;
+ else
+ sigtype =
+ RBTDB_RDATATYPE_SIGCNAME;
+ }
+ /*
+ * If we've got all we need, end the search.
+ */
+ if (!maybe_zonecut && foundsig != NULL)
+ break;
+ } else if (header->type == sigtype) {
+ /*
+ * We've found the RRSIG rdataset for our
+ * target type. Remember it.
+ */
+ foundsig = header;
+ /*
+ * If we've got all we need, end the search.
+ */
+ if (!maybe_zonecut && found != NULL)
+ break;
+ } else if (header->type == dns_rdatatype_nsec) {
+ /*
+ * Remember a NSEC rdataset even if we're
+ * not specifically looking for it, because
+ * we might need it later.
+ */
+ nsecheader = header;
+ } else if (header->type == RBTDB_RDATATYPE_SIGNSEC) {
+ /*
+ * If we need the NSEC rdataset, we'll also
+ * need its signature.
+ */
+ nsecsig = header;
+ } else if (cname_ok &&
+ header->type == RBTDB_RDATATYPE_SIGCNAME) {
+ /*
+ * If we get a CNAME match, we'll also need
+ * its signature.
+ */
+ cnamesig = header;
+ }
+ }
+ }
+
+ if (empty_node) {
+ /*
+ * We have an exact match for the name, but there are no
+ * active rdatasets in the desired version. That means that
+ * this node doesn't exist in the desired version, and that
+ * we really have a partial match.
+ */
+ if (!wild) {
+ lock = &search.rbtdb->node_locks[node->locknum].lock;
+ NODE_UNLOCK(lock, isc_rwlocktype_read);
+ goto partial_match;
+ }
+ }
+
+ /*
+ * If we didn't find what we were looking for...
+ */
+ if (found == NULL) {
+ if (search.zonecut != NULL) {
+ /*
+ * We were trying to find glue at a node beneath a
+ * zone cut, but didn't.
+ *
+ * Return the delegation.
+ */
+ lock = &search.rbtdb->node_locks[node->locknum].lock;
+ NODE_UNLOCK(lock, isc_rwlocktype_read);
+ result = setup_delegation(&search, nodep, foundname,
+ rdataset, sigrdataset);
+ goto tree_exit;
+ }
+ /*
+ * The desired type doesn't exist.
+ */
+ result = DNS_R_NXRRSET;
+ if (search.rbtdb->secure &&
+ (nsecheader == NULL || nsecsig == NULL)) {
+ /*
+ * The zone is secure but there's no NSEC,
+ * or the NSEC has no signature!
+ */
+ if (!wild) {
+ result = DNS_R_BADDB;
+ goto node_exit;
+ }
+
+ lock = &search.rbtdb->node_locks[node->locknum].lock;
+ NODE_UNLOCK(lock, isc_rwlocktype_read);
+ result = find_closest_nsec(&search, nodep, foundname,
+ rdataset, sigrdataset,
+ search.rbtdb->secure);
+ if (result == ISC_R_SUCCESS)
+ result = DNS_R_EMPTYWILD;
+ goto tree_exit;
+ }
+ if ((search.options & DNS_DBFIND_FORCENSEC) != 0 &&
+ nsecheader == NULL)
+ {
+ /*
+ * There's no NSEC record, and we were told
+ * to find one.
+ */
+ result = DNS_R_BADDB;
+ goto node_exit;
+ }
+ if (nodep != NULL) {
+ new_reference(search.rbtdb, node);
+ *nodep = node;
+ }
+ if (search.rbtdb->secure ||
+ (search.options & DNS_DBFIND_FORCENSEC) != 0)
+ {
+ bind_rdataset(search.rbtdb, node, nsecheader,
+ 0, rdataset);
+ if (nsecsig != NULL)
+ bind_rdataset(search.rbtdb, node,
+ nsecsig, 0, sigrdataset);
+ }
+ if (wild)
+ foundname->attributes |= DNS_NAMEATTR_WILDCARD;
+ goto node_exit;
+ }
+
+ /*
+ * We found what we were looking for, or we found a CNAME.
+ */
+
+ if (type != found->type &&
+ type != dns_rdatatype_any &&
+ found->type == dns_rdatatype_cname) {
+ /*
+ * We weren't doing an ANY query and we found a CNAME instead
+ * of the type we were looking for, so we need to indicate
+ * that result to the caller.
+ */
+ result = DNS_R_CNAME;
+ } else if (search.zonecut != NULL) {
+ /*
+ * If we're beneath a zone cut, we must indicate that the
+ * result is glue, unless we're actually at the zone cut
+ * and the type is NSEC or KEY.
+ */
+ if (search.zonecut == node) {
+ /*
+ * It is not clear if KEY should still be
+ * allowed at the parent side of the zone
+ * cut or not. It is needed for RFC3007
+ * validated updates.
+ */
+ if (type == dns_rdatatype_nsec ||
+ type == dns_rdatatype_key)
+ result = ISC_R_SUCCESS;
+ else if (type == dns_rdatatype_any)
+ result = DNS_R_ZONECUT;
+ else
+ result = DNS_R_GLUE;
+ } else
+ result = DNS_R_GLUE;
+ /*
+ * We might have found data that isn't glue, but was occluded
+ * by a dynamic update. If the caller cares about this, they
+ * will have told us to validate glue.
+ *
+ * XXX We should cache the glue validity state!
+ */
+ if (result == DNS_R_GLUE &&
+ (search.options & DNS_DBFIND_VALIDATEGLUE) != 0 &&
+ !valid_glue(&search, foundname, type, node)) {
+ lock = &search.rbtdb->node_locks[node->locknum].lock;
+ NODE_UNLOCK(lock, isc_rwlocktype_read);
+ result = setup_delegation(&search, nodep, foundname,
+ rdataset, sigrdataset);
+ goto tree_exit;
+ }
+ } else {
+ /*
+ * An ordinary successful query!
+ */
+ result = ISC_R_SUCCESS;
+ }
+
+ if (nodep != NULL) {
+ if (!at_zonecut)
+ new_reference(search.rbtdb, node);
+ else
+ search.need_cleanup = ISC_FALSE;
+ *nodep = node;
+ }
+
+ if (type != dns_rdatatype_any) {
+ bind_rdataset(search.rbtdb, node, found, 0, rdataset);
+ if (foundsig != NULL)
+ bind_rdataset(search.rbtdb, node, foundsig, 0,
+ sigrdataset);
+ }
+
+ if (wild)
+ foundname->attributes |= DNS_NAMEATTR_WILDCARD;
+
+ node_exit:
+ NODE_UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+
+ tree_exit:
+ RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+
+ /*
+ * If we found a zonecut but aren't going to use it, we have to
+ * let go of it.
+ */
+ if (search.need_cleanup) {
+ node = search.zonecut;
+ lock = &(search.rbtdb->node_locks[node->locknum].lock);
+
+ NODE_LOCK(lock, isc_rwlocktype_read);
+ decrement_reference(search.rbtdb, node, 0,
+ isc_rwlocktype_read, isc_rwlocktype_none);
+ NODE_UNLOCK(lock, isc_rwlocktype_read);
+ }
+
+ if (close_version)
+ closeversion(db, &version, ISC_FALSE);
+
+ dns_rbtnodechain_reset(&search.chain);
+
+ return (result);
+}
+
+static isc_result_t
+zone_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
+ isc_stdtime_t now, dns_dbnode_t **nodep,
+ dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ UNUSED(db);
+ UNUSED(name);
+ UNUSED(options);
+ UNUSED(now);
+ UNUSED(nodep);
+ UNUSED(foundname);
+ UNUSED(rdataset);
+ UNUSED(sigrdataset);
+
+ FATAL_ERROR(__FILE__, __LINE__, "zone_findzonecut() called!");
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
+ rbtdb_search_t *search = arg;
+ rdatasetheader_t *header, *header_prev, *header_next;
+ rdatasetheader_t *dname_header, *sigdname_header;
+ isc_result_t result;
+ nodelock_t *lock;
+ isc_rwlocktype_t locktype;
+
+ /* XXX comment */
+
+ REQUIRE(search->zonecut == NULL);
+
+ /*
+ * Keep compiler silent.
+ */
+ UNUSED(name);
+
+ lock = &(search->rbtdb->node_locks[node->locknum].lock);
+ locktype = isc_rwlocktype_read;
+ NODE_LOCK(lock, locktype);
+
+ /*
+ * Look for a DNAME or RRSIG DNAME rdataset.
+ */
+ dname_header = NULL;
+ sigdname_header = NULL;
+ header_prev = NULL;
+ for (header = node->data; header != NULL; header = header_next) {
+ header_next = header->next;
+ if (header->ttl <= search->now) {
+ /*
+ * This rdataset is stale. If no one else is
+ * using the node, we can clean it up right
+ * now, otherwise we mark it as stale, and
+ * the node as dirty, so it will get cleaned
+ * up later.
+ */
+ if ((header->ttl <= search->now - RBTDB_VIRTUAL) &&
+ (locktype == isc_rwlocktype_write ||
+ NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+ /*
+ * We update the node's status only when we
+ * can get write access; otherwise, we leave
+ * others to this work. Periodical cleaning
+ * will eventually take the job as the last
+ * resort.
+ * We won't downgrade the lock, since other
+ * rdatasets are probably stale, too.
+ */
+ locktype = isc_rwlocktype_write;
+
+ if (dns_rbtnode_refcurrent(node) == 0) {
+ isc_mem_t *mctx;
+
+ /*
+ * header->down can be non-NULL if the
+ * refcount has just decremented to 0
+ * but decrement_reference() has not
+ * performed clean_cache_node(), in
+ * which case we need to purge the
+ * stale headers first.
+ */
+ mctx = search->rbtdb->common.mctx;
+ clean_stale_headers(mctx, header);
+ if (header_prev != NULL)
+ header_prev->next =
+ header->next;
+ else
+ node->data = header->next;
+ free_rdataset(mctx, header);
+ } else {
+ header->attributes |=
+ RDATASET_ATTR_STALE;
+ node->dirty = 1;
+ header_prev = header;
+ }
+ } else
+ header_prev = header;
+ } else if (header->type == dns_rdatatype_dname &&
+ EXISTS(header)) {
+ dname_header = header;
+ header_prev = header;
+ } else if (header->type == RBTDB_RDATATYPE_SIGDNAME &&
+ EXISTS(header)) {
+ sigdname_header = header;
+ header_prev = header;
+ } else
+ header_prev = header;
+ }
+
+ if (dname_header != NULL &&
+ (dname_header->trust != dns_trust_pending ||
+ (search->options & DNS_DBFIND_PENDINGOK) != 0)) {
+ /*
+ * We increment the reference count on node to ensure that
+ * search->zonecut_rdataset will still be valid later.
+ */
+ new_reference(search->rbtdb, node);
+ search->zonecut = node;
+ search->zonecut_rdataset = dname_header;
+ search->zonecut_sigrdataset = sigdname_header;
+ search->need_cleanup = ISC_TRUE;
+ result = DNS_R_PARTIALMATCH;
+ } else
+ result = DNS_R_CONTINUE;
+
+ NODE_UNLOCK(lock, locktype);
+
+ return (result);
+}
+
+static inline isc_result_t
+find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
+ dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ unsigned int i;
+ dns_rbtnode_t *level_node;
+ rdatasetheader_t *header, *header_prev, *header_next;
+ rdatasetheader_t *found, *foundsig;
+ isc_result_t result = ISC_R_NOTFOUND;
+ dns_name_t name;
+ dns_rbtdb_t *rbtdb;
+ isc_boolean_t done;
+ nodelock_t *lock;
+ isc_rwlocktype_t locktype;
+
+ /*
+ * Caller must be holding the tree lock.
+ */
+
+ rbtdb = search->rbtdb;
+ i = search->chain.level_matches;
+ done = ISC_FALSE;
+ do {
+ locktype = isc_rwlocktype_read;
+ lock = &rbtdb->node_locks[node->locknum].lock;
+ NODE_LOCK(lock, locktype);
+
+ /*
+ * Look for NS and RRSIG NS rdatasets.
+ */
+ found = NULL;
+ foundsig = NULL;
+ header_prev = NULL;
+ for (header = node->data;
+ header != NULL;
+ header = header_next) {
+ header_next = header->next;
+ if (header->ttl <= search->now) {
+ /*
+ * This rdataset is stale. If no one else is
+ * using the node, we can clean it up right
+ * now, otherwise we mark it as stale, and
+ * the node as dirty, so it will get cleaned
+ * up later.
+ */
+ if ((header->ttl <= search->now -
+ RBTDB_VIRTUAL) &&
+ (locktype == isc_rwlocktype_write ||
+ NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+ /*
+ * We update the node's status only
+ * when we can get write access.
+ */
+ locktype = isc_rwlocktype_write;
+
+ if (dns_rbtnode_refcurrent(node)
+ == 0) {
+ isc_mem_t *m;
+
+ m = search->rbtdb->common.mctx;
+ clean_stale_headers(m, header);
+ if (header_prev != NULL)
+ header_prev->next =
+ header->next;
+ else
+ node->data =
+ header->next;
+ free_rdataset(m, header);
+ } else {
+ header->attributes |=
+ RDATASET_ATTR_STALE;
+ node->dirty = 1;
+ header_prev = header;
+ }
+ } else
+ header_prev = header;
+ } else if (EXISTS(header)) {
+ /*
+ * We've found an extant rdataset. See if
+ * we're interested in it.
+ */
+ if (header->type == dns_rdatatype_ns) {
+ found = header;
+ if (foundsig != NULL)
+ break;
+ } else if (header->type ==
+ RBTDB_RDATATYPE_SIGNS) {
+ foundsig = header;
+ if (found != NULL)
+ break;
+ }
+ header_prev = header;
+ } else
+ header_prev = header;
+ }
+
+ if (found != NULL) {
+ /*
+ * If we have to set foundname, we do it before
+ * anything else. If we were to set foundname after
+ * we had set nodep or bound the rdataset, then we'd
+ * have to undo that work if dns_name_concatenate()
+ * failed. By setting foundname first, there's
+ * nothing to undo if we have trouble.
+ */
+ if (foundname != NULL) {
+ dns_name_init(&name, NULL);
+ dns_rbt_namefromnode(node, &name);
+ result = dns_name_copy(&name, foundname, NULL);
+ while (result == ISC_R_SUCCESS && i > 0) {
+ i--;
+ level_node = search->chain.levels[i];
+ dns_name_init(&name, NULL);
+ dns_rbt_namefromnode(level_node,
+ &name);
+ result =
+ dns_name_concatenate(foundname,
+ &name,
+ foundname,
+ NULL);
+ }
+ if (result != ISC_R_SUCCESS) {
+ *nodep = NULL;
+ goto node_exit;
+ }
+ }
+ result = DNS_R_DELEGATION;
+ if (nodep != NULL) {
+ new_reference(search->rbtdb, node);
+ *nodep = node;
+ }
+ bind_rdataset(search->rbtdb, node, found, search->now,
+ rdataset);
+ if (foundsig != NULL)
+ bind_rdataset(search->rbtdb, node, foundsig,
+ search->now, sigrdataset);
+ }
+
+ node_exit:
+ NODE_UNLOCK(lock, locktype);
+
+ if (found == NULL && i > 0) {
+ i--;
+ node = search->chain.levels[i];
+ } else
+ done = ISC_TRUE;
+
+ } while (!done);
+
+ return (result);
+}
+
+static isc_result_t
+find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
+ isc_stdtime_t now, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ dns_rbtnode_t *node;
+ rdatasetheader_t *header, *header_next, *header_prev;
+ rdatasetheader_t *found, *foundsig;
+ isc_boolean_t empty_node;
+ isc_result_t result;
+ dns_fixedname_t fname, forigin;
+ dns_name_t *name, *origin;
+ rbtdb_rdatatype_t matchtype, sigmatchtype;
+ nodelock_t *lock;
+ isc_rwlocktype_t locktype;
+
+ matchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_nsec, 0);
+ sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig,
+ dns_rdatatype_nsec);
+
+ do {
+ node = NULL;
+ dns_fixedname_init(&fname);
+ name = dns_fixedname_name(&fname);
+ dns_fixedname_init(&forigin);
+ origin = dns_fixedname_name(&forigin);
+ result = dns_rbtnodechain_current(&search->chain, name,
+ origin, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ locktype = isc_rwlocktype_read;
+ lock = &(search->rbtdb->node_locks[node->locknum].lock);
+ NODE_LOCK(lock, locktype);
+ found = NULL;
+ foundsig = NULL;
+ empty_node = ISC_TRUE;
+ header_prev = NULL;
+ for (header = node->data;
+ header != NULL;
+ header = header_next) {
+ header_next = header->next;
+ if (header->ttl <= now) {
+ /*
+ * This rdataset is stale. If no one else is
+ * using the node, we can clean it up right
+ * now, otherwise we mark it as stale, and the
+ * node as dirty, so it will get cleaned up
+ * later.
+ */
+ if ((header->ttl <= now - RBTDB_VIRTUAL) &&
+ (locktype == isc_rwlocktype_write ||
+ NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+ /*
+ * We update the node's status only
+ * when we can get write access.
+ */
+ locktype = isc_rwlocktype_write;
+
+ if (dns_rbtnode_refcurrent(node)
+ == 0) {
+ isc_mem_t *m;
+
+ m = search->rbtdb->common.mctx;
+ clean_stale_headers(m, header);
+ if (header_prev != NULL)
+ header_prev->next =
+ header->next;
+ else
+ node->data = header->next;
+ free_rdataset(m, header);
+ } else {
+ header->attributes |=
+ RDATASET_ATTR_STALE;
+ node->dirty = 1;
+ header_prev = header;
+ }
+ } else
+ header_prev = header;
+ continue;
+ }
+ if (NONEXISTENT(header) ||
+ RBTDB_RDATATYPE_BASE(header->type) == 0) {
+ header_prev = header;
+ continue;
+ }
+ empty_node = ISC_FALSE;
+ if (header->type == matchtype)
+ found = header;
+ else if (header->type == sigmatchtype)
+ foundsig = header;
+ header_prev = header;
+ }
+ if (found != NULL) {
+ result = dns_name_concatenate(name, origin,
+ foundname, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto unlock_node;
+ bind_rdataset(search->rbtdb, node, found,
+ now, rdataset);
+ if (foundsig != NULL)
+ bind_rdataset(search->rbtdb, node, foundsig,
+ now, sigrdataset);
+ new_reference(search->rbtdb, node);
+ *nodep = node;
+ result = DNS_R_COVERINGNSEC;
+ } else if (!empty_node) {
+ result = ISC_R_NOTFOUND;
+ } else
+ result = dns_rbtnodechain_prev(&search->chain, NULL,
+ NULL);
+ unlock_node:
+ NODE_UNLOCK(lock, locktype);
+ } while (empty_node && result == ISC_R_SUCCESS);
+ return (result);
+}
+
+static isc_result_t
+cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
+ dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
+ dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ dns_rbtnode_t *node = NULL;
+ isc_result_t result;
+ rbtdb_search_t search;
+ isc_boolean_t cname_ok = ISC_TRUE;
+ isc_boolean_t empty_node;
+ nodelock_t *lock;
+ isc_rwlocktype_t locktype;
+ rdatasetheader_t *header, *header_prev, *header_next;
+ rdatasetheader_t *found, *nsheader;
+ rdatasetheader_t *foundsig, *nssig, *cnamesig;
+ rbtdb_rdatatype_t sigtype, negtype;
+
+ UNUSED(version);
+
+ search.rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(search.rbtdb));
+ REQUIRE(version == NULL);
+
+ if (now == 0)
+ isc_stdtime_get(&now);
+
+ search.rbtversion = NULL;
+ search.serial = 1;
+ search.options = options;
+ search.copy_name = ISC_FALSE;
+ search.need_cleanup = ISC_FALSE;
+ search.wild = ISC_FALSE;
+ search.zonecut = NULL;
+ dns_fixedname_init(&search.zonecut_name);
+ dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
+ search.now = now;
+
+ RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+
+ /*
+ * Search down from the root of the tree. If, while going down, we
+ * encounter a callback node, cache_zonecut_callback() will search the
+ * rdatasets at the zone cut for a DNAME rdataset.
+ */
+ result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
+ &search.chain, DNS_RBTFIND_EMPTYDATA,
+ cache_zonecut_callback, &search);
+
+ if (result == DNS_R_PARTIALMATCH) {
+ if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0) {
+ result = find_coveringnsec(&search, nodep, now,
+ foundname, rdataset,
+ sigrdataset);
+ if (result == DNS_R_COVERINGNSEC)
+ goto tree_exit;
+ }
+ if (search.zonecut != NULL) {
+ result = setup_delegation(&search, nodep, foundname,
+ rdataset, sigrdataset);
+ goto tree_exit;
+ } else {
+ find_ns:
+ result = find_deepest_zonecut(&search, node, nodep,
+ foundname, rdataset,
+ sigrdataset);
+ goto tree_exit;
+ }
+ } else if (result != ISC_R_SUCCESS)
+ goto tree_exit;
+
+ /*
+ * Certain DNSSEC types are not subject to CNAME matching
+ * (RFC4035, section 2.5 and RFC3007).
+ *
+ * We don't check for RRSIG, because we don't store RRSIG records
+ * directly.
+ */
+ if (type == dns_rdatatype_key || type == dns_rdatatype_nsec)
+ cname_ok = ISC_FALSE;
+
+ /*
+ * We now go looking for rdata...
+ */
+
+ lock = &(search.rbtdb->node_locks[node->locknum].lock);
+ locktype = isc_rwlocktype_read;
+ NODE_LOCK(lock, locktype);
+
+ found = NULL;
+ foundsig = NULL;
+ sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
+ negtype = RBTDB_RDATATYPE_VALUE(0, type);
+ nsheader = NULL;
+ nssig = NULL;
+ cnamesig = NULL;
+ empty_node = ISC_TRUE;
+ header_prev = NULL;
+ for (header = node->data; header != NULL; header = header_next) {
+ header_next = header->next;
+ if (header->ttl <= now) {
+ /*
+ * This rdataset is stale. If no one else is using the
+ * node, we can clean it up right now, otherwise we
+ * mark it as stale, and the node as dirty, so it will
+ * get cleaned up later.
+ */
+ if ((header->ttl <= now - RBTDB_VIRTUAL) &&
+ (locktype == isc_rwlocktype_write ||
+ NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+ /*
+ * We update the node's status only when we
+ * can get write access.
+ */
+ locktype = isc_rwlocktype_write;
+
+ if (dns_rbtnode_refcurrent(node) == 0) {
+ isc_mem_t *mctx;
+
+ mctx = search.rbtdb->common.mctx;
+ clean_stale_headers(mctx, header);
+ if (header_prev != NULL)
+ header_prev->next =
+ header->next;
+ else
+ node->data = header->next;
+ free_rdataset(mctx, header);
+ } else {
+ header->attributes |=
+ RDATASET_ATTR_STALE;
+ node->dirty = 1;
+ header_prev = header;
+ }
+ } else
+ header_prev = header;
+ } else if (EXISTS(header)) {
+ /*
+ * We now know that there is at least one active
+ * non-stale rdataset at this node.
+ */
+ empty_node = ISC_FALSE;
+
+ /*
+ * If we found a type we were looking for, remember
+ * it.
+ */
+ if (header->type == type ||
+ (type == dns_rdatatype_any &&
+ RBTDB_RDATATYPE_BASE(header->type) != 0) ||
+ (cname_ok && header->type ==
+ dns_rdatatype_cname)) {
+ /*
+ * We've found the answer.
+ */
+ found = header;
+ if (header->type == dns_rdatatype_cname &&
+ cname_ok &&
+ cnamesig != NULL) {
+ /*
+ * If we've already got the CNAME RRSIG,
+ * use it, otherwise change sigtype
+ * so that we find it.
+ */
+ if (cnamesig != NULL)
+ foundsig = cnamesig;
+ else
+ sigtype =
+ RBTDB_RDATATYPE_SIGCNAME;
+ foundsig = cnamesig;
+ }
+ } else if (header->type == sigtype) {
+ /*
+ * We've found the RRSIG rdataset for our
+ * target type. Remember it.
+ */
+ foundsig = header;
+ } else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
+ header->type == negtype) {
+ /*
+ * We've found a negative cache entry.
+ */
+ found = header;
+ } else if (header->type == dns_rdatatype_ns) {
+ /*
+ * Remember a NS rdataset even if we're
+ * not specifically looking for it, because
+ * we might need it later.
+ */
+ nsheader = header;
+ } else if (header->type == RBTDB_RDATATYPE_SIGNS) {
+ /*
+ * If we need the NS rdataset, we'll also
+ * need its signature.
+ */
+ nssig = header;
+ } else if (cname_ok &&
+ header->type == RBTDB_RDATATYPE_SIGCNAME) {
+ /*
+ * If we get a CNAME match, we'll also need
+ * its signature.
+ */
+ cnamesig = header;
+ }
+ header_prev = header;
+ } else
+ header_prev = header;
+ }
+
+ if (empty_node) {
+ /*
+ * We have an exact match for the name, but there are no
+ * extant rdatasets. That means that this node doesn't
+ * meaningfully exist, and that we really have a partial match.
+ */
+ NODE_UNLOCK(lock, locktype);
+ goto find_ns;
+ }
+
+ /*
+ * If we didn't find what we were looking for...
+ */
+ if (found == NULL ||
+ (found->trust == dns_trust_glue &&
+ ((options & DNS_DBFIND_GLUEOK) == 0)) ||
+ (found->trust == dns_trust_pending &&
+ ((options & DNS_DBFIND_PENDINGOK) == 0))) {
+ /*
+ * If there is an NS rdataset at this node, then this is the
+ * deepest zone cut.
+ */
+ if (nsheader != NULL) {
+ if (nodep != NULL) {
+ new_reference(search.rbtdb, node);
+ *nodep = node;
+ }
+ bind_rdataset(search.rbtdb, node, nsheader, search.now,
+ rdataset);
+ if (nssig != NULL)
+ bind_rdataset(search.rbtdb, node, nssig,
+ search.now, sigrdataset);
+ result = DNS_R_DELEGATION;
+ goto node_exit;
+ }
+
+ /*
+ * Go find the deepest zone cut.
+ */
+ NODE_UNLOCK(lock, locktype);
+ goto find_ns;
+ }
+
+ /*
+ * We found what we were looking for, or we found a CNAME.
+ */
+
+ if (nodep != NULL) {
+ new_reference(search.rbtdb, node);
+ *nodep = node;
+ }
+
+ if (RBTDB_RDATATYPE_BASE(found->type) == 0) {
+ /*
+ * We found a negative cache entry.
+ */
+ if (NXDOMAIN(found))
+ result = DNS_R_NCACHENXDOMAIN;
+ else
+ result = DNS_R_NCACHENXRRSET;
+ } else if (type != found->type &&
+ type != dns_rdatatype_any &&
+ found->type == dns_rdatatype_cname) {
+ /*
+ * We weren't doing an ANY query and we found a CNAME instead
+ * of the type we were looking for, so we need to indicate
+ * that result to the caller.
+ */
+ result = DNS_R_CNAME;
+ } else {
+ /*
+ * An ordinary successful query!
+ */
+ result = ISC_R_SUCCESS;
+ }
+
+ if (type != dns_rdatatype_any || result == DNS_R_NCACHENXDOMAIN ||
+ result == DNS_R_NCACHENXRRSET) {
+ bind_rdataset(search.rbtdb, node, found, search.now,
+ rdataset);
+ if (foundsig != NULL)
+ bind_rdataset(search.rbtdb, node, foundsig, search.now,
+ sigrdataset);
+ }
+
+ node_exit:
+ NODE_UNLOCK(lock, locktype);
+
+ tree_exit:
+ RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+
+ /*
+ * If we found a zonecut but aren't going to use it, we have to
+ * let go of it.
+ */
+ if (search.need_cleanup) {
+ node = search.zonecut;
+ lock = &(search.rbtdb->node_locks[node->locknum].lock);
+
+ NODE_LOCK(lock, isc_rwlocktype_read);
+ decrement_reference(search.rbtdb, node, 0,
+ isc_rwlocktype_read, isc_rwlocktype_none);
+ NODE_UNLOCK(lock, isc_rwlocktype_read);
+ }
+
+ dns_rbtnodechain_reset(&search.chain);
+
+ return (result);
+}
+
+static isc_result_t
+cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
+ isc_stdtime_t now, dns_dbnode_t **nodep,
+ dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ dns_rbtnode_t *node = NULL;
+ nodelock_t *lock;
+ isc_result_t result;
+ rbtdb_search_t search;
+ rdatasetheader_t *header, *header_prev, *header_next;
+ rdatasetheader_t *found, *foundsig;
+ unsigned int rbtoptions = DNS_RBTFIND_EMPTYDATA;
+ isc_rwlocktype_t locktype;
+
+ search.rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(search.rbtdb));
+
+ if (now == 0)
+ isc_stdtime_get(&now);
+
+ search.rbtversion = NULL;
+ search.serial = 1;
+ search.options = options;
+ search.copy_name = ISC_FALSE;
+ search.need_cleanup = ISC_FALSE;
+ search.wild = ISC_FALSE;
+ search.zonecut = NULL;
+ dns_fixedname_init(&search.zonecut_name);
+ dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
+ search.now = now;
+
+ if ((options & DNS_DBFIND_NOEXACT) != 0)
+ rbtoptions |= DNS_RBTFIND_NOEXACT;
+
+ RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+
+ /*
+ * Search down from the root of the tree.
+ */
+ result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
+ &search.chain, rbtoptions, NULL, &search);
+
+ if (result == DNS_R_PARTIALMATCH) {
+ find_ns:
+ result = find_deepest_zonecut(&search, node, nodep, foundname,
+ rdataset, sigrdataset);
+ goto tree_exit;
+ } else if (result != ISC_R_SUCCESS)
+ goto tree_exit;
+
+ /*
+ * We now go looking for an NS rdataset at the node.
+ */
+
+ lock = &(search.rbtdb->node_locks[node->locknum].lock);
+ locktype = isc_rwlocktype_read;
+ NODE_LOCK(lock, locktype);
+
+ found = NULL;
+ foundsig = NULL;
+ header_prev = NULL;
+ for (header = node->data; header != NULL; header = header_next) {
+ header_next = header->next;
+ if (header->ttl <= now) {
+ /*
+ * This rdataset is stale. If no one else is using the
+ * node, we can clean it up right now, otherwise we
+ * mark it as stale, and the node as dirty, so it will
+ * get cleaned up later.
+ */
+ if ((header->ttl <= now - RBTDB_VIRTUAL) &&
+ (locktype == isc_rwlocktype_write ||
+ NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+ /*
+ * We update the node's status only when we
+ * can get write access.
+ */
+ locktype = isc_rwlocktype_write;
+
+ if (dns_rbtnode_refcurrent(node) == 0) {
+ isc_mem_t *mctx;
+
+ mctx = search.rbtdb->common.mctx;
+ clean_stale_headers(mctx, header);
+ if (header_prev != NULL)
+ header_prev->next =
+ header->next;
+ else
+ node->data = header->next;
+ free_rdataset(mctx, header);
+ } else {
+ header->attributes |=
+ RDATASET_ATTR_STALE;
+ node->dirty = 1;
+ header_prev = header;
+ }
+ } else
+ header_prev = header;
+ } else if (EXISTS(header)) {
+ /*
+ * If we found a type we were looking for, remember
+ * it.
+ */
+ if (header->type == dns_rdatatype_ns) {
+ /*
+ * Remember a NS rdataset even if we're
+ * not specifically looking for it, because
+ * we might need it later.
+ */
+ found = header;
+ } else if (header->type == RBTDB_RDATATYPE_SIGNS) {
+ /*
+ * If we need the NS rdataset, we'll also
+ * need its signature.
+ */
+ foundsig = header;
+ }
+ header_prev = header;
+ } else
+ header_prev = header;
+ }
+
+ if (found == NULL) {
+ /*
+ * No NS records here.
+ */
+ NODE_UNLOCK(lock, locktype);
+ goto find_ns;
+ }
+
+ if (nodep != NULL) {
+ new_reference(search.rbtdb, node);
+ *nodep = node;
+ }
+
+ bind_rdataset(search.rbtdb, node, found, search.now, rdataset);
+ if (foundsig != NULL)
+ bind_rdataset(search.rbtdb, node, foundsig, search.now,
+ sigrdataset);
+
+ NODE_UNLOCK(lock, locktype);
+
+ tree_exit:
+ RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+
+ INSIST(!search.need_cleanup);
+
+ dns_rbtnodechain_reset(&search.chain);
+
+ if (result == DNS_R_DELEGATION)
+ result = ISC_R_SUCCESS;
+
+ return (result);
+}
+
+static void
+attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *node = (dns_rbtnode_t *)source;
+ unsigned int refs;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
+ dns_rbtnode_refincrement(node, &refs);
+ INSIST(refs != 0);
+ NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+
+ *targetp = source;
+}
+
+static void
+detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *node;
+ isc_boolean_t want_free = ISC_FALSE;
+ isc_boolean_t inactive = ISC_FALSE;
+ rbtdb_nodelock_t *nodelock;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+ REQUIRE(targetp != NULL && *targetp != NULL);
+
+ node = (dns_rbtnode_t *)(*targetp);
+ nodelock = &rbtdb->node_locks[node->locknum];
+
+ NODE_LOCK(&nodelock->lock, isc_rwlocktype_read);
+
+ if (decrement_reference(rbtdb, node, 0, isc_rwlocktype_read,
+ isc_rwlocktype_none)) {
+ if (isc_refcount_current(&nodelock->references) == 0 &&
+ nodelock->exiting) {
+ inactive = ISC_TRUE;
+ }
+ }
+
+ NODE_UNLOCK(&nodelock->lock, isc_rwlocktype_read);
+
+ *targetp = NULL;
+
+ if (inactive) {
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+ rbtdb->active--;
+ if (rbtdb->active == 0)
+ want_free = ISC_TRUE;
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+ if (want_free) {
+ char buf[DNS_NAME_FORMATSIZE];
+ if (dns_name_dynamic(&rbtdb->common.origin))
+ dns_name_format(&rbtdb->common.origin, buf,
+ sizeof(buf));
+ else
+ strcpy(buf, "<UNKNOWN>");
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+ "calling free_rbtdb(%s)", buf);
+ free_rbtdb(rbtdb, ISC_TRUE, NULL);
+ }
+ }
+}
+
+static isc_result_t
+expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *rbtnode = node;
+ rdatasetheader_t *header;
+ isc_boolean_t force_expire = ISC_FALSE;
+ /*
+ * These are the category and module used by the cache cleaner.
+ */
+ isc_boolean_t log = ISC_FALSE;
+ isc_logcategory_t *category = DNS_LOGCATEGORY_DATABASE;
+ isc_logmodule_t *module = DNS_LOGMODULE_CACHE;
+ int level = ISC_LOG_DEBUG(2);
+ char printname[DNS_NAME_FORMATSIZE];
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ /*
+ * Caller must hold a tree lock.
+ */
+
+ if (now == 0)
+ isc_stdtime_get(&now);
+
+ if (rbtdb->overmem) {
+ isc_uint32_t val;
+
+ isc_random_get(&val);
+ /*
+ * XXXDCL Could stand to have a better policy, like LRU.
+ */
+ force_expire = ISC_TF(rbtnode->down == NULL && val % 4 == 0);
+
+ /*
+ * Note that 'log' can be true IFF rbtdb->overmem is also true.
+ * rbtdb->ovemem can currently only be true for cache databases
+ * -- hence all of the "overmem cache" log strings.
+ */
+ log = ISC_TF(isc_log_wouldlog(dns_lctx, level));
+ if (log)
+ isc_log_write(dns_lctx, category, module, level,
+ "overmem cache: %s %s",
+ force_expire ? "FORCE" : "check",
+ dns_rbt_formatnodename(rbtnode,
+ printname,
+ sizeof(printname)));
+ }
+
+ /*
+ * We may not need write access, but this code path is not performance
+ * sensitive, so it should be okay to always lock as a writer.
+ */
+ NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_write);
+
+ for (header = rbtnode->data; header != NULL; header = header->next)
+ if (header->ttl <= now - RBTDB_VIRTUAL) {
+ /*
+ * We don't check if refcurrent(rbtnode) == 0 and try
+ * to free like we do in cache_find(), because
+ * refcurrent(rbtnode) must be non-zero. This is so
+ * because 'node' is an argument to the function.
+ */
+ header->attributes |= RDATASET_ATTR_STALE;
+ rbtnode->dirty = 1;
+ if (log)
+ isc_log_write(dns_lctx, category, module,
+ level, "overmem cache: stale %s",
+ printname);
+ } else if (force_expire) {
+ if (! RETAIN(header)) {
+ header->ttl = 0;
+ header->attributes |= RDATASET_ATTR_STALE;
+ rbtnode->dirty = 1;
+ } else if (log) {
+ isc_log_write(dns_lctx, category, module,
+ level, "overmem cache: "
+ "reprieve by RETAIN() %s",
+ printname);
+ }
+ } else if (rbtdb->overmem && log)
+ isc_log_write(dns_lctx, category, module, level,
+ "overmem cache: saved %s", printname);
+
+ NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_write);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+overmem(dns_db_t *db, isc_boolean_t overmem) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+
+ if (IS_CACHE(rbtdb)) {
+ rbtdb->overmem = overmem;
+ }
+}
+
+static void
+printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *rbtnode = node;
+ isc_boolean_t first;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_read);
+
+ fprintf(out, "node %p, %u references, locknum = %u\n",
+ rbtnode, dns_rbtnode_refcurrent(rbtnode),
+ rbtnode->locknum);
+ if (rbtnode->data != NULL) {
+ rdatasetheader_t *current, *top_next;
+
+ for (current = rbtnode->data; current != NULL;
+ current = top_next) {
+ top_next = current->next;
+ first = ISC_TRUE;
+ fprintf(out, "\ttype %u", current->type);
+ do {
+ if (!first)
+ fprintf(out, "\t");
+ first = ISC_FALSE;
+ fprintf(out,
+ "\tserial = %lu, ttl = %u, "
+ "trust = %u, attributes = %u\n",
+ (unsigned long)current->serial,
+ current->ttl,
+ current->trust,
+ current->attributes);
+ current = current->down;
+ } while (current != NULL);
+ }
+ } else
+ fprintf(out, "(empty)\n");
+
+ NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_read);
+}
+
+static isc_result_t
+createiterator(dns_db_t *db, isc_boolean_t relative_names,
+ dns_dbiterator_t **iteratorp)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ rbtdb_dbiterator_t *rbtdbiter;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ rbtdbiter = isc_mem_get(rbtdb->common.mctx, sizeof(*rbtdbiter));
+ if (rbtdbiter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ rbtdbiter->common.methods = &dbiterator_methods;
+ rbtdbiter->common.db = NULL;
+ dns_db_attach(db, &rbtdbiter->common.db);
+ rbtdbiter->common.relative_names = relative_names;
+ rbtdbiter->common.magic = DNS_DBITERATOR_MAGIC;
+ rbtdbiter->common.cleaning = ISC_FALSE;
+ rbtdbiter->paused = ISC_TRUE;
+ rbtdbiter->tree_locked = isc_rwlocktype_none;
+ rbtdbiter->result = ISC_R_SUCCESS;
+ dns_fixedname_init(&rbtdbiter->name);
+ dns_fixedname_init(&rbtdbiter->origin);
+ rbtdbiter->node = NULL;
+ rbtdbiter->delete = 0;
+ memset(rbtdbiter->deletions, 0, sizeof(rbtdbiter->deletions));
+ dns_rbtnodechain_init(&rbtdbiter->chain, db->mctx);
+
+ *iteratorp = (dns_dbiterator_t *)rbtdbiter;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers,
+ isc_stdtime_t now, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+ rdatasetheader_t *header, *header_next, *found, *foundsig;
+ rbtdb_serial_t serial;
+ rbtdb_version_t *rbtversion = version;
+ isc_boolean_t close_version = ISC_FALSE;
+ rbtdb_rdatatype_t matchtype, sigmatchtype;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+ REQUIRE(type != dns_rdatatype_any);
+
+ if (rbtversion == NULL) {
+ currentversion(db, (dns_dbversion_t **) (void *)(&rbtversion));
+ close_version = ISC_TRUE;
+ }
+ serial = rbtversion->serial;
+ now = 0;
+
+ NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_read);
+
+ found = NULL;
+ foundsig = NULL;
+ matchtype = RBTDB_RDATATYPE_VALUE(type, covers);
+ if (covers == 0)
+ sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
+ else
+ sigmatchtype = 0;
+
+ for (header = rbtnode->data; header != NULL; header = header_next) {
+ header_next = header->next;
+ do {
+ if (header->serial <= serial &&
+ !IGNORE(header)) {
+ /*
+ * Is this a "this rdataset doesn't
+ * exist" record?
+ */
+ if (NONEXISTENT(header))
+ header = NULL;
+ break;
+ } else
+ header = header->down;
+ } while (header != NULL);
+ if (header != NULL) {
+ /*
+ * We have an active, extant rdataset. If it's a
+ * type we're looking for, remember it.
+ */
+ if (header->type == matchtype) {
+ found = header;
+ if (foundsig != NULL)
+ break;
+ } else if (header->type == sigmatchtype) {
+ foundsig = header;
+ if (found != NULL)
+ break;
+ }
+ }
+ }
+ if (found != NULL) {
+ bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
+ if (foundsig != NULL)
+ bind_rdataset(rbtdb, rbtnode, foundsig, now,
+ sigrdataset);
+ }
+
+ NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_read);
+
+ if (close_version)
+ closeversion(db, (dns_dbversion_t **) (void *)(&rbtversion),
+ ISC_FALSE);
+
+ if (found == NULL)
+ return (ISC_R_NOTFOUND);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers,
+ isc_stdtime_t now, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+ rdatasetheader_t *header, *header_next, *found, *foundsig;
+ rbtdb_rdatatype_t matchtype, sigmatchtype, negtype;
+ isc_result_t result;
+ nodelock_t *lock;
+ isc_rwlocktype_t locktype;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+ REQUIRE(type != dns_rdatatype_any);
+
+ UNUSED(version);
+
+ result = ISC_R_SUCCESS;
+
+ if (now == 0)
+ isc_stdtime_get(&now);
+
+ lock = &rbtdb->node_locks[rbtnode->locknum].lock;
+ locktype = isc_rwlocktype_read;
+ NODE_LOCK(lock, locktype);
+
+ found = NULL;
+ foundsig = NULL;
+ matchtype = RBTDB_RDATATYPE_VALUE(type, covers);
+ negtype = RBTDB_RDATATYPE_VALUE(0, type);
+ if (covers == 0)
+ sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
+ else
+ sigmatchtype = 0;
+
+ for (header = rbtnode->data; header != NULL; header = header_next) {
+ header_next = header->next;
+ if (header->ttl <= now) {
+ if ((header->ttl <= now - RBTDB_VIRTUAL) &&
+ (locktype == isc_rwlocktype_write ||
+ NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+ /*
+ * We update the node's status only when we
+ * can get write access.
+ */
+ locktype = isc_rwlocktype_write;
+
+ /*
+ * We don't check if refcurrent(rbtnode) == 0
+ * and try to free like we do in cache_find(),
+ * because refcurrent(rbtnode) must be
+ * non-zero. This is so because 'node' is an
+ * argument to the function.
+ */
+ header->attributes |= RDATASET_ATTR_STALE;
+ rbtnode->dirty = 1;
+ }
+ } else if (EXISTS(header)) {
+ if (header->type == matchtype)
+ found = header;
+ else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
+ header->type == negtype)
+ found = header;
+ else if (header->type == sigmatchtype)
+ foundsig = header;
+ }
+ }
+ if (found != NULL) {
+ bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
+ if (foundsig != NULL)
+ bind_rdataset(rbtdb, rbtnode, foundsig, now,
+ sigrdataset);
+ }
+
+ NODE_UNLOCK(lock, locktype);
+
+ if (found == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (RBTDB_RDATATYPE_BASE(found->type) == 0) {
+ /*
+ * We found a negative cache entry.
+ */
+ if (NXDOMAIN(found))
+ result = DNS_R_NCACHENXDOMAIN;
+ else
+ result = DNS_R_NCACHENXRRSET;
+ }
+
+ return (result);
+}
+
+static isc_result_t
+allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+ rbtdb_version_t *rbtversion = version;
+ rbtdb_rdatasetiter_t *iterator;
+ unsigned int refs;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ iterator = isc_mem_get(rbtdb->common.mctx, sizeof(*iterator));
+ if (iterator == NULL)
+ return (ISC_R_NOMEMORY);
+
+ if ((db->attributes & DNS_DBATTR_CACHE) == 0) {
+ now = 0;
+ if (rbtversion == NULL)
+ currentversion(db,
+ (dns_dbversion_t **) (void *)(&rbtversion));
+ else {
+ unsigned int refs;
+
+ isc_refcount_increment(&rbtversion->references,
+ &refs);
+ INSIST(refs > 1);
+ }
+ } else {
+ if (now == 0)
+ isc_stdtime_get(&now);
+ rbtversion = NULL;
+ }
+
+ iterator->common.magic = DNS_RDATASETITER_MAGIC;
+ iterator->common.methods = &rdatasetiter_methods;
+ iterator->common.db = db;
+ iterator->common.node = node;
+ iterator->common.version = (dns_dbversion_t *)rbtversion;
+ iterator->common.now = now;
+
+ NODE_STRONGLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
+
+ dns_rbtnode_refincrement(rbtnode, &refs);
+ INSIST(refs != 0);
+
+ iterator->current = NULL;
+
+ NODE_STRONGUNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
+
+ *iteratorp = (dns_rdatasetiter_t *)iterator;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_boolean_t
+cname_and_other_data(dns_rbtnode_t *node, rbtdb_serial_t serial) {
+ rdatasetheader_t *header, *header_next;
+ isc_boolean_t cname, other_data;
+ dns_rdatatype_t rdtype;
+
+ /*
+ * The caller must hold the node lock.
+ */
+
+ /*
+ * Look for CNAME and "other data" rdatasets active in our version.
+ */
+ cname = ISC_FALSE;
+ other_data = ISC_FALSE;
+ for (header = node->data; header != NULL; header = header_next) {
+ header_next = header->next;
+ if (header->type == dns_rdatatype_cname) {
+ /*
+ * Look for an active extant CNAME.
+ */
+ do {
+ if (header->serial <= serial &&
+ !IGNORE(header)) {
+ /*
+ * Is this a "this rdataset doesn't
+ * exist" record?
+ */
+ if (NONEXISTENT(header))
+ header = NULL;
+ break;
+ } else
+ header = header->down;
+ } while (header != NULL);
+ if (header != NULL)
+ cname = ISC_TRUE;
+ } else {
+ /*
+ * Look for active extant "other data".
+ *
+ * "Other data" is any rdataset whose type is not
+ * KEY, RRSIG KEY, NSEC, RRSIG NSEC or RRSIG CNAME.
+ */
+ rdtype = RBTDB_RDATATYPE_BASE(header->type);
+ if (rdtype == dns_rdatatype_rrsig ||
+ rdtype == dns_rdatatype_sig)
+ rdtype = RBTDB_RDATATYPE_EXT(header->type);
+ if (rdtype != dns_rdatatype_nsec &&
+ rdtype != dns_rdatatype_key &&
+ rdtype != dns_rdatatype_cname) {
+ /*
+ * We've found a type that isn't
+ * NSEC, KEY, CNAME, or one of their
+ * signatures. Is it active and extant?
+ */
+ do {
+ if (header->serial <= serial &&
+ !IGNORE(header)) {
+ /*
+ * Is this a "this rdataset
+ * doesn't exist" record?
+ */
+ if (NONEXISTENT(header))
+ header = NULL;
+ break;
+ } else
+ header = header->down;
+ } while (header != NULL);
+ if (header != NULL)
+ other_data = ISC_TRUE;
+ }
+ }
+ }
+
+ if (cname && other_data)
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
+ rdatasetheader_t *newheader, unsigned int options, isc_boolean_t loading,
+ dns_rdataset_t *addedrdataset, isc_stdtime_t now)
+{
+ rbtdb_changed_t *changed = NULL;
+ rdatasetheader_t *topheader, *topheader_prev, *header;
+ unsigned char *merged;
+ isc_result_t result;
+ isc_boolean_t header_nx;
+ isc_boolean_t newheader_nx;
+ isc_boolean_t merge;
+ dns_rdatatype_t rdtype, covers;
+ rbtdb_rdatatype_t negtype;
+ dns_trust_t trust;
+
+ /*
+ * Add an rdatasetheader_t to a node.
+ */
+
+ /*
+ * Caller must be holding the node lock.
+ */
+
+ if ((options & DNS_DBADD_MERGE) != 0) {
+ REQUIRE(rbtversion != NULL);
+ merge = ISC_TRUE;
+ } else
+ merge = ISC_FALSE;
+
+ if ((options & DNS_DBADD_FORCE) != 0)
+ trust = dns_trust_ultimate;
+ else
+ trust = newheader->trust;
+
+ if (rbtversion != NULL && !loading) {
+ /*
+ * We always add a changed record, even if no changes end up
+ * being made to this node, because it's harmless and
+ * simplifies the code.
+ */
+ changed = add_changed(rbtdb, rbtversion, rbtnode);
+ if (changed == NULL) {
+ free_rdataset(rbtdb->common.mctx, newheader);
+ return (ISC_R_NOMEMORY);
+ }
+ }
+
+ newheader_nx = NONEXISTENT(newheader) ? ISC_TRUE : ISC_FALSE;
+ topheader_prev = NULL;
+
+ negtype = 0;
+ if (rbtversion == NULL && !newheader_nx) {
+ rdtype = RBTDB_RDATATYPE_BASE(newheader->type);
+ if (rdtype == 0) {
+ /*
+ * We're adding a negative cache entry.
+ */
+ covers = RBTDB_RDATATYPE_EXT(newheader->type);
+ if (covers == dns_rdatatype_any) {
+ /*
+ * We're adding an negative cache entry
+ * which covers all types (NXDOMAIN,
+ * NODATA(QTYPE=ANY)).
+ *
+ * We make all other data stale so that the
+ * only rdataset that can be found at this
+ * node is the negative cache entry.
+ */
+ for (topheader = rbtnode->data;
+ topheader != NULL;
+ topheader = topheader->next) {
+ topheader->ttl = 0;
+ topheader->attributes |=
+ RDATASET_ATTR_STALE;
+ }
+ rbtnode->dirty = 1;
+ goto find_header;
+ }
+ negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
+ } else {
+ /*
+ * We're adding something that isn't a
+ * negative cache entry. Look for an extant
+ * non-stale NXDOMAIN/NODATA(QTYPE=ANY) negative
+ * cache entry.
+ */
+ for (topheader = rbtnode->data;
+ topheader != NULL;
+ topheader = topheader->next) {
+ if (topheader->type ==
+ RBTDB_RDATATYPE_NCACHEANY)
+ break;
+ }
+ if (topheader != NULL && EXISTS(topheader) &&
+ topheader->ttl > now) {
+ /*
+ * Found one.
+ */
+ if (trust < topheader->trust) {
+ /*
+ * The NXDOMAIN/NODATA(QTYPE=ANY)
+ * is more trusted.
+ */
+
+ free_rdataset(rbtdb->common.mctx,
+ newheader);
+ if (addedrdataset != NULL)
+ bind_rdataset(rbtdb, rbtnode,
+ topheader, now,
+ addedrdataset);
+ return (DNS_R_UNCHANGED);
+ }
+ /*
+ * The new rdataset is better. Expire the
+ * NXDOMAIN/NODATA(QTYPE=ANY).
+ */
+ topheader->ttl = 0;
+ topheader->attributes |= RDATASET_ATTR_STALE;
+ rbtnode->dirty = 1;
+ topheader = NULL;
+ goto find_header;
+ }
+ negtype = RBTDB_RDATATYPE_VALUE(0, rdtype);
+ }
+ }
+
+ for (topheader = rbtnode->data;
+ topheader != NULL;
+ topheader = topheader->next) {
+ if (topheader->type == newheader->type ||
+ topheader->type == negtype)
+ break;
+ topheader_prev = topheader;
+ }
+
+ find_header:
+ /*
+ * If header isn't NULL, we've found the right type. There may be
+ * IGNORE rdatasets between the top of the chain and the first real
+ * data. We skip over them.
+ */
+ header = topheader;
+ while (header != NULL && IGNORE(header))
+ header = header->down;
+ if (header != NULL) {
+ header_nx = NONEXISTENT(header) ? ISC_TRUE : ISC_FALSE;
+
+ /*
+ * Deleting an already non-existent rdataset has no effect.
+ */
+ if (header_nx && newheader_nx) {
+ free_rdataset(rbtdb->common.mctx, newheader);
+ return (DNS_R_UNCHANGED);
+ }
+
+ /*
+ * Trying to add an rdataset with lower trust to a cache DB
+ * has no effect, provided that the cache data isn't stale.
+ */
+ if (rbtversion == NULL && trust < header->trust &&
+ (header->ttl > now || header_nx)) {
+ free_rdataset(rbtdb->common.mctx, newheader);
+ if (addedrdataset != NULL)
+ bind_rdataset(rbtdb, rbtnode, header, now,
+ addedrdataset);
+ return (DNS_R_UNCHANGED);
+ }
+
+ /*
+ * Don't merge if a nonexistent rdataset is involved.
+ */
+ if (merge && (header_nx || newheader_nx))
+ merge = ISC_FALSE;
+
+ /*
+ * If 'merge' is ISC_TRUE, we'll try to create a new rdataset
+ * that is the union of 'newheader' and 'header'.
+ */
+ if (merge) {
+ unsigned int flags = 0;
+ INSIST(rbtversion->serial >= header->serial);
+ merged = NULL;
+ result = ISC_R_SUCCESS;
+
+ if ((options & DNS_DBADD_EXACT) != 0)
+ flags |= DNS_RDATASLAB_EXACT;
+ if ((options & DNS_DBADD_EXACTTTL) != 0 &&
+ newheader->ttl != header->ttl)
+ result = DNS_R_NOTEXACT;
+ else if (newheader->ttl != header->ttl)
+ flags |= DNS_RDATASLAB_FORCE;
+ if (result == ISC_R_SUCCESS)
+ result = dns_rdataslab_merge(
+ (unsigned char *)header,
+ (unsigned char *)newheader,
+ (unsigned int)(sizeof(*newheader)),
+ rbtdb->common.mctx,
+ rbtdb->common.rdclass,
+ (dns_rdatatype_t)header->type,
+ flags, &merged);
+ if (result == ISC_R_SUCCESS) {
+ /*
+ * If 'header' has the same serial number as
+ * we do, we could clean it up now if we knew
+ * that our caller had no references to it.
+ * We don't know this, however, so we leave it
+ * alone. It will get cleaned up when
+ * clean_zone_node() runs.
+ */
+ free_rdataset(rbtdb->common.mctx, newheader);
+ newheader = (rdatasetheader_t *)merged;
+ } else {
+ free_rdataset(rbtdb->common.mctx, newheader);
+ return (result);
+ }
+ }
+ /*
+ * Don't replace existing NS, A and AAAA RRsets
+ * in the cache if they are already exist. This
+ * prevents named being locked to old servers.
+ * Don't lower trust of existing record if the
+ * update is forced.
+ */
+ if (IS_CACHE(rbtdb) && header->ttl > now &&
+ header->type == dns_rdatatype_ns &&
+ !header_nx && !newheader_nx &&
+ header->trust >= newheader->trust &&
+ dns_rdataslab_equalx((unsigned char *)header,
+ (unsigned char *)newheader,
+ (unsigned int)(sizeof(*newheader)),
+ rbtdb->common.rdclass,
+ (dns_rdatatype_t)header->type)) {
+ /*
+ * Honour the new ttl if it is less than the
+ * older one.
+ */
+ if (header->ttl > newheader->ttl)
+ header->ttl = newheader->ttl;
+ if (header->noqname == NULL &&
+ newheader->noqname != NULL) {
+ header->noqname = newheader->noqname;
+ newheader->noqname = NULL;
+ }
+ free_rdataset(rbtdb->common.mctx, newheader);
+ if (addedrdataset != NULL)
+ bind_rdataset(rbtdb, rbtnode, header, now,
+ addedrdataset);
+ return (ISC_R_SUCCESS);
+ }
+ if (IS_CACHE(rbtdb) && header->ttl > now &&
+ (header->type == dns_rdatatype_a ||
+ header->type == dns_rdatatype_aaaa) &&
+ !header_nx && !newheader_nx &&
+ header->trust >= newheader->trust &&
+ dns_rdataslab_equal((unsigned char *)header,
+ (unsigned char *)newheader,
+ (unsigned int)(sizeof(*newheader)))) {
+ /*
+ * Honour the new ttl if it is less than the
+ * older one.
+ */
+ if (header->ttl > newheader->ttl)
+ header->ttl = newheader->ttl;
+ if (header->noqname == NULL &&
+ newheader->noqname != NULL) {
+ header->noqname = newheader->noqname;
+ newheader->noqname = NULL;
+ }
+ free_rdataset(rbtdb->common.mctx, newheader);
+ if (addedrdataset != NULL)
+ bind_rdataset(rbtdb, rbtnode, header, now,
+ addedrdataset);
+ return (ISC_R_SUCCESS);
+ }
+ INSIST(rbtversion == NULL ||
+ rbtversion->serial >= topheader->serial);
+ if (topheader_prev != NULL)
+ topheader_prev->next = newheader;
+ else
+ rbtnode->data = newheader;
+ newheader->next = topheader->next;
+ if (loading) {
+ /*
+ * There are no other references to 'header' when
+ * loading, so we MAY clean up 'header' now.
+ * Since we don't generate changed records when
+ * loading, we MUST clean up 'header' now.
+ */
+ newheader->down = NULL;
+ free_rdataset(rbtdb->common.mctx, header);
+ } else {
+ newheader->down = topheader;
+ topheader->next = newheader;
+ rbtnode->dirty = 1;
+ if (changed != NULL)
+ changed->dirty = ISC_TRUE;
+ if (rbtversion == NULL) {
+ header->ttl = 0;
+ header->attributes |= RDATASET_ATTR_STALE;
+ }
+ }
+ } else {
+ /*
+ * No non-IGNORED rdatasets of the given type exist at
+ * this node.
+ */
+
+ /*
+ * If we're trying to delete the type, don't bother.
+ */
+ if (newheader_nx) {
+ free_rdataset(rbtdb->common.mctx, newheader);
+ return (DNS_R_UNCHANGED);
+ }
+
+ if (topheader != NULL) {
+ /*
+ * We have an list of rdatasets of the given type,
+ * but they're all marked IGNORE. We simply insert
+ * the new rdataset at the head of the list.
+ *
+ * Ignored rdatasets cannot occur during loading, so
+ * we INSIST on it.
+ */
+ INSIST(!loading);
+ INSIST(rbtversion == NULL ||
+ rbtversion->serial >= topheader->serial);
+ if (topheader_prev != NULL)
+ topheader_prev->next = newheader;
+ else
+ rbtnode->data = newheader;
+ newheader->next = topheader->next;
+ newheader->down = topheader;
+ topheader->next = newheader;
+ rbtnode->dirty = 1;
+ if (changed != NULL)
+ changed->dirty = ISC_TRUE;
+ } else {
+ /*
+ * No rdatasets of the given type exist at the node.
+ */
+ newheader->next = rbtnode->data;
+ newheader->down = NULL;
+ rbtnode->data = newheader;
+ }
+ }
+
+ /*
+ * Check if the node now contains CNAME and other data.
+ */
+ if (rbtversion != NULL &&
+ cname_and_other_data(rbtnode, rbtversion->serial))
+ return (DNS_R_CNAMEANDOTHER);
+
+ if (addedrdataset != NULL)
+ bind_rdataset(rbtdb, rbtnode, newheader, now, addedrdataset);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_boolean_t
+delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
+ rbtdb_rdatatype_t type)
+{
+ if (IS_CACHE(rbtdb)) {
+ if (type == dns_rdatatype_dname)
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+ } else if (type == dns_rdatatype_dname ||
+ (type == dns_rdatatype_ns &&
+ (node != rbtdb->origin_node || IS_STUB(rbtdb))))
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+static inline isc_result_t
+addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
+ dns_rdataset_t *rdataset)
+{
+ struct noqname *noqname;
+ isc_mem_t *mctx = rbtdb->common.mctx;
+ dns_name_t name;
+ dns_rdataset_t nsec, nsecsig;
+ isc_result_t result;
+ isc_region_t r;
+
+ dns_name_init(&name, NULL);
+ dns_rdataset_init(&nsec);
+ dns_rdataset_init(&nsecsig);
+
+ result = dns_rdataset_getnoqname(rdataset, &name, &nsec, &nsecsig);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ noqname = isc_mem_get(mctx, sizeof(*noqname));
+ if (noqname == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ dns_name_init(&noqname->name, NULL);
+ noqname->nsec = NULL;
+ noqname->nsecsig = NULL;
+ result = dns_name_dup(&name, mctx, &noqname->name);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_rdataslab_fromrdataset(&nsec, mctx, &r, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ noqname->nsec = r.base;
+ result = dns_rdataslab_fromrdataset(&nsecsig, mctx, &r, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ noqname->nsecsig = r.base;
+ dns_rdataset_disassociate(&nsec);
+ dns_rdataset_disassociate(&nsecsig);
+ newheader->noqname = noqname;
+ return (ISC_R_SUCCESS);
+
+cleanup:
+ dns_rdataset_disassociate(&nsec);
+ dns_rdataset_disassociate(&nsecsig);
+ free_noqname(mctx, &noqname);
+ return(result);
+}
+
+static isc_result_t
+addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
+ dns_rdataset_t *addedrdataset)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+ rbtdb_version_t *rbtversion = version;
+ isc_region_t region;
+ rdatasetheader_t *newheader;
+ isc_result_t result;
+ isc_boolean_t delegating;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ if (rbtversion == NULL) {
+ if (now == 0)
+ isc_stdtime_get(&now);
+ } else
+ now = 0;
+
+ result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
+ &region,
+ sizeof(rdatasetheader_t));
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ newheader = (rdatasetheader_t *)region.base;
+ newheader->ttl = rdataset->ttl + now;
+ newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
+ rdataset->covers);
+ newheader->attributes = 0;
+ newheader->noqname = NULL;
+ newheader->count = init_count++;
+ newheader->trust = rdataset->trust;
+ newheader->additional_auth = NULL;
+ newheader->additional_glue = NULL;
+ if (rbtversion != NULL) {
+ newheader->serial = rbtversion->serial;
+ now = 0;
+ } else {
+ newheader->serial = 1;
+ if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
+ newheader->attributes |= RDATASET_ATTR_NXDOMAIN;
+ if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
+ result = addnoqname(rbtdb, newheader, rdataset);
+ if (result != ISC_R_SUCCESS) {
+ free_rdataset(rbtdb->common.mctx, newheader);
+ return (result);
+ }
+ }
+ }
+
+ /*
+ * If we're adding a delegation type (e.g. NS or DNAME for a zone,
+ * just DNAME for the cache), then we need to set the callback bit
+ * on the node, and to do that we must be holding an exclusive lock
+ * on the tree.
+ */
+ if (delegating_type(rbtdb, rbtnode, rdataset->type)) {
+ delegating = ISC_TRUE;
+ RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+ } else
+ delegating = ISC_FALSE;
+
+ NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_write);
+
+ result = add(rbtdb, rbtnode, rbtversion, newheader, options, ISC_FALSE,
+ addedrdataset, now);
+ if (result == ISC_R_SUCCESS && delegating)
+ rbtnode->find_callback = 1;
+
+ NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_write);
+
+ if (delegating)
+ RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+
+ /*
+ * Update the zone's secure status. If version is non-NULL
+ * this is defered until closeversion() is called.
+ */
+ if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
+ rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+
+ return (result);
+}
+
+static isc_result_t
+subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdataset_t *rdataset, unsigned int options,
+ dns_rdataset_t *newrdataset)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+ rbtdb_version_t *rbtversion = version;
+ rdatasetheader_t *topheader, *topheader_prev, *header, *newheader;
+ unsigned char *subresult;
+ isc_region_t region;
+ isc_result_t result;
+ rbtdb_changed_t *changed;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
+ &region,
+ sizeof(rdatasetheader_t));
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ newheader = (rdatasetheader_t *)region.base;
+ newheader->ttl = rdataset->ttl;
+ newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
+ rdataset->covers);
+ newheader->attributes = 0;
+ newheader->serial = rbtversion->serial;
+ newheader->trust = 0;
+ newheader->noqname = NULL;
+ newheader->count = init_count++;
+ newheader->additional_auth = NULL;
+ newheader->additional_glue = NULL;
+
+ NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_write);
+
+ changed = add_changed(rbtdb, rbtversion, rbtnode);
+ if (changed == NULL) {
+ free_rdataset(rbtdb->common.mctx, newheader);
+ NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_write);
+ return (ISC_R_NOMEMORY);
+ }
+
+ topheader_prev = NULL;
+ for (topheader = rbtnode->data;
+ topheader != NULL;
+ topheader = topheader->next) {
+ if (topheader->type == newheader->type)
+ break;
+ topheader_prev = topheader;
+ }
+ /*
+ * If header isn't NULL, we've found the right type. There may be
+ * IGNORE rdatasets between the top of the chain and the first real
+ * data. We skip over them.
+ */
+ header = topheader;
+ while (header != NULL && IGNORE(header))
+ header = header->down;
+ if (header != NULL && EXISTS(header)) {
+ unsigned int flags = 0;
+ subresult = NULL;
+ result = ISC_R_SUCCESS;
+ if ((options & DNS_DBSUB_EXACT) != 0) {
+ flags |= DNS_RDATASLAB_EXACT;
+ if (newheader->ttl != header->ttl)
+ result = DNS_R_NOTEXACT;
+ }
+ if (result == ISC_R_SUCCESS)
+ result = dns_rdataslab_subtract(
+ (unsigned char *)header,
+ (unsigned char *)newheader,
+ (unsigned int)(sizeof(*newheader)),
+ rbtdb->common.mctx,
+ rbtdb->common.rdclass,
+ (dns_rdatatype_t)header->type,
+ flags, &subresult);
+ if (result == ISC_R_SUCCESS) {
+ free_rdataset(rbtdb->common.mctx, newheader);
+ newheader = (rdatasetheader_t *)subresult;
+ /*
+ * We have to set the serial since the rdataslab
+ * subtraction routine copies the reserved portion of
+ * header, not newheader.
+ */
+ newheader->serial = rbtversion->serial;
+ /*
+ * XXXJT: dns_rdataslab_subtract() copied the pointers
+ * to additional info. We need to clear these fields
+ * to avoid having duplicated references.
+ */
+ newheader->additional_auth = NULL;
+ newheader->additional_glue = NULL;
+ } else if (result == DNS_R_NXRRSET) {
+ /*
+ * This subtraction would remove all of the rdata;
+ * add a nonexistent header instead.
+ */
+ free_rdataset(rbtdb->common.mctx, newheader);
+ newheader = isc_mem_get(rbtdb->common.mctx,
+ sizeof(*newheader));
+ if (newheader == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto unlock;
+ }
+ newheader->ttl = 0;
+ newheader->type = topheader->type;
+ newheader->attributes = RDATASET_ATTR_NONEXISTENT;
+ newheader->trust = 0;
+ newheader->serial = rbtversion->serial;
+ newheader->noqname = NULL;
+ newheader->count = 0;
+ newheader->additional_auth = NULL;
+ newheader->additional_glue = NULL;
+ } else {
+ free_rdataset(rbtdb->common.mctx, newheader);
+ goto unlock;
+ }
+
+ /*
+ * If we're here, we want to link newheader in front of
+ * topheader.
+ */
+ INSIST(rbtversion->serial >= topheader->serial);
+ if (topheader_prev != NULL)
+ topheader_prev->next = newheader;
+ else
+ rbtnode->data = newheader;
+ newheader->next = topheader->next;
+ newheader->down = topheader;
+ topheader->next = newheader;
+ rbtnode->dirty = 1;
+ changed->dirty = ISC_TRUE;
+ } else {
+ /*
+ * The rdataset doesn't exist, so we don't need to do anything
+ * to satisfy the deletion request.
+ */
+ free_rdataset(rbtdb->common.mctx, newheader);
+ if ((options & DNS_DBSUB_EXACT) != 0)
+ result = DNS_R_NOTEXACT;
+ else
+ result = DNS_R_UNCHANGED;
+ }
+
+ if (result == ISC_R_SUCCESS && newrdataset != NULL)
+ bind_rdataset(rbtdb, rbtnode, newheader, 0, newrdataset);
+
+ unlock:
+ NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_write);
+
+ /*
+ * Update the zone's secure status. If version is non-NULL
+ * this is defered until closeversion() is called.
+ */
+ if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
+ rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+
+ return (result);
+}
+
+static isc_result_t
+deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+ rbtdb_version_t *rbtversion = version;
+ isc_result_t result;
+ rdatasetheader_t *newheader;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ if (type == dns_rdatatype_any)
+ return (ISC_R_NOTIMPLEMENTED);
+ if (type == dns_rdatatype_rrsig && covers == 0)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ newheader = isc_mem_get(rbtdb->common.mctx, sizeof(*newheader));
+ if (newheader == NULL)
+ return (ISC_R_NOMEMORY);
+ newheader->ttl = 0;
+ newheader->type = RBTDB_RDATATYPE_VALUE(type, covers);
+ newheader->attributes = RDATASET_ATTR_NONEXISTENT;
+ newheader->trust = 0;
+ newheader->noqname = NULL;
+ newheader->additional_auth = NULL;
+ newheader->additional_glue = NULL;
+ if (rbtversion != NULL)
+ newheader->serial = rbtversion->serial;
+ else
+ newheader->serial = 0;
+ newheader->count = 0;
+
+ NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_write);
+
+ result = add(rbtdb, rbtnode, rbtversion, newheader, DNS_DBADD_FORCE,
+ ISC_FALSE, NULL, 0);
+
+ NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_write);
+
+ /*
+ * Update the zone's secure status. If version is non-NULL
+ * this is defered until closeversion() is called.
+ */
+ if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
+ rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+
+ return (result);
+}
+
+static isc_result_t
+loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) {
+ rbtdb_load_t *loadctx = arg;
+ dns_rbtdb_t *rbtdb = loadctx->rbtdb;
+ dns_rbtnode_t *node;
+ isc_result_t result;
+ isc_region_t region;
+ rdatasetheader_t *newheader;
+
+ /*
+ * This routine does no node locking. See comments in
+ * 'load' below for more information on loading and
+ * locking.
+ */
+
+
+ /*
+ * SOA records are only allowed at top of zone.
+ */
+ if (rdataset->type == dns_rdatatype_soa &&
+ !IS_CACHE(rbtdb) && !dns_name_equal(name, &rbtdb->common.origin))
+ return (DNS_R_NOTZONETOP);
+
+ add_empty_wildcards(rbtdb, name);
+
+ if (dns_name_iswildcard(name)) {
+ /*
+ * NS record owners cannot legally be wild cards.
+ */
+ if (rdataset->type == dns_rdatatype_ns)
+ return (DNS_R_INVALIDNS);
+ result = add_wildcard_magic(rbtdb, name);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ node = NULL;
+ result = dns_rbt_addnode(rbtdb->tree, name, &node);
+ if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
+ return (result);
+ if (result != ISC_R_EXISTS) {
+ dns_name_t foundname;
+ dns_name_init(&foundname, NULL);
+ dns_rbt_namefromnode(node, &foundname);
+#ifdef DNS_RBT_USEHASH
+ node->locknum = node->hashval % rbtdb->node_lock_count;
+#else
+ node->locknum = dns_name_hash(&foundname, ISC_TRUE) %
+ rbtdb->node_lock_count;
+#endif
+ }
+
+ result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
+ &region,
+ sizeof(rdatasetheader_t));
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ newheader = (rdatasetheader_t *)region.base;
+ newheader->ttl = rdataset->ttl + loadctx->now; /* XXX overflow check */
+ newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
+ rdataset->covers);
+ newheader->attributes = 0;
+ newheader->trust = rdataset->trust;
+ newheader->serial = 1;
+ newheader->noqname = NULL;
+ newheader->count = init_count++;
+ newheader->additional_auth = NULL;
+ newheader->additional_glue = NULL;
+
+ result = add(rbtdb, node, rbtdb->current_version, newheader,
+ DNS_DBADD_MERGE, ISC_TRUE, NULL, 0);
+ if (result == ISC_R_SUCCESS &&
+ delegating_type(rbtdb, node, rdataset->type))
+ node->find_callback = 1;
+ else if (result == DNS_R_UNCHANGED)
+ result = ISC_R_SUCCESS;
+
+ return (result);
+}
+
+static isc_result_t
+beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
+ rbtdb_load_t *loadctx;
+ dns_rbtdb_t *rbtdb;
+
+ rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ loadctx = isc_mem_get(rbtdb->common.mctx, sizeof(*loadctx));
+ if (loadctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ loadctx->rbtdb = rbtdb;
+ if (IS_CACHE(rbtdb))
+ isc_stdtime_get(&loadctx->now);
+ else
+ loadctx->now = 0;
+
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+
+ REQUIRE((rbtdb->attributes & (RBTDB_ATTR_LOADED|RBTDB_ATTR_LOADING))
+ == 0);
+ rbtdb->attributes |= RBTDB_ATTR_LOADING;
+
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+
+ *addp = loading_addrdataset;
+ *dbloadp = loadctx;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+endload(dns_db_t *db, dns_dbload_t **dbloadp) {
+ rbtdb_load_t *loadctx;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+ REQUIRE(dbloadp != NULL);
+ loadctx = *dbloadp;
+ REQUIRE(loadctx->rbtdb == rbtdb);
+
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+
+ REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADING) != 0);
+ REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADED) == 0);
+
+ rbtdb->attributes &= ~RBTDB_ATTR_LOADING;
+ rbtdb->attributes |= RBTDB_ATTR_LOADED;
+
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+
+ /*
+ * If there's a KEY rdataset at the zone origin containing a
+ * zone key, we consider the zone secure.
+ */
+ if (! IS_CACHE(rbtdb))
+ rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+
+ *dbloadp = NULL;
+
+ isc_mem_put(rbtdb->common.mctx, loadctx, sizeof(*loadctx));
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
+ dns_masterformat_t masterformat) {
+ dns_rbtdb_t *rbtdb;
+
+ rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ return (dns_master_dump2(rbtdb->common.mctx, db, version,
+ &dns_master_style_default,
+ filename, masterformat));
+}
+
+static void
+delete_callback(void *data, void *arg) {
+ dns_rbtdb_t *rbtdb = arg;
+ rdatasetheader_t *current, *next;
+
+ for (current = data; current != NULL; current = next) {
+ next = current->next;
+ free_rdataset(rbtdb->common.mctx, current);
+ }
+}
+
+static isc_boolean_t
+issecure(dns_db_t *db) {
+ dns_rbtdb_t *rbtdb;
+ isc_boolean_t secure;
+
+ rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+ secure = rbtdb->secure;
+ RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+
+ return (secure);
+}
+
+static unsigned int
+nodecount(dns_db_t *db) {
+ dns_rbtdb_t *rbtdb;
+ unsigned int count;
+
+ rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+ count = dns_rbt_nodecount(rbtdb->tree);
+ RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+
+ return (count);
+}
+
+static void
+settask(dns_db_t *db, isc_task_t *task) {
+ dns_rbtdb_t *rbtdb;
+
+ rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+ if (rbtdb->task != NULL)
+ isc_task_detach(&rbtdb->task);
+ if (task != NULL)
+ isc_task_attach(task, &rbtdb->task);
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+}
+
+static isc_boolean_t
+ispersistent(dns_db_t *db) {
+ UNUSED(db);
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *onode;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+ REQUIRE(nodep != NULL && *nodep == NULL);
+
+ /* Note that the access to origin_node doesn't require a DB lock */
+ onode = (dns_rbtnode_t *)rbtdb->origin_node;
+ if (onode != NULL) {
+ NODE_STRONGLOCK(&rbtdb->node_locks[onode->locknum].lock);
+ new_reference(rbtdb, onode);
+ NODE_STRONGUNLOCK(&rbtdb->node_locks[onode->locknum].lock);
+
+ *nodep = rbtdb->origin_node;
+ } else {
+ INSIST(!IS_CACHE(rbtdb));
+ result = ISC_R_NOTFOUND;
+ }
+
+ return (result);
+}
+
+static dns_dbmethods_t zone_methods = {
+ attach,
+ detach,
+ beginload,
+ endload,
+ dump,
+ currentversion,
+ newversion,
+ attachversion,
+ closeversion,
+ findnode,
+ zone_find,
+ zone_findzonecut,
+ attachnode,
+ detachnode,
+ expirenode,
+ printnode,
+ createiterator,
+ zone_findrdataset,
+ allrdatasets,
+ addrdataset,
+ subtractrdataset,
+ deleterdataset,
+ issecure,
+ nodecount,
+ ispersistent,
+ overmem,
+ settask,
+ getoriginnode
+};
+
+static dns_dbmethods_t cache_methods = {
+ attach,
+ detach,
+ beginload,
+ endload,
+ dump,
+ currentversion,
+ newversion,
+ attachversion,
+ closeversion,
+ findnode,
+ cache_find,
+ cache_findzonecut,
+ attachnode,
+ detachnode,
+ expirenode,
+ printnode,
+ createiterator,
+ cache_findrdataset,
+ allrdatasets,
+ addrdataset,
+ subtractrdataset,
+ deleterdataset,
+ issecure,
+ nodecount,
+ ispersistent,
+ overmem,
+ settask,
+ getoriginnode
+};
+
+isc_result_t
+#ifdef DNS_RBTDB_VERSION64
+dns_rbtdb64_create
+#else
+dns_rbtdb_create
+#endif
+ (isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
+ dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
+ void *driverarg, dns_db_t **dbp)
+{
+ dns_rbtdb_t *rbtdb;
+ isc_result_t result;
+ int i;
+ dns_name_t name;
+
+ /* Keep the compiler happy. */
+ UNUSED(argc);
+ UNUSED(argv);
+ UNUSED(driverarg);
+
+ rbtdb = isc_mem_get(mctx, sizeof(*rbtdb));
+ if (rbtdb == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(rbtdb, '\0', sizeof(*rbtdb));
+ dns_name_init(&rbtdb->common.origin, NULL);
+ rbtdb->common.attributes = 0;
+ if (type == dns_dbtype_cache) {
+ rbtdb->common.methods = &cache_methods;
+ rbtdb->common.attributes |= DNS_DBATTR_CACHE;
+ } else if (type == dns_dbtype_stub) {
+ rbtdb->common.methods = &zone_methods;
+ rbtdb->common.attributes |= DNS_DBATTR_STUB;
+ } else
+ rbtdb->common.methods = &zone_methods;
+ rbtdb->common.rdclass = rdclass;
+ rbtdb->common.mctx = NULL;
+
+ result = RBTDB_INITLOCK(&rbtdb->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_rbtdb;
+
+ result = isc_rwlock_init(&rbtdb->tree_lock, 0, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+
+ if (rbtdb->node_lock_count == 0) {
+ if (IS_CACHE(rbtdb))
+ rbtdb->node_lock_count = DEFAULT_CACHE_NODE_LOCK_COUNT;
+ else
+ rbtdb->node_lock_count = DEFAULT_NODE_LOCK_COUNT;
+ }
+ INSIST(rbtdb->node_lock_count < (1 << DNS_RBT_LOCKLENGTH));
+ rbtdb->node_locks = isc_mem_get(mctx, rbtdb->node_lock_count *
+ sizeof(rbtdb_nodelock_t));
+ if (rbtdb->node_locks == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_tree_lock;
+ }
+
+ rbtdb->active = rbtdb->node_lock_count;
+
+ for (i = 0; i < (int)(rbtdb->node_lock_count); i++) {
+ result = NODE_INITLOCK(&rbtdb->node_locks[i].lock);
+ if (result == ISC_R_SUCCESS) {
+ result = isc_refcount_init(&rbtdb->node_locks[i].references, 0);
+ if (result != ISC_R_SUCCESS)
+ NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
+ }
+ if (result != ISC_R_SUCCESS) {
+ while (i-- > 0) {
+ NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
+ isc_refcount_decrement(&rbtdb->node_locks[i].references, NULL);
+ isc_refcount_destroy(&rbtdb->node_locks[i].references);
+ }
+ goto cleanup_node_locks;
+ }
+ rbtdb->node_locks[i].exiting = ISC_FALSE;
+ }
+
+ /*
+ * Attach to the mctx. The database will persist so long as there
+ * are references to it, and attaching to the mctx ensures that our
+ * mctx won't disappear out from under us.
+ */
+ isc_mem_attach(mctx, &rbtdb->common.mctx);
+
+ /*
+ * Must be initalized before free_rbtdb() is called.
+ */
+ isc_ondestroy_init(&rbtdb->common.ondest);
+
+ /*
+ * Make a copy of the origin name.
+ */
+ result = dns_name_dupwithoffsets(origin, mctx, &rbtdb->common.origin);
+ if (result != ISC_R_SUCCESS) {
+ free_rbtdb(rbtdb, ISC_FALSE, NULL);
+ return (result);
+ }
+
+ /*
+ * Make the Red-Black Tree.
+ */
+ result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree);
+ if (result != ISC_R_SUCCESS) {
+ free_rbtdb(rbtdb, ISC_FALSE, NULL);
+ return (result);
+ }
+ /*
+ * In order to set the node callback bit correctly in zone databases,
+ * we need to know if the node has the origin name of the zone.
+ * In loading_addrdataset() we could simply compare the new name
+ * to the origin name, but this is expensive. Also, we don't know the
+ * node name in addrdataset(), so we need another way of knowing the
+ * zone's top.
+ *
+ * We now explicitly create a node for the zone's origin, and then
+ * we simply remember the node's address. This is safe, because
+ * the top-of-zone node can never be deleted, nor can its address
+ * change.
+ */
+ if (!IS_CACHE(rbtdb)) {
+ rbtdb->origin_node = NULL;
+ result = dns_rbt_addnode(rbtdb->tree, &rbtdb->common.origin,
+ &rbtdb->origin_node);
+ if (result != ISC_R_SUCCESS) {
+ INSIST(result != ISC_R_EXISTS);
+ free_rbtdb(rbtdb, ISC_FALSE, NULL);
+ return (result);
+ }
+ /*
+ * We need to give the origin node the right locknum.
+ */
+ dns_name_init(&name, NULL);
+ dns_rbt_namefromnode(rbtdb->origin_node, &name);
+#ifdef DNS_RBT_USEHASH
+ rbtdb->origin_node->locknum =
+ rbtdb->origin_node->hashval %
+ rbtdb->node_lock_count;
+#else
+ rbtdb->origin_node->locknum =
+ dns_name_hash(&name, ISC_TRUE) %
+ rbtdb->node_lock_count;
+#endif
+ }
+
+ /*
+ * Misc. Initialization.
+ */
+ result = isc_refcount_init(&rbtdb->references, 1);
+ if (result != ISC_R_SUCCESS) {
+ free_rbtdb(rbtdb, ISC_FALSE, NULL);
+ return (result);
+ }
+ rbtdb->attributes = 0;
+ rbtdb->secure = ISC_FALSE;
+ rbtdb->overmem = ISC_FALSE;
+ rbtdb->task = NULL;
+
+ /*
+ * Version Initialization.
+ */
+ rbtdb->current_serial = 1;
+ rbtdb->least_serial = 1;
+ rbtdb->next_serial = 2;
+ rbtdb->current_version = allocate_version(mctx, 1, 1, ISC_FALSE);
+ if (rbtdb->current_version == NULL) {
+ isc_refcount_decrement(&rbtdb->references, NULL);
+ isc_refcount_destroy(&rbtdb->references);
+ free_rbtdb(rbtdb, ISC_FALSE, NULL);
+ return (ISC_R_NOMEMORY);
+ }
+ rbtdb->future_version = NULL;
+ ISC_LIST_INIT(rbtdb->open_versions);
+ /*
+ * Keep the current version in the open list so that list operation
+ * won't happen in normal lookup operations.
+ */
+ PREPEND(rbtdb->open_versions, rbtdb->current_version, link);
+
+ rbtdb->common.magic = DNS_DB_MAGIC;
+ rbtdb->common.impmagic = RBTDB_MAGIC;
+
+ *dbp = (dns_db_t *)rbtdb;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_node_locks:
+ isc_mem_put(mctx, rbtdb->node_locks,
+ rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t));
+
+ cleanup_tree_lock:
+ isc_rwlock_destroy(&rbtdb->tree_lock);
+
+ cleanup_lock:
+ RBTDB_DESTROYLOCK(&rbtdb->lock);
+
+ cleanup_rbtdb:
+ isc_mem_put(mctx, rbtdb, sizeof(*rbtdb));
+ return (result);
+}
+
+
+/*
+ * Slabbed Rdataset Methods
+ */
+
+static void
+rdataset_disassociate(dns_rdataset_t *rdataset) {
+ dns_db_t *db = rdataset->private1;
+ dns_dbnode_t *node = rdataset->private2;
+
+ detachnode(db, &node);
+}
+
+static isc_result_t
+rdataset_first(dns_rdataset_t *rdataset) {
+ unsigned char *raw = rdataset->private3; /* RDATASLAB */
+ unsigned int count;
+
+ count = raw[0] * 256 + raw[1];
+ if (count == 0) {
+ rdataset->private5 = NULL;
+ return (ISC_R_NOMORE);
+ }
+
+#if DNS_RDATASET_FIXED
+ if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0)
+ raw += 2 + (4 * count);
+ else
+#endif
+ raw += 2;
+
+ /*
+ * The privateuint4 field is the number of rdata beyond the
+ * cursor position, so we decrement the total count by one
+ * before storing it.
+ *
+ * If DNS_RDATASETATTR_LOADORDER is not set 'raw' points to the
+ * first record. If DNS_RDATASETATTR_LOADORDER is set 'raw' points
+ * to the first entry in the offset table.
+ */
+ count--;
+ rdataset->privateuint4 = count;
+ rdataset->private5 = raw;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+rdataset_next(dns_rdataset_t *rdataset) {
+ unsigned int count;
+ unsigned int length;
+ unsigned char *raw; /* RDATASLAB */
+
+ count = rdataset->privateuint4;
+ if (count == 0)
+ return (ISC_R_NOMORE);
+ count--;
+ rdataset->privateuint4 = count;
+
+ /*
+ * Skip forward one record (length + 4) or one offset (4).
+ */
+ raw = rdataset->private5;
+#if DNS_RDATASET_FIXED
+ if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0) {
+#endif
+ length = raw[0] * 256 + raw[1];
+ raw += length;
+#if DNS_RDATASET_FIXED
+ }
+ rdataset->private5 = raw + 4; /* length(2) + order(2) */
+#else
+ rdataset->private5 = raw + 2; /* length(2) */
+#endif
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
+ unsigned char *raw = rdataset->private5; /* RDATASLAB */
+#if DNS_RDATASET_FIXED
+ unsigned int offset;
+#endif
+ isc_region_t r;
+
+ REQUIRE(raw != NULL);
+
+ /*
+ * Find the start of the record if not already in private5
+ * then skip the length and order fields.
+ */
+#if DNS_RDATASET_FIXED
+ if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) != 0) {
+ offset = (raw[0] << 24) + (raw[1] << 16) +
+ (raw[2] << 8) + raw[3];
+ raw = rdataset->private3;
+ raw += offset;
+ }
+#endif
+ r.length = raw[0] * 256 + raw[1];
+
+#if DNS_RDATASET_FIXED
+ raw += 4;
+#else
+ raw += 2;
+#endif
+ r.base = raw;
+ dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
+}
+
+static void
+rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
+ dns_db_t *db = source->private1;
+ dns_dbnode_t *node = source->private2;
+ dns_dbnode_t *cloned_node = NULL;
+
+ attachnode(db, node, &cloned_node);
+ *target = *source;
+
+ /*
+ * Reset iterator state.
+ */
+ target->privateuint4 = 0;
+ target->private5 = NULL;
+}
+
+static unsigned int
+rdataset_count(dns_rdataset_t *rdataset) {
+ unsigned char *raw = rdataset->private3; /* RDATASLAB */
+ unsigned int count;
+
+ count = raw[0] * 256 + raw[1];
+
+ return (count);
+}
+
+static isc_result_t
+rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
+ dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
+{
+ dns_db_t *db = rdataset->private1;
+ dns_dbnode_t *node = rdataset->private2;
+ dns_dbnode_t *cloned_node;
+ struct noqname *noqname = rdataset->private6;
+
+ cloned_node = NULL;
+ attachnode(db, node, &cloned_node);
+ nsec->methods = &rdataset_methods;
+ nsec->rdclass = db->rdclass;
+ nsec->type = dns_rdatatype_nsec;
+ nsec->covers = 0;
+ nsec->ttl = rdataset->ttl;
+ nsec->trust = rdataset->trust;
+ nsec->private1 = rdataset->private1;
+ nsec->private2 = rdataset->private2;
+ nsec->private3 = noqname->nsec;
+ nsec->privateuint4 = 0;
+ nsec->private5 = NULL;
+ nsec->private6 = NULL;
+
+ cloned_node = NULL;
+ attachnode(db, node, &cloned_node);
+ nsecsig->methods = &rdataset_methods;
+ nsecsig->rdclass = db->rdclass;
+ nsecsig->type = dns_rdatatype_rrsig;
+ nsecsig->covers = dns_rdatatype_nsec;
+ nsecsig->ttl = rdataset->ttl;
+ nsecsig->trust = rdataset->trust;
+ nsecsig->private1 = rdataset->private1;
+ nsecsig->private2 = rdataset->private2;
+ nsecsig->private3 = noqname->nsecsig;
+ nsecsig->privateuint4 = 0;
+ nsecsig->private5 = NULL;
+ nsec->private6 = NULL;
+
+ dns_name_clone(&noqname->name, name);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Rdataset Iterator Methods
+ */
+
+static void
+rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
+ rbtdb_rdatasetiter_t *rbtiterator;
+
+ rbtiterator = (rbtdb_rdatasetiter_t *)(*iteratorp);
+
+ if (rbtiterator->common.version != NULL)
+ closeversion(rbtiterator->common.db,
+ &rbtiterator->common.version, ISC_FALSE);
+ detachnode(rbtiterator->common.db, &rbtiterator->common.node);
+ isc_mem_put(rbtiterator->common.db->mctx, rbtiterator,
+ sizeof(*rbtiterator));
+
+ *iteratorp = NULL;
+}
+
+static isc_result_t
+rdatasetiter_first(dns_rdatasetiter_t *iterator) {
+ rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
+ dns_rbtnode_t *rbtnode = rbtiterator->common.node;
+ rbtdb_version_t *rbtversion = rbtiterator->common.version;
+ rdatasetheader_t *header, *top_next;
+ rbtdb_serial_t serial;
+ isc_stdtime_t now;
+
+ if (IS_CACHE(rbtdb)) {
+ serial = 1;
+ now = rbtiterator->common.now;
+ } else {
+ serial = rbtversion->serial;
+ now = 0;
+ }
+
+ NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_read);
+
+ for (header = rbtnode->data; header != NULL; header = top_next) {
+ top_next = header->next;
+ do {
+ if (header->serial <= serial && !IGNORE(header)) {
+ /*
+ * Is this a "this rdataset doesn't exist"
+ * record? Or is it too old in the cache?
+ *
+ * Note: unlike everywhere else, we
+ * check for now > header->ttl instead
+ * of now >= header->ttl. This allows
+ * ANY and RRSIG queries for 0 TTL
+ * rdatasets to work.
+ */
+ if (NONEXISTENT(header) ||
+ (now != 0 && now > header->ttl))
+ header = NULL;
+ break;
+ } else
+ header = header->down;
+ } while (header != NULL);
+ if (header != NULL)
+ break;
+ }
+
+ NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_read);
+
+ rbtiterator->current = header;
+
+ if (header == NULL)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+rdatasetiter_next(dns_rdatasetiter_t *iterator) {
+ rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
+ dns_rbtnode_t *rbtnode = rbtiterator->common.node;
+ rbtdb_version_t *rbtversion = rbtiterator->common.version;
+ rdatasetheader_t *header, *top_next;
+ rbtdb_serial_t serial;
+ isc_stdtime_t now;
+ rbtdb_rdatatype_t type, negtype;
+ dns_rdatatype_t rdtype, covers;
+
+ header = rbtiterator->current;
+ if (header == NULL)
+ return (ISC_R_NOMORE);
+
+ if (IS_CACHE(rbtdb)) {
+ serial = 1;
+ now = rbtiterator->common.now;
+ } else {
+ serial = rbtversion->serial;
+ now = 0;
+ }
+
+ NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_read);
+
+ type = header->type;
+ rdtype = RBTDB_RDATATYPE_BASE(header->type);
+ if (rdtype == 0) {
+ covers = RBTDB_RDATATYPE_EXT(header->type);
+ negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
+ } else
+ negtype = RBTDB_RDATATYPE_VALUE(0, rdtype);
+ for (header = header->next; header != NULL; header = top_next) {
+ top_next = header->next;
+ /*
+ * If not walking back up the down list.
+ */
+ if (header->type != type && header->type != negtype) {
+ do {
+ if (header->serial <= serial &&
+ !IGNORE(header)) {
+ /*
+ * Is this a "this rdataset doesn't
+ * exist" record?
+ *
+ * Note: unlike everywhere else, we
+ * check for now > header->ttl instead
+ * of now >= header->ttl. This allows
+ * ANY and RRSIG queries for 0 TTL
+ * rdatasets to work.
+ */
+ if ((header->attributes &
+ RDATASET_ATTR_NONEXISTENT) != 0 ||
+ (now != 0 && now > header->ttl))
+ header = NULL;
+ break;
+ } else
+ header = header->down;
+ } while (header != NULL);
+ if (header != NULL)
+ break;
+ }
+ }
+
+ NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_read);
+
+ rbtiterator->current = header;
+
+ if (header == NULL)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
+ rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
+ dns_rbtnode_t *rbtnode = rbtiterator->common.node;
+ rdatasetheader_t *header;
+
+ header = rbtiterator->current;
+ REQUIRE(header != NULL);
+
+ NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_read);
+
+ bind_rdataset(rbtdb, rbtnode, header, rbtiterator->common.now,
+ rdataset);
+
+ NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_read);
+}
+
+
+/*
+ * Database Iterator Methods
+ */
+
+static inline void
+reference_iter_node(rbtdb_dbiterator_t *rbtdbiter) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
+ dns_rbtnode_t *node = rbtdbiter->node;
+
+ if (node == NULL)
+ return;
+
+ INSIST(rbtdbiter->tree_locked != isc_rwlocktype_none);
+ NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
+ new_reference(rbtdb, node);
+ NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+}
+
+static inline void
+dereference_iter_node(rbtdb_dbiterator_t *rbtdbiter) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
+ dns_rbtnode_t *node = rbtdbiter->node;
+ nodelock_t *lock;
+
+ if (node == NULL)
+ return;
+
+ lock = &rbtdb->node_locks[node->locknum].lock;
+ NODE_LOCK(lock, isc_rwlocktype_read);
+ decrement_reference(rbtdb, node, 0, isc_rwlocktype_read,
+ rbtdbiter->tree_locked);
+ NODE_UNLOCK(lock, isc_rwlocktype_read);
+
+ rbtdbiter->node = NULL;
+}
+
+static void
+flush_deletions(rbtdb_dbiterator_t *rbtdbiter) {
+ dns_rbtnode_t *node;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
+ isc_boolean_t was_read_locked = ISC_FALSE;
+ nodelock_t *lock;
+ int i;
+
+ if (rbtdbiter->delete != 0) {
+ /*
+ * Note that "%d node of %d in tree" can report things like
+ * "flush_deletions: 59 nodes of 41 in tree". This means
+ * That some nodes appear on the deletions list more than
+ * once. Only the last occurence will actually be deleted.
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+ "flush_deletions: %d nodes of %d in tree",
+ rbtdbiter->delete,
+ dns_rbt_nodecount(rbtdb->tree));
+
+ if (rbtdbiter->tree_locked == isc_rwlocktype_read) {
+ RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+ was_read_locked = ISC_TRUE;
+ }
+ RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+ rbtdbiter->tree_locked = isc_rwlocktype_write;
+
+ for (i = 0; i < rbtdbiter->delete; i++) {
+ node = rbtdbiter->deletions[i];
+ lock = &rbtdb->node_locks[node->locknum].lock;
+
+ NODE_LOCK(lock, isc_rwlocktype_read);
+ decrement_reference(rbtdb, node, 0,
+ isc_rwlocktype_read,
+ rbtdbiter->tree_locked);
+ NODE_UNLOCK(lock, isc_rwlocktype_read);
+ }
+
+ rbtdbiter->delete = 0;
+
+ RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+ if (was_read_locked) {
+ RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+ rbtdbiter->tree_locked = isc_rwlocktype_read;
+
+ } else {
+ rbtdbiter->tree_locked = isc_rwlocktype_none;
+ }
+ }
+}
+
+static inline void
+resume_iteration(rbtdb_dbiterator_t *rbtdbiter) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
+
+ REQUIRE(rbtdbiter->paused);
+ REQUIRE(rbtdbiter->tree_locked == isc_rwlocktype_none);
+
+ RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+ rbtdbiter->tree_locked = isc_rwlocktype_read;
+
+ rbtdbiter->paused = ISC_FALSE;
+}
+
+static void
+dbiterator_destroy(dns_dbiterator_t **iteratorp) {
+ rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)(*iteratorp);
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
+ dns_db_t *db = NULL;
+
+ if (rbtdbiter->tree_locked == isc_rwlocktype_read) {
+ RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+ rbtdbiter->tree_locked = isc_rwlocktype_none;
+ } else
+ INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none);
+
+ dereference_iter_node(rbtdbiter);
+
+ flush_deletions(rbtdbiter);
+
+ dns_db_attach(rbtdbiter->common.db, &db);
+ dns_db_detach(&rbtdbiter->common.db);
+
+ dns_rbtnodechain_reset(&rbtdbiter->chain);
+ isc_mem_put(db->mctx, rbtdbiter, sizeof(*rbtdbiter));
+ dns_db_detach(&db);
+
+ *iteratorp = NULL;
+}
+
+static isc_result_t
+dbiterator_first(dns_dbiterator_t *iterator) {
+ isc_result_t result;
+ rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
+ dns_name_t *name, *origin;
+
+ if (rbtdbiter->result != ISC_R_SUCCESS &&
+ rbtdbiter->result != ISC_R_NOMORE)
+ return (rbtdbiter->result);
+
+ if (rbtdbiter->paused)
+ resume_iteration(rbtdbiter);
+
+ dereference_iter_node(rbtdbiter);
+
+ name = dns_fixedname_name(&rbtdbiter->name);
+ origin = dns_fixedname_name(&rbtdbiter->origin);
+ dns_rbtnodechain_reset(&rbtdbiter->chain);
+
+ result = dns_rbtnodechain_first(&rbtdbiter->chain, rbtdb->tree, name,
+ origin);
+
+ if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
+ result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+ NULL, &rbtdbiter->node);
+ if (result == ISC_R_SUCCESS) {
+ rbtdbiter->new_origin = ISC_TRUE;
+ reference_iter_node(rbtdbiter);
+ }
+ } else {
+ INSIST(result == ISC_R_NOTFOUND);
+ result = ISC_R_NOMORE; /* The tree is empty. */
+ }
+
+ rbtdbiter->result = result;
+
+ return (result);
+}
+
+static isc_result_t
+dbiterator_last(dns_dbiterator_t *iterator) {
+ isc_result_t result;
+ rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
+ dns_name_t *name, *origin;
+
+ if (rbtdbiter->result != ISC_R_SUCCESS &&
+ rbtdbiter->result != ISC_R_NOMORE)
+ return (rbtdbiter->result);
+
+ if (rbtdbiter->paused)
+ resume_iteration(rbtdbiter);
+
+ dereference_iter_node(rbtdbiter);
+
+ name = dns_fixedname_name(&rbtdbiter->name);
+ origin = dns_fixedname_name(&rbtdbiter->origin);
+ dns_rbtnodechain_reset(&rbtdbiter->chain);
+
+ result = dns_rbtnodechain_last(&rbtdbiter->chain, rbtdb->tree, name,
+ origin);
+ if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
+ result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+ NULL, &rbtdbiter->node);
+ if (result == ISC_R_SUCCESS) {
+ rbtdbiter->new_origin = ISC_TRUE;
+ reference_iter_node(rbtdbiter);
+ }
+ } else {
+ INSIST(result == ISC_R_NOTFOUND);
+ result = ISC_R_NOMORE; /* The tree is empty. */
+ }
+
+ rbtdbiter->result = result;
+
+ return (result);
+}
+
+static isc_result_t
+dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
+ isc_result_t result;
+ rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
+ dns_name_t *iname, *origin;
+
+ if (rbtdbiter->result != ISC_R_SUCCESS &&
+ rbtdbiter->result != ISC_R_NOMORE)
+ return (rbtdbiter->result);
+
+ if (rbtdbiter->paused)
+ resume_iteration(rbtdbiter);
+
+ dereference_iter_node(rbtdbiter);
+
+ iname = dns_fixedname_name(&rbtdbiter->name);
+ origin = dns_fixedname_name(&rbtdbiter->origin);
+ dns_rbtnodechain_reset(&rbtdbiter->chain);
+
+ result = dns_rbt_findnode(rbtdb->tree, name, NULL, &rbtdbiter->node,
+ &rbtdbiter->chain, DNS_RBTFIND_EMPTYDATA,
+ NULL, NULL);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_rbtnodechain_current(&rbtdbiter->chain, iname,
+ origin, NULL);
+ if (result == ISC_R_SUCCESS) {
+ rbtdbiter->new_origin = ISC_TRUE;
+ reference_iter_node(rbtdbiter);
+ }
+
+ } else if (result == DNS_R_PARTIALMATCH)
+ result = ISC_R_NOTFOUND;
+
+ rbtdbiter->result = result;
+
+ return (result);
+}
+
+static isc_result_t
+dbiterator_prev(dns_dbiterator_t *iterator) {
+ isc_result_t result;
+ rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+ dns_name_t *name, *origin;
+
+ REQUIRE(rbtdbiter->node != NULL);
+
+ if (rbtdbiter->result != ISC_R_SUCCESS)
+ return (rbtdbiter->result);
+
+ if (rbtdbiter->paused)
+ resume_iteration(rbtdbiter);
+
+ name = dns_fixedname_name(&rbtdbiter->name);
+ origin = dns_fixedname_name(&rbtdbiter->origin);
+ result = dns_rbtnodechain_prev(&rbtdbiter->chain, name, origin);
+
+ dereference_iter_node(rbtdbiter);
+
+ if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
+ rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN);
+ result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+ NULL, &rbtdbiter->node);
+ }
+
+ if (result == ISC_R_SUCCESS)
+ reference_iter_node(rbtdbiter);
+
+ rbtdbiter->result = result;
+
+ return (result);
+}
+
+static isc_result_t
+dbiterator_next(dns_dbiterator_t *iterator) {
+ isc_result_t result;
+ rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+ dns_name_t *name, *origin;
+
+ REQUIRE(rbtdbiter->node != NULL);
+
+ if (rbtdbiter->result != ISC_R_SUCCESS)
+ return (rbtdbiter->result);
+
+ if (rbtdbiter->paused)
+ resume_iteration(rbtdbiter);
+
+ name = dns_fixedname_name(&rbtdbiter->name);
+ origin = dns_fixedname_name(&rbtdbiter->origin);
+ result = dns_rbtnodechain_next(&rbtdbiter->chain, name, origin);
+
+ dereference_iter_node(rbtdbiter);
+
+ if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
+ rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN);
+ result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+ NULL, &rbtdbiter->node);
+ }
+ if (result == ISC_R_SUCCESS)
+ reference_iter_node(rbtdbiter);
+
+ rbtdbiter->result = result;
+
+ return (result);
+}
+
+static isc_result_t
+dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
+ dns_name_t *name)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
+ rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+ dns_rbtnode_t *node = rbtdbiter->node;
+ isc_result_t result;
+ dns_name_t *nodename = dns_fixedname_name(&rbtdbiter->name);
+ dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin);
+
+ REQUIRE(rbtdbiter->result == ISC_R_SUCCESS);
+ REQUIRE(rbtdbiter->node != NULL);
+
+ if (rbtdbiter->paused)
+ resume_iteration(rbtdbiter);
+
+ if (name != NULL) {
+ if (rbtdbiter->common.relative_names)
+ origin = NULL;
+ result = dns_name_concatenate(nodename, origin, name, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (rbtdbiter->common.relative_names && rbtdbiter->new_origin)
+ result = DNS_R_NEWORIGIN;
+ } else
+ result = ISC_R_SUCCESS;
+
+ NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
+ new_reference(rbtdb, node);
+ NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+
+ *nodep = rbtdbiter->node;
+
+ if (iterator->cleaning && result == ISC_R_SUCCESS) {
+ isc_result_t expire_result;
+
+ /*
+ * If the deletion array is full, flush it before trying
+ * to expire the current node. The current node can't
+ * fully deleted while the iteration cursor is still on it.
+ */
+ if (rbtdbiter->delete == DELETION_BATCH_MAX)
+ flush_deletions(rbtdbiter);
+
+ expire_result = expirenode(iterator->db, *nodep, 0);
+
+ /*
+ * expirenode() currently always returns success.
+ */
+ if (expire_result == ISC_R_SUCCESS && node->down == NULL) {
+ unsigned int refs;
+
+ rbtdbiter->deletions[rbtdbiter->delete++] = node;
+ NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
+ dns_rbtnode_refincrement(node, &refs);
+ INSIST(refs != 0);
+ NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+ }
+ }
+
+ return (result);
+}
+
+static isc_result_t
+dbiterator_pause(dns_dbiterator_t *iterator) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
+ rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+
+ if (rbtdbiter->result != ISC_R_SUCCESS &&
+ rbtdbiter->result != ISC_R_NOMORE)
+ return (rbtdbiter->result);
+
+ if (rbtdbiter->paused)
+ return (ISC_R_SUCCESS);
+
+ rbtdbiter->paused = ISC_TRUE;
+
+ if (rbtdbiter->tree_locked != isc_rwlocktype_none) {
+ INSIST(rbtdbiter->tree_locked == isc_rwlocktype_read);
+ RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+ rbtdbiter->tree_locked = isc_rwlocktype_none;
+ }
+
+ flush_deletions(rbtdbiter);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
+ rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+ dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin);
+
+ if (rbtdbiter->result != ISC_R_SUCCESS)
+ return (rbtdbiter->result);
+
+ return (dns_name_copy(origin, name, NULL));
+}
+
+/*%
+ * Additional cache routines.
+ */
+static isc_result_t
+rdataset_getadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype, dns_acache_t *acache,
+ dns_zone_t **zonep, dns_db_t **dbp,
+ dns_dbversion_t **versionp, dns_dbnode_t **nodep,
+ dns_name_t *fname, dns_message_t *msg,
+ isc_stdtime_t now)
+{
+ dns_rbtdb_t *rbtdb = rdataset->private1;
+ dns_rbtnode_t *rbtnode = rdataset->private2;
+ unsigned char *raw = rdataset->private3; /* RDATASLAB */
+ unsigned int current_count = rdataset->privateuint4;
+ unsigned int count;
+ rdatasetheader_t *header;
+ nodelock_t *nodelock;
+ unsigned int total_count;
+ acachectl_t *acarray;
+ dns_acacheentry_t *entry;
+ isc_result_t result;
+
+ UNUSED(qtype); /* we do not use this value at least for now */
+ UNUSED(acache);
+
+ header = (struct rdatasetheader *)(raw - sizeof(*header));
+
+ total_count = raw[0] * 256 + raw[1];
+ INSIST(total_count > current_count);
+ count = total_count - current_count - 1;
+
+ acarray = NULL;
+
+ nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
+ NODE_LOCK(nodelock, isc_rwlocktype_read);
+
+ switch (type) {
+ case dns_rdatasetadditional_fromauth:
+ acarray = header->additional_auth;
+ break;
+ case dns_rdatasetadditional_fromcache:
+ acarray = NULL;
+ break;
+ case dns_rdatasetadditional_fromglue:
+ acarray = header->additional_glue;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ if (acarray == NULL) {
+ if (type != dns_rdatasetadditional_fromcache)
+ dns_acache_countquerymiss(acache);
+ NODE_UNLOCK(nodelock, isc_rwlocktype_read);
+ return (ISC_R_NOTFOUND);
+ }
+
+ if (acarray[count].entry == NULL) {
+ dns_acache_countquerymiss(acache);
+ NODE_UNLOCK(nodelock, isc_rwlocktype_read);
+ return (ISC_R_NOTFOUND);
+ }
+
+ entry = NULL;
+ dns_acache_attachentry(acarray[count].entry, &entry);
+
+ NODE_UNLOCK(nodelock, isc_rwlocktype_read);
+
+ result = dns_acache_getentry(entry, zonep, dbp, versionp,
+ nodep, fname, msg, now);
+
+ dns_acache_detachentry(&entry);
+
+ return (result);
+}
+
+static void
+acache_callback(dns_acacheentry_t *entry, void **arg) {
+ dns_rbtdb_t *rbtdb;
+ dns_rbtnode_t *rbtnode;
+ nodelock_t *nodelock;
+ acachectl_t *acarray = NULL;
+ acache_cbarg_t *cbarg;
+ unsigned int count;
+
+ REQUIRE(arg != NULL);
+ cbarg = *arg;
+
+ /*
+ * The caller must hold the entry lock.
+ */
+
+ rbtdb = (dns_rbtdb_t *)cbarg->db;
+ rbtnode = (dns_rbtnode_t *)cbarg->node;
+
+ nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
+ NODE_LOCK(nodelock, isc_rwlocktype_write);
+
+ switch (cbarg->type) {
+ case dns_rdatasetadditional_fromauth:
+ acarray = cbarg->header->additional_auth;
+ break;
+ case dns_rdatasetadditional_fromglue:
+ acarray = cbarg->header->additional_glue;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ count = cbarg->count;
+ if (acarray[count].entry == entry)
+ acarray[count].entry = NULL;
+ INSIST(acarray[count].cbarg != NULL);
+ isc_mem_put(rbtdb->common.mctx, acarray[count].cbarg,
+ sizeof(acache_cbarg_t));
+ acarray[count].cbarg = NULL;
+
+ dns_acache_detachentry(&entry);
+
+ NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+
+ dns_db_detachnode((dns_db_t *)rbtdb, (dns_dbnode_t **)(void*)&rbtnode);
+ dns_db_detach((dns_db_t **)(void*)&rbtdb);
+
+ *arg = NULL;
+}
+
+static void
+acache_cancelentry(isc_mem_t *mctx, dns_acacheentry_t *entry,
+ acache_cbarg_t **cbargp)
+{
+ acache_cbarg_t *cbarg;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(entry != NULL);
+ REQUIRE(cbargp != NULL && *cbargp != NULL);
+
+ cbarg = *cbargp;
+
+ dns_acache_cancelentry(entry);
+ dns_db_detachnode(cbarg->db, &cbarg->node);
+ dns_db_detach(&cbarg->db);
+
+ isc_mem_put(mctx, cbarg, sizeof(acache_cbarg_t));
+
+ *cbargp = NULL;
+}
+
+static isc_result_t
+rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype, dns_acache_t *acache,
+ dns_zone_t *zone, dns_db_t *db,
+ dns_dbversion_t *version, dns_dbnode_t *node,
+ dns_name_t *fname)
+{
+ dns_rbtdb_t *rbtdb = rdataset->private1;
+ dns_rbtnode_t *rbtnode = rdataset->private2;
+ unsigned char *raw = rdataset->private3; /* RDATASLAB */
+ unsigned int current_count = rdataset->privateuint4;
+ rdatasetheader_t *header;
+ unsigned int total_count, count;
+ nodelock_t *nodelock;
+ isc_result_t result;
+ acachectl_t *acarray;
+ dns_acacheentry_t *newentry, *oldentry = NULL;
+ acache_cbarg_t *newcbarg, *oldcbarg = NULL;
+
+ UNUSED(qtype);
+
+ if (type == dns_rdatasetadditional_fromcache)
+ return (ISC_R_SUCCESS);
+
+ header = (struct rdatasetheader *)(raw - sizeof(*header));
+
+ total_count = raw[0] * 256 + raw[1];
+ INSIST(total_count > current_count);
+ count = total_count - current_count - 1; /* should be private data */
+
+ newcbarg = isc_mem_get(rbtdb->common.mctx, sizeof(*newcbarg));
+ if (newcbarg == NULL)
+ return (ISC_R_NOMEMORY);
+ newcbarg->type = type;
+ newcbarg->count = count;
+ newcbarg->header = header;
+ newcbarg->db = NULL;
+ dns_db_attach((dns_db_t *)rbtdb, &newcbarg->db);
+ newcbarg->node = NULL;
+ dns_db_attachnode((dns_db_t *)rbtdb, (dns_dbnode_t *)rbtnode,
+ &newcbarg->node);
+ newentry = NULL;
+ result = dns_acache_createentry(acache, (dns_db_t *)rbtdb,
+ acache_callback, newcbarg, &newentry);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+ /* Set cache data in the new entry. */
+ result = dns_acache_setentry(acache, newentry, zone, db,
+ version, node, fname);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+
+ nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
+ NODE_LOCK(nodelock, isc_rwlocktype_write);
+
+ acarray = NULL;
+ switch (type) {
+ case dns_rdatasetadditional_fromauth:
+ acarray = header->additional_auth;
+ break;
+ case dns_rdatasetadditional_fromglue:
+ acarray = header->additional_glue;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ if (acarray == NULL) {
+ unsigned int i;
+
+ acarray = isc_mem_get(rbtdb->common.mctx, total_count *
+ sizeof(acachectl_t));
+
+ if (acarray == NULL) {
+ NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+ goto fail;
+ }
+
+ for (i = 0; i < total_count; i++) {
+ acarray[i].entry = NULL;
+ acarray[i].cbarg = NULL;
+ }
+ }
+ switch (type) {
+ case dns_rdatasetadditional_fromauth:
+ header->additional_auth = acarray;
+ break;
+ case dns_rdatasetadditional_fromglue:
+ header->additional_glue = acarray;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ if (acarray[count].entry != NULL) {
+ /*
+ * Swap the entry. Delay cleaning-up the old entry since
+ * it would require a node lock.
+ */
+ oldentry = acarray[count].entry;
+ INSIST(acarray[count].cbarg != NULL);
+ oldcbarg = acarray[count].cbarg;
+ }
+ acarray[count].entry = newentry;
+ acarray[count].cbarg = newcbarg;
+
+ NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+
+ if (oldentry != NULL) {
+ if (oldcbarg != NULL)
+ acache_cancelentry(rbtdb->common.mctx, oldentry,
+ &oldcbarg);
+ dns_acache_detachentry(&oldentry);
+ }
+
+ return (ISC_R_SUCCESS);
+
+ fail:
+ if (newcbarg != NULL) {
+ if (newentry != NULL) {
+ acache_cancelentry(rbtdb->common.mctx, newentry,
+ &newcbarg);
+ dns_acache_detachentry(&newentry);
+ } else {
+ dns_db_detachnode((dns_db_t *)rbtdb, &newcbarg->node);
+ dns_db_detach(&newcbarg->db);
+ isc_mem_put(rbtdb->common.mctx, newcbarg,
+ sizeof(*newcbarg));
+ }
+ }
+
+ return (result);
+}
+
+static isc_result_t
+rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type, dns_rdatatype_t qtype)
+{
+ dns_rbtdb_t *rbtdb = rdataset->private1;
+ dns_rbtnode_t *rbtnode = rdataset->private2;
+ unsigned char *raw = rdataset->private3; /* RDATASLAB */
+ unsigned int current_count = rdataset->privateuint4;
+ rdatasetheader_t *header;
+ nodelock_t *nodelock;
+ unsigned int total_count, count;
+ acachectl_t *acarray;
+ dns_acacheentry_t *entry;
+ acache_cbarg_t *cbarg;
+
+ UNUSED(qtype); /* we do not use this value at least for now */
+ UNUSED(acache);
+
+ if (type == dns_rdatasetadditional_fromcache)
+ return (ISC_R_SUCCESS);
+
+ header = (struct rdatasetheader *)(raw - sizeof(*header));
+
+ total_count = raw[0] * 256 + raw[1];
+ INSIST(total_count > current_count);
+ count = total_count - current_count - 1;
+
+ acarray = NULL;
+ entry = NULL;
+
+ nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
+ NODE_LOCK(nodelock, isc_rwlocktype_write);
+
+ switch (type) {
+ case dns_rdatasetadditional_fromauth:
+ acarray = header->additional_auth;
+ break;
+ case dns_rdatasetadditional_fromglue:
+ acarray = header->additional_glue;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ if (acarray == NULL) {
+ NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+ return (ISC_R_NOTFOUND);
+ }
+
+ entry = acarray[count].entry;
+ if (entry == NULL) {
+ NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+ return (ISC_R_NOTFOUND);
+ }
+
+ acarray[count].entry = NULL;
+ cbarg = acarray[count].cbarg;
+ acarray[count].cbarg = NULL;
+
+ NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+
+ if (entry != NULL) {
+ if (cbarg != NULL)
+ acache_cancelentry(rbtdb->common.mctx, entry, &cbarg);
+ dns_acache_detachentry(&entry);
+ }
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/dns/rbtdb.h b/lib/dns/rbtdb.h
new file mode 100644
index 0000000..f9fb50b
--- /dev/null
+++ b/lib/dns/rbtdb.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2004, 2005 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: rbtdb.h,v 1.14.18.2 2005/04/29 00:16:02 marka Exp $ */
+
+#ifndef DNS_RBTDB_H
+#define DNS_RBTDB_H 1
+
+#include <isc/lang.h>
+#include <dns/types.h>
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * DNS Red-Black Tree DB Implementation
+ */
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_rbtdb_create(isc_mem_t *mctx, dns_name_t *base, dns_dbtype_t type,
+ dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
+ void *driverarg, dns_db_t **dbp);
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RBTDB_H */
diff --git a/lib/dns/rbtdb64.c b/lib/dns/rbtdb64.c
new file mode 100644
index 0000000..773fe91
--- /dev/null
+++ b/lib/dns/rbtdb64.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2004, 2005 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: rbtdb64.c,v 1.7.18.2 2005/04/29 00:16:02 marka Exp $ */
+
+/*! \file */
+
+#define DNS_RBTDB_VERSION64 1
+#include "rbtdb.c"
diff --git a/lib/dns/rbtdb64.h b/lib/dns/rbtdb64.h
new file mode 100644
index 0000000..e2de45c
--- /dev/null
+++ b/lib/dns/rbtdb64.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2005 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: rbtdb64.h,v 1.13.18.2 2005/04/29 00:16:02 marka Exp $ */
+
+#ifndef DNS_RBTDB64_H
+#define DNS_RBTDB64_H 1
+
+#include <isc/lang.h>
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * DNS Red-Black Tree DB Implementation with 64-bit version numbers
+ */
+
+#include <dns/db.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_rbtdb64_create(isc_mem_t *mctx, dns_name_t *base, dns_dbtype_t type,
+ dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
+ void *driverarg, dns_db_t **dbp);
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RBTDB64_H */
diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c
new file mode 100644
index 0000000..f61aa35
--- /dev/null
+++ b/lib/dns/rcode.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: rcode.c,v 1.2.18.2 2006/01/27 23:57:44 marka Exp $ */
+
+#include <config.h>
+#include <ctype.h>
+
+#include <isc/buffer.h>
+#include <isc/parseint.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/result.h>
+#include <isc/stdio.h>
+#include <isc/stdlib.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <dns/cert.h>
+#include <dns/keyflags.h>
+#include <dns/keyvalues.h>
+#include <dns/rcode.h>
+#include <dns/rdataclass.h>
+#include <dns/result.h>
+#include <dns/secalg.h>
+#include <dns/secproto.h>
+
+#define RETERR(x) \
+ do { \
+ isc_result_t _r = (x); \
+ if (_r != ISC_R_SUCCESS) \
+ return (_r); \
+ } while (0)
+
+#define NUMBERSIZE sizeof("037777777777") /* 2^32-1 octal + NUL */
+
+#define RCODENAMES \
+ /* standard rcodes */ \
+ { dns_rcode_noerror, "NOERROR", 0}, \
+ { dns_rcode_formerr, "FORMERR", 0}, \
+ { dns_rcode_servfail, "SERVFAIL", 0}, \
+ { dns_rcode_nxdomain, "NXDOMAIN", 0}, \
+ { dns_rcode_notimp, "NOTIMP", 0}, \
+ { dns_rcode_refused, "REFUSED", 0}, \
+ { dns_rcode_yxdomain, "YXDOMAIN", 0}, \
+ { dns_rcode_yxrrset, "YXRRSET", 0}, \
+ { dns_rcode_nxrrset, "NXRRSET", 0}, \
+ { dns_rcode_notauth, "NOTAUTH", 0}, \
+ { dns_rcode_notzone, "NOTZONE", 0},
+
+#define ERCODENAMES \
+ /* extended rcodes */ \
+ { dns_rcode_badvers, "BADVERS", 0}, \
+ { 0, NULL, 0 }
+
+#define TSIGRCODENAMES \
+ /* extended rcodes */ \
+ { dns_tsigerror_badsig, "BADSIG", 0}, \
+ { dns_tsigerror_badkey, "BADKEY", 0}, \
+ { dns_tsigerror_badtime, "BADTIME", 0}, \
+ { dns_tsigerror_badmode, "BADMODE", 0}, \
+ { dns_tsigerror_badname, "BADNAME", 0}, \
+ { dns_tsigerror_badalg, "BADALG", 0}, \
+ { dns_tsigerror_badtrunc, "BADTRUNC", 0}, \
+ { 0, NULL, 0 }
+
+/* RFC2538 section 2.1 */
+
+#define CERTNAMES \
+ { 1, "PKIX", 0}, \
+ { 2, "SPKI", 0}, \
+ { 3, "PGP", 0}, \
+ { 253, "URI", 0}, \
+ { 254, "OID", 0}, \
+ { 0, NULL, 0}
+
+/* RFC2535 section 7, RFC3110 */
+
+#define SECALGNAMES \
+ { DNS_KEYALG_RSAMD5, "RSAMD5", 0 }, \
+ { DNS_KEYALG_RSAMD5, "RSA", 0 }, \
+ { DNS_KEYALG_DH, "DH", 0 }, \
+ { DNS_KEYALG_DSA, "DSA", 0 }, \
+ { DNS_KEYALG_ECC, "ECC", 0 }, \
+ { DNS_KEYALG_RSASHA1, "RSASHA1", 0 }, \
+ { DNS_KEYALG_INDIRECT, "INDIRECT", 0 }, \
+ { DNS_KEYALG_PRIVATEDNS, "PRIVATEDNS", 0 }, \
+ { DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, \
+ { 0, NULL, 0}
+
+/* RFC2535 section 7.1 */
+
+#define SECPROTONAMES \
+ { 0, "NONE", 0 }, \
+ { 1, "TLS", 0 }, \
+ { 2, "EMAIL", 0 }, \
+ { 3, "DNSSEC", 0 }, \
+ { 4, "IPSEC", 0 }, \
+ { 255, "ALL", 0 }, \
+ { 0, NULL, 0}
+
+struct tbl {
+ unsigned int value;
+ const char *name;
+ int flags;
+};
+
+static struct tbl rcodes[] = { RCODENAMES ERCODENAMES };
+static struct tbl tsigrcodes[] = { RCODENAMES TSIGRCODENAMES };
+static struct tbl certs[] = { CERTNAMES };
+static struct tbl secalgs[] = { SECALGNAMES };
+static struct tbl secprotos[] = { SECPROTONAMES };
+
+static struct keyflag {
+ const char *name;
+ unsigned int value;
+ unsigned int mask;
+} keyflags[] = {
+ { "NOCONF", 0x4000, 0xC000 },
+ { "NOAUTH", 0x8000, 0xC000 },
+ { "NOKEY", 0xC000, 0xC000 },
+ { "FLAG2", 0x2000, 0x2000 },
+ { "EXTEND", 0x1000, 0x1000 },
+ { "FLAG4", 0x0800, 0x0800 },
+ { "FLAG5", 0x0400, 0x0400 },
+ { "USER", 0x0000, 0x0300 },
+ { "ZONE", 0x0100, 0x0300 },
+ { "HOST", 0x0200, 0x0300 },
+ { "NTYP3", 0x0300, 0x0300 },
+ { "FLAG8", 0x0080, 0x0080 },
+ { "FLAG9", 0x0040, 0x0040 },
+ { "FLAG10", 0x0020, 0x0020 },
+ { "FLAG11", 0x0010, 0x0010 },
+ { "SIG0", 0x0000, 0x000F },
+ { "SIG1", 0x0001, 0x000F },
+ { "SIG2", 0x0002, 0x000F },
+ { "SIG3", 0x0003, 0x000F },
+ { "SIG4", 0x0004, 0x000F },
+ { "SIG5", 0x0005, 0x000F },
+ { "SIG6", 0x0006, 0x000F },
+ { "SIG7", 0x0007, 0x000F },
+ { "SIG8", 0x0008, 0x000F },
+ { "SIG9", 0x0009, 0x000F },
+ { "SIG10", 0x000A, 0x000F },
+ { "SIG11", 0x000B, 0x000F },
+ { "SIG12", 0x000C, 0x000F },
+ { "SIG13", 0x000D, 0x000F },
+ { "SIG14", 0x000E, 0x000F },
+ { "SIG15", 0x000F, 0x000F },
+ { "KSK", DNS_KEYFLAG_KSK, DNS_KEYFLAG_KSK },
+ { NULL, 0, 0 }
+};
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target) {
+ unsigned int l;
+ isc_region_t region;
+
+ isc_buffer_availableregion(target, &region);
+ l = strlen(source);
+
+ if (l > region.length)
+ return (ISC_R_NOSPACE);
+
+ memcpy(region.base, source, l);
+ isc_buffer_add(target, l);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+maybe_numeric(unsigned int *valuep, isc_textregion_t *source,
+ unsigned int max, isc_boolean_t hex_allowed)
+{
+ isc_result_t result;
+ isc_uint32_t n;
+ char buffer[NUMBERSIZE];
+
+ if (! isdigit(source->base[0] & 0xff) ||
+ source->length > NUMBERSIZE - 1)
+ return (ISC_R_BADNUMBER);
+
+ /*
+ * We have a potential number. Try to parse it with
+ * isc_parse_uint32(). isc_parse_uint32() requires
+ * null termination, so we must make a copy.
+ */
+ strncpy(buffer, source->base, NUMBERSIZE);
+ INSIST(buffer[source->length] == '\0');
+
+ result = isc_parse_uint32(&n, buffer, 10);
+ if (result == ISC_R_BADNUMBER && hex_allowed)
+ result = isc_parse_uint32(&n, buffer, 16);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (n > max)
+ return (ISC_R_RANGE);
+ *valuep = n;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dns_mnemonic_fromtext(unsigned int *valuep, isc_textregion_t *source,
+ struct tbl *table, unsigned int max)
+{
+ isc_result_t result;
+ int i;
+
+ result = maybe_numeric(valuep, source, max, ISC_FALSE);
+ if (result != ISC_R_BADNUMBER)
+ return (result);
+
+ for (i = 0; table[i].name != NULL; i++) {
+ unsigned int n;
+ n = strlen(table[i].name);
+ if (n == source->length &&
+ strncasecmp(source->base, table[i].name, n) == 0) {
+ *valuep = table[i].value;
+ return (ISC_R_SUCCESS);
+ }
+ }
+ return (DNS_R_UNKNOWN);
+}
+
+static isc_result_t
+dns_mnemonic_totext(unsigned int value, isc_buffer_t *target,
+ struct tbl *table)
+{
+ int i = 0;
+ char buf[sizeof("4294967296")];
+ while (table[i].name != NULL) {
+ if (table[i].value == value) {
+ return (str_totext(table[i].name, target));
+ }
+ i++;
+ }
+ snprintf(buf, sizeof(buf), "%u", value);
+ return (str_totext(buf, target));
+}
+
+isc_result_t
+dns_rcode_fromtext(dns_rcode_t *rcodep, isc_textregion_t *source) {
+ unsigned int value;
+ RETERR(dns_mnemonic_fromtext(&value, source, rcodes, 0xffff));
+ *rcodep = value;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_rcode_totext(dns_rcode_t rcode, isc_buffer_t *target) {
+ return (dns_mnemonic_totext(rcode, target, rcodes));
+}
+
+isc_result_t
+dns_tsigrcode_fromtext(dns_rcode_t *rcodep, isc_textregion_t *source) {
+ unsigned int value;
+ RETERR(dns_mnemonic_fromtext(&value, source, tsigrcodes, 0xffff));
+ *rcodep = value;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_tsigrcode_totext(dns_rcode_t rcode, isc_buffer_t *target) {
+ return (dns_mnemonic_totext(rcode, target, tsigrcodes));
+}
+
+isc_result_t
+dns_cert_fromtext(dns_cert_t *certp, isc_textregion_t *source) {
+ unsigned int value;
+ RETERR(dns_mnemonic_fromtext(&value, source, certs, 0xffff));
+ *certp = value;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_cert_totext(dns_cert_t cert, isc_buffer_t *target) {
+ return (dns_mnemonic_totext(cert, target, certs));
+}
+
+isc_result_t
+dns_secalg_fromtext(dns_secalg_t *secalgp, isc_textregion_t *source) {
+ unsigned int value;
+ RETERR(dns_mnemonic_fromtext(&value, source, secalgs, 0xff));
+ *secalgp = value;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target) {
+ return (dns_mnemonic_totext(secalg, target, secalgs));
+}
+
+isc_result_t
+dns_secproto_fromtext(dns_secproto_t *secprotop, isc_textregion_t *source) {
+ unsigned int value;
+ RETERR(dns_mnemonic_fromtext(&value, source, secprotos, 0xff));
+ *secprotop = value;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_secproto_totext(dns_secproto_t secproto, isc_buffer_t *target) {
+ return (dns_mnemonic_totext(secproto, target, secprotos));
+}
+
+isc_result_t
+dns_keyflags_fromtext(dns_keyflags_t *flagsp, isc_textregion_t *source)
+{
+ isc_result_t result;
+ char *text, *end;
+ unsigned int value, mask;
+
+ result = maybe_numeric(&value, source, 0xffff, ISC_TRUE);
+ if (result == ISC_R_SUCCESS) {
+ *flagsp = value;
+ return (ISC_R_SUCCESS);
+ }
+ if (result != ISC_R_BADNUMBER)
+ return (result);
+
+ text = source->base;
+ end = source->base + source->length;
+ value = mask = 0;
+
+ while (text < end) {
+ struct keyflag *p;
+ unsigned int len;
+ char *delim = memchr(text, '|', end - text);
+ if (delim != NULL)
+ len = delim - text;
+ else
+ len = end - text;
+ for (p = keyflags; p->name != NULL; p++) {
+ if (strncasecmp(p->name, text, len) == 0)
+ break;
+ }
+ if (p->name == NULL)
+ return (DNS_R_UNKNOWNFLAG);
+ value |= p->value;
+#ifdef notyet
+ if ((mask & p->mask) != 0)
+ warn("overlapping key flags");
+#endif
+ mask |= p->mask;
+ text += len;
+ if (delim != NULL)
+ text++; /* Skip "|" */
+ }
+ *flagsp = value;
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This uses lots of hard coded values, but how often do we actually
+ * add classes?
+ */
+isc_result_t
+dns_rdataclass_fromtext(dns_rdataclass_t *classp, isc_textregion_t *source) {
+#define COMPARE(string, rdclass) \
+ if (((sizeof(string) - 1) == source->length) \
+ && (strncasecmp(source->base, string, source->length) == 0)) { \
+ *classp = rdclass; \
+ return (ISC_R_SUCCESS); \
+ }
+
+ switch (tolower((unsigned char)source->base[0])) {
+ case 'a':
+ COMPARE("any", dns_rdataclass_any);
+ break;
+ case 'c':
+ /*
+ * RFC1035 says the mnemonic for the CHAOS class is CH,
+ * but historical BIND practice is to call it CHAOS.
+ * We will accept both forms, but only generate CH.
+ */
+ COMPARE("ch", dns_rdataclass_chaos);
+ COMPARE("chaos", dns_rdataclass_chaos);
+
+ if (source->length > 5 &&
+ source->length < (5 + sizeof("65000")) &&
+ strncasecmp("class", source->base, 5) == 0) {
+ char buf[sizeof("65000")];
+ char *endp;
+ unsigned int val;
+
+ strncpy(buf, source->base + 5, source->length - 5);
+ buf[source->length - 5] = '\0';
+ val = strtoul(buf, &endp, 10);
+ if (*endp == '\0' && val <= 0xffff) {
+ *classp = (dns_rdataclass_t)val;
+ return (ISC_R_SUCCESS);
+ }
+ }
+ break;
+ case 'h':
+ COMPARE("hs", dns_rdataclass_hs);
+ COMPARE("hesiod", dns_rdataclass_hs);
+ break;
+ case 'i':
+ COMPARE("in", dns_rdataclass_in);
+ break;
+ case 'n':
+ COMPARE("none", dns_rdataclass_none);
+ break;
+ case 'r':
+ COMPARE("reserved0", dns_rdataclass_reserved0);
+ break;
+ }
+
+#undef COMPARE
+
+ return (DNS_R_UNKNOWN);
+}
+
+isc_result_t
+dns_rdataclass_totext(dns_rdataclass_t rdclass, isc_buffer_t *target) {
+ char buf[sizeof("CLASS65535")];
+
+ switch (rdclass) {
+ case dns_rdataclass_any:
+ return (str_totext("ANY", target));
+ case dns_rdataclass_chaos:
+ return (str_totext("CH", target));
+ case dns_rdataclass_hs:
+ return (str_totext("HS", target));
+ case dns_rdataclass_in:
+ return (str_totext("IN", target));
+ case dns_rdataclass_none:
+ return (str_totext("NONE", target));
+ case dns_rdataclass_reserved0:
+ return (str_totext("RESERVED0", target));
+ default:
+ snprintf(buf, sizeof(buf), "CLASS%u", rdclass);
+ return (str_totext(buf, target));
+ }
+}
+
+void
+dns_rdataclass_format(dns_rdataclass_t rdclass,
+ char *array, unsigned int size)
+{
+ isc_result_t result;
+ isc_buffer_t buf;
+
+ isc_buffer_init(&buf, array, size);
+ result = dns_rdataclass_totext(rdclass, &buf);
+ /*
+ * Null terminate.
+ */
+ if (result == ISC_R_SUCCESS) {
+ if (isc_buffer_availablelength(&buf) >= 1)
+ isc_buffer_putuint8(&buf, 0);
+ else
+ result = ISC_R_NOSPACE;
+ }
+ if (result != ISC_R_SUCCESS) {
+ snprintf(array, size, "<unknown>");
+ array[size - 1] = '\0';
+ }
+}
diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c
new file mode 100644
index 0000000..5641777
--- /dev/null
+++ b/lib/dns/rdata.c
@@ -0,0 +1,1746 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: rdata.c,v 1.184.18.9 2006/07/21 02:05:57 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+#include <ctype.h>
+
+#include <isc/base64.h>
+#include <isc/hex.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/parseint.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/stdlib.h>
+#include <isc/util.h>
+
+#include <dns/callbacks.h>
+#include <dns/cert.h>
+#include <dns/compress.h>
+#include <dns/enumtype.h>
+#include <dns/keyflags.h>
+#include <dns/keyvalues.h>
+#include <dns/rcode.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatastruct.h>
+#include <dns/rdatatype.h>
+#include <dns/result.h>
+#include <dns/secalg.h>
+#include <dns/secproto.h>
+#include <dns/time.h>
+#include <dns/ttl.h>
+
+#define RETERR(x) \
+ do { \
+ isc_result_t _r = (x); \
+ if (_r != ISC_R_SUCCESS) \
+ return (_r); \
+ } while (0)
+
+#define RETTOK(x) \
+ do { \
+ isc_result_t _r = (x); \
+ if (_r != ISC_R_SUCCESS) { \
+ isc_lex_ungettoken(lexer, &token); \
+ return (_r); \
+ } \
+ } while (0)
+
+#define DNS_AS_STR(t) ((t).value.as_textregion.base)
+
+#define ARGS_FROMTEXT int rdclass, dns_rdatatype_t type, \
+ isc_lex_t *lexer, dns_name_t *origin, \
+ unsigned int options, isc_buffer_t *target, \
+ dns_rdatacallbacks_t *callbacks
+
+#define ARGS_TOTEXT dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, \
+ isc_buffer_t *target
+
+#define ARGS_FROMWIRE int rdclass, dns_rdatatype_t type, \
+ isc_buffer_t *source, dns_decompress_t *dctx, \
+ unsigned int options, isc_buffer_t *target
+
+#define ARGS_TOWIRE dns_rdata_t *rdata, dns_compress_t *cctx, \
+ isc_buffer_t *target
+
+#define ARGS_COMPARE const dns_rdata_t *rdata1, const dns_rdata_t *rdata2
+
+#define ARGS_FROMSTRUCT int rdclass, dns_rdatatype_t type, \
+ void *source, isc_buffer_t *target
+
+#define ARGS_TOSTRUCT dns_rdata_t *rdata, void *target, isc_mem_t *mctx
+
+#define ARGS_FREESTRUCT void *source
+
+#define ARGS_ADDLDATA dns_rdata_t *rdata, dns_additionaldatafunc_t add, \
+ void *arg
+
+#define ARGS_DIGEST dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg
+
+#define ARGS_CHECKOWNER dns_name_t *name, dns_rdataclass_t rdclass, \
+ dns_rdatatype_t type, isc_boolean_t wildcard
+
+#define ARGS_CHECKNAMES dns_rdata_t *rdata, dns_name_t *owner, dns_name_t *bad
+
+
+/*%
+ * Context structure for the totext_ functions.
+ * Contains formatting options for rdata-to-text
+ * conversion.
+ */
+typedef struct dns_rdata_textctx {
+ dns_name_t *origin; /*%< Current origin, or NULL. */
+ unsigned int flags; /*%< DNS_STYLEFLAG_* */
+ unsigned int width; /*%< Width of rdata column. */
+ const char *linebreak; /*%< Line break string. */
+} dns_rdata_textctx_t;
+
+static isc_result_t
+txt_totext(isc_region_t *source, isc_buffer_t *target);
+
+static isc_result_t
+txt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
+
+static isc_result_t
+txt_fromwire(isc_buffer_t *source, isc_buffer_t *target);
+
+static isc_boolean_t
+name_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target);
+
+static unsigned int
+name_length(dns_name_t *name);
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target);
+
+static isc_result_t
+inet_totext(int af, isc_region_t *src, isc_buffer_t *target);
+
+static isc_boolean_t
+buffer_empty(isc_buffer_t *source);
+
+static void
+buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region);
+
+static isc_result_t
+uint32_tobuffer(isc_uint32_t, isc_buffer_t *target);
+
+static isc_result_t
+uint16_tobuffer(isc_uint32_t, isc_buffer_t *target);
+
+static isc_result_t
+uint8_tobuffer(isc_uint32_t, isc_buffer_t *target);
+
+static isc_result_t
+name_tobuffer(dns_name_t *name, isc_buffer_t *target);
+
+static isc_uint32_t
+uint32_fromregion(isc_region_t *region);
+
+static isc_uint16_t
+uint16_fromregion(isc_region_t *region);
+
+static isc_uint8_t
+uint8_fromregion(isc_region_t *region);
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
+
+static int
+hexvalue(char value);
+
+static int
+decvalue(char value);
+
+static isc_result_t
+btoa_totext(unsigned char *inbuf, int inbuflen, isc_buffer_t *target);
+
+static isc_result_t
+atob_tobuffer(isc_lex_t *lexer, isc_buffer_t *target);
+
+static void
+default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *, ...)
+ ISC_FORMAT_PRINTF(2, 3);
+
+static void
+fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
+ dns_rdatacallbacks_t *callbacks, const char *name,
+ unsigned long line, isc_token_t *token, isc_result_t result);
+
+static void
+fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks);
+
+static isc_result_t
+rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
+ isc_buffer_t *target);
+
+static void
+warn_badname(dns_name_t *name, isc_lex_t *lexer,
+ dns_rdatacallbacks_t *callbacks);
+
+static void
+warn_badmx(isc_token_t *token, isc_lex_t *lexer,
+ dns_rdatacallbacks_t *callbacks);
+
+static inline int
+getquad(const void *src, struct in_addr *dst,
+ isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks)
+{
+ int result;
+ struct in_addr *tmp;
+
+ result = inet_aton(src, dst);
+ if (result == 1 && callbacks != NULL &&
+ inet_pton(AF_INET, src, &tmp) != 1) {
+ const char *name = isc_lex_getsourcename(lexer);
+ if (name == NULL)
+ name = "UNKNOWN";
+ (*callbacks->warn)(callbacks, "%s:%lu: \"%s\" "
+ "is not a decimal dotted quad", name,
+ isc_lex_getsourceline(lexer), src);
+ }
+ return (result);
+}
+
+static inline isc_result_t
+name_duporclone(dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
+
+ if (mctx != NULL)
+ return (dns_name_dup(source, mctx, target));
+ dns_name_clone(source, target);
+ return (ISC_R_SUCCESS);
+}
+
+static inline void *
+mem_maybedup(isc_mem_t *mctx, void *source, size_t length) {
+ void *new;
+
+ if (mctx == NULL)
+ return (source);
+ new = isc_mem_allocate(mctx, length);
+ if (new != NULL)
+ memcpy(new, source, length);
+
+ return (new);
+}
+
+static const char hexdigits[] = "0123456789abcdef";
+static const char decdigits[] = "0123456789";
+
+#include "code.h"
+
+#define META 0x0001
+#define RESERVED 0x0002
+
+/***
+ *** Initialization
+ ***/
+
+void
+dns_rdata_init(dns_rdata_t *rdata) {
+
+ REQUIRE(rdata != NULL);
+
+ rdata->data = NULL;
+ rdata->length = 0;
+ rdata->rdclass = 0;
+ rdata->type = 0;
+ rdata->flags = 0;
+ ISC_LINK_INIT(rdata, link);
+ /* ISC_LIST_INIT(rdata->list); */
+}
+
+#if 0
+#define DNS_RDATA_INITIALIZED(rdata) \
+ ((rdata)->data == NULL && (rdata)->length == 0 && \
+ (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \
+ !ISC_LINK_LINKED((rdata), link))
+#else
+#ifdef ISC_LIST_CHECKINIT
+#define DNS_RDATA_INITIALIZED(rdata) \
+ (!ISC_LINK_LINKED((rdata), link))
+#else
+#define DNS_RDATA_INITIALIZED(rdata) ISC_TRUE
+#endif
+#endif
+#define DNS_RDATA_VALIDFLAGS(rdata) \
+ (((rdata)->flags & ~DNS_RDATA_UPDATE) == 0)
+
+void
+dns_rdata_reset(dns_rdata_t *rdata) {
+
+ REQUIRE(rdata != NULL);
+
+ REQUIRE(!ISC_LINK_LINKED(rdata, link));
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+
+ rdata->data = NULL;
+ rdata->length = 0;
+ rdata->rdclass = 0;
+ rdata->type = 0;
+ rdata->flags = 0;
+}
+
+/***
+ ***
+ ***/
+
+void
+dns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target) {
+
+ REQUIRE(src != NULL);
+ REQUIRE(target != NULL);
+
+ REQUIRE(DNS_RDATA_INITIALIZED(target));
+
+ REQUIRE(DNS_RDATA_VALIDFLAGS(src));
+ REQUIRE(DNS_RDATA_VALIDFLAGS(target));
+
+ target->data = src->data;
+ target->length = src->length;
+ target->rdclass = src->rdclass;
+ target->type = src->type;
+ target->flags = src->flags;
+}
+
+
+/***
+ *** Comparisons
+ ***/
+
+int
+dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) {
+ int result = 0;
+ isc_boolean_t use_default = ISC_FALSE;
+
+ REQUIRE(rdata1 != NULL);
+ REQUIRE(rdata2 != NULL);
+ REQUIRE(rdata1->data != NULL);
+ REQUIRE(rdata2->data != NULL);
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1));
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2));
+
+ if (rdata1->rdclass != rdata2->rdclass)
+ return (rdata1->rdclass < rdata2->rdclass ? -1 : 1);
+
+ if (rdata1->type != rdata2->type)
+ return (rdata1->type < rdata2->type ? -1 : 1);
+
+ COMPARESWITCH
+
+ if (use_default) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ result = isc_region_compare(&r1, &r2);
+ }
+ return (result);
+}
+
+/***
+ *** Conversions
+ ***/
+
+void
+dns_rdata_fromregion(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, isc_region_t *r)
+{
+
+ REQUIRE(rdata != NULL);
+ REQUIRE(DNS_RDATA_INITIALIZED(rdata));
+ REQUIRE(r != NULL);
+
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+
+ rdata->data = r->base;
+ rdata->length = r->length;
+ rdata->rdclass = rdclass;
+ rdata->type = type;
+ rdata->flags = 0;
+}
+
+void
+dns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r) {
+
+ REQUIRE(rdata != NULL);
+ REQUIRE(r != NULL);
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+
+ r->base = rdata->data;
+ r->length = rdata->length;
+}
+
+isc_result_t
+dns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, isc_buffer_t *source,
+ dns_decompress_t *dctx, unsigned int options,
+ isc_buffer_t *target)
+{
+ isc_result_t result = ISC_R_NOTIMPLEMENTED;
+ isc_region_t region;
+ isc_buffer_t ss;
+ isc_buffer_t st;
+ isc_boolean_t use_default = ISC_FALSE;
+ isc_uint32_t activelength;
+
+ REQUIRE(dctx != NULL);
+ if (rdata != NULL) {
+ REQUIRE(DNS_RDATA_INITIALIZED(rdata));
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+ }
+
+ if (type == 0)
+ return (DNS_R_FORMERR);
+
+ ss = *source;
+ st = *target;
+
+ activelength = isc_buffer_activelength(source);
+ INSIST(activelength < 65536);
+
+ FROMWIRESWITCH
+
+ if (use_default) {
+ if (activelength > isc_buffer_availablelength(target))
+ result = ISC_R_NOSPACE;
+ else {
+ isc_buffer_putmem(target, isc_buffer_current(source),
+ activelength);
+ isc_buffer_forward(source, activelength);
+ result = ISC_R_SUCCESS;
+ }
+ }
+
+ /*
+ * We should have consumed all of our buffer.
+ */
+ if (result == ISC_R_SUCCESS && !buffer_empty(source))
+ result = DNS_R_EXTRADATA;
+
+ if (rdata != NULL && result == ISC_R_SUCCESS) {
+ region.base = isc_buffer_used(&st);
+ region.length = isc_buffer_usedlength(target) -
+ isc_buffer_usedlength(&st);
+ dns_rdata_fromregion(rdata, rdclass, type, &region);
+ }
+
+ if (result != ISC_R_SUCCESS) {
+ *source = ss;
+ *target = st;
+ }
+ return (result);
+}
+
+isc_result_t
+dns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx,
+ isc_buffer_t *target)
+{
+ isc_result_t result = ISC_R_NOTIMPLEMENTED;
+ isc_boolean_t use_default = ISC_FALSE;
+ isc_region_t tr;
+ isc_buffer_t st;
+
+ REQUIRE(rdata != NULL);
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+
+ /*
+ * Some DynDNS meta-RRs have empty rdata.
+ */
+ if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
+ INSIST(rdata->length == 0);
+ return (ISC_R_SUCCESS);
+ }
+
+ st = *target;
+
+ TOWIRESWITCH
+
+ if (use_default) {
+ isc_buffer_availableregion(target, &tr);
+ if (tr.length < rdata->length)
+ return (ISC_R_NOSPACE);
+ memcpy(tr.base, rdata->data, rdata->length);
+ isc_buffer_add(target, rdata->length);
+ return (ISC_R_SUCCESS);
+ }
+ if (result != ISC_R_SUCCESS) {
+ *target = st;
+ INSIST(target->used < 65536);
+ dns_compress_rollback(cctx, (isc_uint16_t)target->used);
+ }
+ return (result);
+}
+
+/*
+ * If the binary data in 'src' is valid uncompressed wire format
+ * rdata of class 'rdclass' and type 'type', return ISC_R_SUCCESS
+ * and copy the validated rdata to 'dest'. Otherwise return an error.
+ */
+static isc_result_t
+rdata_validate(isc_buffer_t *src, isc_buffer_t *dest, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type)
+{
+ dns_decompress_t dctx;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_result_t result;
+
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
+ isc_buffer_setactive(src, isc_buffer_usedlength(src));
+ result = dns_rdata_fromwire(&rdata, rdclass, type, src,
+ &dctx, 0, dest);
+ dns_decompress_invalidate(&dctx);
+
+ return (result);
+}
+
+static isc_result_t
+unknown_fromtext(dns_rdataclass_t rdclass, dns_rdatatype_t type,
+ isc_lex_t *lexer, isc_mem_t *mctx, isc_buffer_t *target)
+{
+ isc_result_t result;
+ isc_buffer_t *buf = NULL;
+ isc_token_t token;
+
+ if (type == 0 || dns_rdatatype_ismeta(type))
+ return (DNS_R_METATYPE);
+
+ result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE);
+ if (result == ISC_R_SUCCESS && token.value.as_ulong > 65535U)
+ return (ISC_R_RANGE);
+ result = isc_buffer_allocate(mctx, &buf, token.value.as_ulong);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = isc_hex_tobuffer(lexer, buf,
+ (unsigned int)token.value.as_ulong);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ if (isc_buffer_usedlength(buf) != token.value.as_ulong) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto failure;
+ }
+
+ if (dns_rdatatype_isknown(type)) {
+ result = rdata_validate(buf, target, rdclass, type);
+ } else {
+ isc_region_t r;
+ isc_buffer_usedregion(buf, &r);
+ result = isc_buffer_copyregion(target, &r);
+ }
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ isc_buffer_free(&buf);
+ return (ISC_R_SUCCESS);
+
+ failure:
+ isc_buffer_free(&buf);
+ return (result);
+}
+
+isc_result_t
+dns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, isc_lex_t *lexer,
+ dns_name_t *origin, unsigned int options, isc_mem_t *mctx,
+ isc_buffer_t *target, dns_rdatacallbacks_t *callbacks)
+{
+ isc_result_t result = ISC_R_NOTIMPLEMENTED;
+ isc_region_t region;
+ isc_buffer_t st;
+ isc_token_t token;
+ unsigned int lexoptions = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
+ ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
+ char *name;
+ unsigned long line;
+ void (*callback)(dns_rdatacallbacks_t *, const char *, ...);
+ isc_result_t tresult;
+
+ REQUIRE(origin == NULL || dns_name_isabsolute(origin) == ISC_TRUE);
+ if (rdata != NULL) {
+ REQUIRE(DNS_RDATA_INITIALIZED(rdata));
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+ }
+ if (callbacks != NULL) {
+ REQUIRE(callbacks->warn != NULL);
+ REQUIRE(callbacks->error != NULL);
+ }
+
+ st = *target;
+
+ if (callbacks != NULL)
+ callback = callbacks->error;
+ else
+ callback = default_fromtext_callback;
+
+ result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
+ ISC_FALSE);
+ if (result != ISC_R_SUCCESS) {
+ name = isc_lex_getsourcename(lexer);
+ line = isc_lex_getsourceline(lexer);
+ fromtext_error(callback, callbacks, name, line,
+ &token, result);
+ return (result);
+ }
+
+ if (strcmp(DNS_AS_STR(token), "\\#") == 0)
+ result = unknown_fromtext(rdclass, type, lexer, mctx, target);
+ else {
+ isc_lex_ungettoken(lexer, &token);
+
+ FROMTEXTSWITCH
+ }
+
+ /*
+ * Consume to end of line / file.
+ * If not at end of line initially set error code.
+ * Call callback via fromtext_error once if there was an error.
+ */
+ do {
+ name = isc_lex_getsourcename(lexer);
+ line = isc_lex_getsourceline(lexer);
+ tresult = isc_lex_gettoken(lexer, lexoptions, &token);
+ if (tresult != ISC_R_SUCCESS) {
+ if (result == ISC_R_SUCCESS)
+ result = tresult;
+ if (callback != NULL)
+ fromtext_error(callback, callbacks, name,
+ line, NULL, result);
+ break;
+ } else if (token.type != isc_tokentype_eol &&
+ token.type != isc_tokentype_eof) {
+ if (result == ISC_R_SUCCESS)
+ result = DNS_R_EXTRATOKEN;
+ if (callback != NULL) {
+ fromtext_error(callback, callbacks, name,
+ line, &token, result);
+ callback = NULL;
+ }
+ } else if (result != ISC_R_SUCCESS && callback != NULL) {
+ fromtext_error(callback, callbacks, name, line,
+ &token, result);
+ break;
+ } else {
+ if (token.type == isc_tokentype_eof)
+ fromtext_warneof(lexer, callbacks);
+ break;
+ }
+ } while (1);
+
+ if (rdata != NULL && result == ISC_R_SUCCESS) {
+ region.base = isc_buffer_used(&st);
+ region.length = isc_buffer_usedlength(target) -
+ isc_buffer_usedlength(&st);
+ dns_rdata_fromregion(rdata, rdclass, type, &region);
+ }
+ if (result != ISC_R_SUCCESS) {
+ *target = st;
+ }
+ return (result);
+}
+
+static isc_result_t
+rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
+ isc_buffer_t *target)
+{
+ isc_result_t result = ISC_R_NOTIMPLEMENTED;
+ isc_boolean_t use_default = ISC_FALSE;
+ char buf[sizeof("65535")];
+ isc_region_t sr;
+
+ REQUIRE(rdata != NULL);
+ REQUIRE(tctx->origin == NULL ||
+ dns_name_isabsolute(tctx->origin) == ISC_TRUE);
+
+ /*
+ * Some DynDNS meta-RRs have empty rdata.
+ */
+ if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
+ INSIST(rdata->length == 0);
+ return (ISC_R_SUCCESS);
+ }
+
+ TOTEXTSWITCH
+
+ if (use_default) {
+ strlcpy(buf, "\\# ", sizeof(buf));
+ result = str_totext(buf, target);
+ dns_rdata_toregion(rdata, &sr);
+ INSIST(sr.length < 65536);
+ snprintf(buf, sizeof(buf), "%u", sr.length);
+ result = str_totext(buf, target);
+ if (sr.length != 0 && result == ISC_R_SUCCESS) {
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ result = str_totext(" ( ", target);
+ else
+ result = str_totext(" ", target);
+ if (result == ISC_R_SUCCESS)
+ result = isc_hex_totext(&sr, tctx->width - 2,
+ tctx->linebreak,
+ target);
+ if (result == ISC_R_SUCCESS &&
+ (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ result = str_totext(" )", target);
+ }
+ }
+
+ return (result);
+}
+
+isc_result_t
+dns_rdata_totext(dns_rdata_t *rdata, dns_name_t *origin, isc_buffer_t *target)
+{
+ dns_rdata_textctx_t tctx;
+
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+
+ /*
+ * Set up formatting options for single-line output.
+ */
+ tctx.origin = origin;
+ tctx.flags = 0;
+ tctx.width = 60;
+ tctx.linebreak = " ";
+ return (rdata_totext(rdata, &tctx, target));
+}
+
+isc_result_t
+dns_rdata_tofmttext(dns_rdata_t *rdata, dns_name_t *origin,
+ unsigned int flags, unsigned int width,
+ char *linebreak, isc_buffer_t *target)
+{
+ dns_rdata_textctx_t tctx;
+
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+
+ /*
+ * Set up formatting options for formatted output.
+ */
+ tctx.origin = origin;
+ tctx.flags = flags;
+ if ((flags & DNS_STYLEFLAG_MULTILINE) != 0) {
+ tctx.width = width;
+ tctx.linebreak = linebreak;
+ } else {
+ tctx.width = 60; /* Used for hex word length only. */
+ tctx.linebreak = " ";
+ }
+ return (rdata_totext(rdata, &tctx, target));
+}
+
+isc_result_t
+dns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, void *source,
+ isc_buffer_t *target)
+{
+ isc_result_t result = ISC_R_NOTIMPLEMENTED;
+ isc_buffer_t st;
+ isc_region_t region;
+ isc_boolean_t use_default = ISC_FALSE;
+
+ REQUIRE(source != NULL);
+ if (rdata != NULL) {
+ REQUIRE(DNS_RDATA_INITIALIZED(rdata));
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+ }
+
+ st = *target;
+
+ FROMSTRUCTSWITCH
+
+ if (use_default)
+ (void)NULL;
+
+ if (rdata != NULL && result == ISC_R_SUCCESS) {
+ region.base = isc_buffer_used(&st);
+ region.length = isc_buffer_usedlength(target) -
+ isc_buffer_usedlength(&st);
+ dns_rdata_fromregion(rdata, rdclass, type, &region);
+ }
+ if (result != ISC_R_SUCCESS)
+ *target = st;
+ return (result);
+}
+
+isc_result_t
+dns_rdata_tostruct(dns_rdata_t *rdata, void *target, isc_mem_t *mctx) {
+ isc_result_t result = ISC_R_NOTIMPLEMENTED;
+ isc_boolean_t use_default = ISC_FALSE;
+
+ REQUIRE(rdata != NULL);
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+
+ TOSTRUCTSWITCH
+
+ if (use_default)
+ (void)NULL;
+
+ return (result);
+}
+
+void
+dns_rdata_freestruct(void *source) {
+ dns_rdatacommon_t *common = source;
+ REQUIRE(source != NULL);
+
+ FREESTRUCTSWITCH
+}
+
+isc_result_t
+dns_rdata_additionaldata(dns_rdata_t *rdata, dns_additionaldatafunc_t add,
+ void *arg)
+{
+ isc_result_t result = ISC_R_NOTIMPLEMENTED;
+ isc_boolean_t use_default = ISC_FALSE;
+
+ /*
+ * Call 'add' for each name and type from 'rdata' which is subject to
+ * additional section processing.
+ */
+
+ REQUIRE(rdata != NULL);
+ REQUIRE(add != NULL);
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+
+ ADDITIONALDATASWITCH
+
+ /* No additional processing for unknown types */
+ if (use_default)
+ result = ISC_R_SUCCESS;
+
+ return (result);
+}
+
+isc_result_t
+dns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg) {
+ isc_result_t result = ISC_R_NOTIMPLEMENTED;
+ isc_boolean_t use_default = ISC_FALSE;
+ isc_region_t r;
+
+ /*
+ * Send 'rdata' in DNSSEC canonical form to 'digest'.
+ */
+
+ REQUIRE(rdata != NULL);
+ REQUIRE(digest != NULL);
+ REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
+
+ DIGESTSWITCH
+
+ if (use_default) {
+ dns_rdata_toregion(rdata, &r);
+ result = (digest)(arg, &r);
+ }
+
+ return (result);
+}
+
+isc_boolean_t
+dns_rdata_checkowner(dns_name_t *name, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type, isc_boolean_t wildcard)
+{
+ isc_boolean_t result;
+
+ CHECKOWNERSWITCH
+ return (result);
+}
+
+isc_boolean_t
+dns_rdata_checknames(dns_rdata_t *rdata, dns_name_t *owner, dns_name_t *bad)
+{
+ isc_boolean_t result;
+
+ CHECKNAMESSWITCH
+ return (result);
+}
+
+unsigned int
+dns_rdatatype_attributes(dns_rdatatype_t type)
+{
+ RDATATYPE_ATTRIBUTE_SW
+ if (type >= (dns_rdatatype_t)128 && type < (dns_rdatatype_t)255)
+ return (DNS_RDATATYPEATTR_UNKNOWN | DNS_RDATATYPEATTR_META);
+ return (DNS_RDATATYPEATTR_UNKNOWN);
+}
+
+isc_result_t
+dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) {
+ unsigned int hash;
+ unsigned int n;
+ unsigned char a, b;
+
+ n = source->length;
+
+ if (n == 0)
+ return (DNS_R_UNKNOWN);
+
+ a = tolower((unsigned char)source->base[0]);
+ b = tolower((unsigned char)source->base[n - 1]);
+
+ hash = ((a + n) * b) % 256;
+
+ /*
+ * This switch block is inlined via #define, and will use "return"
+ * to return a result to the caller if it is a valid (known)
+ * rdatatype name.
+ */
+ RDATATYPE_FROMTEXT_SW(hash, source->base, n, typep);
+
+ if (source->length > 4 && source->length < (4 + sizeof("65000")) &&
+ strncasecmp("type", source->base, 4) == 0) {
+ char buf[sizeof("65000")];
+ char *endp;
+ unsigned int val;
+
+ strncpy(buf, source->base + 4, source->length - 4);
+ buf[source->length - 4] = '\0';
+ val = strtoul(buf, &endp, 10);
+ if (*endp == '\0' && val <= 0xffff) {
+ *typep = (dns_rdatatype_t)val;
+ return (ISC_R_SUCCESS);
+ }
+ }
+
+ return (DNS_R_UNKNOWN);
+}
+
+isc_result_t
+dns_rdatatype_totext(dns_rdatatype_t type, isc_buffer_t *target) {
+ char buf[sizeof("TYPE65535")];
+
+ RDATATYPE_TOTEXT_SW
+ snprintf(buf, sizeof(buf), "TYPE%u", type);
+ return (str_totext(buf, target));
+}
+
+void
+dns_rdatatype_format(dns_rdatatype_t rdtype,
+ char *array, unsigned int size)
+{
+ isc_result_t result;
+ isc_buffer_t buf;
+
+ isc_buffer_init(&buf, array, size);
+ result = dns_rdatatype_totext(rdtype, &buf);
+ /*
+ * Null terminate.
+ */
+ if (result == ISC_R_SUCCESS) {
+ if (isc_buffer_availablelength(&buf) >= 1)
+ isc_buffer_putuint8(&buf, 0);
+ else
+ result = ISC_R_NOSPACE;
+ }
+ if (result != ISC_R_SUCCESS) {
+ snprintf(array, size, "<unknown>");
+ array[size - 1] = '\0';
+ }
+}
+
+/*
+ * Private function.
+ */
+
+static unsigned int
+name_length(dns_name_t *name) {
+ return (name->length);
+}
+
+static isc_result_t
+txt_totext(isc_region_t *source, isc_buffer_t *target) {
+ unsigned int tl;
+ unsigned int n;
+ unsigned char *sp;
+ char *tp;
+ isc_region_t region;
+
+ isc_buffer_availableregion(target, &region);
+ sp = source->base;
+ tp = (char *)region.base;
+ tl = region.length;
+
+ n = *sp++;
+
+ REQUIRE(n + 1 <= source->length);
+
+ if (tl < 1)
+ return (ISC_R_NOSPACE);
+ *tp++ = '"';
+ tl--;
+ while (n--) {
+ if (*sp < 0x20 || *sp >= 0x7f) {
+ if (tl < 4)
+ return (ISC_R_NOSPACE);
+ *tp++ = 0x5c;
+ *tp++ = 0x30 + ((*sp / 100) % 10);
+ *tp++ = 0x30 + ((*sp / 10) % 10);
+ *tp++ = 0x30 + (*sp % 10);
+ sp++;
+ tl -= 4;
+ continue;
+ }
+ /* double quote, semi-colon, backslash */
+ if (*sp == 0x22 || *sp == 0x3b || *sp == 0x5c) {
+ if (tl < 2)
+ return (ISC_R_NOSPACE);
+ *tp++ = '\\';
+ tl--;
+ }
+ if (tl < 1)
+ return (ISC_R_NOSPACE);
+ *tp++ = *sp++;
+ tl--;
+ }
+ if (tl < 1)
+ return (ISC_R_NOSPACE);
+ *tp++ = '"';
+ tl--;
+ isc_buffer_add(target, tp - (char *)region.base);
+ isc_region_consume(source, *source->base + 1);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
+ isc_region_t tregion;
+ isc_boolean_t escape;
+ unsigned int n, nrem;
+ char *s;
+ unsigned char *t;
+ int d;
+ int c;
+
+ isc_buffer_availableregion(target, &tregion);
+ s = source->base;
+ n = source->length;
+ t = tregion.base;
+ nrem = tregion.length;
+ escape = ISC_FALSE;
+ if (nrem < 1)
+ return (ISC_R_NOSPACE);
+ /*
+ * Length byte.
+ */
+ nrem--;
+ t++;
+ /*
+ * Maximum text string length.
+ */
+ if (nrem > 255)
+ nrem = 255;
+ while (n-- != 0) {
+ c = (*s++) & 0xff;
+ if (escape && (d = decvalue((char)c)) != -1) {
+ c = d;
+ if (n == 0)
+ return (DNS_R_SYNTAX);
+ n--;
+ if ((d = decvalue(*s++)) != -1)
+ c = c * 10 + d;
+ else
+ return (DNS_R_SYNTAX);
+ if (n == 0)
+ return (DNS_R_SYNTAX);
+ n--;
+ if ((d = decvalue(*s++)) != -1)
+ c = c * 10 + d;
+ else
+ return (DNS_R_SYNTAX);
+ if (c > 255)
+ return (DNS_R_SYNTAX);
+ } else if (!escape && c == '\\') {
+ escape = ISC_TRUE;
+ continue;
+ }
+ escape = ISC_FALSE;
+ if (nrem == 0)
+ return (ISC_R_NOSPACE);
+ *t++ = c;
+ nrem--;
+ }
+ if (escape)
+ return (DNS_R_SYNTAX);
+ *tregion.base = t - tregion.base - 1;
+ isc_buffer_add(target, *tregion.base + 1);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+txt_fromwire(isc_buffer_t *source, isc_buffer_t *target) {
+ unsigned int n;
+ isc_region_t sregion;
+ isc_region_t tregion;
+
+ isc_buffer_activeregion(source, &sregion);
+ if (sregion.length == 0)
+ return(ISC_R_UNEXPECTEDEND);
+ n = *sregion.base + 1;
+ if (n > sregion.length)
+ return (ISC_R_UNEXPECTEDEND);
+
+ isc_buffer_availableregion(target, &tregion);
+ if (n > tregion.length)
+ return (ISC_R_NOSPACE);
+
+ memcpy(tregion.base, sregion.base, n);
+ isc_buffer_forward(source, n);
+ isc_buffer_add(target, n);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_boolean_t
+name_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target) {
+ int l1, l2;
+
+ if (origin == NULL)
+ goto return_false;
+
+ if (dns_name_compare(origin, dns_rootname) == 0)
+ goto return_false;
+
+ if (!dns_name_issubdomain(name, origin))
+ goto return_false;
+
+ l1 = dns_name_countlabels(name);
+ l2 = dns_name_countlabels(origin);
+
+ if (l1 == l2)
+ goto return_false;
+
+ dns_name_getlabelsequence(name, 0, l1 - l2, target);
+ return (ISC_TRUE);
+
+return_false:
+ *target = *name;
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target) {
+ unsigned int l;
+ isc_region_t region;
+
+ isc_buffer_availableregion(target, &region);
+ l = strlen(source);
+
+ if (l > region.length)
+ return (ISC_R_NOSPACE);
+
+ memcpy(region.base, source, l);
+ isc_buffer_add(target, l);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+inet_totext(int af, isc_region_t *src, isc_buffer_t *target) {
+ char tmpbuf[64];
+
+ /* Note - inet_ntop doesn't do size checking on its input. */
+ if (inet_ntop(af, src->base, tmpbuf, sizeof(tmpbuf)) == NULL)
+ return (ISC_R_NOSPACE);
+ if (strlen(tmpbuf) > isc_buffer_availablelength(target))
+ return (ISC_R_NOSPACE);
+ isc_buffer_putstr(target, tmpbuf);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_boolean_t
+buffer_empty(isc_buffer_t *source) {
+ return((source->current == source->active) ? ISC_TRUE : ISC_FALSE);
+}
+
+static void
+buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region) {
+ isc_buffer_init(buffer, region->base, region->length);
+ isc_buffer_add(buffer, region->length);
+ isc_buffer_setactive(buffer, region->length);
+}
+
+static isc_result_t
+uint32_tobuffer(isc_uint32_t value, isc_buffer_t *target) {
+ isc_region_t region;
+
+ isc_buffer_availableregion(target, &region);
+ if (region.length < 4)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint32(target, value);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+uint16_tobuffer(isc_uint32_t value, isc_buffer_t *target) {
+ isc_region_t region;
+
+ if (value > 0xffff)
+ return (ISC_R_RANGE);
+ isc_buffer_availableregion(target, &region);
+ if (region.length < 2)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint16(target, (isc_uint16_t)value);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+uint8_tobuffer(isc_uint32_t value, isc_buffer_t *target) {
+ isc_region_t region;
+
+ if (value > 0xff)
+ return (ISC_R_RANGE);
+ isc_buffer_availableregion(target, &region);
+ if (region.length < 1)
+ return (ISC_R_NOSPACE);
+ isc_buffer_putuint8(target, (isc_uint8_t)value);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+name_tobuffer(dns_name_t *name, isc_buffer_t *target) {
+ isc_region_t r;
+ dns_name_toregion(name, &r);
+ return (isc_buffer_copyregion(target, &r));
+}
+
+static isc_uint32_t
+uint32_fromregion(isc_region_t *region) {
+ isc_uint32_t value;
+
+ REQUIRE(region->length >= 4);
+ value = region->base[0] << 24;
+ value |= region->base[1] << 16;
+ value |= region->base[2] << 8;
+ value |= region->base[3];
+ return(value);
+}
+
+static isc_uint16_t
+uint16_fromregion(isc_region_t *region) {
+
+ REQUIRE(region->length >= 2);
+
+ return ((region->base[0] << 8) | region->base[1]);
+}
+
+static isc_uint8_t
+uint8_fromregion(isc_region_t *region) {
+
+ REQUIRE(region->length >= 1);
+
+ return (region->base[0]);
+}
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
+ isc_region_t tr;
+
+ isc_buffer_availableregion(target, &tr);
+ if (length > tr.length)
+ return (ISC_R_NOSPACE);
+ memcpy(tr.base, base, length);
+ isc_buffer_add(target, length);
+ return (ISC_R_SUCCESS);
+}
+
+static int
+hexvalue(char value) {
+ char *s;
+ unsigned char c;
+
+ c = (unsigned char)value;
+
+ if (!isascii(c))
+ return (-1);
+ if (isupper(c))
+ c = tolower(c);
+ if ((s = strchr(hexdigits, c)) == NULL)
+ return (-1);
+ return (s - hexdigits);
+}
+
+static int
+decvalue(char value) {
+ char *s;
+
+ /*
+ * isascii() is valid for full range of int values, no need to
+ * mask or cast.
+ */
+ if (!isascii(value))
+ return (-1);
+ if ((s = strchr(decdigits, value)) == NULL)
+ return (-1);
+ return (s - decdigits);
+}
+
+static const char atob_digits[86] =
+ "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" \
+ "abcdefghijklmnopqrstu";
+/*
+ * Subroutines to convert between 8 bit binary bytes and printable ASCII.
+ * Computes the number of bytes, and three kinds of simple checksums.
+ * Incoming bytes are collected into 32-bit words, then printed in base 85:
+ * exp(85,5) > exp(2,32)
+ * The ASCII characters used are between '!' and 'u';
+ * 'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data.
+ *
+ * Originally by Paul Rutter (philabs!per) and Joe Orost (petsd!joe) for
+ * the atob/btoa programs, released with the compress program, in mod.sources.
+ * Modified by Mike Schwartz 8/19/86 for use in BIND.
+ * Modified to be re-entrant 3/2/99.
+ */
+
+
+struct state {
+ isc_int32_t Ceor;
+ isc_int32_t Csum;
+ isc_int32_t Crot;
+ isc_int32_t word;
+ isc_int32_t bcount;
+};
+
+#define Ceor state->Ceor
+#define Csum state->Csum
+#define Crot state->Crot
+#define word state->word
+#define bcount state->bcount
+
+#define times85(x) ((((((x<<2)+x)<<2)+x)<<2)+x)
+
+static isc_result_t byte_atob(int c, isc_buffer_t *target,
+ struct state *state);
+static isc_result_t putbyte(int c, isc_buffer_t *, struct state *state);
+static isc_result_t byte_btoa(int c, isc_buffer_t *, struct state *state);
+
+/*
+ * Decode ASCII-encoded byte c into binary representation and
+ * place into *bufp, advancing bufp.
+ */
+static isc_result_t
+byte_atob(int c, isc_buffer_t *target, struct state *state) {
+ char *s;
+ if (c == 'z') {
+ if (bcount != 0)
+ return(DNS_R_SYNTAX);
+ else {
+ RETERR(putbyte(0, target, state));
+ RETERR(putbyte(0, target, state));
+ RETERR(putbyte(0, target, state));
+ RETERR(putbyte(0, target, state));
+ }
+ } else if ((s = strchr(atob_digits, c)) != NULL) {
+ if (bcount == 0) {
+ word = s - atob_digits;
+ ++bcount;
+ } else if (bcount < 4) {
+ word = times85(word);
+ word += s - atob_digits;
+ ++bcount;
+ } else {
+ word = times85(word);
+ word += s - atob_digits;
+ RETERR(putbyte((word >> 24) & 0xff, target, state));
+ RETERR(putbyte((word >> 16) & 0xff, target, state));
+ RETERR(putbyte((word >> 8) & 0xff, target, state));
+ RETERR(putbyte(word & 0xff, target, state));
+ word = 0;
+ bcount = 0;
+ }
+ } else
+ return(DNS_R_SYNTAX);
+ return(ISC_R_SUCCESS);
+}
+
+/*
+ * Compute checksum info and place c into target.
+ */
+static isc_result_t
+putbyte(int c, isc_buffer_t *target, struct state *state) {
+ isc_region_t tr;
+
+ Ceor ^= c;
+ Csum += c;
+ Csum += 1;
+ if ((Crot & 0x80000000)) {
+ Crot <<= 1;
+ Crot += 1;
+ } else {
+ Crot <<= 1;
+ }
+ Crot += c;
+ isc_buffer_availableregion(target, &tr);
+ if (tr.length < 1)
+ return (ISC_R_NOSPACE);
+ tr.base[0] = c;
+ isc_buffer_add(target, 1);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Read the ASCII-encoded data from inbuf, of length inbuflen, and convert
+ * it into T_UNSPEC (binary data) in outbuf, not to exceed outbuflen bytes;
+ * outbuflen must be divisible by 4. (Note: this is because outbuf is filled
+ * in 4 bytes at a time. If the actual data doesn't end on an even 4-byte
+ * boundary, there will be no problem...it will be padded with 0 bytes, and
+ * numbytes will indicate the correct number of bytes. The main point is
+ * that since the buffer is filled in 4 bytes at a time, even if there is
+ * not a full 4 bytes of data at the end, there has to be room to 0-pad the
+ * data, so the buffer must be of size divisible by 4). Place the number of
+ * output bytes in numbytes, and return a failure/success status.
+ */
+
+static isc_result_t
+atob_tobuffer(isc_lex_t *lexer, isc_buffer_t *target) {
+ long oeor, osum, orot;
+ struct state statebuf, *state= &statebuf;
+ isc_token_t token;
+ char c;
+ char *e;
+
+ Ceor = Csum = Crot = word = bcount = 0;
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ while (token.value.as_textregion.length != 0) {
+ if ((c = token.value.as_textregion.base[0]) == 'x') {
+ break;
+ } else
+ RETERR(byte_atob(c, target, state));
+ isc_textregion_consume(&token.value.as_textregion, 1);
+ }
+
+ /*
+ * Number of bytes.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if ((token.value.as_ulong % 4) != 0U)
+ isc_buffer_subtract(target, 4 - (token.value.as_ulong % 4));
+
+ /*
+ * Checksum.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ oeor = strtol(DNS_AS_STR(token), &e, 16);
+ if (*e != 0)
+ return (DNS_R_SYNTAX);
+
+ /*
+ * Checksum.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ osum = strtol(DNS_AS_STR(token), &e, 16);
+ if (*e != 0)
+ return (DNS_R_SYNTAX);
+
+ /*
+ * Checksum.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ orot = strtol(DNS_AS_STR(token), &e, 16);
+ if (*e != 0)
+ return (DNS_R_SYNTAX);
+
+ if ((oeor != Ceor) || (osum != Csum) || (orot != Crot))
+ return(DNS_R_BADCKSUM);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Encode binary byte c into ASCII representation and place into *bufp,
+ * advancing bufp.
+ */
+static isc_result_t
+byte_btoa(int c, isc_buffer_t *target, struct state *state) {
+ isc_region_t tr;
+
+ isc_buffer_availableregion(target, &tr);
+ Ceor ^= c;
+ Csum += c;
+ Csum += 1;
+ if ((Crot & 0x80000000)) {
+ Crot <<= 1;
+ Crot += 1;
+ } else {
+ Crot <<= 1;
+ }
+ Crot += c;
+
+ word <<= 8;
+ word |= c;
+ if (bcount == 3) {
+ if (word == 0) {
+ if (tr.length < 1)
+ return (ISC_R_NOSPACE);
+ tr.base[0] = 'z';
+ isc_buffer_add(target, 1);
+ } else {
+ register int tmp = 0;
+ register isc_int32_t tmpword = word;
+
+ if (tmpword < 0) {
+ /*
+ * Because some don't support u_long.
+ */
+ tmp = 32;
+ tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32);
+ }
+ if (tmpword < 0) {
+ tmp = 64;
+ tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32);
+ }
+ if (tr.length < 5)
+ return (ISC_R_NOSPACE);
+ tr.base[0] = atob_digits[(tmpword /
+ (isc_int32_t)(85 * 85 * 85 * 85))
+ + tmp];
+ tmpword %= (isc_int32_t)(85 * 85 * 85 * 85);
+ tr.base[1] = atob_digits[tmpword / (85 * 85 * 85)];
+ tmpword %= (85 * 85 * 85);
+ tr.base[2] = atob_digits[tmpword / (85 * 85)];
+ tmpword %= (85 * 85);
+ tr.base[3] = atob_digits[tmpword / 85];
+ tmpword %= 85;
+ tr.base[4] = atob_digits[tmpword];
+ isc_buffer_add(target, 5);
+ }
+ bcount = 0;
+ } else {
+ bcount += 1;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+
+/*
+ * Encode the binary data from inbuf, of length inbuflen, into a
+ * target. Return success/failure status
+ */
+static isc_result_t
+btoa_totext(unsigned char *inbuf, int inbuflen, isc_buffer_t *target) {
+ int inc;
+ struct state statebuf, *state = &statebuf;
+ char buf[sizeof("x 2000000000 ffffffff ffffffff ffffffff")];
+
+ Ceor = Csum = Crot = word = bcount = 0;
+ for (inc = 0; inc < inbuflen; inbuf++, inc++)
+ RETERR(byte_btoa(*inbuf, target, state));
+
+ while (bcount != 0)
+ RETERR(byte_btoa(0, target, state));
+
+ /*
+ * Put byte count and checksum information at end of buffer,
+ * delimited by 'x'
+ */
+ snprintf(buf, sizeof(buf), "x %d %x %x %x", inbuflen, Ceor, Csum, Crot);
+ return (str_totext(buf, target));
+}
+
+
+static void
+default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *fmt,
+ ...)
+{
+ va_list ap;
+
+ UNUSED(callbacks);
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void
+fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) {
+ if (isc_lex_isfile(lexer) && callbacks != NULL) {
+ const char *name = isc_lex_getsourcename(lexer);
+ if (name == NULL)
+ name = "UNKNOWN";
+ (*callbacks->warn)(callbacks,
+ "%s:%lu: file does not end with newline",
+ name, isc_lex_getsourceline(lexer));
+ }
+}
+
+static void
+warn_badmx(isc_token_t *token, isc_lex_t *lexer,
+ dns_rdatacallbacks_t *callbacks)
+{
+ const char *file;
+ unsigned long line;
+
+ if (lexer != NULL) {
+ file = isc_lex_getsourcename(lexer);
+ line = isc_lex_getsourceline(lexer);
+ (*callbacks->warn)(callbacks, "%s:%u: warning: '%s': %s",
+ file, line, DNS_AS_STR(*token),
+ dns_result_totext(DNS_R_MXISADDRESS));
+ }
+}
+
+static void
+warn_badname(dns_name_t *name, isc_lex_t *lexer,
+ dns_rdatacallbacks_t *callbacks)
+{
+ const char *file;
+ unsigned long line;
+ char namebuf[DNS_NAME_FORMATSIZE];
+
+ if (lexer != NULL) {
+ file = isc_lex_getsourcename(lexer);
+ line = isc_lex_getsourceline(lexer);
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ (*callbacks->warn)(callbacks, "%s:%u: warning: %s: %s",
+ file, line, namebuf,
+ dns_result_totext(DNS_R_BADNAME));
+ }
+}
+
+static void
+fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
+ dns_rdatacallbacks_t *callbacks, const char *name,
+ unsigned long line, isc_token_t *token, isc_result_t result)
+{
+ if (name == NULL)
+ name = "UNKNOWN";
+
+ if (token != NULL) {
+ switch (token->type) {
+ case isc_tokentype_eol:
+ (*callback)(callbacks, "%s: %s:%lu: near eol: %s",
+ "dns_rdata_fromtext", name, line,
+ dns_result_totext(result));
+ break;
+ case isc_tokentype_eof:
+ (*callback)(callbacks, "%s: %s:%lu: near eof: %s",
+ "dns_rdata_fromtext", name, line,
+ dns_result_totext(result));
+ break;
+ case isc_tokentype_number:
+ (*callback)(callbacks, "%s: %s:%lu: near %lu: %s",
+ "dns_rdata_fromtext", name, line,
+ token->value.as_ulong,
+ dns_result_totext(result));
+ break;
+ case isc_tokentype_string:
+ case isc_tokentype_qstring:
+ (*callback)(callbacks, "%s: %s:%lu: near '%s': %s",
+ "dns_rdata_fromtext", name, line,
+ DNS_AS_STR(*token),
+ dns_result_totext(result));
+ break;
+ default:
+ (*callback)(callbacks, "%s: %s:%lu: %s",
+ "dns_rdata_fromtext", name, line,
+ dns_result_totext(result));
+ break;
+ }
+ } else {
+ (*callback)(callbacks, "dns_rdata_fromtext: %s:%lu: %s",
+ name, line, dns_result_totext(result));
+ }
+}
+
+dns_rdatatype_t
+dns_rdata_covers(dns_rdata_t *rdata) {
+ if (rdata->type == 46)
+ return (covers_rrsig(rdata));
+ return (covers_sig(rdata));
+}
+
+isc_boolean_t
+dns_rdatatype_ismeta(dns_rdatatype_t type) {
+ if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_META) != 0)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_rdatatype_issingleton(dns_rdatatype_t type) {
+ if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_SINGLETON)
+ != 0)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_rdatatype_notquestion(dns_rdatatype_t type) {
+ if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_NOTQUESTION)
+ != 0)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_rdatatype_questiononly(dns_rdatatype_t type) {
+ if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_QUESTIONONLY)
+ != 0)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_rdatatype_atparent(dns_rdatatype_t type) {
+ if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATPARENT) != 0)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_rdataclass_ismeta(dns_rdataclass_t rdclass) {
+
+ if (rdclass == dns_rdataclass_reserved0
+ || rdclass == dns_rdataclass_none
+ || rdclass == dns_rdataclass_any)
+ return (ISC_TRUE);
+
+ return (ISC_FALSE); /* Assume it is not a meta class. */
+}
+
+isc_boolean_t
+dns_rdatatype_isdnssec(dns_rdatatype_t type) {
+ if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_DNSSEC) != 0)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_rdatatype_iszonecutauth(dns_rdatatype_t type) {
+ if ((dns_rdatatype_attributes(type)
+ & (DNS_RDATATYPEATTR_DNSSEC | DNS_RDATATYPEATTR_ZONECUTAUTH))
+ != 0)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_rdatatype_isknown(dns_rdatatype_t type) {
+ if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_UNKNOWN)
+ == 0)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
diff --git a/lib/dns/rdata/any_255/tsig_250.c b/lib/dns/rdata/any_255/tsig_250.c
new file mode 100644
index 0000000..4fdadd3
--- /dev/null
+++ b/lib/dns/rdata/any_255/tsig_250.c
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2004, 2005 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: tsig_250.c,v 1.59.18.2 2005/03/20 22:34:32 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 13:39:43 PST 2000 by gson */
+
+#ifndef RDATA_ANY_255_TSIG_250_C
+#define RDATA_ANY_255_TSIG_250_C
+
+#define RRTYPE_TSIG_ATTRIBUTES \
+ (DNS_RDATATYPEATTR_META | DNS_RDATATYPEATTR_NOTQUESTION)
+
+static inline isc_result_t
+fromtext_any_tsig(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_uint64_t sigtime;
+ isc_buffer_t buffer;
+ dns_rcode_t rcode;
+ long i;
+ char *e;
+
+ REQUIRE(type == 250);
+ REQUIRE(rdclass == 255);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Algorithm Name.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+
+ /*
+ * Time Signed: 48 bits.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ sigtime = isc_string_touint64(DNS_AS_STR(token), &e, 10);
+ if (*e != 0)
+ RETTOK(DNS_R_SYNTAX);
+ if ((sigtime >> 48) != 0)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer((isc_uint16_t)(sigtime >> 32), target));
+ RETERR(uint32_tobuffer((isc_uint32_t)(sigtime & 0xffffffffU), target));
+
+ /*
+ * Fudge.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Signature Size.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Signature.
+ */
+ RETERR(isc_base64_tobuffer(lexer, target, (int)token.value.as_ulong));
+
+ /*
+ * Original ID.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Error.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ if (dns_tsigrcode_fromtext(&rcode, &token.value.as_textregion)
+ != ISC_R_SUCCESS)
+ {
+ i = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e != 0)
+ RETTOK(DNS_R_UNKNOWN);
+ if (i < 0 || i > 0xffff)
+ RETTOK(ISC_R_RANGE);
+ rcode = (dns_rcode_t)i;
+ }
+ RETERR(uint16_tobuffer(rcode, target));
+
+ /*
+ * Other Len.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Other Data.
+ */
+ return (isc_base64_tobuffer(lexer, target, (int)token.value.as_ulong));
+}
+
+static inline isc_result_t
+totext_any_tsig(ARGS_TOTEXT) {
+ isc_region_t sr;
+ isc_region_t sigr;
+ char buf[sizeof("281474976710655 ")];
+ char *bufp;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+ isc_uint64_t sigtime;
+ unsigned short n;
+
+ REQUIRE(rdata->type == 250);
+ REQUIRE(rdata->rdclass == 255);
+ REQUIRE(rdata->length != 0);
+
+ dns_rdata_toregion(rdata, &sr);
+ /*
+ * Algorithm Name.
+ */
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+ dns_name_fromregion(&name, &sr);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ RETERR(dns_name_totext(&prefix, sub, target));
+ RETERR(str_totext(" ", target));
+ isc_region_consume(&sr, name_length(&name));
+
+ /*
+ * Time Signed.
+ */
+ sigtime = ((isc_uint64_t)sr.base[0] << 40) |
+ ((isc_uint64_t)sr.base[1] << 32) |
+ ((isc_uint64_t)sr.base[2] << 24) |
+ ((isc_uint64_t)sr.base[3] << 16) |
+ ((isc_uint64_t)sr.base[4] << 8) |
+ (isc_uint64_t)sr.base[5];
+ isc_region_consume(&sr, 6);
+ bufp = &buf[sizeof(buf) - 1];
+ *bufp-- = 0;
+ *bufp-- = ' ';
+ do {
+ *bufp-- = decdigits[sigtime % 10];
+ sigtime /= 10;
+ } while (sigtime != 0);
+ bufp++;
+ RETERR(str_totext(bufp, target));
+
+ /*
+ * Fudge.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%u ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Signature Size.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%u", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Signature.
+ */
+ REQUIRE(n <= sr.length);
+ sigr = sr;
+ sigr.length = n;
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_base64_totext(&sigr, tctx->width - 2,
+ tctx->linebreak, target));
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" ) ", target));
+ else
+ RETERR(str_totext(" ", target));
+ isc_region_consume(&sr, n);
+
+ /*
+ * Original ID.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%u ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Error.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ if (dns_tsigrcode_totext((dns_rcode_t)n, target) == ISC_R_SUCCESS)
+ RETERR(str_totext(" ", target));
+ else {
+ sprintf(buf, "%u ", n);
+ RETERR(str_totext(buf, target));
+ }
+
+ /*
+ * Other Size.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%u ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Other.
+ */
+ return (isc_base64_totext(&sr, 60, " ", target));
+}
+
+static inline isc_result_t
+fromwire_any_tsig(ARGS_FROMWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+ unsigned long n;
+
+ REQUIRE(type == 250);
+ REQUIRE(rdclass == 255);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ /*
+ * Algorithm Name.
+ */
+ dns_name_init(&name, NULL);
+ RETERR(dns_name_fromwire(&name, source, dctx, options, target));
+
+ isc_buffer_activeregion(source, &sr);
+ /*
+ * Time Signed + Fudge.
+ */
+ if (sr.length < 8)
+ return (ISC_R_UNEXPECTEDEND);
+ RETERR(mem_tobuffer(target, sr.base, 8));
+ isc_region_consume(&sr, 8);
+ isc_buffer_forward(source, 8);
+
+ /*
+ * Signature Length + Signature.
+ */
+ if (sr.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ n = uint16_fromregion(&sr);
+ if (sr.length < n + 2)
+ return (ISC_R_UNEXPECTEDEND);
+ RETERR(mem_tobuffer(target, sr.base, n + 2));
+ isc_region_consume(&sr, n + 2);
+ isc_buffer_forward(source, n + 2);
+
+ /*
+ * Original ID + Error.
+ */
+ if (sr.length < 4)
+ return (ISC_R_UNEXPECTEDEND);
+ RETERR(mem_tobuffer(target, sr.base, 4));
+ isc_region_consume(&sr, 4);
+ isc_buffer_forward(source, 4);
+
+ /*
+ * Other Length + Other.
+ */
+ if (sr.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ n = uint16_fromregion(&sr);
+ if (sr.length < n + 2)
+ return (ISC_R_UNEXPECTEDEND);
+ isc_buffer_forward(source, n + 2);
+ return (mem_tobuffer(target, sr.base, n + 2));
+}
+
+static inline isc_result_t
+towire_any_tsig(ARGS_TOWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+ dns_offsets_t offsets;
+
+ REQUIRE(rdata->type == 250);
+ REQUIRE(rdata->rdclass == 255);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ dns_rdata_toregion(rdata, &sr);
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &sr);
+ RETERR(dns_name_towire(&name, cctx, target));
+ isc_region_consume(&sr, name_length(&name));
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_any_tsig(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+ dns_name_t name1;
+ dns_name_t name2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 250);
+ REQUIRE(rdata1->rdclass == 255);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+ dns_name_fromregion(&name1, &r1);
+ dns_name_fromregion(&name2, &r2);
+ order = dns_name_rdatacompare(&name1, &name2);
+ if (order != 0)
+ return (order);
+ isc_region_consume(&r1, name_length(&name1));
+ isc_region_consume(&r2, name_length(&name2));
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_any_tsig(ARGS_FROMSTRUCT) {
+ dns_rdata_any_tsig_t *tsig = source;
+ isc_region_t tr;
+
+ REQUIRE(type == 250);
+ REQUIRE(rdclass == 255);
+ REQUIRE(source != NULL);
+ REQUIRE(tsig->common.rdclass == rdclass);
+ REQUIRE(tsig->common.rdtype == type);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ /*
+ * Algorithm Name.
+ */
+ RETERR(name_tobuffer(&tsig->algorithm, target));
+
+ isc_buffer_availableregion(target, &tr);
+ if (tr.length < 6 + 2 + 2)
+ return (ISC_R_NOSPACE);
+
+ /*
+ * Time Signed: 48 bits.
+ */
+ RETERR(uint16_tobuffer((isc_uint16_t)(tsig->timesigned >> 32),
+ target));
+ RETERR(uint32_tobuffer((isc_uint32_t)(tsig->timesigned & 0xffffffffU),
+ target));
+
+ /*
+ * Fudge.
+ */
+ RETERR(uint16_tobuffer(tsig->fudge, target));
+
+ /*
+ * Signature Size.
+ */
+ RETERR(uint16_tobuffer(tsig->siglen, target));
+
+ /*
+ * Signature.
+ */
+ RETERR(mem_tobuffer(target, tsig->signature, tsig->siglen));
+
+ isc_buffer_availableregion(target, &tr);
+ if (tr.length < 2 + 2 + 2)
+ return (ISC_R_NOSPACE);
+
+ /*
+ * Original ID.
+ */
+ RETERR(uint16_tobuffer(tsig->originalid, target));
+
+ /*
+ * Error.
+ */
+ RETERR(uint16_tobuffer(tsig->error, target));
+
+ /*
+ * Other Len.
+ */
+ RETERR(uint16_tobuffer(tsig->otherlen, target));
+
+ /*
+ * Other Data.
+ */
+ return (mem_tobuffer(target, tsig->other, tsig->otherlen));
+}
+
+static inline isc_result_t
+tostruct_any_tsig(ARGS_TOSTRUCT) {
+ dns_rdata_any_tsig_t *tsig;
+ dns_name_t alg;
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 250);
+ REQUIRE(rdata->rdclass == 255);
+ REQUIRE(rdata->length != 0);
+
+ tsig = (dns_rdata_any_tsig_t *) target;
+ tsig->common.rdclass = rdata->rdclass;
+ tsig->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&tsig->common, link);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /*
+ * Algorithm Name.
+ */
+ dns_name_init(&alg, NULL);
+ dns_name_fromregion(&alg, &sr);
+ dns_name_init(&tsig->algorithm, NULL);
+ RETERR(name_duporclone(&alg, mctx, &tsig->algorithm));
+
+ isc_region_consume(&sr, name_length(&tsig->algorithm));
+
+ /*
+ * Time Signed.
+ */
+ INSIST(sr.length >= 6);
+ tsig->timesigned = ((isc_uint64_t)sr.base[0] << 40) |
+ ((isc_uint64_t)sr.base[1] << 32) |
+ ((isc_uint64_t)sr.base[2] << 24) |
+ ((isc_uint64_t)sr.base[3] << 16) |
+ ((isc_uint64_t)sr.base[4] << 8) |
+ (isc_uint64_t)sr.base[5];
+ isc_region_consume(&sr, 6);
+
+ /*
+ * Fudge.
+ */
+ tsig->fudge = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /*
+ * Signature Size.
+ */
+ tsig->siglen = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /*
+ * Signature.
+ */
+ INSIST(sr.length >= tsig->siglen);
+ tsig->signature = mem_maybedup(mctx, sr.base, tsig->siglen);
+ if (tsig->signature == NULL)
+ goto cleanup;
+ isc_region_consume(&sr, tsig->siglen);
+
+ /*
+ * Original ID.
+ */
+ tsig->originalid = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /*
+ * Error.
+ */
+ tsig->error = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /*
+ * Other Size.
+ */
+ tsig->otherlen = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /*
+ * Other.
+ */
+ INSIST(sr.length == tsig->otherlen);
+ tsig->other = mem_maybedup(mctx, sr.base, tsig->otherlen);
+ if (tsig->other == NULL)
+ goto cleanup;
+
+ tsig->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL)
+ dns_name_free(&tsig->algorithm, tsig->mctx);
+ if (mctx != NULL && tsig->signature != NULL)
+ isc_mem_free(mctx, tsig->signature);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_any_tsig(ARGS_FREESTRUCT) {
+ dns_rdata_any_tsig_t *tsig = (dns_rdata_any_tsig_t *) source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(tsig->common.rdclass == 255);
+ REQUIRE(tsig->common.rdtype == 250);
+
+ if (tsig->mctx == NULL)
+ return;
+
+ dns_name_free(&tsig->algorithm, tsig->mctx);
+ if (tsig->signature != NULL)
+ isc_mem_free(tsig->mctx, tsig->signature);
+ if (tsig->other != NULL)
+ isc_mem_free(tsig->mctx, tsig->other);
+ tsig->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_any_tsig(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 250);
+ REQUIRE(rdata->rdclass == 255);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_any_tsig(ARGS_DIGEST) {
+
+ REQUIRE(rdata->type == 250);
+ REQUIRE(rdata->rdclass == 255);
+
+ UNUSED(rdata);
+ UNUSED(digest);
+ UNUSED(arg);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline isc_boolean_t
+checkowner_any_tsig(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 250);
+ REQUIRE(rdclass == 255);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_any_tsig(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 250);
+ REQUIRE(rdata->rdclass == 250);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_ANY_255_TSIG_250_C */
diff --git a/lib/dns/rdata/any_255/tsig_250.h b/lib/dns/rdata/any_255/tsig_250.h
new file mode 100644
index 0000000..b84a715
--- /dev/null
+++ b/lib/dns/rdata/any_255/tsig_250.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2004, 2005 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: tsig_250.h,v 1.21.18.2 2005/04/29 00:16:29 marka Exp $ */
+
+#ifndef ANY_255_TSIG_250_H
+#define ANY_255_TSIG_250_H 1
+
+/*% RFC2845 */
+typedef struct dns_rdata_any_tsig {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ dns_name_t algorithm;
+ isc_uint64_t timesigned;
+ isc_uint16_t fudge;
+ isc_uint16_t siglen;
+ unsigned char * signature;
+ isc_uint16_t originalid;
+ isc_uint16_t error;
+ isc_uint16_t otherlen;
+ unsigned char * other;
+} dns_rdata_any_tsig_t;
+
+#endif /* ANY_255_TSIG_250_H */
diff --git a/lib/dns/rdata/ch_3/a_1.c b/lib/dns/rdata/ch_3/a_1.c
new file mode 100644
index 0000000..6a9b70c
--- /dev/null
+++ b/lib/dns/rdata/ch_3/a_1.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: a_1.c,v 1.2.2.3 2005/08/23 04:10:09 marka Exp $ */
+
+/* by Bjorn.Victor@it.uu.se, 2005-05-07 */
+/* Based on generic/soa_6.c and generic/mx_15.c */
+
+#ifndef RDATA_CH_3_A_1_C
+#define RDATA_CH_3_A_1_C
+
+#include <isc/net.h>
+
+#define RRTYPE_A_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_ch_a(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 1);
+ REQUIRE(rdclass == dns_rdataclass_ch); /* 3 */
+
+ UNUSED(type);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ /* get domain name */
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ if ((options & DNS_RDATA_CHECKNAMES) != 0 &&
+ (options & DNS_RDATA_CHECKREVERSE) != 0) {
+ isc_boolean_t ok;
+ ok = dns_name_ishostname(&name, ISC_FALSE);
+ if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0)
+ RETTOK(DNS_R_BADNAME);
+ if (!ok && callbacks != NULL)
+ warn_badname(&name, lexer, callbacks);
+ }
+
+ /* 16-bit octal address */
+ RETERR(isc_lex_getoctaltoken(lexer, &token, ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ return (uint16_tobuffer(token.value.as_ulong, target));
+}
+
+static inline isc_result_t
+totext_ch_a(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+ char buf[sizeof("0177777")];
+ isc_uint16_t addr;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == dns_rdataclass_ch); /* 3 */
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ isc_region_consume(&region, name_length(&name));
+ addr = uint16_fromregion(&region);
+
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ RETERR(dns_name_totext(&prefix, sub, target));
+
+ sprintf(buf, "%o", addr); /* note octal */
+ RETERR(str_totext(" ", target));
+ return (str_totext(buf, target));
+}
+
+static inline isc_result_t
+fromwire_ch_a(ARGS_FROMWIRE) {
+ isc_region_t sregion;
+ isc_region_t tregion;
+ dns_name_t name;
+
+ REQUIRE(type == 1);
+ REQUIRE(rdclass == dns_rdataclass_ch);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, NULL);
+
+ RETERR(dns_name_fromwire(&name, source, dctx, options, target));
+
+ isc_buffer_activeregion(source, &sregion);
+ isc_buffer_availableregion(target, &tregion);
+ if (sregion.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ if (tregion.length < 2)
+ return (ISC_R_NOSPACE);
+
+ memcpy(tregion.base, sregion.base, 2);
+ isc_buffer_forward(source, 2);
+ isc_buffer_add(target, 2);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_ch_a(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t sregion;
+ isc_region_t tregion;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == dns_rdataclass_ch);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, offsets);
+
+ dns_rdata_toregion(rdata, &sregion);
+
+ dns_name_fromregion(&name, &sregion);
+ isc_region_consume(&sregion, name_length(&name));
+ RETERR(dns_name_towire(&name, cctx, target));
+
+ isc_buffer_availableregion(target, &tregion);
+ if (tregion.length < 2)
+ return (ISC_R_NOSPACE);
+
+ memcpy(tregion.base, sregion.base, 2);
+ isc_buffer_add(target, 2);
+ return (ISC_R_SUCCESS);
+}
+
+static inline int
+compare_ch_a(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 1);
+ REQUIRE(rdata1->rdclass == dns_rdataclass_ch);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+ isc_region_consume(&region1, name_length(&name1));
+ isc_region_consume(&region2, name_length(&name2));
+
+ order = dns_name_rdatacompare(&name1, &name2);
+ if (order != 0)
+ return (order);
+
+ order = memcmp(rdata1->data, rdata2->data, 2);
+ if (order != 0)
+ order = (order < 0) ? -1 : 1;
+ return (order);
+}
+
+static inline isc_result_t
+fromstruct_ch_a(ARGS_FROMSTRUCT) {
+ dns_rdata_ch_a_t *a = source;
+ isc_region_t region;
+
+ REQUIRE(type == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(a->common.rdtype == type);
+ REQUIRE(a->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&a->ch_addr_dom, &region);
+ RETERR(isc_buffer_copyregion(target, &region));
+
+ return (uint16_tobuffer(ntohs(a->ch_addr), target));
+}
+
+static inline isc_result_t
+tostruct_ch_a(ARGS_TOSTRUCT) {
+ dns_rdata_ch_a_t *a = target;
+ isc_region_t region;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == dns_rdataclass_ch);
+ REQUIRE(rdata->length != 0);
+
+ a->common.rdclass = rdata->rdclass;
+ a->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&a->common, link);
+
+ dns_rdata_toregion(rdata, &region);
+
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ isc_region_consume(&region, name_length(&name));
+
+ dns_name_init(&a->ch_addr_dom, NULL);
+ RETERR(name_duporclone(&name, mctx, &a->ch_addr_dom));
+ a->ch_addr = htons(uint16_fromregion(&region));
+ a->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_ch_a(ARGS_FREESTRUCT) {
+ dns_rdata_ch_a_t *a = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(a->common.rdtype == 1);
+
+ if (a->mctx == NULL)
+ return;
+
+ dns_name_free(&a->ch_addr_dom, a->mctx);
+ a->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_ch_a(ARGS_ADDLDATA) {
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == dns_rdataclass_ch);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_ch_a(ARGS_DIGEST) {
+ isc_region_t r;
+
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == dns_rdataclass_ch);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+ isc_region_consume(&r, name_length(&name));
+ RETERR(dns_name_digest(&name, digest, arg));
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_ch_a(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 1);
+ REQUIRE(rdclass == dns_rdataclass_ch);
+
+ UNUSED(type);
+
+ return (dns_name_ishostname(name, wildcard));
+}
+
+static inline isc_boolean_t
+checknames_ch_a(ARGS_CHECKNAMES) {
+ isc_region_t region;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == dns_rdataclass_ch);
+
+ UNUSED(owner);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ishostname(&name, ISC_FALSE)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_CH_3_A_1_C */
diff --git a/lib/dns/rdata/ch_3/a_1.h b/lib/dns/rdata/ch_3/a_1.h
new file mode 100644
index 0000000..9f67977
--- /dev/null
+++ b/lib/dns/rdata/ch_3/a_1.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: a_1.h,v 1.2.2.2 2005/06/05 00:02:22 marka Exp $ */
+
+/* by Bjorn.Victor@it.uu.se, 2005-05-07 */
+/* Based on generic/mx_15.h */
+
+#ifndef CH_3_A_1_H
+#define CH_3_A_1_H 1
+
+typedef isc_uint16_t ch_addr_t;
+
+typedef struct dns_rdata_ch_a {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t ch_addr_dom; /* ch-addr domain for back mapping */
+ ch_addr_t ch_addr; /* chaos address (16 bit) network order */
+} dns_rdata_ch_a_t;
+
+#endif /* CH_3_A_1_H */
diff --git a/lib/dns/rdata/generic/afsdb_18.c b/lib/dns/rdata/generic/afsdb_18.c
new file mode 100644
index 0000000..24a63e6
--- /dev/null
+++ b/lib/dns/rdata/generic/afsdb_18.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2004, 2005 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: afsdb_18.c,v 1.43.18.2 2005/04/29 00:16:30 marka Exp $ */
+
+/* Reviewed: Wed Mar 15 14:59:00 PST 2000 by explorer */
+
+/* RFC1183 */
+
+#ifndef RDATA_GENERIC_AFSDB_18_C
+#define RDATA_GENERIC_AFSDB_18_C
+
+#define RRTYPE_AFSDB_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_afsdb(ARGS_FROMTEXT) {
+ isc_token_t token;
+ isc_buffer_t buffer;
+ dns_name_t name;
+ isc_boolean_t ok;
+
+ REQUIRE(type == 18);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Subtype.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Hostname.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ ok = ISC_TRUE;
+ if ((options & DNS_RDATA_CHECKNAMES) != 0)
+ ok = dns_name_ishostname(&name, ISC_FALSE);
+ if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0)
+ RETTOK(DNS_R_BADNAME);
+ if (!ok && callbacks != NULL)
+ warn_badname(&name, lexer, callbacks);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_afsdb(ARGS_TOTEXT) {
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_region_t region;
+ char buf[sizeof("64000 ")];
+ isc_boolean_t sub;
+ unsigned int num;
+
+ REQUIRE(rdata->type == 18);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ num = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ sprintf(buf, "%u ", num);
+ RETERR(str_totext(buf, target));
+ dns_name_fromregion(&name, &region);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_afsdb(ARGS_FROMWIRE) {
+ dns_name_t name;
+ isc_region_t sr;
+ isc_region_t tr;
+
+ REQUIRE(type == 18);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&name, NULL);
+
+ isc_buffer_activeregion(source, &sr);
+ isc_buffer_availableregion(target, &tr);
+ if (tr.length < 2)
+ return (ISC_R_NOSPACE);
+ if (sr.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ memcpy(tr.base, sr.base, 2);
+ isc_buffer_forward(source, 2);
+ isc_buffer_add(target, 2);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_afsdb(ARGS_TOWIRE) {
+ isc_region_t tr;
+ isc_region_t sr;
+ dns_name_t name;
+ dns_offsets_t offsets;
+
+ REQUIRE(rdata->type == 18);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ isc_buffer_availableregion(target, &tr);
+ dns_rdata_toregion(rdata, &sr);
+ if (tr.length < 2)
+ return (ISC_R_NOSPACE);
+ memcpy(tr.base, sr.base, 2);
+ isc_region_consume(&sr, 2);
+ isc_buffer_add(target, 2);
+
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &sr);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_afsdb(ARGS_COMPARE) {
+ int result;
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 18);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ result = memcmp(rdata1->data, rdata2->data, 2);
+ if (result != 0)
+ return (result < 0 ? -1 : 1);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ isc_region_consume(&region1, 2);
+ isc_region_consume(&region2, 2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_afsdb(ARGS_FROMSTRUCT) {
+ dns_rdata_afsdb_t *afsdb = source;
+ isc_region_t region;
+
+ REQUIRE(type == 18);
+ REQUIRE(source != NULL);
+ REQUIRE(afsdb->common.rdclass == rdclass);
+ REQUIRE(afsdb->common.rdtype == type);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint16_tobuffer(afsdb->subtype, target));
+ dns_name_toregion(&afsdb->server, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_afsdb(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_afsdb_t *afsdb = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 18);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ afsdb->common.rdclass = rdata->rdclass;
+ afsdb->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&afsdb->common, link);
+
+ dns_name_init(&afsdb->server, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+
+ afsdb->subtype = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+
+ RETERR(name_duporclone(&name, mctx, &afsdb->server));
+ afsdb->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_afsdb(ARGS_FREESTRUCT) {
+ dns_rdata_afsdb_t *afsdb = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(afsdb->common.rdtype == 18);
+
+ if (afsdb->mctx == NULL)
+ return;
+
+ dns_name_free(&afsdb->server, afsdb->mctx);
+ afsdb->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_afsdb(ARGS_ADDLDATA) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 18);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ isc_region_consume(&region, 2);
+ dns_name_fromregion(&name, &region);
+
+ return ((add)(arg, &name, dns_rdatatype_a));
+}
+
+static inline isc_result_t
+digest_afsdb(ARGS_DIGEST) {
+ isc_region_t r1, r2;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 18);
+
+ dns_rdata_toregion(rdata, &r1);
+ r2 = r1;
+ isc_region_consume(&r2, 2);
+ r1.length = 2;
+ RETERR((digest)(arg, &r1));
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r2);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_afsdb(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 18);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_afsdb(ARGS_CHECKNAMES) {
+ isc_region_t region;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 18);
+
+ UNUSED(owner);
+
+ dns_rdata_toregion(rdata, &region);
+ isc_region_consume(&region, 2);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ishostname(&name, ISC_FALSE)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_AFSDB_18_C */
diff --git a/lib/dns/rdata/generic/afsdb_18.h b/lib/dns/rdata/generic/afsdb_18.h
new file mode 100644
index 0000000..1532da1
--- /dev/null
+++ b/lib/dns/rdata/generic/afsdb_18.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_AFSDB_18_H
+#define GENERIC_AFSDB_18_H 1
+
+/* $Id: afsdb_18.h,v 1.16.18.2 2005/04/29 00:16:30 marka Exp $ */
+
+/*!
+ * \brief Per RFC1183 */
+
+typedef struct dns_rdata_afsdb {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t subtype;
+ dns_name_t server;
+} dns_rdata_afsdb_t;
+
+#endif /* GENERIC_AFSDB_18_H */
+
diff --git a/lib/dns/rdata/generic/cert_37.c b/lib/dns/rdata/generic/cert_37.c
new file mode 100644
index 0000000..c6ba3a8
--- /dev/null
+++ b/lib/dns/rdata/generic/cert_37.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2004, 2005 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: cert_37.c,v 1.46.18.2 2005/04/29 00:16:30 marka Exp $ */
+
+/* Reviewed: Wed Mar 15 21:14:32 EST 2000 by tale */
+
+/* RFC2538 */
+
+#ifndef RDATA_GENERIC_CERT_37_C
+#define RDATA_GENERIC_CERT_37_C
+
+#define RRTYPE_CERT_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_cert(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_secalg_t secalg;
+ dns_cert_t cert;
+
+ REQUIRE(type == 37);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ /*
+ * Cert type.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_cert_fromtext(&cert, &token.value.as_textregion));
+ RETERR(uint16_tobuffer(cert, target));
+
+ /*
+ * Key tag.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Algorithm.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_secalg_fromtext(&secalg, &token.value.as_textregion));
+ RETERR(mem_tobuffer(target, &secalg, 1));
+
+ return (isc_base64_tobuffer(lexer, target, -1));
+}
+
+static inline isc_result_t
+totext_cert(ARGS_TOTEXT) {
+ isc_region_t sr;
+ char buf[sizeof("64000 ")];
+ unsigned int n;
+
+ REQUIRE(rdata->type == 37);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /*
+ * Type.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ RETERR(dns_cert_totext((dns_cert_t)n, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Key tag.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%u ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Algorithm.
+ */
+ RETERR(dns_secalg_totext(sr.base[0], target));
+ isc_region_consume(&sr, 1);
+
+ /*
+ * Cert.
+ */
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_base64_totext(&sr, tctx->width - 2,
+ tctx->linebreak, target));
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" )", target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_cert(ARGS_FROMWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(type == 37);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(dctx);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sr);
+ if (sr.length < 5)
+ return (ISC_R_UNEXPECTEDEND);
+
+ isc_buffer_forward(source, sr.length);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline isc_result_t
+towire_cert(ARGS_TOWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 37);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(cctx);
+
+ dns_rdata_toregion(rdata, &sr);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_cert(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 37);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_cert(ARGS_FROMSTRUCT) {
+ dns_rdata_cert_t *cert = source;
+
+ REQUIRE(type == 37);
+ REQUIRE(source != NULL);
+ REQUIRE(cert->common.rdtype == type);
+ REQUIRE(cert->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint16_tobuffer(cert->type, target));
+ RETERR(uint16_tobuffer(cert->key_tag, target));
+ RETERR(uint8_tobuffer(cert->algorithm, target));
+
+ return (mem_tobuffer(target, cert->certificate, cert->length));
+}
+
+static inline isc_result_t
+tostruct_cert(ARGS_TOSTRUCT) {
+ dns_rdata_cert_t *cert = target;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 37);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ cert->common.rdclass = rdata->rdclass;
+ cert->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&cert->common, link);
+
+ dns_rdata_toregion(rdata, &region);
+
+ cert->type = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ cert->key_tag = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ cert->algorithm = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ cert->length = region.length;
+
+ cert->certificate = mem_maybedup(mctx, region.base, region.length);
+ if (cert->certificate == NULL)
+ return (ISC_R_NOMEMORY);
+
+ cert->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_cert(ARGS_FREESTRUCT) {
+ dns_rdata_cert_t *cert = source;
+
+ REQUIRE(cert != NULL);
+ REQUIRE(cert->common.rdtype == 37);
+
+ if (cert->mctx == NULL)
+ return;
+
+ if (cert->certificate != NULL)
+ isc_mem_free(cert->mctx, cert->certificate);
+ cert->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_cert(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 37);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_cert(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 37);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_cert(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 37);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_cert(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 37);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_CERT_37_C */
+
diff --git a/lib/dns/rdata/generic/cert_37.h b/lib/dns/rdata/generic/cert_37.h
new file mode 100644
index 0000000..2af25b7
--- /dev/null
+++ b/lib/dns/rdata/generic/cert_37.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2004, 2005 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: cert_37.h,v 1.16.18.2 2005/04/29 00:16:31 marka Exp $ */
+
+#ifndef GENERIC_CERT_37_H
+#define GENERIC_CERT_37_H 1
+
+/*% RFC2538 */
+typedef struct dns_rdata_cert {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t type;
+ isc_uint16_t key_tag;
+ isc_uint8_t algorithm;
+ isc_uint16_t length;
+ unsigned char *certificate;
+} dns_rdata_cert_t;
+
+#endif /* GENERIC_CERT_37_H */
diff --git a/lib/dns/rdata/generic/cname_5.c b/lib/dns/rdata/generic/cname_5.c
new file mode 100644
index 0000000..6ea1db1
--- /dev/null
+++ b/lib/dns/rdata/generic/cname_5.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: cname_5.c,v 1.45 2004/03/05 05:10:10 marka Exp $ */
+
+/* reviewed: Wed Mar 15 16:48:45 PST 2000 by brister */
+
+#ifndef RDATA_GENERIC_CNAME_5_C
+#define RDATA_GENERIC_CNAME_5_C
+
+#define RRTYPE_CNAME_ATTRIBUTES \
+ (DNS_RDATATYPEATTR_EXCLUSIVE | DNS_RDATATYPEATTR_SINGLETON)
+
+static inline isc_result_t
+fromtext_cname(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 5);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_cname(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 5);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ sub = name_prefix(&name, tctx->origin, &prefix);
+
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_cname(ARGS_FROMWIRE) {
+ dns_name_t name;
+
+ REQUIRE(type == 5);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, NULL);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_cname(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 5);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_cname(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 5);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_cname(ARGS_FROMSTRUCT) {
+ dns_rdata_cname_t *cname = source;
+ isc_region_t region;
+
+ REQUIRE(type == 5);
+ REQUIRE(source != NULL);
+ REQUIRE(cname->common.rdtype == type);
+ REQUIRE(cname->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&cname->cname, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_cname(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_cname_t *cname = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 5);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ cname->common.rdclass = rdata->rdclass;
+ cname->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&cname->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&cname->cname, NULL);
+ RETERR(name_duporclone(&name, mctx, &cname->cname));
+ cname->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_cname(ARGS_FREESTRUCT) {
+ dns_rdata_cname_t *cname = source;
+
+ REQUIRE(source != NULL);
+
+ if (cname->mctx == NULL)
+ return;
+
+ dns_name_free(&cname->cname, cname->mctx);
+ cname->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_cname(ARGS_ADDLDATA) {
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ REQUIRE(rdata->type == 5);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_cname(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 5);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_cname(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 5);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_cname(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 5);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_CNAME_5_C */
diff --git a/lib/dns/rdata/generic/cname_5.h b/lib/dns/rdata/generic/cname_5.h
new file mode 100644
index 0000000..dc24383
--- /dev/null
+++ b/lib/dns/rdata/generic/cname_5.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: cname_5.h,v 1.24 2004/03/05 05:10:10 marka Exp $ */
+
+#ifndef GENERIC_CNAME_5_H
+#define GENERIC_CNAME_5_H 1
+
+typedef struct dns_rdata_cname {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t cname;
+} dns_rdata_cname_t;
+
+#endif /* GENERIC_CNAME_5_H */
diff --git a/lib/dns/rdata/generic/dlv_32769.c b/lib/dns/rdata/generic/dlv_32769.c
new file mode 100644
index 0000000..c0bb348
--- /dev/null
+++ b/lib/dns/rdata/generic/dlv_32769.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2004, 2006, 2007 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: dlv_32769.c,v 1.2.2.5 2007/08/28 07:20:06 tbox Exp $ */
+
+/* draft-ietf-dnsext-delegation-signer-05.txt */
+
+#ifndef RDATA_GENERIC_DLV_32769_C
+#define RDATA_GENERIC_DLV_32769_C
+
+#define RRTYPE_DLV_ATTRIBUTES 0
+
+#include <isc/sha1.h>
+#include <isc/sha2.h>
+
+#include <dns/ds.h>
+
+
+static inline isc_result_t
+fromtext_dlv(ARGS_FROMTEXT) {
+ isc_token_t token;
+ unsigned char c;
+ int length;
+
+ REQUIRE(type == 32769);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ /*
+ * Key tag.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Algorithm.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint8_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Digest type.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint8_tobuffer(token.value.as_ulong, target));
+ c = (unsigned char) token.value.as_ulong;
+
+ /*
+ * Digest.
+ */
+ if (c == DNS_DSDIGEST_SHA1)
+ length = ISC_SHA1_DIGESTLENGTH;
+ else if (c == DNS_DSDIGEST_SHA256)
+ length = ISC_SHA256_DIGESTLENGTH;
+ else
+ length = -1;
+ return (isc_hex_tobuffer(lexer, target, -1));
+}
+
+static inline isc_result_t
+totext_dlv(ARGS_TOTEXT) {
+ isc_region_t sr;
+ char buf[sizeof("64000 ")];
+ unsigned int n;
+
+ REQUIRE(rdata->type == 32769);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /*
+ * Key tag.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%u ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Algorithm.
+ */
+ n = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+ sprintf(buf, "%u ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Digest type.
+ */
+ n = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+ sprintf(buf, "%u", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Digest.
+ */
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_hex_totext(&sr, tctx->width - 2, tctx->linebreak, target));
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" )", target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_dlv(ARGS_FROMWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(type == 32769);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(dctx);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sr);
+
+ /*
+ * Check digest lengths if we know them.
+ */
+ if (sr.length < 4 ||
+ (sr.base[3] == DNS_DSDIGEST_SHA1 &&
+ sr.length < 4 + ISC_SHA1_DIGESTLENGTH) ||
+ (sr.base[3] == DNS_DSDIGEST_SHA256 &&
+ sr.length < 4 + ISC_SHA256_DIGESTLENGTH))
+ return (ISC_R_UNEXPECTEDEND);
+
+ /*
+ * Only copy digest lengths if we know them.
+ * If there is extra data dns_rdata_fromwire() will
+ * detect that.
+ */
+ if (sr.base[3] == DNS_DSDIGEST_SHA1)
+ sr.length = 4 + ISC_SHA1_DIGESTLENGTH;
+ else if (sr.base[3] == DNS_DSDIGEST_SHA256)
+ sr.length = 4 + ISC_SHA256_DIGESTLENGTH;
+
+ isc_buffer_forward(source, sr.length);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline isc_result_t
+towire_dlv(ARGS_TOWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 32769);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(cctx);
+
+ dns_rdata_toregion(rdata, &sr);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_dlv(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 32769);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_dlv(ARGS_FROMSTRUCT) {
+ dns_rdata_dlv_t *dlv = source;
+
+ REQUIRE(type == 32769);
+ REQUIRE(source != NULL);
+ REQUIRE(dlv->common.rdtype == type);
+ REQUIRE(dlv->common.rdclass == rdclass);
+ switch (dlv->digest_type) {
+ case DNS_DSDIGEST_SHA1:
+ REQUIRE(dlv->length == ISC_SHA1_DIGESTLENGTH);
+ break;
+ case DNS_DSDIGEST_SHA256:
+ REQUIRE(dlv->length == ISC_SHA256_DIGESTLENGTH);
+ break;
+ }
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint16_tobuffer(dlv->key_tag, target));
+ RETERR(uint8_tobuffer(dlv->algorithm, target));
+ RETERR(uint8_tobuffer(dlv->digest_type, target));
+
+ return (mem_tobuffer(target, dlv->digest, dlv->length));
+}
+
+static inline isc_result_t
+tostruct_dlv(ARGS_TOSTRUCT) {
+ dns_rdata_dlv_t *dlv = target;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 32769);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ dlv->common.rdclass = rdata->rdclass;
+ dlv->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&dlv->common, link);
+
+ dns_rdata_toregion(rdata, &region);
+
+ dlv->key_tag = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ dlv->algorithm = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ dlv->digest_type = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ dlv->length = region.length;
+
+ dlv->digest = mem_maybedup(mctx, region.base, region.length);
+ if (dlv->digest == NULL)
+ return (ISC_R_NOMEMORY);
+
+ dlv->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_dlv(ARGS_FREESTRUCT) {
+ dns_rdata_dlv_t *dlv = source;
+
+ REQUIRE(dlv != NULL);
+ REQUIRE(dlv->common.rdtype == 32769);
+
+ if (dlv->mctx == NULL)
+ return;
+
+ if (dlv->digest != NULL)
+ isc_mem_free(dlv->mctx, dlv->digest);
+ dlv->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_dlv(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 32769);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_dlv(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 32769);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_dlv(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 32769);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_dlv(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 32769);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_DLV_32769_C */
diff --git a/lib/dns/rdata/generic/dlv_32769.h b/lib/dns/rdata/generic/dlv_32769.h
new file mode 100644
index 0000000..bd03c73
--- /dev/null
+++ b/lib/dns/rdata/generic/dlv_32769.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: dlv_32769.h,v 1.2.2.2 2006/02/19 06:50:47 marka Exp $ */
+
+/* draft-ietf-dnsext-delegation-signer-05.txt */
+#ifndef GENERIC_DLV_32769_H
+#define GENERIC_DLV_32769_H 1
+
+typedef struct dns_rdata_dlv {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t key_tag;
+ isc_uint8_t algorithm;
+ isc_uint8_t digest_type;
+ isc_uint16_t length;
+ unsigned char *digest;
+} dns_rdata_dlv_t;
+
+#endif /* GENERIC_DLV_32769_H */
diff --git a/lib/dns/rdata/generic/dname_39.c b/lib/dns/rdata/generic/dname_39.c
new file mode 100644
index 0000000..ed3133c
--- /dev/null
+++ b/lib/dns/rdata/generic/dname_39.c
@@ -0,0 +1,233 @@
+/*
+ * 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: dname_39.c,v 1.36 2004/03/05 05:10:10 marka Exp $ */
+
+/* Reviewed: Wed Mar 15 16:52:38 PST 2000 by explorer */
+
+/* RFC2672 */
+
+#ifndef RDATA_GENERIC_DNAME_39_C
+#define RDATA_GENERIC_DNAME_39_C
+
+#define RRTYPE_DNAME_ATTRIBUTES (DNS_RDATATYPEATTR_SINGLETON)
+
+static inline isc_result_t
+fromtext_dname(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 39);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_dname(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 39);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ sub = name_prefix(&name, tctx->origin, &prefix);
+
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_dname(ARGS_FROMWIRE) {
+ dns_name_t name;
+
+ REQUIRE(type == 39);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&name, NULL);
+ return(dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_dname(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 39);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_dname(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 39);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_dname(ARGS_FROMSTRUCT) {
+ dns_rdata_dname_t *dname = source;
+ isc_region_t region;
+
+ REQUIRE(type == 39);
+ REQUIRE(source != NULL);
+ REQUIRE(dname->common.rdtype == type);
+ REQUIRE(dname->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&dname->dname, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_dname(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_dname_t *dname = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 39);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ dname->common.rdclass = rdata->rdclass;
+ dname->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&dname->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&dname->dname, NULL);
+ RETERR(name_duporclone(&name, mctx, &dname->dname));
+ dname->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_dname(ARGS_FREESTRUCT) {
+ dns_rdata_dname_t *dname = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(dname->common.rdtype == 39);
+
+ if (dname->mctx == NULL)
+ return;
+
+ dns_name_free(&dname->dname, dname->mctx);
+ dname->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_dname(ARGS_ADDLDATA) {
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ REQUIRE(rdata->type == 39);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_dname(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 39);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_dname(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 39);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_dname(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 39);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_DNAME_39_C */
diff --git a/lib/dns/rdata/generic/dname_39.h b/lib/dns/rdata/generic/dname_39.h
new file mode 100644
index 0000000..93ec709
--- /dev/null
+++ b/lib/dns/rdata/generic/dname_39.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_DNAME_39_H
+#define GENERIC_DNAME_39_H 1
+
+/* $Id: dname_39.h,v 1.17.18.2 2005/04/29 00:16:31 marka Exp $ */
+
+/*!
+ * \brief per RFC2672 */
+
+typedef struct dns_rdata_dname {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t dname;
+} dns_rdata_dname_t;
+
+#endif /* GENERIC_DNAME_39_H */
diff --git a/lib/dns/rdata/generic/dnskey_48.c b/lib/dns/rdata/generic/dnskey_48.c
new file mode 100644
index 0000000..5a4e453
--- /dev/null
+++ b/lib/dns/rdata/generic/dnskey_48.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: dnskey_48.c,v 1.4.20.2 2005/04/29 00:16:31 marka Exp $ */
+
+/*
+ * Reviewed: Wed Mar 15 16:47:10 PST 2000 by halley.
+ */
+
+/* RFC2535 */
+
+#ifndef RDATA_GENERIC_DNSKEY_48_C
+#define RDATA_GENERIC_DNSKEY_48_C
+
+#include <dst/dst.h>
+
+#define RRTYPE_DNSKEY_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC)
+
+static inline isc_result_t
+fromtext_dnskey(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_secalg_t alg;
+ dns_secproto_t proto;
+ dns_keyflags_t flags;
+
+ REQUIRE(type == 48);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ /* flags */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_keyflags_fromtext(&flags, &token.value.as_textregion));
+ RETERR(uint16_tobuffer(flags, target));
+
+ /* protocol */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_secproto_fromtext(&proto, &token.value.as_textregion));
+ RETERR(mem_tobuffer(target, &proto, 1));
+
+ /* algorithm */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_secalg_fromtext(&alg, &token.value.as_textregion));
+ RETERR(mem_tobuffer(target, &alg, 1));
+
+ /* No Key? */
+ if ((flags & 0xc000) == 0xc000)
+ return (ISC_R_SUCCESS);
+
+ return (isc_base64_tobuffer(lexer, target, -1));
+}
+
+static inline isc_result_t
+totext_dnskey(ARGS_TOTEXT) {
+ isc_region_t sr;
+ char buf[sizeof("64000")];
+ unsigned int flags;
+ unsigned char algorithm;
+
+ REQUIRE(rdata->type == 48);
+ REQUIRE(rdata->length != 0);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /* flags */
+ flags = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%u", flags);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /* protocol */
+ sprintf(buf, "%u", sr.base[0]);
+ isc_region_consume(&sr, 1);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /* algorithm */
+ algorithm = sr.base[0];
+ sprintf(buf, "%u", algorithm);
+ isc_region_consume(&sr, 1);
+ RETERR(str_totext(buf, target));
+
+ /* No Key? */
+ if ((flags & 0xc000) == 0xc000)
+ return (ISC_R_SUCCESS);
+
+ /* key */
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_base64_totext(&sr, tctx->width - 2,
+ tctx->linebreak, target));
+
+ if ((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0)
+ RETERR(str_totext(tctx->linebreak, target));
+ else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" ", target));
+
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(")", target));
+
+ if ((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0) {
+ isc_region_t tmpr;
+
+ RETERR(str_totext(" ; key id = ", target));
+ dns_rdata_toregion(rdata, &tmpr);
+ sprintf(buf, "%u", dst_region_computeid(&tmpr, algorithm));
+ RETERR(str_totext(buf, target));
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_dnskey(ARGS_FROMWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(type == 48);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(dctx);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sr);
+ if (sr.length < 4)
+ return (ISC_R_UNEXPECTEDEND);
+
+ isc_buffer_forward(source, sr.length);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline isc_result_t
+towire_dnskey(ARGS_TOWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 48);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(cctx);
+
+ dns_rdata_toregion(rdata, &sr);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_dnskey(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 48);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_dnskey(ARGS_FROMSTRUCT) {
+ dns_rdata_dnskey_t *dnskey = source;
+
+ REQUIRE(type == 48);
+ REQUIRE(source != NULL);
+ REQUIRE(dnskey->common.rdtype == type);
+ REQUIRE(dnskey->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ /* Flags */
+ RETERR(uint16_tobuffer(dnskey->flags, target));
+
+ /* Protocol */
+ RETERR(uint8_tobuffer(dnskey->protocol, target));
+
+ /* Algorithm */
+ RETERR(uint8_tobuffer(dnskey->algorithm, target));
+
+ /* Data */
+ return (mem_tobuffer(target, dnskey->data, dnskey->datalen));
+}
+
+static inline isc_result_t
+tostruct_dnskey(ARGS_TOSTRUCT) {
+ dns_rdata_dnskey_t *dnskey = target;
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 48);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ dnskey->common.rdclass = rdata->rdclass;
+ dnskey->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&dnskey->common, link);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /* Flags */
+ if (sr.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ dnskey->flags = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /* Protocol */
+ if (sr.length < 1)
+ return (ISC_R_UNEXPECTEDEND);
+ dnskey->protocol = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ /* Algorithm */
+ if (sr.length < 1)
+ return (ISC_R_UNEXPECTEDEND);
+ dnskey->algorithm = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ /* Data */
+ dnskey->datalen = sr.length;
+ dnskey->data = mem_maybedup(mctx, sr.base, dnskey->datalen);
+ if (dnskey->data == NULL)
+ return (ISC_R_NOMEMORY);
+
+ dnskey->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_dnskey(ARGS_FREESTRUCT) {
+ dns_rdata_dnskey_t *dnskey = (dns_rdata_dnskey_t *) source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(dnskey->common.rdtype == 48);
+
+ if (dnskey->mctx == NULL)
+ return;
+
+ if (dnskey->data != NULL)
+ isc_mem_free(dnskey->mctx, dnskey->data);
+ dnskey->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_dnskey(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 48);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_dnskey(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 48);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_dnskey(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 48);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_dnskey(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 48);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_DNSKEY_48_C */
diff --git a/lib/dns/rdata/generic/dnskey_48.h b/lib/dns/rdata/generic/dnskey_48.h
new file mode 100644
index 0000000..9b3d262
--- /dev/null
+++ b/lib/dns/rdata/generic/dnskey_48.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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.
+ */
+
+#ifndef GENERIC_DNSKEY_48_H
+#define GENERIC_DNSKEY_48_H 1
+
+/* $Id: dnskey_48.h,v 1.3.20.2 2005/04/29 00:16:32 marka Exp $ */
+
+/*!
+ * \brief per RFC2535 */
+
+typedef struct dns_rdata_dnskey {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ isc_uint16_t flags;
+ isc_uint8_t protocol;
+ isc_uint8_t algorithm;
+ isc_uint16_t datalen;
+ unsigned char * data;
+} dns_rdata_dnskey_t;
+
+
+#endif /* GENERIC_DNSKEY_48_H */
diff --git a/lib/dns/rdata/generic/ds_43.c b/lib/dns/rdata/generic/ds_43.c
new file mode 100644
index 0000000..212a56f
--- /dev/null
+++ b/lib/dns/rdata/generic/ds_43.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2002 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ds_43.c,v 1.7.18.5 2007/08/28 07:20:06 tbox Exp $ */
+
+/* draft-ietf-dnsext-delegation-signer-05.txt */
+
+#ifndef RDATA_GENERIC_DS_43_C
+#define RDATA_GENERIC_DS_43_C
+
+#define RRTYPE_DS_ATTRIBUTES \
+ (DNS_RDATATYPEATTR_DNSSEC|DNS_RDATATYPEATTR_ATPARENT)
+
+#include <isc/sha1.h>
+#include <isc/sha2.h>
+
+#include <dns/ds.h>
+
+static inline isc_result_t
+fromtext_ds(ARGS_FROMTEXT) {
+ isc_token_t token;
+ unsigned char c;
+ int length;
+
+ REQUIRE(type == 43);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ /*
+ * Key tag.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Algorithm.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_secalg_fromtext(&c, &token.value.as_textregion));
+ RETERR(mem_tobuffer(target, &c, 1));
+
+ /*
+ * Digest type.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint8_tobuffer(token.value.as_ulong, target));
+ c = (unsigned char) token.value.as_ulong;
+
+ /*
+ * Digest.
+ */
+ if (c == DNS_DSDIGEST_SHA1)
+ length = ISC_SHA1_DIGESTLENGTH;
+ else if (c == DNS_DSDIGEST_SHA256)
+ length = ISC_SHA256_DIGESTLENGTH;
+ else
+ length = -1;
+ return (isc_hex_tobuffer(lexer, target, length));
+}
+
+static inline isc_result_t
+totext_ds(ARGS_TOTEXT) {
+ isc_region_t sr;
+ char buf[sizeof("64000 ")];
+ unsigned int n;
+
+ REQUIRE(rdata->type == 43);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /*
+ * Key tag.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%u ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Algorithm.
+ */
+ n = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+ sprintf(buf, "%u ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Digest type.
+ */
+ n = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+ sprintf(buf, "%u", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Digest.
+ */
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_hex_totext(&sr, tctx->width - 2, tctx->linebreak, target));
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" )", target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_ds(ARGS_FROMWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(type == 43);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(dctx);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sr);
+
+ /*
+ * Check digest lengths if we know them.
+ */
+ if (sr.length < 4 ||
+ (sr.base[3] == DNS_DSDIGEST_SHA1 &&
+ sr.length < 4 + ISC_SHA1_DIGESTLENGTH) ||
+ (sr.base[3] == DNS_DSDIGEST_SHA256 &&
+ sr.length < 4 + ISC_SHA256_DIGESTLENGTH))
+ return (ISC_R_UNEXPECTEDEND);
+
+ /*
+ * Only copy digest lengths if we know them.
+ * If there is extra data dns_rdata_fromwire() will
+ * detect that.
+ */
+ if (sr.base[3] == DNS_DSDIGEST_SHA1)
+ sr.length = 4 + ISC_SHA1_DIGESTLENGTH;
+ else if (sr.base[3] == DNS_DSDIGEST_SHA256)
+ sr.length = 4 + ISC_SHA256_DIGESTLENGTH;
+
+ isc_buffer_forward(source, sr.length);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline isc_result_t
+towire_ds(ARGS_TOWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 43);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(cctx);
+
+ dns_rdata_toregion(rdata, &sr);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_ds(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 43);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_ds(ARGS_FROMSTRUCT) {
+ dns_rdata_ds_t *ds = source;
+
+ REQUIRE(type == 43);
+ REQUIRE(source != NULL);
+ REQUIRE(ds->common.rdtype == type);
+ REQUIRE(ds->common.rdclass == rdclass);
+ switch (ds->digest_type) {
+ case DNS_DSDIGEST_SHA1:
+ REQUIRE(ds->length == ISC_SHA1_DIGESTLENGTH);
+ break;
+ case DNS_DSDIGEST_SHA256:
+ REQUIRE(ds->length == ISC_SHA256_DIGESTLENGTH);
+ break;
+ }
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint16_tobuffer(ds->key_tag, target));
+ RETERR(uint8_tobuffer(ds->algorithm, target));
+ RETERR(uint8_tobuffer(ds->digest_type, target));
+
+ return (mem_tobuffer(target, ds->digest, ds->length));
+}
+
+static inline isc_result_t
+tostruct_ds(ARGS_TOSTRUCT) {
+ dns_rdata_ds_t *ds = target;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 43);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ ds->common.rdclass = rdata->rdclass;
+ ds->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&ds->common, link);
+
+ dns_rdata_toregion(rdata, &region);
+
+ ds->key_tag = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ ds->algorithm = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ ds->digest_type = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ ds->length = region.length;
+
+ ds->digest = mem_maybedup(mctx, region.base, region.length);
+ if (ds->digest == NULL)
+ return (ISC_R_NOMEMORY);
+
+ ds->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_ds(ARGS_FREESTRUCT) {
+ dns_rdata_ds_t *ds = source;
+
+ REQUIRE(ds != NULL);
+ REQUIRE(ds->common.rdtype == 43);
+
+ if (ds->mctx == NULL)
+ return;
+
+ if (ds->digest != NULL)
+ isc_mem_free(ds->mctx, ds->digest);
+ ds->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_ds(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 43);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_ds(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 43);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_ds(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 43);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_ds(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 43);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_DS_43_C */
diff --git a/lib/dns/rdata/generic/ds_43.h b/lib/dns/rdata/generic/ds_43.h
new file mode 100644
index 0000000..dae7bef
--- /dev/null
+++ b/lib/dns/rdata/generic/ds_43.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: ds_43.h,v 1.3.20.2 2005/04/29 00:16:32 marka Exp $ */
+
+#ifndef GENERIC_DS_43_H
+#define GENERIC_DS_43_H 1
+
+/*!
+ * \brief per draft-ietf-dnsext-delegation-signer-05.txt */
+typedef struct dns_rdata_ds {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t key_tag;
+ isc_uint8_t algorithm;
+ isc_uint8_t digest_type;
+ isc_uint16_t length;
+ unsigned char *digest;
+} dns_rdata_ds_t;
+
+#endif /* GENERIC_DS_43_H */
diff --git a/lib/dns/rdata/generic/gpos_27.c b/lib/dns/rdata/generic/gpos_27.c
new file mode 100644
index 0000000..9b37905
--- /dev/null
+++ b/lib/dns/rdata/generic/gpos_27.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2004, 2005 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: gpos_27.c,v 1.37.18.2 2005/04/29 00:16:32 marka Exp $ */
+
+/* reviewed: Wed Mar 15 16:48:45 PST 2000 by brister */
+
+/* RFC1712 */
+
+#ifndef RDATA_GENERIC_GPOS_27_C
+#define RDATA_GENERIC_GPOS_27_C
+
+#define RRTYPE_GPOS_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_gpos(ARGS_FROMTEXT) {
+ isc_token_t token;
+ int i;
+
+ REQUIRE(type == 27);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ for (i = 0; i < 3; i++) {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_qstring,
+ ISC_FALSE));
+ RETTOK(txt_fromtext(&token.value.as_textregion, target));
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_gpos(ARGS_TOTEXT) {
+ isc_region_t region;
+ int i;
+
+ REQUIRE(rdata->type == 27);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &region);
+
+ for (i = 0; i < 3; i++) {
+ RETERR(txt_totext(&region, target));
+ if (i != 2)
+ RETERR(str_totext(" ", target));
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_gpos(ARGS_FROMWIRE) {
+ int i;
+
+ REQUIRE(type == 27);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(rdclass);
+ UNUSED(options);
+
+ for (i = 0; i < 3; i++)
+ RETERR(txt_fromwire(source, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_gpos(ARGS_TOWIRE) {
+
+ REQUIRE(rdata->type == 27);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(cctx);
+
+ return (mem_tobuffer(target, rdata->data, rdata->length));
+}
+
+static inline int
+compare_gpos(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 27);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_gpos(ARGS_FROMSTRUCT) {
+ dns_rdata_gpos_t *gpos = source;
+
+ REQUIRE(type == 27);
+ REQUIRE(source != NULL);
+ REQUIRE(gpos->common.rdtype == type);
+ REQUIRE(gpos->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint8_tobuffer(gpos->long_len, target));
+ RETERR(mem_tobuffer(target, gpos->longitude, gpos->long_len));
+ RETERR(uint8_tobuffer(gpos->lat_len, target));
+ RETERR(mem_tobuffer(target, gpos->latitude, gpos->lat_len));
+ RETERR(uint8_tobuffer(gpos->alt_len, target));
+ return (mem_tobuffer(target, gpos->altitude, gpos->alt_len));
+}
+
+static inline isc_result_t
+tostruct_gpos(ARGS_TOSTRUCT) {
+ dns_rdata_gpos_t *gpos = target;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 27);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ gpos->common.rdclass = rdata->rdclass;
+ gpos->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&gpos->common, link);
+
+ dns_rdata_toregion(rdata, &region);
+ gpos->long_len = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ gpos->longitude = mem_maybedup(mctx, region.base, gpos->long_len);
+ if (gpos->longitude == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_region_consume(&region, gpos->long_len);
+
+ gpos->lat_len = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ gpos->latitude = mem_maybedup(mctx, region.base, gpos->lat_len);
+ if (gpos->latitude == NULL)
+ goto cleanup_longitude;
+ isc_region_consume(&region, gpos->lat_len);
+
+ gpos->alt_len = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ if (gpos->lat_len > 0) {
+ gpos->altitude =
+ mem_maybedup(mctx, region.base, gpos->alt_len);
+ if (gpos->altitude == NULL)
+ goto cleanup_latitude;
+ } else
+ gpos->altitude = NULL;
+
+ gpos->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup_latitude:
+ if (mctx != NULL && gpos->longitude != NULL)
+ isc_mem_free(mctx, gpos->longitude);
+
+ cleanup_longitude:
+ if (mctx != NULL && gpos->latitude != NULL)
+ isc_mem_free(mctx, gpos->latitude);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_gpos(ARGS_FREESTRUCT) {
+ dns_rdata_gpos_t *gpos = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(gpos->common.rdtype == 27);
+
+ if (gpos->mctx == NULL)
+ return;
+
+ if (gpos->longitude != NULL)
+ isc_mem_free(gpos->mctx, gpos->longitude);
+ if (gpos->latitude != NULL)
+ isc_mem_free(gpos->mctx, gpos->latitude);
+ if (gpos->altitude != NULL)
+ isc_mem_free(gpos->mctx, gpos->altitude);
+ gpos->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_gpos(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 27);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_gpos(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 27);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_gpos(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 27);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_gpos(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 27);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_GPOS_27_C */
diff --git a/lib/dns/rdata/generic/gpos_27.h b/lib/dns/rdata/generic/gpos_27.h
new file mode 100644
index 0000000..4949bde
--- /dev/null
+++ b/lib/dns/rdata/generic/gpos_27.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_GPOS_27_H
+#define GENERIC_GPOS_27_H 1
+
+/* $Id: gpos_27.h,v 1.13.18.2 2005/04/29 00:16:32 marka Exp $ */
+
+/*!
+ * \brief per RFC1712 */
+
+typedef struct dns_rdata_gpos {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ char *longitude;
+ char *latitude;
+ char *altitude;
+ isc_uint8_t long_len;
+ isc_uint8_t lat_len;
+ isc_uint8_t alt_len;
+} dns_rdata_gpos_t;
+
+#endif /* GENERIC_GPOS_27_H */
diff --git a/lib/dns/rdata/generic/hinfo_13.c b/lib/dns/rdata/generic/hinfo_13.c
new file mode 100644
index 0000000..70c433c
--- /dev/null
+++ b/lib/dns/rdata/generic/hinfo_13.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: hinfo_13.c,v 1.42 2004/03/05 05:10:11 marka Exp $ */
+
+/*
+ * Reviewed: Wed Mar 15 16:47:10 PST 2000 by halley.
+ */
+
+#ifndef RDATA_GENERIC_HINFO_13_C
+#define RDATA_GENERIC_HINFO_13_C
+
+#define RRTYPE_HINFO_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_hinfo(ARGS_FROMTEXT) {
+ isc_token_t token;
+ int i;
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ REQUIRE(type == 13);
+
+ for (i = 0; i < 2; i++) {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_qstring,
+ ISC_FALSE));
+ RETTOK(txt_fromtext(&token.value.as_textregion, target));
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_hinfo(ARGS_TOTEXT) {
+ isc_region_t region;
+
+ UNUSED(tctx);
+
+ REQUIRE(rdata->type == 13);
+ REQUIRE(rdata->length != 0);
+
+ dns_rdata_toregion(rdata, &region);
+ RETERR(txt_totext(&region, target));
+ RETERR(str_totext(" ", target));
+ return (txt_totext(&region, target));
+}
+
+static inline isc_result_t
+fromwire_hinfo(ARGS_FROMWIRE) {
+
+ REQUIRE(type == 13);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(rdclass);
+ UNUSED(options);
+
+ RETERR(txt_fromwire(source, target));
+ return (txt_fromwire(source, target));
+}
+
+static inline isc_result_t
+towire_hinfo(ARGS_TOWIRE) {
+
+ UNUSED(cctx);
+
+ REQUIRE(rdata->type == 13);
+ REQUIRE(rdata->length != 0);
+
+ return (mem_tobuffer(target, rdata->data, rdata->length));
+}
+
+static inline int
+compare_hinfo(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 13);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_hinfo(ARGS_FROMSTRUCT) {
+ dns_rdata_hinfo_t *hinfo = source;
+
+ REQUIRE(type == 13);
+ REQUIRE(source != NULL);
+ REQUIRE(hinfo->common.rdtype == type);
+ REQUIRE(hinfo->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint8_tobuffer(hinfo->cpu_len, target));
+ RETERR(mem_tobuffer(target, hinfo->cpu, hinfo->cpu_len));
+ RETERR(uint8_tobuffer(hinfo->os_len, target));
+ return (mem_tobuffer(target, hinfo->os, hinfo->os_len));
+}
+
+static inline isc_result_t
+tostruct_hinfo(ARGS_TOSTRUCT) {
+ dns_rdata_hinfo_t *hinfo = target;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 13);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ hinfo->common.rdclass = rdata->rdclass;
+ hinfo->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&hinfo->common, link);
+
+ dns_rdata_toregion(rdata, &region);
+ hinfo->cpu_len = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ hinfo->cpu = mem_maybedup(mctx, region.base, hinfo->cpu_len);
+ if (hinfo->cpu == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_region_consume(&region, hinfo->cpu_len);
+
+ hinfo->os_len = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ hinfo->os = mem_maybedup(mctx, region.base, hinfo->os_len);
+ if (hinfo->os == NULL)
+ goto cleanup;
+
+ hinfo->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL && hinfo->cpu != NULL)
+ isc_mem_free(mctx, hinfo->cpu);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_hinfo(ARGS_FREESTRUCT) {
+ dns_rdata_hinfo_t *hinfo = source;
+
+ REQUIRE(source != NULL);
+
+ if (hinfo->mctx == NULL)
+ return;
+
+ if (hinfo->cpu != NULL)
+ isc_mem_free(hinfo->mctx, hinfo->cpu);
+ if (hinfo->os != NULL)
+ isc_mem_free(hinfo->mctx, hinfo->os);
+ hinfo->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_hinfo(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 13);
+
+ UNUSED(add);
+ UNUSED(arg);
+ UNUSED(rdata);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_hinfo(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 13);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_hinfo(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 13);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_hinfo(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 13);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_HINFO_13_C */
diff --git a/lib/dns/rdata/generic/hinfo_13.h b/lib/dns/rdata/generic/hinfo_13.h
new file mode 100644
index 0000000..e542c48
--- /dev/null
+++ b/lib/dns/rdata/generic/hinfo_13.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_HINFO_13_H
+#define GENERIC_HINFO_13_H 1
+
+/* $Id: hinfo_13.h,v 1.23 2004/03/05 05:10:12 marka Exp $ */
+
+typedef struct dns_rdata_hinfo {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ char *cpu;
+ char *os;
+ isc_uint8_t cpu_len;
+ isc_uint8_t os_len;
+} dns_rdata_hinfo_t;
+
+#endif /* GENERIC_HINFO_13_H */
diff --git a/lib/dns/rdata/generic/ipseckey_45.c b/lib/dns/rdata/generic/ipseckey_45.c
new file mode 100644
index 0000000..3c3736e
--- /dev/null
+++ b/lib/dns/rdata/generic/ipseckey_45.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ipseckey_45.c,v 1.2.2.1 2005/07/07 03:17:36 marka Exp $ */
+
+#ifndef RDATA_GENERIC_IPSECKEY_45_C
+#define RDATA_GENERIC_IPSECKEY_45_C
+
+#include <string.h>
+
+#include <isc/net.h>
+
+#define RRTYPE_IPSECKEY_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_ipseckey(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ unsigned int gateway;
+ struct in_addr addr;
+ unsigned char addr6[16];
+ isc_region_t region;
+
+ REQUIRE(type == 45);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Precedence.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint8_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Gateway type.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0x3U)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint8_tobuffer(token.value.as_ulong, target));
+ gateway = token.value.as_ulong;
+
+ /*
+ * Algorithm.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint8_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Gateway.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ switch (gateway) {
+ case 0:
+ if (strcmp(DNS_AS_STR(token), ".") != 0)
+ RETTOK(DNS_R_SYNTAX);
+ break;
+
+ case 1:
+ if (getquad(DNS_AS_STR(token), &addr, lexer, callbacks) != 1)
+ RETTOK(DNS_R_BADDOTTEDQUAD);
+ isc_buffer_availableregion(target, &region);
+ if (region.length < 4)
+ return (ISC_R_NOSPACE);
+ memcpy(region.base, &addr, 4);
+ isc_buffer_add(target, 4);
+ break;
+
+ case 2:
+ if (inet_pton(AF_INET6, DNS_AS_STR(token), addr6) != 1)
+ RETTOK(DNS_R_BADAAAA);
+ isc_buffer_availableregion(target, &region);
+ if (region.length < 16)
+ return (ISC_R_NOSPACE);
+ memcpy(region.base, addr6, 16);
+ isc_buffer_add(target, 16);
+ break;
+
+ case 3:
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin,
+ options, target));
+ break;
+ }
+
+ /*
+ * Public key.
+ */
+ return (isc_base64_tobuffer(lexer, target, -1));
+}
+
+static inline isc_result_t
+totext_ipseckey(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+ char buf[sizeof("255 ")];
+ unsigned short num;
+ unsigned short gateway;
+
+ REQUIRE(rdata->type == 45);
+ REQUIRE(rdata->length >= 3);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ if (rdata->data[1] > 3U)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext("( ", target));
+
+ /*
+ * Precendence.
+ */
+ dns_rdata_toregion(rdata, &region);
+ num = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ sprintf(buf, "%u ", num);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Gateway type.
+ */
+ gateway = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ sprintf(buf, "%u ", gateway);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Algorithm.
+ */
+ num = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ sprintf(buf, "%u ", num);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Gateway.
+ */
+ switch (gateway) {
+ case 0:
+ RETERR(str_totext(".", target));
+ break;
+
+ case 1:
+ RETERR(inet_totext(AF_INET, &region, target));
+ isc_region_consume(&region, 4);
+ break;
+
+ case 2:
+ RETERR(inet_totext(AF_INET6, &region, target));
+ isc_region_consume(&region, 16);
+ break;
+
+ case 3:
+ dns_name_fromregion(&name, &region);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ RETERR(dns_name_totext(&prefix, sub, target));
+ isc_region_consume(&region, name_length(&name));
+ break;
+ }
+
+ /*
+ * Key.
+ */
+ if (region.length > 0U) {
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_base64_totext(&region, tctx->width - 2,
+ tctx->linebreak, target));
+ }
+
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" )", target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_ipseckey(ARGS_FROMWIRE) {
+ dns_name_t name;
+ isc_region_t region;
+
+ REQUIRE(type == 45);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&name, NULL);
+
+ isc_buffer_activeregion(source, &region);
+ if (region.length < 3)
+ return (ISC_R_UNEXPECTEDEND);
+
+ switch (region.base[1]) {
+ case 0:
+ isc_buffer_forward(source, region.length);
+ return (mem_tobuffer(target, region.base, region.length));
+
+ case 1:
+ if (region.length < 7)
+ return (ISC_R_UNEXPECTEDEND);
+ isc_buffer_forward(source, region.length);
+ return (mem_tobuffer(target, region.base, region.length));
+
+ case 2:
+ if (region.length < 19)
+ return (ISC_R_UNEXPECTEDEND);
+ isc_buffer_forward(source, region.length);
+ return (mem_tobuffer(target, region.base, region.length));
+
+ case 3:
+ RETERR(mem_tobuffer(target, region.base, 3));
+ isc_buffer_forward(source, 3);
+ RETERR(dns_name_fromwire(&name, source, dctx, options, target));
+ isc_buffer_activeregion(source, &region);
+ return(mem_tobuffer(target, region.base, region.length));
+
+ default:
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+}
+
+static inline isc_result_t
+towire_ipseckey(ARGS_TOWIRE) {
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 45);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(cctx);
+
+ dns_rdata_toregion(rdata, &region);
+ return (mem_tobuffer(target, region.base, region.length));
+}
+
+static inline int
+compare_ipseckey(ARGS_COMPARE) {
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 45);
+ REQUIRE(rdata1->length >= 3);
+ REQUIRE(rdata2->length >= 3);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ return (isc_region_compare(&region1, &region2));
+}
+
+static inline isc_result_t
+fromstruct_ipseckey(ARGS_FROMSTRUCT) {
+ dns_rdata_ipseckey_t *ipseckey = source;
+ isc_region_t region;
+ isc_uint32_t n;
+
+ REQUIRE(type == 45);
+ REQUIRE(source != NULL);
+ REQUIRE(ipseckey->common.rdtype == type);
+ REQUIRE(ipseckey->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ if (ipseckey->gateway_type > 3U)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ RETERR(uint8_tobuffer(ipseckey->precedence, target));
+ RETERR(uint8_tobuffer(ipseckey->gateway_type, target));
+ RETERR(uint8_tobuffer(ipseckey->algorithm, target));
+
+ switch (ipseckey->gateway_type) {
+ case 0:
+ break;
+
+ case 1:
+ n = ntohl(ipseckey->in_addr.s_addr);
+ RETERR(uint32_tobuffer(n, target));
+ break;
+
+ case 2:
+ RETERR(mem_tobuffer(target, ipseckey->in6_addr.s6_addr, 16));
+ break;
+
+ case 3:
+ dns_name_toregion(&ipseckey->gateway, &region);
+ RETERR(isc_buffer_copyregion(target, &region));
+ break;
+ }
+
+ return (mem_tobuffer(target, ipseckey->key, ipseckey->keylength));
+}
+
+static inline isc_result_t
+tostruct_ipseckey(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_ipseckey_t *ipseckey = target;
+ dns_name_t name;
+ isc_uint32_t n;
+
+ REQUIRE(rdata->type == 45);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length >= 3);
+
+ if (rdata->data[1] > 3U)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ ipseckey->common.rdclass = rdata->rdclass;
+ ipseckey->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&ipseckey->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+
+ ipseckey->precedence = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+
+ ipseckey->gateway_type = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+
+ ipseckey->algorithm = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+
+ switch (ipseckey->gateway_type) {
+ case 0:
+ break;
+
+ case 1:
+ n = uint32_fromregion(&region);
+ ipseckey->in_addr.s_addr = htonl(n);
+ isc_region_consume(&region, 4);
+ break;
+
+ case 2:
+ memcpy(ipseckey->in6_addr.s6_addr, region.base, 16);
+ isc_region_consume(&region, 16);
+ break;
+
+ case 3:
+ dns_name_init(&ipseckey->gateway, NULL);
+ dns_name_fromregion(&name, &region);
+ RETERR(name_duporclone(&name, mctx, &ipseckey->gateway));
+ isc_region_consume(&region, name_length(&name));
+ break;
+ }
+
+ ipseckey->keylength = region.length;
+ if (ipseckey->keylength != 0U) {
+ ipseckey->key = mem_maybedup(mctx, region.base,
+ ipseckey->keylength);
+ if (ipseckey->key == NULL) {
+ if (ipseckey->gateway_type == 3)
+ dns_name_free(&ipseckey->gateway,
+ ipseckey->mctx);
+ return (ISC_R_NOMEMORY);
+ }
+ } else
+ ipseckey->key = NULL;
+
+ ipseckey->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_ipseckey(ARGS_FREESTRUCT) {
+ dns_rdata_ipseckey_t *ipseckey = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(ipseckey->common.rdtype == 45);
+
+ if (ipseckey->mctx == NULL)
+ return;
+
+ if (ipseckey->gateway_type == 3)
+ dns_name_free(&ipseckey->gateway, ipseckey->mctx);
+
+ if (ipseckey->key != NULL)
+ isc_mem_free(ipseckey->mctx, ipseckey->key);
+
+ ipseckey->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_ipseckey(ARGS_ADDLDATA) {
+
+ REQUIRE(rdata->type == 45);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_ipseckey(ARGS_DIGEST) {
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 45);
+
+ dns_rdata_toregion(rdata, &region);
+ return ((digest)(arg, &region));
+}
+
+static inline isc_boolean_t
+checkowner_ipseckey(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 45);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_ipseckey(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 45);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_IPSECKEY_45_C */
diff --git a/lib/dns/rdata/generic/ipseckey_45.h b/lib/dns/rdata/generic/ipseckey_45.h
new file mode 100644
index 0000000..b766fa0
--- /dev/null
+++ b/lib/dns/rdata/generic/ipseckey_45.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ipseckey_45.h,v 1.2.2.1 2005/07/07 03:17:36 marka Exp $ */
+
+#ifndef GENERIC_IPSECKEY_45_H
+#define GENERIC_IPSECKEY_45_H 1
+
+typedef struct dns_rdata_ipseckey {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint8_t precedence;
+ isc_uint8_t gateway_type;
+ isc_uint8_t algorithm;
+ struct in_addr in_addr; /* gateway type 1 */
+ struct in6_addr in6_addr; /* gateway type 2 */
+ dns_name_t gateway; /* gateway type 3 */
+ unsigned char *key;
+ isc_uint16_t keylength;
+} dns_rdata_ipseckey_t;
+
+#endif /* GENERIC_IPSECKEY_45_H */
diff --git a/lib/dns/rdata/generic/isdn_20.c b/lib/dns/rdata/generic/isdn_20.c
new file mode 100644
index 0000000..1813759
--- /dev/null
+++ b/lib/dns/rdata/generic/isdn_20.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2004, 2005 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: isdn_20.c,v 1.34.18.2 2005/04/29 00:16:33 marka Exp $ */
+
+/* Reviewed: Wed Mar 15 16:53:11 PST 2000 by bwelling */
+
+/* RFC1183 */
+
+#ifndef RDATA_GENERIC_ISDN_20_C
+#define RDATA_GENERIC_ISDN_20_C
+
+#define RRTYPE_ISDN_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_isdn(ARGS_FROMTEXT) {
+ isc_token_t token;
+
+ REQUIRE(type == 20);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ /* ISDN-address */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
+ ISC_FALSE));
+ RETTOK(txt_fromtext(&token.value.as_textregion, target));
+
+ /* sa: optional */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
+ ISC_TRUE));
+ if (token.type != isc_tokentype_string &&
+ token.type != isc_tokentype_qstring) {
+ isc_lex_ungettoken(lexer, &token);
+ return (ISC_R_SUCCESS);
+ }
+ RETTOK(txt_fromtext(&token.value.as_textregion, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_isdn(ARGS_TOTEXT) {
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 20);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &region);
+ RETERR(txt_totext(&region, target));
+ if (region.length == 0)
+ return (ISC_R_SUCCESS);
+ RETERR(str_totext(" ", target));
+ return (txt_totext(&region, target));
+}
+
+static inline isc_result_t
+fromwire_isdn(ARGS_FROMWIRE) {
+ REQUIRE(type == 20);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(rdclass);
+ UNUSED(options);
+
+ RETERR(txt_fromwire(source, target));
+ if (buffer_empty(source))
+ return (ISC_R_SUCCESS);
+ return (txt_fromwire(source, target));
+}
+
+static inline isc_result_t
+towire_isdn(ARGS_TOWIRE) {
+ UNUSED(cctx);
+
+ REQUIRE(rdata->type == 20);
+ REQUIRE(rdata->length != 0);
+
+ return (mem_tobuffer(target, rdata->data, rdata->length));
+}
+
+static inline int
+compare_isdn(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 20);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_isdn(ARGS_FROMSTRUCT) {
+ dns_rdata_isdn_t *isdn = source;
+
+ REQUIRE(type == 20);
+ REQUIRE(source != NULL);
+ REQUIRE(isdn->common.rdtype == type);
+ REQUIRE(isdn->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint8_tobuffer(isdn->isdn_len, target));
+ RETERR(mem_tobuffer(target, isdn->isdn, isdn->isdn_len));
+ RETERR(uint8_tobuffer(isdn->subaddress_len, target));
+ return (mem_tobuffer(target, isdn->subaddress, isdn->subaddress_len));
+}
+
+static inline isc_result_t
+tostruct_isdn(ARGS_TOSTRUCT) {
+ dns_rdata_isdn_t *isdn = target;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 20);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ isdn->common.rdclass = rdata->rdclass;
+ isdn->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&isdn->common, link);
+
+ dns_rdata_toregion(rdata, &r);
+
+ isdn->isdn_len = uint8_fromregion(&r);
+ isc_region_consume(&r, 1);
+ isdn->isdn = mem_maybedup(mctx, r.base, isdn->isdn_len);
+ if (isdn->isdn == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_region_consume(&r, isdn->isdn_len);
+
+ isdn->subaddress_len = uint8_fromregion(&r);
+ isc_region_consume(&r, 1);
+ isdn->subaddress = mem_maybedup(mctx, r.base, isdn->subaddress_len);
+ if (isdn->subaddress == NULL)
+ goto cleanup;
+
+ isdn->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL && isdn->isdn != NULL)
+ isc_mem_free(mctx, isdn->isdn);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_isdn(ARGS_FREESTRUCT) {
+ dns_rdata_isdn_t *isdn = source;
+
+ REQUIRE(source != NULL);
+
+ if (isdn->mctx == NULL)
+ return;
+
+ if (isdn->isdn != NULL)
+ isc_mem_free(isdn->mctx, isdn->isdn);
+ if (isdn->subaddress != NULL)
+ isc_mem_free(isdn->mctx, isdn->subaddress);
+ isdn->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_isdn(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 20);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_isdn(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 20);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_isdn(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 20);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_isdn(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 20);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_ISDN_20_C */
diff --git a/lib/dns/rdata/generic/isdn_20.h b/lib/dns/rdata/generic/isdn_20.h
new file mode 100644
index 0000000..6a51317
--- /dev/null
+++ b/lib/dns/rdata/generic/isdn_20.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_ISDN_20_H
+#define GENERIC_ISDN_20_H 1
+
+/* $Id: isdn_20.h,v 1.14.18.2 2005/04/29 00:16:33 marka Exp $ */
+
+/*!
+ * \brief Per RFC1183 */
+
+typedef struct dns_rdata_isdn {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ char *isdn;
+ char *subaddress;
+ isc_uint8_t isdn_len;
+ isc_uint8_t subaddress_len;
+} dns_rdata_isdn_t;
+
+#endif /* GENERIC_ISDN_20_H */
diff --git a/lib/dns/rdata/generic/key_25.c b/lib/dns/rdata/generic/key_25.c
new file mode 100644
index 0000000..24dc10f
--- /dev/null
+++ b/lib/dns/rdata/generic/key_25.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2004, 2005 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: key_25.c,v 1.47.18.2 2005/04/29 00:16:33 marka Exp $ */
+
+/*
+ * Reviewed: Wed Mar 15 16:47:10 PST 2000 by halley.
+ */
+
+/* RFC2535 */
+
+#ifndef RDATA_GENERIC_KEY_25_C
+#define RDATA_GENERIC_KEY_25_C
+
+#include <dst/dst.h>
+
+#define RRTYPE_KEY_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_key(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_secalg_t alg;
+ dns_secproto_t proto;
+ dns_keyflags_t flags;
+
+ REQUIRE(type == 25);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ /* flags */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_keyflags_fromtext(&flags, &token.value.as_textregion));
+ RETERR(uint16_tobuffer(flags, target));
+
+ /* protocol */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_secproto_fromtext(&proto, &token.value.as_textregion));
+ RETERR(mem_tobuffer(target, &proto, 1));
+
+ /* algorithm */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_secalg_fromtext(&alg, &token.value.as_textregion));
+ RETERR(mem_tobuffer(target, &alg, 1));
+
+ /* No Key? */
+ if ((flags & 0xc000) == 0xc000)
+ return (ISC_R_SUCCESS);
+
+ return (isc_base64_tobuffer(lexer, target, -1));
+}
+
+static inline isc_result_t
+totext_key(ARGS_TOTEXT) {
+ isc_region_t sr;
+ char buf[sizeof("64000")];
+ unsigned int flags;
+ unsigned char algorithm;
+
+ REQUIRE(rdata->type == 25);
+ REQUIRE(rdata->length != 0);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /* flags */
+ flags = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%u", flags);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /* protocol */
+ sprintf(buf, "%u", sr.base[0]);
+ isc_region_consume(&sr, 1);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /* algorithm */
+ algorithm = sr.base[0];
+ sprintf(buf, "%u", algorithm);
+ isc_region_consume(&sr, 1);
+ RETERR(str_totext(buf, target));
+
+ /* No Key? */
+ if ((flags & 0xc000) == 0xc000)
+ return (ISC_R_SUCCESS);
+
+ /* key */
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_base64_totext(&sr, tctx->width - 2,
+ tctx->linebreak, target));
+
+ if ((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0)
+ RETERR(str_totext(tctx->linebreak, target));
+ else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" ", target));
+
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(")", target));
+
+ if ((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0) {
+ isc_region_t tmpr;
+
+ RETERR(str_totext(" ; key id = ", target));
+ dns_rdata_toregion(rdata, &tmpr);
+ sprintf(buf, "%u", dst_region_computeid(&tmpr, algorithm));
+ RETERR(str_totext(buf, target));
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_key(ARGS_FROMWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(type == 25);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(dctx);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sr);
+ if (sr.length < 4)
+ return (ISC_R_UNEXPECTEDEND);
+
+ isc_buffer_forward(source, sr.length);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline isc_result_t
+towire_key(ARGS_TOWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 25);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(cctx);
+
+ dns_rdata_toregion(rdata, &sr);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_key(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 25);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_key(ARGS_FROMSTRUCT) {
+ dns_rdata_key_t *key = source;
+
+ REQUIRE(type == 25);
+ REQUIRE(source != NULL);
+ REQUIRE(key->common.rdtype == type);
+ REQUIRE(key->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ /* Flags */
+ RETERR(uint16_tobuffer(key->flags, target));
+
+ /* Protocol */
+ RETERR(uint8_tobuffer(key->protocol, target));
+
+ /* Algorithm */
+ RETERR(uint8_tobuffer(key->algorithm, target));
+
+ /* Data */
+ return (mem_tobuffer(target, key->data, key->datalen));
+}
+
+static inline isc_result_t
+tostruct_key(ARGS_TOSTRUCT) {
+ dns_rdata_key_t *key = target;
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 25);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ key->common.rdclass = rdata->rdclass;
+ key->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&key->common, link);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /* Flags */
+ if (sr.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ key->flags = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /* Protocol */
+ if (sr.length < 1)
+ return (ISC_R_UNEXPECTEDEND);
+ key->protocol = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ /* Algorithm */
+ if (sr.length < 1)
+ return (ISC_R_UNEXPECTEDEND);
+ key->algorithm = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ /* Data */
+ key->datalen = sr.length;
+ key->data = mem_maybedup(mctx, sr.base, key->datalen);
+ if (key->data == NULL)
+ return (ISC_R_NOMEMORY);
+
+ key->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_key(ARGS_FREESTRUCT) {
+ dns_rdata_key_t *key = (dns_rdata_key_t *) source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(key->common.rdtype == 25);
+
+ if (key->mctx == NULL)
+ return;
+
+ if (key->data != NULL)
+ isc_mem_free(key->mctx, key->data);
+ key->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_key(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 25);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_key(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 25);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_key(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 25);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_key(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 25);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_KEY_25_C */
diff --git a/lib/dns/rdata/generic/key_25.h b/lib/dns/rdata/generic/key_25.h
new file mode 100644
index 0000000..03400db
--- /dev/null
+++ b/lib/dns/rdata/generic/key_25.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_KEY_25_H
+#define GENERIC_KEY_25_H 1
+
+/* $Id: key_25.h,v 1.15.18.2 2005/04/29 00:16:33 marka Exp $ */
+
+/*!
+ * \brief Per RFC2535 */
+
+typedef struct dns_rdata_key_t {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ isc_uint16_t flags;
+ isc_uint8_t protocol;
+ isc_uint8_t algorithm;
+ isc_uint16_t datalen;
+ unsigned char * data;
+} dns_rdata_key_t;
+
+
+#endif /* GENERIC_KEY_25_H */
diff --git a/lib/dns/rdata/generic/loc_29.c b/lib/dns/rdata/generic/loc_29.c
new file mode 100644
index 0000000..c93ac90
--- /dev/null
+++ b/lib/dns/rdata/generic/loc_29.c
@@ -0,0 +1,794 @@
+/*
+ * Copyright (C) 2004, 2005 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: loc_29.c,v 1.41.18.2 2005/04/29 00:16:34 marka Exp $ */
+
+/* Reviewed: Wed Mar 15 18:13:09 PST 2000 by explorer */
+
+/* RFC1876 */
+
+#ifndef RDATA_GENERIC_LOC_29_C
+#define RDATA_GENERIC_LOC_29_C
+
+#define RRTYPE_LOC_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_loc(ARGS_FROMTEXT) {
+ isc_token_t token;
+ int d1, m1, s1;
+ int d2, m2, s2;
+ unsigned char size;
+ unsigned char hp;
+ unsigned char vp;
+ unsigned char version;
+ isc_boolean_t east = ISC_FALSE;
+ isc_boolean_t north = ISC_FALSE;
+ long tmp;
+ long m;
+ long cm;
+ long poweroften[8] = { 1, 10, 100, 1000,
+ 10000, 100000, 1000000, 10000000 };
+ int man;
+ int exp;
+ char *e;
+ int i;
+ unsigned long latitude;
+ unsigned long longitude;
+ unsigned long altitude;
+
+ REQUIRE(type == 29);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+
+ /*
+ * Defaults.
+ */
+ m1 = s1 = 0;
+ m2 = s2 = 0;
+ size = 0x12; /* 1.00m */
+ hp = 0x16; /* 10000.00 m */
+ vp = 0x13; /* 10.00 m */
+ version = 0;
+
+ /*
+ * Degrees.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 90U)
+ RETTOK(ISC_R_RANGE);
+ d1 = (int)token.value.as_ulong;
+ /*
+ * Minutes.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ if (strcasecmp(DNS_AS_STR(token), "N") == 0)
+ north = ISC_TRUE;
+ if (north || strcasecmp(DNS_AS_STR(token), "S") == 0)
+ goto getlong;
+ m1 = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e != 0)
+ RETTOK(DNS_R_SYNTAX);
+ if (m1 < 0 || m1 > 59)
+ RETTOK(ISC_R_RANGE);
+ if (d1 == 90 && m1 != 0)
+ RETTOK(ISC_R_RANGE);
+
+ /*
+ * Seconds.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ if (strcasecmp(DNS_AS_STR(token), "N") == 0)
+ north = ISC_TRUE;
+ if (north || strcasecmp(DNS_AS_STR(token), "S") == 0)
+ goto getlong;
+ s1 = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e != 0 && *e != '.')
+ RETTOK(DNS_R_SYNTAX);
+ if (s1 < 0 || s1 > 59)
+ RETTOK(ISC_R_RANGE);
+ if (*e == '.') {
+ const char *l;
+ e++;
+ for (i = 0; i < 3; i++) {
+ if (*e == 0)
+ break;
+ if ((tmp = decvalue(*e++)) < 0)
+ RETTOK(DNS_R_SYNTAX);
+ s1 *= 10;
+ s1 += tmp;
+ }
+ for (; i < 3; i++)
+ s1 *= 10;
+ l = e;
+ while (*e != 0) {
+ if (decvalue(*e++) < 0)
+ RETTOK(DNS_R_SYNTAX);
+ }
+ if (*l != '\0' && callbacks != NULL) {
+ const char *file = isc_lex_getsourcename(lexer);
+ unsigned long line = isc_lex_getsourceline(lexer);
+
+ if (file == NULL)
+ file = "UNKNOWN";
+ (*callbacks->warn)(callbacks, "%s: %s:%u: '%s' extra "
+ "precision digits ignored",
+ "dns_rdata_fromtext", file, line,
+ DNS_AS_STR(token));
+ }
+ } else
+ s1 *= 1000;
+ if (d1 == 90 && s1 != 0)
+ RETTOK(ISC_R_RANGE);
+
+ /*
+ * Direction.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ if (strcasecmp(DNS_AS_STR(token), "N") == 0)
+ north = ISC_TRUE;
+ if (!north && strcasecmp(DNS_AS_STR(token), "S") != 0)
+ RETTOK(DNS_R_SYNTAX);
+
+ getlong:
+ /*
+ * Degrees.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 180U)
+ RETTOK(ISC_R_RANGE);
+ d2 = (int)token.value.as_ulong;
+
+ /*
+ * Minutes.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ if (strcasecmp(DNS_AS_STR(token), "E") == 0)
+ east = ISC_TRUE;
+ if (east || strcasecmp(DNS_AS_STR(token), "W") == 0)
+ goto getalt;
+ m2 = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e != 0)
+ RETTOK(DNS_R_SYNTAX);
+ if (m2 < 0 || m2 > 59)
+ RETTOK(ISC_R_RANGE);
+ if (d2 == 180 && m2 != 0)
+ RETTOK(ISC_R_RANGE);
+
+ /*
+ * Seconds.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ if (strcasecmp(DNS_AS_STR(token), "E") == 0)
+ east = ISC_TRUE;
+ if (east || strcasecmp(DNS_AS_STR(token), "W") == 0)
+ goto getalt;
+ s2 = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e != 0 && *e != '.')
+ RETTOK(DNS_R_SYNTAX);
+ if (s2 < 0 || s2 > 59)
+ RETTOK(ISC_R_RANGE);
+ if (*e == '.') {
+ const char *l;
+ e++;
+ for (i = 0; i < 3; i++) {
+ if (*e == 0)
+ break;
+ if ((tmp = decvalue(*e++)) < 0)
+ RETTOK(DNS_R_SYNTAX);
+ s2 *= 10;
+ s2 += tmp;
+ }
+ for (; i < 3; i++)
+ s2 *= 10;
+ l = e;
+ while (*e != 0) {
+ if (decvalue(*e++) < 0)
+ RETTOK(DNS_R_SYNTAX);
+ }
+ if (*l != '\0' && callbacks != NULL) {
+ const char *file = isc_lex_getsourcename(lexer);
+ unsigned long line = isc_lex_getsourceline(lexer);
+
+ if (file == NULL)
+ file = "UNKNOWN";
+ (*callbacks->warn)(callbacks, "%s: %s:%u: '%s' extra "
+ "precision digits ignored",
+ "dns_rdata_fromtext",
+ file, line, DNS_AS_STR(token));
+ }
+ } else
+ s2 *= 1000;
+ if (d2 == 180 && s2 != 0)
+ RETTOK(ISC_R_RANGE);
+
+ /*
+ * Direction.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ if (strcasecmp(DNS_AS_STR(token), "E") == 0)
+ east = ISC_TRUE;
+ if (!east && strcasecmp(DNS_AS_STR(token), "W") != 0)
+ RETTOK(DNS_R_SYNTAX);
+
+ getalt:
+ /*
+ * Altitude.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ m = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e != 0 && *e != '.' && *e != 'm')
+ RETTOK(DNS_R_SYNTAX);
+ if (m < -100000 || m > 42849672)
+ RETTOK(ISC_R_RANGE);
+ cm = 0;
+ if (*e == '.') {
+ e++;
+ for (i = 0; i < 2; i++) {
+ if (*e == 0 || *e == 'm')
+ break;
+ if ((tmp = decvalue(*e++)) < 0)
+ return (DNS_R_SYNTAX);
+ cm *= 10;
+ if (m < 0)
+ cm -= tmp;
+ else
+ cm += tmp;
+ }
+ for (; i < 2; i++)
+ cm *= 10;
+ }
+ if (*e == 'm')
+ e++;
+ if (*e != 0)
+ RETTOK(DNS_R_SYNTAX);
+ if (m == -100000 && cm != 0)
+ RETTOK(ISC_R_RANGE);
+ if (m == 42849672 && cm > 95)
+ RETTOK(ISC_R_RANGE);
+ /*
+ * Adjust base.
+ */
+ altitude = m + 100000;
+ altitude *= 100;
+ altitude += cm;
+
+ /*
+ * Size: optional.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_TRUE));
+ if (token.type == isc_tokentype_eol ||
+ token.type == isc_tokentype_eof) {
+ isc_lex_ungettoken(lexer, &token);
+ goto encode;
+ }
+ m = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e != 0 && *e != '.' && *e != 'm')
+ RETTOK(DNS_R_SYNTAX);
+ if (m < 0 || m > 90000000)
+ RETTOK(ISC_R_RANGE);
+ cm = 0;
+ if (*e == '.') {
+ e++;
+ for (i = 0; i < 2; i++) {
+ if (*e == 0 || *e == 'm')
+ break;
+ if ((tmp = decvalue(*e++)) < 0)
+ RETTOK(DNS_R_SYNTAX);
+ cm *= 10;
+ cm += tmp;
+ }
+ for (; i < 2; i++)
+ cm *= 10;
+ }
+ if (*e == 'm')
+ e++;
+ if (*e != 0)
+ RETTOK(DNS_R_SYNTAX);
+ /*
+ * We don't just multiply out as we will overflow.
+ */
+ if (m > 0) {
+ for (exp = 0; exp < 7; exp++)
+ if (m < poweroften[exp+1])
+ break;
+ man = m / poweroften[exp];
+ exp += 2;
+ } else {
+ if (cm >= 10) {
+ man = cm / 10;
+ exp = 1;
+ } else {
+ man = cm;
+ exp = 0;
+ }
+ }
+ size = (man << 4) + exp;
+
+ /*
+ * Horizontal precision: optional.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_TRUE));
+ if (token.type == isc_tokentype_eol ||
+ token.type == isc_tokentype_eof) {
+ isc_lex_ungettoken(lexer, &token);
+ goto encode;
+ }
+ m = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e != 0 && *e != '.' && *e != 'm')
+ RETTOK(DNS_R_SYNTAX);
+ if (m < 0 || m > 90000000)
+ RETTOK(ISC_R_RANGE);
+ cm = 0;
+ if (*e == '.') {
+ e++;
+ for (i = 0; i < 2; i++) {
+ if (*e == 0 || *e == 'm')
+ break;
+ if ((tmp = decvalue(*e++)) < 0)
+ RETTOK(DNS_R_SYNTAX);
+ cm *= 10;
+ cm += tmp;
+ }
+ for (; i < 2; i++)
+ cm *= 10;
+ }
+ if (*e == 'm')
+ e++;
+ if (*e != 0)
+ RETTOK(DNS_R_SYNTAX);
+ /*
+ * We don't just multiply out as we will overflow.
+ */
+ if (m > 0) {
+ for (exp = 0; exp < 7; exp++)
+ if (m < poweroften[exp+1])
+ break;
+ man = m / poweroften[exp];
+ exp += 2;
+ } else if (cm >= 10) {
+ man = cm / 10;
+ exp = 1;
+ } else {
+ man = cm;
+ exp = 0;
+ }
+ hp = (man << 4) + exp;
+
+ /*
+ * Vertical precision: optional.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_TRUE));
+ if (token.type == isc_tokentype_eol ||
+ token.type == isc_tokentype_eof) {
+ isc_lex_ungettoken(lexer, &token);
+ goto encode;
+ }
+ m = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e != 0 && *e != '.' && *e != 'm')
+ RETTOK(DNS_R_SYNTAX);
+ if (m < 0 || m > 90000000)
+ RETTOK(ISC_R_RANGE);
+ cm = 0;
+ if (*e == '.') {
+ e++;
+ for (i = 0; i < 2; i++) {
+ if (*e == 0 || *e == 'm')
+ break;
+ if ((tmp = decvalue(*e++)) < 0)
+ RETTOK(DNS_R_SYNTAX);
+ cm *= 10;
+ cm += tmp;
+ }
+ for (; i < 2; i++)
+ cm *= 10;
+ }
+ if (*e == 'm')
+ e++;
+ if (*e != 0)
+ RETTOK(DNS_R_SYNTAX);
+ /*
+ * We don't just multiply out as we will overflow.
+ */
+ if (m > 0) {
+ for (exp = 0; exp < 7; exp++)
+ if (m < poweroften[exp+1])
+ break;
+ man = m / poweroften[exp];
+ exp += 2;
+ } else if (cm >= 10) {
+ man = cm / 10;
+ exp = 1;
+ } else {
+ man = cm;
+ exp = 0;
+ }
+ vp = (man << 4) + exp;
+
+ encode:
+ RETERR(mem_tobuffer(target, &version, 1));
+ RETERR(mem_tobuffer(target, &size, 1));
+ RETERR(mem_tobuffer(target, &hp, 1));
+ RETERR(mem_tobuffer(target, &vp, 1));
+ if (north)
+ latitude = 0x80000000 + ( d1 * 3600 + m1 * 60 ) * 1000 + s1;
+ else
+ latitude = 0x80000000 - ( d1 * 3600 + m1 * 60 ) * 1000 - s1;
+ RETERR(uint32_tobuffer(latitude, target));
+
+ if (east)
+ longitude = 0x80000000 + ( d2 * 3600 + m2 * 60 ) * 1000 + s2;
+ else
+ longitude = 0x80000000 - ( d2 * 3600 + m2 * 60 ) * 1000 - s2;
+ RETERR(uint32_tobuffer(longitude, target));
+
+ return (uint32_tobuffer(altitude, target));
+}
+
+static inline isc_result_t
+totext_loc(ARGS_TOTEXT) {
+ int d1, m1, s1, fs1;
+ int d2, m2, s2, fs2;
+ unsigned long latitude;
+ unsigned long longitude;
+ unsigned long altitude;
+ isc_boolean_t north;
+ isc_boolean_t east;
+ isc_boolean_t below;
+ isc_region_t sr;
+ char buf[sizeof("89 59 59.999 N 179 59 59.999 E "
+ "42849672.95m 90000000m 90000000m 90000000m")];
+ char sbuf[sizeof("90000000m")];
+ char hbuf[sizeof("90000000m")];
+ char vbuf[sizeof("90000000m")];
+ unsigned char size, hp, vp;
+ unsigned long poweroften[8] = { 1, 10, 100, 1000,
+ 10000, 100000, 1000000, 10000000 };
+
+ UNUSED(tctx);
+
+ REQUIRE(rdata->type == 29);
+ REQUIRE(rdata->length != 0);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /* version = sr.base[0]; */
+ size = sr.base[1];
+ if ((size&0x0f)> 1)
+ sprintf(sbuf, "%lum", (size>>4) * poweroften[(size&0x0f)-2]);
+ else
+ sprintf(sbuf, "0.%02lum", (size>>4) * poweroften[(size&0x0f)]);
+ hp = sr.base[2];
+ if ((hp&0x0f)> 1)
+ sprintf(hbuf, "%lum", (hp>>4) * poweroften[(hp&0x0f)-2]);
+ else
+ sprintf(hbuf, "0.%02lum", (hp>>4) * poweroften[(hp&0x0f)]);
+ vp = sr.base[3];
+ if ((vp&0x0f)> 1)
+ sprintf(vbuf, "%lum", (vp>>4) * poweroften[(vp&0x0f)-2]);
+ else
+ sprintf(vbuf, "0.%02lum", (vp>>4) * poweroften[(vp&0x0f)]);
+ isc_region_consume(&sr, 4);
+
+ latitude = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+ if (latitude >= 0x80000000) {
+ north = ISC_TRUE;
+ latitude -= 0x80000000;
+ } else {
+ north = ISC_FALSE;
+ latitude = 0x80000000 - latitude;
+ }
+ fs1 = (int)(latitude % 1000);
+ latitude /= 1000;
+ s1 = (int)(latitude % 60);
+ latitude /= 60;
+ m1 = (int)(latitude % 60);
+ latitude /= 60;
+ d1 = (int)latitude;
+
+ longitude = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+ if (longitude >= 0x80000000) {
+ east = ISC_TRUE;
+ longitude -= 0x80000000;
+ } else {
+ east = ISC_FALSE;
+ longitude = 0x80000000 - longitude;
+ }
+ fs2 = (int)(longitude % 1000);
+ longitude /= 1000;
+ s2 = (int)(longitude % 60);
+ longitude /= 60;
+ m2 = (int)(longitude % 60);
+ longitude /= 60;
+ d2 = (int)longitude;
+
+ altitude = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+ if (altitude < 10000000U) {
+ below = ISC_TRUE;
+ altitude = 10000000 - altitude;
+ } else {
+ below =ISC_FALSE;
+ altitude -= 10000000;
+ }
+
+ sprintf(buf, "%d %d %d.%03d %s %d %d %d.%03d %s %s%ld.%02ldm %s %s %s",
+ d1, m1, s1, fs1, north ? "N" : "S",
+ d2, m2, s2, fs2, east ? "E" : "W",
+ below ? "-" : "", altitude/100, altitude % 100,
+ sbuf, hbuf, vbuf);
+
+ return (str_totext(buf, target));
+}
+
+static inline isc_result_t
+fromwire_loc(ARGS_FROMWIRE) {
+ isc_region_t sr;
+ unsigned char c;
+ unsigned long latitude;
+ unsigned long longitude;
+
+ REQUIRE(type == 29);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(dctx);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sr);
+ if (sr.length < 1)
+ return (ISC_R_UNEXPECTEDEND);
+ if (sr.base[0] != 0)
+ return (ISC_R_NOTIMPLEMENTED);
+ if (sr.length < 16)
+ return (ISC_R_UNEXPECTEDEND);
+
+ /*
+ * Size.
+ */
+ c = sr.base[1];
+ if (c != 0)
+ if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
+ return (ISC_R_RANGE);
+
+ /*
+ * Horizontal precision.
+ */
+ c = sr.base[2];
+ if (c != 0)
+ if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
+ return (ISC_R_RANGE);
+
+ /*
+ * Vertical precision.
+ */
+ c = sr.base[3];
+ if (c != 0)
+ if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
+ return (ISC_R_RANGE);
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Latitude.
+ */
+ latitude = uint32_fromregion(&sr);
+ if (latitude < (0x80000000UL - 90 * 3600000) ||
+ latitude > (0x80000000UL + 90 * 3600000))
+ return (ISC_R_RANGE);
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Longitude.
+ */
+ longitude = uint32_fromregion(&sr);
+ if (longitude < (0x80000000UL - 180 * 3600000) ||
+ longitude > (0x80000000UL + 180 * 3600000))
+ return (ISC_R_RANGE);
+
+ /*
+ * Altitiude.
+ * All values possible.
+ */
+
+ isc_buffer_activeregion(source, &sr);
+ isc_buffer_forward(source, 16);
+ return (mem_tobuffer(target, sr.base, 16));
+}
+
+static inline isc_result_t
+towire_loc(ARGS_TOWIRE) {
+ UNUSED(cctx);
+
+ REQUIRE(rdata->type == 29);
+ REQUIRE(rdata->length != 0);
+
+ return (mem_tobuffer(target, rdata->data, rdata->length));
+}
+
+static inline int
+compare_loc(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 29);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_loc(ARGS_FROMSTRUCT) {
+ dns_rdata_loc_t *loc = source;
+ isc_uint8_t c;
+
+ REQUIRE(type == 29);
+ REQUIRE(source != NULL);
+ REQUIRE(loc->common.rdtype == type);
+ REQUIRE(loc->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ if (loc->v.v0.version != 0)
+ return (ISC_R_NOTIMPLEMENTED);
+ RETERR(uint8_tobuffer(loc->v.v0.version, target));
+
+ c = loc->v.v0.size;
+ if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
+ return (ISC_R_RANGE);
+ RETERR(uint8_tobuffer(loc->v.v0.size, target));
+
+ c = loc->v.v0.horizontal;
+ if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
+ return (ISC_R_RANGE);
+ RETERR(uint8_tobuffer(loc->v.v0.horizontal, target));
+
+ c = loc->v.v0.vertical;
+ if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
+ return (ISC_R_RANGE);
+ RETERR(uint8_tobuffer(loc->v.v0.vertical, target));
+
+ if (loc->v.v0.latitude < (0x80000000UL - 90 * 3600000) ||
+ loc->v.v0.latitude > (0x80000000UL + 90 * 3600000))
+ return (ISC_R_RANGE);
+ RETERR(uint32_tobuffer(loc->v.v0.latitude, target));
+
+ if (loc->v.v0.longitude < (0x80000000UL - 180 * 3600000) ||
+ loc->v.v0.longitude > (0x80000000UL + 180 * 3600000))
+ return (ISC_R_RANGE);
+ RETERR(uint32_tobuffer(loc->v.v0.longitude, target));
+ return (uint32_tobuffer(loc->v.v0.altitude, target));
+}
+
+static inline isc_result_t
+tostruct_loc(ARGS_TOSTRUCT) {
+ dns_rdata_loc_t *loc = target;
+ isc_region_t r;
+ isc_uint8_t version;
+
+ REQUIRE(rdata->type == 29);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(mctx);
+
+ dns_rdata_toregion(rdata, &r);
+ version = uint8_fromregion(&r);
+ if (version != 0)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ loc->common.rdclass = rdata->rdclass;
+ loc->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&loc->common, link);
+
+ loc->v.v0.version = version;
+ isc_region_consume(&r, 1);
+ loc->v.v0.size = uint8_fromregion(&r);
+ isc_region_consume(&r, 1);
+ loc->v.v0.horizontal = uint8_fromregion(&r);
+ isc_region_consume(&r, 1);
+ loc->v.v0.vertical = uint8_fromregion(&r);
+ isc_region_consume(&r, 1);
+ loc->v.v0.latitude = uint32_fromregion(&r);
+ isc_region_consume(&r, 4);
+ loc->v.v0.longitude = uint32_fromregion(&r);
+ isc_region_consume(&r, 4);
+ loc->v.v0.altitude = uint32_fromregion(&r);
+ isc_region_consume(&r, 4);
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_loc(ARGS_FREESTRUCT) {
+ dns_rdata_loc_t *loc = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(loc->common.rdtype == 29);
+
+ UNUSED(source);
+ UNUSED(loc);
+}
+
+static inline isc_result_t
+additionaldata_loc(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 29);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_loc(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 29);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_loc(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 29);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_loc(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 29);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_LOC_29_C */
diff --git a/lib/dns/rdata/generic/loc_29.h b/lib/dns/rdata/generic/loc_29.h
new file mode 100644
index 0000000..d8eae16
--- /dev/null
+++ b/lib/dns/rdata/generic/loc_29.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_LOC_29_H
+#define GENERIC_LOC_29_H 1
+
+/* $Id: loc_29.h,v 1.15.18.2 2005/04/29 00:16:34 marka Exp $ */
+
+/*!
+ * \brief Per RFC1876 */
+
+typedef struct dns_rdata_loc_0 {
+ isc_uint8_t version; /* must be first and zero */
+ isc_uint8_t size;
+ isc_uint8_t horizontal;
+ isc_uint8_t vertical;
+ isc_uint32_t latitude;
+ isc_uint32_t longitude;
+ isc_uint32_t altitude;
+} dns_rdata_loc_0_t;
+
+typedef struct dns_rdata_loc {
+ dns_rdatacommon_t common;
+ union {
+ dns_rdata_loc_0_t v0;
+ } v;
+} dns_rdata_loc_t;
+
+#endif /* GENERIC_LOC_29_H */
diff --git a/lib/dns/rdata/generic/mb_7.c b/lib/dns/rdata/generic/mb_7.c
new file mode 100644
index 0000000..94c622d
--- /dev/null
+++ b/lib/dns/rdata/generic/mb_7.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: mb_7.c,v 1.43 2004/03/05 05:10:13 marka Exp $ */
+
+/* Reviewed: Wed Mar 15 17:31:26 PST 2000 by bwelling */
+
+#ifndef RDATA_GENERIC_MB_7_C
+#define RDATA_GENERIC_MB_7_C
+
+#define RRTYPE_MB_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_mb(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 7);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_mb(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 7);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ sub = name_prefix(&name, tctx->origin, &prefix);
+
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_mb(ARGS_FROMWIRE) {
+ dns_name_t name;
+
+ REQUIRE(type == 7);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, NULL);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_mb(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 7);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_mb(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 7);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_mb(ARGS_FROMSTRUCT) {
+ dns_rdata_mb_t *mb = source;
+ isc_region_t region;
+
+ REQUIRE(type == 7);
+ REQUIRE(source != NULL);
+ REQUIRE(mb->common.rdtype == type);
+ REQUIRE(mb->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&mb->mb, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_mb(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_mb_t *mb = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 7);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ mb->common.rdclass = rdata->rdclass;
+ mb->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&mb->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&mb->mb, NULL);
+ RETERR(name_duporclone(&name, mctx, &mb->mb));
+ mb->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_mb(ARGS_FREESTRUCT) {
+ dns_rdata_mb_t *mb = source;
+
+ REQUIRE(source != NULL);
+
+ if (mb->mctx == NULL)
+ return;
+
+ dns_name_free(&mb->mb, mb->mctx);
+ mb->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_mb(ARGS_ADDLDATA) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 7);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return ((add)(arg, &name, dns_rdatatype_a));
+}
+
+static inline isc_result_t
+digest_mb(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 7);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_mb(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 7);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (dns_name_ismailbox(name));
+}
+
+static inline isc_boolean_t
+checknames_mb(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 7);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_MB_7_C */
diff --git a/lib/dns/rdata/generic/mb_7.h b/lib/dns/rdata/generic/mb_7.h
new file mode 100644
index 0000000..f6a8b35
--- /dev/null
+++ b/lib/dns/rdata/generic/mb_7.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_MB_7_H
+#define GENERIC_MB_7_H 1
+
+/* $Id: mb_7.h,v 1.23.18.2 2005/04/29 00:16:34 marka Exp $ */
+
+typedef struct dns_rdata_mb {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t mb;
+} dns_rdata_mb_t;
+
+#endif /* GENERIC_MB_7_H */
diff --git a/lib/dns/rdata/generic/md_3.c b/lib/dns/rdata/generic/md_3.c
new file mode 100644
index 0000000..75e4970
--- /dev/null
+++ b/lib/dns/rdata/generic/md_3.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: md_3.c,v 1.45 2004/03/05 05:10:13 marka Exp $ */
+
+/* Reviewed: Wed Mar 15 17:48:20 PST 2000 by bwelling */
+
+#ifndef RDATA_GENERIC_MD_3_C
+#define RDATA_GENERIC_MD_3_C
+
+#define RRTYPE_MD_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_md(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 3);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_md(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 3);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ sub = name_prefix(&name, tctx->origin, &prefix);
+
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_md(ARGS_FROMWIRE) {
+ dns_name_t name;
+
+ REQUIRE(type == 3);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, NULL);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_md(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 3);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_md(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 3);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_md(ARGS_FROMSTRUCT) {
+ dns_rdata_md_t *md = source;
+ isc_region_t region;
+
+ REQUIRE(type == 3);
+ REQUIRE(source != NULL);
+ REQUIRE(md->common.rdtype == type);
+ REQUIRE(md->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&md->md, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_md(ARGS_TOSTRUCT) {
+ dns_rdata_md_t *md = target;
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 3);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ md->common.rdclass = rdata->rdclass;
+ md->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&md->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &r);
+ dns_name_fromregion(&name, &r);
+ dns_name_init(&md->md, NULL);
+ RETERR(name_duporclone(&name, mctx, &md->md));
+ md->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_md(ARGS_FREESTRUCT) {
+ dns_rdata_md_t *md = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(md->common.rdtype == 3);
+
+ if (md->mctx == NULL)
+ return;
+
+ dns_name_free(&md->md, md->mctx);
+ md->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_md(ARGS_ADDLDATA) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 3);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return ((add)(arg, &name, dns_rdatatype_a));
+}
+
+static inline isc_result_t
+digest_md(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 3);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_md(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 3);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_md(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 3);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_MD_3_C */
diff --git a/lib/dns/rdata/generic/md_3.h b/lib/dns/rdata/generic/md_3.h
new file mode 100644
index 0000000..578ce66
--- /dev/null
+++ b/lib/dns/rdata/generic/md_3.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_MD_3_H
+#define GENERIC_MD_3_H 1
+
+/* $Id: md_3.h,v 1.24.18.2 2005/04/29 00:16:35 marka Exp $ */
+
+typedef struct dns_rdata_md {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t md;
+} dns_rdata_md_t;
+
+
+#endif /* GENERIC_MD_3_H */
diff --git a/lib/dns/rdata/generic/mf_4.c b/lib/dns/rdata/generic/mf_4.c
new file mode 100644
index 0000000..362d300
--- /dev/null
+++ b/lib/dns/rdata/generic/mf_4.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: mf_4.c,v 1.43 2004/03/05 05:10:14 marka Exp $ */
+
+/* reviewed: Wed Mar 15 17:47:33 PST 2000 by brister */
+
+#ifndef RDATA_GENERIC_MF_4_C
+#define RDATA_GENERIC_MF_4_C
+
+#define RRTYPE_MF_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_mf(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 4);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_mf(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 4);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ sub = name_prefix(&name, tctx->origin, &prefix);
+
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_mf(ARGS_FROMWIRE) {
+ dns_name_t name;
+
+ REQUIRE(type == 4);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, NULL);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_mf(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 4);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_mf(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 4);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_mf(ARGS_FROMSTRUCT) {
+ dns_rdata_mf_t *mf = source;
+ isc_region_t region;
+
+ REQUIRE(type == 4);
+ REQUIRE(source != NULL);
+ REQUIRE(mf->common.rdtype == type);
+ REQUIRE(mf->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&mf->mf, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_mf(ARGS_TOSTRUCT) {
+ dns_rdata_mf_t *mf = target;
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 4);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ mf->common.rdclass = rdata->rdclass;
+ mf->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&mf->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &r);
+ dns_name_fromregion(&name, &r);
+ dns_name_init(&mf->mf, NULL);
+ RETERR(name_duporclone(&name, mctx, &mf->mf));
+ mf->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_mf(ARGS_FREESTRUCT) {
+ dns_rdata_mf_t *mf = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(mf->common.rdtype == 4);
+
+ if (mf->mctx == NULL)
+ return;
+ dns_name_free(&mf->mf, mf->mctx);
+ mf->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_mf(ARGS_ADDLDATA) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 4);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return ((add)(arg, &name, dns_rdatatype_a));
+}
+
+static inline isc_result_t
+digest_mf(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 4);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_mf(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 4);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_mf(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 4);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_MF_4_C */
diff --git a/lib/dns/rdata/generic/mf_4.h b/lib/dns/rdata/generic/mf_4.h
new file mode 100644
index 0000000..2be0eec
--- /dev/null
+++ b/lib/dns/rdata/generic/mf_4.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_MF_4_H
+#define GENERIC_MF_4_H 1
+
+/* $Id: mf_4.h,v 1.22.18.2 2005/04/29 00:16:35 marka Exp $ */
+
+typedef struct dns_rdata_mf {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t mf;
+} dns_rdata_mf_t;
+
+#endif /* GENERIC_MF_4_H */
diff --git a/lib/dns/rdata/generic/mg_8.c b/lib/dns/rdata/generic/mg_8.c
new file mode 100644
index 0000000..602d820
--- /dev/null
+++ b/lib/dns/rdata/generic/mg_8.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: mg_8.c,v 1.41 2004/03/05 05:10:14 marka Exp $ */
+
+/* reviewed: Wed Mar 15 17:49:21 PST 2000 by brister */
+
+#ifndef RDATA_GENERIC_MG_8_C
+#define RDATA_GENERIC_MG_8_C
+
+#define RRTYPE_MG_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_mg(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 8);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_mg(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 8);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ sub = name_prefix(&name, tctx->origin, &prefix);
+
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_mg(ARGS_FROMWIRE) {
+ dns_name_t name;
+
+ REQUIRE(type == 8);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, NULL);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_mg(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 8);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_mg(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 8);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_mg(ARGS_FROMSTRUCT) {
+ dns_rdata_mg_t *mg = source;
+ isc_region_t region;
+
+ REQUIRE(type == 8);
+ REQUIRE(source != NULL);
+ REQUIRE(mg->common.rdtype == type);
+ REQUIRE(mg->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&mg->mg, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_mg(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_mg_t *mg = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 8);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ mg->common.rdclass = rdata->rdclass;
+ mg->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&mg->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&mg->mg, NULL);
+ RETERR(name_duporclone(&name, mctx, &mg->mg));
+ mg->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_mg(ARGS_FREESTRUCT) {
+ dns_rdata_mg_t *mg = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(mg->common.rdtype == 8);
+
+ if (mg->mctx == NULL)
+ return;
+ dns_name_free(&mg->mg, mg->mctx);
+ mg->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_mg(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 8);
+
+ UNUSED(add);
+ UNUSED(arg);
+ UNUSED(rdata);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_mg(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 8);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_mg(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 8);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (dns_name_ismailbox(name));
+}
+
+static inline isc_boolean_t
+checknames_mg(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 8);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_MG_8_C */
diff --git a/lib/dns/rdata/generic/mg_8.h b/lib/dns/rdata/generic/mg_8.h
new file mode 100644
index 0000000..5679c17
--- /dev/null
+++ b/lib/dns/rdata/generic/mg_8.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_MG_8_H
+#define GENERIC_MG_8_H 1
+
+/* $Id: mg_8.h,v 1.22.18.2 2005/04/29 00:16:35 marka Exp $ */
+
+typedef struct dns_rdata_mg {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t mg;
+} dns_rdata_mg_t;
+
+#endif /* GENERIC_MG_8_H */
diff --git a/lib/dns/rdata/generic/minfo_14.c b/lib/dns/rdata/generic/minfo_14.c
new file mode 100644
index 0000000..b757480
--- /dev/null
+++ b/lib/dns/rdata/generic/minfo_14.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: minfo_14.c,v 1.43 2004/03/05 05:10:14 marka Exp $ */
+
+/* reviewed: Wed Mar 15 17:45:32 PST 2000 by brister */
+
+#ifndef RDATA_GENERIC_MINFO_14_C
+#define RDATA_GENERIC_MINFO_14_C
+
+#define RRTYPE_MINFO_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_minfo(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ int i;
+ isc_boolean_t ok;
+
+ REQUIRE(type == 14);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ for (i = 0; i < 2; i++) {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin,
+ options, target));
+ ok = ISC_TRUE;
+ if ((options & DNS_RDATA_CHECKNAMES) != 0)
+ ok = dns_name_ismailbox(&name);
+ if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0)
+ RETTOK(DNS_R_BADNAME);
+ if (!ok && callbacks != NULL)
+ warn_badname(&name, lexer, callbacks);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_minfo(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t rmail;
+ dns_name_t email;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 14);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&rmail, NULL);
+ dns_name_init(&email, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+
+ dns_name_fromregion(&rmail, &region);
+ isc_region_consume(&region, rmail.length);
+
+ dns_name_fromregion(&email, &region);
+ isc_region_consume(&region, email.length);
+
+ sub = name_prefix(&rmail, tctx->origin, &prefix);
+
+ RETERR(dns_name_totext(&prefix, sub, target));
+
+ RETERR(str_totext(" ", target));
+
+ sub = name_prefix(&email, tctx->origin, &prefix);
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_minfo(ARGS_FROMWIRE) {
+ dns_name_t rmail;
+ dns_name_t email;
+
+ REQUIRE(type == 14);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&rmail, NULL);
+ dns_name_init(&email, NULL);
+
+ RETERR(dns_name_fromwire(&rmail, source, dctx, options, target));
+ return (dns_name_fromwire(&email, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_minfo(ARGS_TOWIRE) {
+ isc_region_t region;
+ dns_name_t rmail;
+ dns_name_t email;
+ dns_offsets_t roffsets;
+ dns_offsets_t eoffsets;
+
+ REQUIRE(rdata->type == 14);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&rmail, roffsets);
+ dns_name_init(&email, eoffsets);
+
+ dns_rdata_toregion(rdata, &region);
+
+ dns_name_fromregion(&rmail, &region);
+ isc_region_consume(&region, name_length(&rmail));
+
+ RETERR(dns_name_towire(&rmail, cctx, target));
+
+ dns_name_fromregion(&rmail, &region);
+ isc_region_consume(&region, rmail.length);
+
+ return (dns_name_towire(&rmail, cctx, target));
+}
+
+static inline int
+compare_minfo(ARGS_COMPARE) {
+ isc_region_t region1;
+ isc_region_t region2;
+ dns_name_t name1;
+ dns_name_t name2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 14);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ order = dns_name_rdatacompare(&name1, &name2);
+ if (order != 0)
+ return (order);
+
+ isc_region_consume(&region1, name_length(&name1));
+ isc_region_consume(&region2, name_length(&name2));
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ order = dns_name_rdatacompare(&name1, &name2);
+ return (order);
+}
+
+static inline isc_result_t
+fromstruct_minfo(ARGS_FROMSTRUCT) {
+ dns_rdata_minfo_t *minfo = source;
+ isc_region_t region;
+
+ REQUIRE(type == 14);
+ REQUIRE(source != NULL);
+ REQUIRE(minfo->common.rdtype == type);
+ REQUIRE(minfo->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&minfo->rmailbox, &region);
+ RETERR(isc_buffer_copyregion(target, &region));
+ dns_name_toregion(&minfo->emailbox, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_minfo(ARGS_TOSTRUCT) {
+ dns_rdata_minfo_t *minfo = target;
+ isc_region_t region;
+ dns_name_t name;
+ isc_result_t result;
+
+ REQUIRE(rdata->type == 14);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ minfo->common.rdclass = rdata->rdclass;
+ minfo->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&minfo->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&minfo->rmailbox, NULL);
+ RETERR(name_duporclone(&name, mctx, &minfo->rmailbox));
+ isc_region_consume(&region, name_length(&name));
+
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&minfo->emailbox, NULL);
+ result = name_duporclone(&name, mctx, &minfo->emailbox);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ minfo->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL)
+ dns_name_free(&minfo->rmailbox, mctx);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_minfo(ARGS_FREESTRUCT) {
+ dns_rdata_minfo_t *minfo = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(minfo->common.rdtype == 14);
+
+ if (minfo->mctx == NULL)
+ return;
+
+ dns_name_free(&minfo->rmailbox, minfo->mctx);
+ dns_name_free(&minfo->emailbox, minfo->mctx);
+ minfo->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_minfo(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 14);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_minfo(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+ isc_result_t result;
+
+ REQUIRE(rdata->type == 14);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+ result = dns_name_digest(&name, digest, arg);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_region_consume(&r, name_length(&name));
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_minfo(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 14);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_minfo(ARGS_CHECKNAMES) {
+ isc_region_t region;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 14);
+
+ UNUSED(owner);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ismailbox(&name)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ isc_region_consume(&region, name_length(&name));
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ismailbox(&name)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_MINFO_14_C */
diff --git a/lib/dns/rdata/generic/minfo_14.h b/lib/dns/rdata/generic/minfo_14.h
new file mode 100644
index 0000000..754fe20
--- /dev/null
+++ b/lib/dns/rdata/generic/minfo_14.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_MINFO_14_H
+#define GENERIC_MINFO_14_H 1
+
+/* $Id: minfo_14.h,v 1.23.18.2 2005/04/29 00:16:35 marka Exp $ */
+
+typedef struct dns_rdata_minfo {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t rmailbox;
+ dns_name_t emailbox;
+} dns_rdata_minfo_t;
+
+#endif /* GENERIC_MINFO_14_H */
diff --git a/lib/dns/rdata/generic/mr_9.c b/lib/dns/rdata/generic/mr_9.c
new file mode 100644
index 0000000..ab4c6e0
--- /dev/null
+++ b/lib/dns/rdata/generic/mr_9.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: mr_9.c,v 1.40 2004/03/05 05:10:15 marka Exp $ */
+
+/* Reviewed: Wed Mar 15 21:30:35 EST 2000 by tale */
+
+#ifndef RDATA_GENERIC_MR_9_C
+#define RDATA_GENERIC_MR_9_C
+
+#define RRTYPE_MR_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_mr(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 9);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_mr(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 9);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ sub = name_prefix(&name, tctx->origin, &prefix);
+
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_mr(ARGS_FROMWIRE) {
+ dns_name_t name;
+
+ REQUIRE(type == 9);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, NULL);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_mr(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 9);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_mr(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 9);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_mr(ARGS_FROMSTRUCT) {
+ dns_rdata_mr_t *mr = source;
+ isc_region_t region;
+
+ REQUIRE(type == 9);
+ REQUIRE(source != NULL);
+ REQUIRE(mr->common.rdtype == type);
+ REQUIRE(mr->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&mr->mr, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_mr(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_mr_t *mr = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 9);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ mr->common.rdclass = rdata->rdclass;
+ mr->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&mr->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&mr->mr, NULL);
+ RETERR(name_duporclone(&name, mctx, &mr->mr));
+ mr->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_mr(ARGS_FREESTRUCT) {
+ dns_rdata_mr_t *mr = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(mr->common.rdtype == 9);
+
+ if (mr->mctx == NULL)
+ return;
+ dns_name_free(&mr->mr, mr->mctx);
+ mr->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_mr(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 9);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_mr(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 9);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_mr(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 9);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_mr(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 9);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_MR_9_C */
diff --git a/lib/dns/rdata/generic/mr_9.h b/lib/dns/rdata/generic/mr_9.h
new file mode 100644
index 0000000..e255d70
--- /dev/null
+++ b/lib/dns/rdata/generic/mr_9.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_MR_9_H
+#define GENERIC_MR_9_H 1
+
+/* $Id: mr_9.h,v 1.22.18.2 2005/04/29 00:16:36 marka Exp $ */
+
+typedef struct dns_rdata_mr {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t mr;
+} dns_rdata_mr_t;
+
+#endif /* GENERIC_MR_9_H */
diff --git a/lib/dns/rdata/generic/mx_15.c b/lib/dns/rdata/generic/mx_15.c
new file mode 100644
index 0000000..fd77ec8
--- /dev/null
+++ b/lib/dns/rdata/generic/mx_15.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2004, 2005 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: mx_15.c,v 1.52.18.2 2005/05/20 01:10:11 marka Exp $ */
+
+/* reviewed: Wed Mar 15 18:05:46 PST 2000 by brister */
+
+#ifndef RDATA_GENERIC_MX_15_C
+#define RDATA_GENERIC_MX_15_C
+
+#include <string.h>
+
+#include <isc/net.h>
+
+#define RRTYPE_MX_ATTRIBUTES (0)
+
+static isc_boolean_t
+check_mx(isc_token_t *token) {
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
+ struct in_addr addr;
+ struct in6_addr addr6;
+
+ if (strlcpy(tmp, DNS_AS_STR(*token), sizeof(tmp)) >= sizeof(tmp))
+ return (ISC_TRUE);
+
+ if (tmp[strlen(tmp) - 1] == '.')
+ tmp[strlen(tmp) - 1] = '\0';
+ if (inet_aton(tmp, &addr) == 1 ||
+ inet_pton(AF_INET6, tmp, &addr6) == 1)
+ return (ISC_FALSE);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_result_t
+fromtext_mx(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ isc_boolean_t ok;
+
+ REQUIRE(type == 15);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ ok = ISC_TRUE;
+ if ((options & DNS_RDATA_CHECKMX) != 0)
+ ok = check_mx(&token);
+ if (!ok && (options & DNS_RDATA_CHECKMXFAIL) != 0)
+ RETTOK(DNS_R_MXISADDRESS);
+ if (!ok && callbacks != NULL)
+ warn_badmx(&token, lexer, callbacks);
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ ok = ISC_TRUE;
+ if ((options & DNS_RDATA_CHECKNAMES) != 0)
+ ok = dns_name_ishostname(&name, ISC_FALSE);
+ if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0)
+ RETTOK(DNS_R_BADNAME);
+ if (!ok && callbacks != NULL)
+ warn_badname(&name, lexer, callbacks);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_mx(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+ char buf[sizeof("64000")];
+ unsigned short num;
+
+ REQUIRE(rdata->type == 15);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ num = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ sprintf(buf, "%u", num);
+ RETERR(str_totext(buf, target));
+
+ RETERR(str_totext(" ", target));
+
+ dns_name_fromregion(&name, &region);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_mx(ARGS_FROMWIRE) {
+ dns_name_t name;
+ isc_region_t sregion;
+
+ REQUIRE(type == 15);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, NULL);
+
+ isc_buffer_activeregion(source, &sregion);
+ if (sregion.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ RETERR(mem_tobuffer(target, sregion.base, 2));
+ isc_buffer_forward(source, 2);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_mx(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 15);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_rdata_toregion(rdata, &region);
+ RETERR(mem_tobuffer(target, region.base, 2));
+ isc_region_consume(&region, 2);
+
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_mx(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 15);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ order = memcmp(rdata1->data, rdata2->data, 2);
+ if (order != 0)
+ return (order < 0 ? -1 : 1);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ isc_region_consume(&region1, 2);
+ isc_region_consume(&region2, 2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_mx(ARGS_FROMSTRUCT) {
+ dns_rdata_mx_t *mx = source;
+ isc_region_t region;
+
+ REQUIRE(type == 15);
+ REQUIRE(source != NULL);
+ REQUIRE(mx->common.rdtype == type);
+ REQUIRE(mx->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint16_tobuffer(mx->pref, target));
+ dns_name_toregion(&mx->mx, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_mx(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_mx_t *mx = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 15);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ mx->common.rdclass = rdata->rdclass;
+ mx->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&mx->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ mx->pref = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&mx->mx, NULL);
+ RETERR(name_duporclone(&name, mctx, &mx->mx));
+ mx->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_mx(ARGS_FREESTRUCT) {
+ dns_rdata_mx_t *mx = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(mx->common.rdtype == 15);
+
+ if (mx->mctx == NULL)
+ return;
+
+ dns_name_free(&mx->mx, mx->mctx);
+ mx->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_mx(ARGS_ADDLDATA) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 15);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ isc_region_consume(&region, 2);
+ dns_name_fromregion(&name, &region);
+
+ return ((add)(arg, &name, dns_rdatatype_a));
+}
+
+static inline isc_result_t
+digest_mx(ARGS_DIGEST) {
+ isc_region_t r1, r2;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 15);
+
+ dns_rdata_toregion(rdata, &r1);
+ r2 = r1;
+ isc_region_consume(&r2, 2);
+ r1.length = 2;
+ RETERR((digest)(arg, &r1));
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r2);
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_mx(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 15);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ return (dns_name_ishostname(name, wildcard));
+}
+
+static inline isc_boolean_t
+checknames_mx(ARGS_CHECKNAMES) {
+ isc_region_t region;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 15);
+
+ UNUSED(owner);
+
+ dns_rdata_toregion(rdata, &region);
+ isc_region_consume(&region, 2);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ishostname(&name, ISC_FALSE)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_MX_15_C */
diff --git a/lib/dns/rdata/generic/mx_15.h b/lib/dns/rdata/generic/mx_15.h
new file mode 100644
index 0000000..4d81b90
--- /dev/null
+++ b/lib/dns/rdata/generic/mx_15.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_MX_15_H
+#define GENERIC_MX_15_H 1
+
+/* $Id: mx_15.h,v 1.25.18.2 2005/04/29 00:16:36 marka Exp $ */
+
+typedef struct dns_rdata_mx {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t pref;
+ dns_name_t mx;
+} dns_rdata_mx_t;
+
+#endif /* GENERIC_MX_15_H */
diff --git a/lib/dns/rdata/generic/ns_2.c b/lib/dns/rdata/generic/ns_2.c
new file mode 100644
index 0000000..2379433
--- /dev/null
+++ b/lib/dns/rdata/generic/ns_2.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: ns_2.c,v 1.44 2004/03/05 05:10:15 marka Exp $ */
+
+/* Reviewed: Wed Mar 15 18:15:00 PST 2000 by bwelling */
+
+#ifndef RDATA_GENERIC_NS_2_C
+#define RDATA_GENERIC_NS_2_C
+
+#define RRTYPE_NS_ATTRIBUTES (DNS_RDATATYPEATTR_ZONECUTAUTH)
+
+static inline isc_result_t
+fromtext_ns(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ isc_boolean_t ok;
+
+ REQUIRE(type == 2);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token,isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ ok = ISC_TRUE;
+ if ((options & DNS_RDATA_CHECKNAMES) != 0)
+ ok = dns_name_ishostname(&name, ISC_FALSE);
+ if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0)
+ RETTOK(DNS_R_BADNAME);
+ if (!ok && callbacks != NULL)
+ warn_badname(&name, lexer, callbacks);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_ns(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 2);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ sub = name_prefix(&name, tctx->origin, &prefix);
+
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_ns(ARGS_FROMWIRE) {
+ dns_name_t name;
+
+ REQUIRE(type == 2);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, NULL);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_ns(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 2);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_ns(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 2);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_ns(ARGS_FROMSTRUCT) {
+ dns_rdata_ns_t *ns = source;
+ isc_region_t region;
+
+ REQUIRE(type == 2);
+ REQUIRE(source != NULL);
+ REQUIRE(ns->common.rdtype == type);
+ REQUIRE(ns->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&ns->name, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_ns(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_ns_t *ns = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 2);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ ns->common.rdclass = rdata->rdclass;
+ ns->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&ns->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&ns->name, NULL);
+ RETERR(name_duporclone(&name, mctx, &ns->name));
+ ns->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_ns(ARGS_FREESTRUCT) {
+ dns_rdata_ns_t *ns = source;
+
+ REQUIRE(source != NULL);
+
+ if (ns->mctx == NULL)
+ return;
+
+ dns_name_free(&ns->name, ns->mctx);
+ ns->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_ns(ARGS_ADDLDATA) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 2);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return ((add)(arg, &name, dns_rdatatype_a));
+}
+
+static inline isc_result_t
+digest_ns(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 2);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_ns(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 2);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_ns(ARGS_CHECKNAMES) {
+ isc_region_t region;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 2);
+
+ UNUSED(owner);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ishostname(&name, ISC_FALSE)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_NS_2_C */
diff --git a/lib/dns/rdata/generic/ns_2.h b/lib/dns/rdata/generic/ns_2.h
new file mode 100644
index 0000000..ec8e771
--- /dev/null
+++ b/lib/dns/rdata/generic/ns_2.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_NS_2_H
+#define GENERIC_NS_2_H 1
+
+/* $Id: ns_2.h,v 1.23.18.2 2005/04/29 00:16:37 marka Exp $ */
+
+typedef struct dns_rdata_ns {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t name;
+} dns_rdata_ns_t;
+
+
+#endif /* GENERIC_NS_2_H */
diff --git a/lib/dns/rdata/generic/nsec_47.c b/lib/dns/rdata/generic/nsec_47.c
new file mode 100644
index 0000000..f3e56ca
--- /dev/null
+++ b/lib/dns/rdata/generic/nsec_47.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: nsec_47.c,v 1.7 2004/03/05 05:10:15 marka Exp $ */
+
+/* reviewed: Wed Mar 15 18:21:15 PST 2000 by brister */
+
+/* draft-ietf-dnsext-nsec-rdata-01.txt */
+
+#ifndef RDATA_GENERIC_NSEC_47_C
+#define RDATA_GENERIC_NSEC_47_C
+
+/*
+ * The attributes do not include DNS_RDATATYPEATTR_SINGLETON
+ * because we must be able to handle a parent/child NSEC pair.
+ */
+#define RRTYPE_NSEC_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC)
+
+static inline isc_result_t
+fromtext_nsec(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ unsigned char bm[8*1024]; /* 64k bits */
+ dns_rdatatype_t covered;
+ int octet;
+ int window;
+
+ REQUIRE(type == 47);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Next domain.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+
+ memset(bm, 0, sizeof(bm));
+ do {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string, ISC_TRUE));
+ if (token.type != isc_tokentype_string)
+ break;
+ RETTOK(dns_rdatatype_fromtext(&covered,
+ &token.value.as_textregion));
+ bm[covered/8] |= (0x80>>(covered%8));
+ } while (1);
+ isc_lex_ungettoken(lexer, &token);
+ for (window = 0; window < 256 ; window++) {
+ /*
+ * Find if we have a type in this window.
+ */
+ for (octet = 31; octet >= 0; octet--)
+ if (bm[window * 32 + octet] != 0)
+ break;
+ if (octet < 0)
+ continue;
+ RETERR(uint8_tobuffer(window, target));
+ RETERR(uint8_tobuffer(octet + 1, target));
+ RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1));
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_nsec(ARGS_TOTEXT) {
+ isc_region_t sr;
+ unsigned int i, j, k;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+ unsigned int window, len;
+
+ REQUIRE(rdata->type == 47);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+ dns_rdata_toregion(rdata, &sr);
+ dns_name_fromregion(&name, &sr);
+ isc_region_consume(&sr, name_length(&name));
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ RETERR(dns_name_totext(&prefix, sub, target));
+
+
+ for (i = 0; i < sr.length; i += len) {
+ INSIST(i + 2 <= sr.length);
+ window = sr.base[i];
+ len = sr.base[i + 1];
+ INSIST(len > 0 && len <= 32);
+ i += 2;
+ INSIST(i + len <= sr.length);
+ for (j = 0; j < len; j++) {
+ dns_rdatatype_t t;
+ if (sr.base[i + j] == 0)
+ continue;
+ for (k = 0; k < 8; k++) {
+ if ((sr.base[i + j] & (0x80 >> k)) == 0)
+ continue;
+ t = window * 256 + j * 8 + k;
+ RETERR(str_totext(" ", target));
+ if (dns_rdatatype_isknown(t)) {
+ RETERR(dns_rdatatype_totext(t, target));
+ } else {
+ char buf[sizeof("TYPE65535")];
+ sprintf(buf, "TYPE%u", t);
+ RETERR(str_totext(buf, target));
+ }
+ }
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static /* inline */ isc_result_t
+fromwire_nsec(ARGS_FROMWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+ unsigned int window, lastwindow = 0;
+ unsigned int len;
+ isc_boolean_t first = ISC_TRUE;
+ unsigned int i;
+
+ REQUIRE(type == 47);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&name, NULL);
+ RETERR(dns_name_fromwire(&name, source, dctx, options, target));
+
+ isc_buffer_activeregion(source, &sr);
+ for (i = 0; i < sr.length; i += len) {
+ /*
+ * Check for overflow.
+ */
+ if (i + 2 > sr.length)
+ RETERR(DNS_R_FORMERR);
+ window = sr.base[i];
+ len = sr.base[i + 1];
+ i += 2;
+ /*
+ * Check that bitmap windows are in the correct order.
+ */
+ if (!first && window <= lastwindow)
+ RETERR(DNS_R_FORMERR);
+ /*
+ * Check for legal lengths.
+ */
+ if (len < 1 || len > 32)
+ RETERR(DNS_R_FORMERR);
+ /*
+ * Check for overflow.
+ */
+ if (i + len > sr.length)
+ RETERR(DNS_R_FORMERR);
+ /*
+ * The last octet of the bitmap must be non zero.
+ */
+ if (sr.base[i + len - 1] == 0)
+ RETERR(DNS_R_FORMERR);
+ lastwindow = window;
+ first = ISC_FALSE;
+ }
+ if (i != sr.length)
+ return (DNS_R_EXTRADATA);
+ if (first)
+ RETERR(DNS_R_FORMERR);
+ RETERR(mem_tobuffer(target, sr.base, sr.length));
+ isc_buffer_forward(source, sr.length);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_nsec(ARGS_TOWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+ dns_offsets_t offsets;
+
+ REQUIRE(rdata->type == 47);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &sr);
+ dns_name_fromregion(&name, &sr);
+ isc_region_consume(&sr, name_length(&name));
+ RETERR(dns_name_towire(&name, cctx, target));
+
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_nsec(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 47);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_nsec(ARGS_FROMSTRUCT) {
+ dns_rdata_nsec_t *nsec = source;
+ isc_region_t region;
+ unsigned int i, len, window, lastwindow = 0;
+ isc_boolean_t first = ISC_TRUE;
+
+ REQUIRE(type == 47);
+ REQUIRE(source != NULL);
+ REQUIRE(nsec->common.rdtype == type);
+ REQUIRE(nsec->common.rdclass == rdclass);
+ REQUIRE(nsec->typebits != NULL || nsec->len == 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&nsec->next, &region);
+ RETERR(isc_buffer_copyregion(target, &region));
+ /*
+ * Perform sanity check.
+ */
+ for (i = 0; i < nsec->len ; i += len) {
+ INSIST(i + 2 <= nsec->len);
+ window = nsec->typebits[i];
+ len = nsec->typebits[i+1];
+ i += 2;
+ INSIST(first || window > lastwindow);
+ INSIST(len > 0 && len <= 32);
+ INSIST(i + len <= nsec->len);
+ INSIST(nsec->typebits[i + len - 1] != 0);
+ lastwindow = window;
+ first = ISC_FALSE;
+ }
+ INSIST(!first);
+ return (mem_tobuffer(target, nsec->typebits, nsec->len));
+}
+
+static inline isc_result_t
+tostruct_nsec(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_nsec_t *nsec = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 47);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ nsec->common.rdclass = rdata->rdclass;
+ nsec->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&nsec->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ isc_region_consume(&region, name_length(&name));
+ dns_name_init(&nsec->next, NULL);
+ RETERR(name_duporclone(&name, mctx, &nsec->next));
+
+ nsec->len = region.length;
+ nsec->typebits = mem_maybedup(mctx, region.base, region.length);
+ if (nsec->typebits == NULL)
+ goto cleanup;
+
+ nsec->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL)
+ dns_name_free(&nsec->next, mctx);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_nsec(ARGS_FREESTRUCT) {
+ dns_rdata_nsec_t *nsec = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(nsec->common.rdtype == 47);
+
+ if (nsec->mctx == NULL)
+ return;
+
+ dns_name_free(&nsec->next, nsec->mctx);
+ if (nsec->typebits != NULL)
+ isc_mem_free(nsec->mctx, nsec->typebits);
+ nsec->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_nsec(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 47);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_nsec(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 47);
+
+ dns_rdata_toregion(rdata, &r);
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_nsec(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 47);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_nsec(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 47);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_NSEC_47_C */
diff --git a/lib/dns/rdata/generic/nsec_47.h b/lib/dns/rdata/generic/nsec_47.h
new file mode 100644
index 0000000..ff03483
--- /dev/null
+++ b/lib/dns/rdata/generic/nsec_47.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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.
+ */
+
+#ifndef GENERIC_NSEC_47_H
+#define GENERIC_NSEC_47_H 1
+
+/* $Id: nsec_47.h,v 1.4.20.2 2005/04/29 00:16:37 marka Exp $ */
+
+/*!
+ * \brief Per draft-ietf-dnsext-nsec-rdata-01.txt */
+
+typedef struct dns_rdata_nsec {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t next;
+ unsigned char *typebits;
+ isc_uint16_t len;
+} dns_rdata_nsec_t;
+
+#endif /* GENERIC_NSEC_47_H */
diff --git a/lib/dns/rdata/generic/null_10.c b/lib/dns/rdata/generic/null_10.c
new file mode 100644
index 0000000..a6f8f9f4
--- /dev/null
+++ b/lib/dns/rdata/generic/null_10.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: null_10.c,v 1.40 2004/03/05 05:10:16 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 13:57:50 PST 2000 by explorer */
+
+#ifndef RDATA_GENERIC_NULL_10_C
+#define RDATA_GENERIC_NULL_10_C
+
+#define RRTYPE_NULL_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_null(ARGS_FROMTEXT) {
+ REQUIRE(type == 10);
+
+ UNUSED(rdclass);
+ UNUSED(type);
+ UNUSED(lexer);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(target);
+ UNUSED(callbacks);
+
+ return (DNS_R_SYNTAX);
+}
+
+static inline isc_result_t
+totext_null(ARGS_TOTEXT) {
+ REQUIRE(rdata->type == 10);
+
+ UNUSED(rdata);
+ UNUSED(tctx);
+ UNUSED(target);
+
+ return (DNS_R_SYNTAX);
+}
+
+static inline isc_result_t
+fromwire_null(ARGS_FROMWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(type == 10);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(dctx);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sr);
+ isc_buffer_forward(source, sr.length);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline isc_result_t
+towire_null(ARGS_TOWIRE) {
+ REQUIRE(rdata->type == 10);
+
+ UNUSED(cctx);
+
+ return (mem_tobuffer(target, rdata->data, rdata->length));
+}
+
+static inline int
+compare_null(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 10);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_null(ARGS_FROMSTRUCT) {
+ dns_rdata_null_t *null = source;
+
+ REQUIRE(type == 10);
+ REQUIRE(source != NULL);
+ REQUIRE(null->common.rdtype == type);
+ REQUIRE(null->common.rdclass == rdclass);
+ REQUIRE(null->data != NULL || null->length == 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ return (mem_tobuffer(target, null->data, null->length));
+}
+
+static inline isc_result_t
+tostruct_null(ARGS_TOSTRUCT) {
+ dns_rdata_null_t *null = target;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 10);
+ REQUIRE(target != NULL);
+
+ null->common.rdclass = rdata->rdclass;
+ null->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&null->common, link);
+
+ dns_rdata_toregion(rdata, &r);
+ null->length = r.length;
+ null->data = mem_maybedup(mctx, r.base, r.length);
+ if (null->data == NULL)
+ return (ISC_R_NOMEMORY);
+
+ null->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_null(ARGS_FREESTRUCT) {
+ dns_rdata_null_t *null = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(null->common.rdtype == 10);
+
+ if (null->mctx == NULL)
+ return;
+
+ if (null->data != NULL)
+ isc_mem_free(null->mctx, null->data);
+ null->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_null(ARGS_ADDLDATA) {
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ REQUIRE(rdata->type == 10);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_null(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 10);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_null(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 10);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_null(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 10);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_NULL_10_C */
diff --git a/lib/dns/rdata/generic/null_10.h b/lib/dns/rdata/generic/null_10.h
new file mode 100644
index 0000000..5afb1ae
--- /dev/null
+++ b/lib/dns/rdata/generic/null_10.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_NULL_10_H
+#define GENERIC_NULL_10_H 1
+
+/* $Id: null_10.h,v 1.21.18.2 2005/04/29 00:16:37 marka Exp $ */
+
+typedef struct dns_rdata_null {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t length;
+ unsigned char *data;
+} dns_rdata_null_t;
+
+
+#endif /* GENERIC_NULL_10_H */
diff --git a/lib/dns/rdata/generic/nxt_30.c b/lib/dns/rdata/generic/nxt_30.c
new file mode 100644
index 0000000..b7358e0
--- /dev/null
+++ b/lib/dns/rdata/generic/nxt_30.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2004, 2005 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: nxt_30.c,v 1.59.18.2 2005/04/29 00:16:38 marka Exp $ */
+
+/* reviewed: Wed Mar 15 18:21:15 PST 2000 by brister */
+
+/* RFC2535 */
+
+#ifndef RDATA_GENERIC_NXT_30_C
+#define RDATA_GENERIC_NXT_30_C
+
+/*
+ * The attributes do not include DNS_RDATATYPEATTR_SINGLETON
+ * because we must be able to handle a parent/child NXT pair.
+ */
+#define RRTYPE_NXT_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_nxt(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ char *e;
+ unsigned char bm[8*1024]; /* 64k bits */
+ dns_rdatatype_t covered;
+ dns_rdatatype_t maxcovered = 0;
+ isc_boolean_t first = ISC_TRUE;
+ long n;
+
+ REQUIRE(type == 30);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Next domain.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+
+ memset(bm, 0, sizeof(bm));
+ do {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string, ISC_TRUE));
+ if (token.type != isc_tokentype_string)
+ break;
+ n = strtol(DNS_AS_STR(token), &e, 10);
+ if (e != DNS_AS_STR(token) && *e == '\0') {
+ covered = (dns_rdatatype_t)n;
+ } else if (dns_rdatatype_fromtext(&covered,
+ &token.value.as_textregion) == DNS_R_UNKNOWN)
+ RETTOK(DNS_R_UNKNOWN);
+ /*
+ * NXT is only specified for types 1..127.
+ */
+ if (covered < 1 || covered > 127)
+ return (ISC_R_RANGE);
+ if (first || covered > maxcovered)
+ maxcovered = covered;
+ first = ISC_FALSE;
+ bm[covered/8] |= (0x80>>(covered%8));
+ } while (1);
+ isc_lex_ungettoken(lexer, &token);
+ if (first)
+ return (ISC_R_SUCCESS);
+ n = (maxcovered + 8) / 8;
+ return (mem_tobuffer(target, bm, n));
+}
+
+static inline isc_result_t
+totext_nxt(ARGS_TOTEXT) {
+ isc_region_t sr;
+ unsigned int i, j;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 30);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+ dns_rdata_toregion(rdata, &sr);
+ dns_name_fromregion(&name, &sr);
+ isc_region_consume(&sr, name_length(&name));
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ RETERR(dns_name_totext(&prefix, sub, target));
+
+ for (i = 0; i < sr.length; i++) {
+ if (sr.base[i] != 0)
+ for (j = 0; j < 8; j++)
+ if ((sr.base[i] & (0x80 >> j)) != 0) {
+ dns_rdatatype_t t = i * 8 + j;
+ RETERR(str_totext(" ", target));
+ if (dns_rdatatype_isknown(t)) {
+ RETERR(dns_rdatatype_totext(t,
+ target));
+ } else {
+ char buf[sizeof("65535")];
+ sprintf(buf, "%u", t);
+ RETERR(str_totext(buf,
+ target));
+ }
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_nxt(ARGS_FROMWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+
+ REQUIRE(type == 30);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&name, NULL);
+ RETERR(dns_name_fromwire(&name, source, dctx, options, target));
+
+ isc_buffer_activeregion(source, &sr);
+ if (sr.length > 0 && (sr.base[0] & 0x80) == 0 &&
+ ((sr.length > 16) || sr.base[sr.length - 1] == 0))
+ return (DNS_R_BADBITMAP);
+ RETERR(mem_tobuffer(target, sr.base, sr.length));
+ isc_buffer_forward(source, sr.length);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_nxt(ARGS_TOWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+ dns_offsets_t offsets;
+
+ REQUIRE(rdata->type == 30);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &sr);
+ dns_name_fromregion(&name, &sr);
+ isc_region_consume(&sr, name_length(&name));
+ RETERR(dns_name_towire(&name, cctx, target));
+
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_nxt(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+ dns_name_t name1;
+ dns_name_t name2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 30);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ dns_name_fromregion(&name1, &r1);
+ dns_name_fromregion(&name2, &r2);
+ order = dns_name_rdatacompare(&name1, &name2);
+ if (order != 0)
+ return (order);
+
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_nxt(ARGS_FROMSTRUCT) {
+ dns_rdata_nxt_t *nxt = source;
+ isc_region_t region;
+
+ REQUIRE(type == 30);
+ REQUIRE(source != NULL);
+ REQUIRE(nxt->common.rdtype == type);
+ REQUIRE(nxt->common.rdclass == rdclass);
+ REQUIRE(nxt->typebits != NULL || nxt->len == 0);
+ if (nxt->typebits != NULL && (nxt->typebits[0] & 0x80) == 0) {
+ REQUIRE(nxt->len <= 16);
+ REQUIRE(nxt->typebits[nxt->len - 1] != 0);
+ }
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&nxt->next, &region);
+ RETERR(isc_buffer_copyregion(target, &region));
+
+ return (mem_tobuffer(target, nxt->typebits, nxt->len));
+}
+
+static inline isc_result_t
+tostruct_nxt(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_nxt_t *nxt = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 30);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ nxt->common.rdclass = rdata->rdclass;
+ nxt->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&nxt->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ isc_region_consume(&region, name_length(&name));
+ dns_name_init(&nxt->next, NULL);
+ RETERR(name_duporclone(&name, mctx, &nxt->next));
+
+ nxt->len = region.length;
+ nxt->typebits = mem_maybedup(mctx, region.base, region.length);
+ if (nxt->typebits == NULL)
+ goto cleanup;
+
+ nxt->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL)
+ dns_name_free(&nxt->next, mctx);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_nxt(ARGS_FREESTRUCT) {
+ dns_rdata_nxt_t *nxt = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(nxt->common.rdtype == 30);
+
+ if (nxt->mctx == NULL)
+ return;
+
+ dns_name_free(&nxt->next, nxt->mctx);
+ if (nxt->typebits != NULL)
+ isc_mem_free(nxt->mctx, nxt->typebits);
+ nxt->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_nxt(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 30);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_nxt(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+ isc_result_t result;
+
+ REQUIRE(rdata->type == 30);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+ result = dns_name_digest(&name, digest, arg);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_region_consume(&r, name_length(&name));
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_nxt(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 30);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_nxt(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 30);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_NXT_30_C */
diff --git a/lib/dns/rdata/generic/nxt_30.h b/lib/dns/rdata/generic/nxt_30.h
new file mode 100644
index 0000000..3700fb1
--- /dev/null
+++ b/lib/dns/rdata/generic/nxt_30.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_NXT_30_H
+#define GENERIC_NXT_30_H 1
+
+/* $Id: nxt_30.h,v 1.21.18.2 2005/04/29 00:16:38 marka Exp $ */
+
+/*!
+ * \brief RFC2535 */
+
+typedef struct dns_rdata_nxt {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t next;
+ unsigned char *typebits;
+ isc_uint16_t len;
+} dns_rdata_nxt_t;
+
+#endif /* GENERIC_NXT_30_H */
diff --git a/lib/dns/rdata/generic/opt_41.c b/lib/dns/rdata/generic/opt_41.c
new file mode 100644
index 0000000..e8f4816
--- /dev/null
+++ b/lib/dns/rdata/generic/opt_41.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: opt_41.c,v 1.29.18.2 2005/04/29 00:16:38 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 14:06:44 PST 2000 by gson */
+
+/* RFC2671 */
+
+#ifndef RDATA_GENERIC_OPT_41_C
+#define RDATA_GENERIC_OPT_41_C
+
+#define RRTYPE_OPT_ATTRIBUTES (DNS_RDATATYPEATTR_SINGLETON | \
+ DNS_RDATATYPEATTR_META | \
+ DNS_RDATATYPEATTR_NOTQUESTION)
+
+static inline isc_result_t
+fromtext_opt(ARGS_FROMTEXT) {
+ /*
+ * OPT records do not have a text format.
+ */
+
+ REQUIRE(type == 41);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(lexer);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(target);
+ UNUSED(callbacks);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline isc_result_t
+totext_opt(ARGS_TOTEXT) {
+ isc_region_t r;
+ isc_region_t or;
+ isc_uint16_t option;
+ isc_uint16_t length;
+ char buf[sizeof("64000 64000")];
+
+ /*
+ * OPT records do not have a text format.
+ */
+
+ REQUIRE(rdata->type == 41);
+
+ dns_rdata_toregion(rdata, &r);
+ while (r.length > 0) {
+ option = uint16_fromregion(&r);
+ isc_region_consume(&r, 2);
+ length = uint16_fromregion(&r);
+ isc_region_consume(&r, 2);
+ sprintf(buf, "%u %u", option, length);
+ RETERR(str_totext(buf, target));
+ INSIST(r.length >= length);
+ if (length > 0) {
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+ or = r;
+ or.length = length;
+ RETERR(isc_base64_totext(&or, tctx->width - 2,
+ tctx->linebreak, target));
+ isc_region_consume(&r, length);
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" )", target));
+ }
+ if (r.length > 0)
+ RETERR(str_totext(" ", target));
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_opt(ARGS_FROMWIRE) {
+ isc_region_t sregion;
+ isc_region_t tregion;
+ isc_uint16_t length;
+ unsigned int total;
+
+ REQUIRE(type == 41);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(dctx);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sregion);
+ total = 0;
+ while (sregion.length != 0) {
+ if (sregion.length < 4)
+ return (ISC_R_UNEXPECTEDEND);
+ /*
+ * Eat the 16bit option code. There is nothing to
+ * be done with it currently.
+ */
+ isc_region_consume(&sregion, 2);
+ length = uint16_fromregion(&sregion);
+ isc_region_consume(&sregion, 2);
+ total += 4;
+ if (sregion.length < length)
+ return (ISC_R_UNEXPECTEDEND);
+ isc_region_consume(&sregion, length);
+ total += length;
+ }
+
+ isc_buffer_activeregion(source, &sregion);
+ isc_buffer_availableregion(target, &tregion);
+ if (tregion.length < total)
+ return (ISC_R_NOSPACE);
+ memcpy(tregion.base, sregion.base, total);
+ isc_buffer_forward(source, total);
+ isc_buffer_add(target, total);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_opt(ARGS_TOWIRE) {
+
+ REQUIRE(rdata->type == 41);
+
+ UNUSED(cctx);
+
+ return (mem_tobuffer(target, rdata->data, rdata->length));
+}
+
+static inline int
+compare_opt(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 41);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_opt(ARGS_FROMSTRUCT) {
+ dns_rdata_opt_t *opt = source;
+ isc_region_t region;
+ isc_uint16_t length;
+
+ REQUIRE(type == 41);
+ REQUIRE(source != NULL);
+ REQUIRE(opt->common.rdtype == type);
+ REQUIRE(opt->common.rdclass == rdclass);
+ REQUIRE(opt->options != NULL || opt->length == 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ region.base = opt->options;
+ region.length = opt->length;
+ while (region.length >= 4) {
+ isc_region_consume(&region, 2); /* opt */
+ length = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ if (region.length < length)
+ return (ISC_R_UNEXPECTEDEND);
+ isc_region_consume(&region, length);
+ }
+ if (region.length != 0)
+ return (ISC_R_UNEXPECTEDEND);
+
+ return (mem_tobuffer(target, opt->options, opt->length));
+}
+
+static inline isc_result_t
+tostruct_opt(ARGS_TOSTRUCT) {
+ dns_rdata_opt_t *opt = target;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 41);
+ REQUIRE(target != NULL);
+
+ opt->common.rdclass = rdata->rdclass;
+ opt->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&opt->common, link);
+
+ dns_rdata_toregion(rdata, &r);
+ opt->length = r.length;
+ opt->options = mem_maybedup(mctx, r.base, r.length);
+ if (opt->options == NULL)
+ return (ISC_R_NOMEMORY);
+
+ opt->offset = 0;
+ opt->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_opt(ARGS_FREESTRUCT) {
+ dns_rdata_opt_t *opt = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(opt->common.rdtype == 41);
+
+ if (opt->mctx == NULL)
+ return;
+
+ if (opt->options != NULL)
+ isc_mem_free(opt->mctx, opt->options);
+ opt->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_opt(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 41);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_opt(ARGS_DIGEST) {
+
+ /*
+ * OPT records are not digested.
+ */
+
+ REQUIRE(rdata->type == 41);
+
+ UNUSED(rdata);
+ UNUSED(digest);
+ UNUSED(arg);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline isc_boolean_t
+checkowner_opt(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 41);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (dns_name_equal(name, dns_rootname));
+}
+
+static inline isc_boolean_t
+checknames_opt(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 41);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_OPT_41_C */
diff --git a/lib/dns/rdata/generic/opt_41.h b/lib/dns/rdata/generic/opt_41.h
new file mode 100644
index 0000000..827936e
--- /dev/null
+++ b/lib/dns/rdata/generic/opt_41.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_OPT_41_H
+#define GENERIC_OPT_41_H 1
+
+/* $Id: opt_41.h,v 1.14.18.2 2005/04/29 00:16:38 marka Exp $ */
+
+/*!
+ * \brief Per RFC2671 */
+
+typedef struct dns_rdata_opt_opcode {
+ isc_uint16_t opcode;
+ isc_uint16_t length;
+ unsigned char *data;
+} dns_rdata_opt_opcode_t;
+
+typedef struct dns_rdata_opt {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ unsigned char *options;
+ isc_uint16_t length;
+ /* private */
+ isc_uint16_t offset;
+} dns_rdata_opt_t;
+
+/*
+ * ISC_LANG_BEGINDECLS and ISC_LANG_ENDDECLS are already done
+ * via rdatastructpre.h and rdatastructsuf.h.
+ */
+
+isc_result_t
+dns_rdata_opt_first(dns_rdata_opt_t *);
+
+isc_result_t
+dns_rdata_opt_next(dns_rdata_opt_t *);
+
+isc_result_t
+dns_rdata_opt_current(dns_rdata_opt_t *, dns_rdata_opt_opcode_t *);
+
+#endif /* GENERIC_OPT_41_H */
diff --git a/lib/dns/rdata/generic/proforma.c b/lib/dns/rdata/generic/proforma.c
new file mode 100644
index 0000000..bf8b2fd
--- /dev/null
+++ b/lib/dns/rdata/generic/proforma.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: proforma.c,v 1.34 2004/03/05 05:10:17 marka Exp $ */
+
+#ifndef RDATA_GENERIC_#_#_C
+#define RDATA_GENERIC_#_#_C
+
+#define RRTYPE_#_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_#(ARGS_FROMTEXT) {
+ isc_token_t token;
+
+ REQUIRE(type == #);
+ REQUIRE(rdclass == #);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline isc_result_t
+totext_#(ARGS_TOTEXT) {
+
+ REQUIRE(rdata->type == #);
+ REQUIRE(rdata->rdclass == #);
+ REQUIRE(rdata->length != 0); /* XXX */
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline isc_result_t
+fromwire_#(ARGS_FROMWIRE) {
+
+ REQUIRE(type == #);
+ REQUIRE(rdclass == #);
+
+ /* NONE or GLOBAL14 */
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline isc_result_t
+towire_#(ARGS_TOWIRE) {
+
+ REQUIRE(rdata->type == #);
+ REQUIRE(rdata->rdclass == #);
+ REQUIRE(rdata->length != 0); /* XXX */
+
+ /* NONE or GLOBAL14 */
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline int
+compare_#(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == #);
+ REQUIRE(rdata1->rdclass == #);
+ REQUIRE(rdata1->length != 0); /* XXX */
+ REQUIRE(rdata2->length != 0); /* XXX */
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_#(ARGS_FROMSTRUCT) {
+ dns_rdata_#_t *# = source;
+
+ REQUIRE(type == #);
+ REQUIRE(rdclass == #);
+ REQUIRE(source != NULL);
+ REQUIRE(#->common.rdtype == type);
+ REQUIRE(#->common.rdclass == rdclass);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline isc_result_t
+tostruct_#(ARGS_TOSTRUCT) {
+
+ REQUIRE(rdata->type == #);
+ REQUIRE(rdata->rdclass == #);
+ REQUIRE(rdata->length != 0); /* XXX */
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline void
+freestruct_#(ARGS_FREESTRUCT) {
+ dns_rdata_#_t *# = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(#->common.rdtype == #);
+ REQUIRE(#->common.rdclass == #);
+
+}
+
+static inline isc_result_t
+additionaldata_#(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == #);
+ REQUIRE(rdata->rdclass == #);
+
+ (void)add;
+ (void)arg;
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_#(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == #);
+ REQUIRE(rdata->rdclass == #);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_#(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == #);
+ REQUIRE(rdclass == #);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_#(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == #);
+ REQUIRE(rdata->rdclass == #);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_#_#_C */
diff --git a/lib/dns/rdata/generic/proforma.h b/lib/dns/rdata/generic/proforma.h
new file mode 100644
index 0000000..89d1606
--- /dev/null
+++ b/lib/dns/rdata/generic/proforma.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_PROFORMA_H
+#define GENERIC_PROFORMA_H 1
+
+/* $Id: proforma.h,v 1.19.18.2 2005/04/29 00:16:39 marka Exp $ */
+
+typedef struct dns_rdata_# {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx; /* if required */
+ /* type & class specific elements */
+} dns_rdata_#_t;
+
+#endif /* GENERIC_PROFORMA_H */
diff --git a/lib/dns/rdata/generic/ptr_12.c b/lib/dns/rdata/generic/ptr_12.c
new file mode 100644
index 0000000..16d5706
--- /dev/null
+++ b/lib/dns/rdata/generic/ptr_12.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: ptr_12.c,v 1.41 2004/03/05 05:10:17 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 14:05:12 PST 2000 by explorer */
+
+#ifndef RDATA_GENERIC_PTR_12_C
+#define RDATA_GENERIC_PTR_12_C
+
+#define RRTYPE_PTR_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_ptr(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 12);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ if (rdclass == dns_rdataclass_in &&
+ (options & DNS_RDATA_CHECKNAMES) != 0 &&
+ (options & DNS_RDATA_CHECKREVERSE) != 0) {
+ isc_boolean_t ok;
+ ok = dns_name_ishostname(&name, ISC_FALSE);
+ if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0)
+ RETTOK(DNS_R_BADNAME);
+ if (!ok && callbacks != NULL)
+ warn_badname(&name, lexer, callbacks);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_ptr(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 12);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ sub = name_prefix(&name, tctx->origin, &prefix);
+
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_ptr(ARGS_FROMWIRE) {
+ dns_name_t name;
+
+ REQUIRE(type == 12);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, NULL);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_ptr(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 12);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_ptr(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 12);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_ptr(ARGS_FROMSTRUCT) {
+ dns_rdata_ptr_t *ptr = source;
+ isc_region_t region;
+
+ REQUIRE(type == 12);
+ REQUIRE(source != NULL);
+ REQUIRE(ptr->common.rdtype == type);
+ REQUIRE(ptr->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&ptr->ptr, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_ptr(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_ptr_t *ptr = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 12);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ ptr->common.rdclass = rdata->rdclass;
+ ptr->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&ptr->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&ptr->ptr, NULL);
+ RETERR(name_duporclone(&name, mctx, &ptr->ptr));
+ ptr->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_ptr(ARGS_FREESTRUCT) {
+ dns_rdata_ptr_t *ptr = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(ptr->common.rdtype == 12);
+
+ if (ptr->mctx == NULL)
+ return;
+
+ dns_name_free(&ptr->ptr, ptr->mctx);
+ ptr->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_ptr(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 12);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_ptr(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 12);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_ptr(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 12);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static unsigned char ip6_arpa_data[] = "\003IP6\004ARPA";
+static unsigned char ip6_arpa_offsets[] = { 0, 4, 9 };
+static const dns_name_t ip6_arpa =
+{
+ DNS_NAME_MAGIC,
+ ip6_arpa_data, 10, 3,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ ip6_arpa_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+static unsigned char ip6_int_data[] = "\003IP6\003INT";
+static unsigned char ip6_int_offsets[] = { 0, 4, 8 };
+static const dns_name_t ip6_int =
+{
+ DNS_NAME_MAGIC,
+ ip6_int_data, 9, 3,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ ip6_int_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+static unsigned char in_addr_arpa_data[] = "\007IN-ADDR\004ARPA";
+static unsigned char in_addr_arpa_offsets[] = { 0, 8, 13 };
+static const dns_name_t in_addr_arpa =
+{
+ DNS_NAME_MAGIC,
+ in_addr_arpa_data, 14, 3,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ in_addr_arpa_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+static inline isc_boolean_t
+checknames_ptr(ARGS_CHECKNAMES) {
+ isc_region_t region;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 12);
+
+ if (rdata->rdclass != dns_rdataclass_in)
+ return (ISC_TRUE);
+
+ if (dns_name_issubdomain(owner, &in_addr_arpa) ||
+ dns_name_issubdomain(owner, &ip6_arpa) ||
+ dns_name_issubdomain(owner, &ip6_int)) {
+ dns_rdata_toregion(rdata, &region);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ishostname(&name, ISC_FALSE)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ }
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_PTR_12_C */
diff --git a/lib/dns/rdata/generic/ptr_12.h b/lib/dns/rdata/generic/ptr_12.h
new file mode 100644
index 0000000..4eb8fa7
--- /dev/null
+++ b/lib/dns/rdata/generic/ptr_12.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_PTR_12_H
+#define GENERIC_PTR_12_H 1
+
+/* $Id: ptr_12.h,v 1.23.18.2 2005/04/29 00:16:39 marka Exp $ */
+
+typedef struct dns_rdata_ptr {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t ptr;
+} dns_rdata_ptr_t;
+
+#endif /* GENERIC_PTR_12_H */
diff --git a/lib/dns/rdata/generic/rp_17.c b/lib/dns/rdata/generic/rp_17.c
new file mode 100644
index 0000000..b153643
--- /dev/null
+++ b/lib/dns/rdata/generic/rp_17.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2004, 2005 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: rp_17.c,v 1.38.18.2 2005/04/29 00:16:39 marka Exp $ */
+
+/* RFC1183 */
+
+#ifndef RDATA_GENERIC_RP_17_C
+#define RDATA_GENERIC_RP_17_C
+
+#define RRTYPE_RP_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_rp(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ int i;
+ isc_boolean_t ok;
+
+ REQUIRE(type == 17);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ origin = (origin != NULL) ? origin : dns_rootname;
+
+ for (i = 0; i < 2; i++) {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ RETTOK(dns_name_fromtext(&name, &buffer, origin,
+ options, target));
+ ok = ISC_TRUE;
+ if ((options & DNS_RDATA_CHECKNAMES) != 0 && i == 0)
+ ok = dns_name_ismailbox(&name);
+ if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0)
+ RETTOK(DNS_R_BADNAME);
+ if (!ok && callbacks != NULL)
+ warn_badname(&name, lexer, callbacks);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_rp(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t rmail;
+ dns_name_t email;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 17);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&rmail, NULL);
+ dns_name_init(&email, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+
+ dns_name_fromregion(&rmail, &region);
+ isc_region_consume(&region, rmail.length);
+
+ dns_name_fromregion(&email, &region);
+ isc_region_consume(&region, email.length);
+
+ sub = name_prefix(&rmail, tctx->origin, &prefix);
+ RETERR(dns_name_totext(&prefix, sub, target));
+
+ RETERR(str_totext(" ", target));
+
+ sub = name_prefix(&email, tctx->origin, &prefix);
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_rp(ARGS_FROMWIRE) {
+ dns_name_t rmail;
+ dns_name_t email;
+
+ REQUIRE(type == 17);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&rmail, NULL);
+ dns_name_init(&email, NULL);
+
+ RETERR(dns_name_fromwire(&rmail, source, dctx, options, target));
+ return (dns_name_fromwire(&email, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_rp(ARGS_TOWIRE) {
+ isc_region_t region;
+ dns_name_t rmail;
+ dns_name_t email;
+ dns_offsets_t roffsets;
+ dns_offsets_t eoffsets;
+
+ REQUIRE(rdata->type == 17);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ dns_name_init(&rmail, roffsets);
+ dns_name_init(&email, eoffsets);
+
+ dns_rdata_toregion(rdata, &region);
+
+ dns_name_fromregion(&rmail, &region);
+ isc_region_consume(&region, rmail.length);
+
+ RETERR(dns_name_towire(&rmail, cctx, target));
+
+ dns_name_fromregion(&rmail, &region);
+ isc_region_consume(&region, rmail.length);
+
+ return (dns_name_towire(&rmail, cctx, target));
+}
+
+static inline int
+compare_rp(ARGS_COMPARE) {
+ isc_region_t region1;
+ isc_region_t region2;
+ dns_name_t name1;
+ dns_name_t name2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 17);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ order = dns_name_rdatacompare(&name1, &name2);
+ if (order != 0)
+ return (order);
+
+ isc_region_consume(&region1, name_length(&name1));
+ isc_region_consume(&region2, name_length(&name2));
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_rp(ARGS_FROMSTRUCT) {
+ dns_rdata_rp_t *rp = source;
+ isc_region_t region;
+
+ REQUIRE(type == 17);
+ REQUIRE(source != NULL);
+ REQUIRE(rp->common.rdtype == type);
+ REQUIRE(rp->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&rp->mail, &region);
+ RETERR(isc_buffer_copyregion(target, &region));
+ dns_name_toregion(&rp->text, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_rp(ARGS_TOSTRUCT) {
+ isc_result_t result;
+ isc_region_t region;
+ dns_rdata_rp_t *rp = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 17);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ rp->common.rdclass = rdata->rdclass;
+ rp->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&rp->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&rp->mail, NULL);
+ RETERR(name_duporclone(&name, mctx, &rp->mail));
+ isc_region_consume(&region, name_length(&name));
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&rp->text, NULL);
+ result = name_duporclone(&name, mctx, &rp->text);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ rp->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL)
+ dns_name_free(&rp->mail, mctx);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_rp(ARGS_FREESTRUCT) {
+ dns_rdata_rp_t *rp = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(rp->common.rdtype == 17);
+
+ if (rp->mctx == NULL)
+ return;
+
+ dns_name_free(&rp->mail, rp->mctx);
+ dns_name_free(&rp->text, rp->mctx);
+ rp->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_rp(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 17);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_rp(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 17);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+
+ dns_name_fromregion(&name, &r);
+ RETERR(dns_name_digest(&name, digest, arg));
+ isc_region_consume(&r, name_length(&name));
+
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_rp(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 17);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_rp(ARGS_CHECKNAMES) {
+ isc_region_t region;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 17);
+
+ UNUSED(owner);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ismailbox(&name)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_RP_17_C */
diff --git a/lib/dns/rdata/generic/rp_17.h b/lib/dns/rdata/generic/rp_17.h
new file mode 100644
index 0000000..533c7e7
--- /dev/null
+++ b/lib/dns/rdata/generic/rp_17.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_RP_17_H
+#define GENERIC_RP_17_H 1
+
+/* $Id: rp_17.h,v 1.17.18.2 2005/04/29 00:16:39 marka Exp $ */
+
+/*!
+ * \brief Per RFC1183 */
+
+typedef struct dns_rdata_rp {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t mail;
+ dns_name_t text;
+} dns_rdata_rp_t;
+
+
+#endif /* GENERIC_RP_17_H */
diff --git a/lib/dns/rdata/generic/rrsig_46.c b/lib/dns/rdata/generic/rrsig_46.c
new file mode 100644
index 0000000..6561f28
--- /dev/null
+++ b/lib/dns/rdata/generic/rrsig_46.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: rrsig_46.c,v 1.5.18.3 2005/04/29 00:16:39 marka Exp $ */
+
+/* Reviewed: Fri Mar 17 09:05:02 PST 2000 by gson */
+
+/* RFC2535 */
+
+#ifndef RDATA_GENERIC_RRSIG_46_C
+#define RDATA_GENERIC_RRSIG_46_C
+
+#define RRTYPE_RRSIG_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC)
+
+static inline isc_result_t
+fromtext_rrsig(ARGS_FROMTEXT) {
+ isc_token_t token;
+ unsigned char c;
+ long i;
+ dns_rdatatype_t covered;
+ char *e;
+ isc_result_t result;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ isc_uint32_t time_signed, time_expire;
+
+ REQUIRE(type == 46);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Type covered.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ result = dns_rdatatype_fromtext(&covered, &token.value.as_textregion);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
+ i = strtol(DNS_AS_STR(token), &e, 10);
+ if (i < 0 || i > 65535)
+ RETTOK(ISC_R_RANGE);
+ if (*e != 0)
+ RETTOK(result);
+ covered = (dns_rdatatype_t)i;
+ }
+ RETERR(uint16_tobuffer(covered, target));
+
+ /*
+ * Algorithm.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_secalg_fromtext(&c, &token.value.as_textregion));
+ RETERR(mem_tobuffer(target, &c, 1));
+
+ /*
+ * Labels.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffU)
+ RETTOK(ISC_R_RANGE);
+ c = (unsigned char)token.value.as_ulong;
+ RETERR(mem_tobuffer(target, &c, 1));
+
+ /*
+ * Original ttl.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ RETERR(uint32_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Signature expiration.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_expire));
+ RETERR(uint32_tobuffer(time_expire, target));
+
+ /*
+ * Time signed.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_signed));
+ RETERR(uint32_tobuffer(time_signed, target));
+
+ /*
+ * Key footprint.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Signer.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+
+ /*
+ * Sig.
+ */
+ return (isc_base64_tobuffer(lexer, target, -1));
+}
+
+static inline isc_result_t
+totext_rrsig(ARGS_TOTEXT) {
+ isc_region_t sr;
+ char buf[sizeof("4294967295")];
+ dns_rdatatype_t covered;
+ unsigned long ttl;
+ unsigned long when;
+ unsigned long exp;
+ unsigned long foot;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 46);
+ REQUIRE(rdata->length != 0);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /*
+ * Type covered.
+ */
+ covered = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ /*
+ * XXXAG We should have something like dns_rdatatype_isknown()
+ * that does the right thing with type 0.
+ */
+ if (dns_rdatatype_isknown(covered) && covered != 0) {
+ RETERR(dns_rdatatype_totext(covered, target));
+ } else {
+ char buf[sizeof("TYPE65535")];
+ sprintf(buf, "TYPE%u", covered);
+ RETERR(str_totext(buf, target));
+ }
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Algorithm.
+ */
+ sprintf(buf, "%u", sr.base[0]);
+ isc_region_consume(&sr, 1);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Labels.
+ */
+ sprintf(buf, "%u", sr.base[0]);
+ isc_region_consume(&sr, 1);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Ttl.
+ */
+ ttl = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+ sprintf(buf, "%lu", ttl);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Sig exp.
+ */
+ exp = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+ RETERR(dns_time32_totext(exp, target));
+
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+
+ /*
+ * Time signed.
+ */
+ when = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+ RETERR(dns_time32_totext(when, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Footprint.
+ */
+ foot = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%lu", foot);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Signer.
+ */
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+ dns_name_fromregion(&name, &sr);
+ isc_region_consume(&sr, name_length(&name));
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ RETERR(dns_name_totext(&prefix, sub, target));
+
+ /*
+ * Sig.
+ */
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_base64_totext(&sr, tctx->width - 2,
+ tctx->linebreak, target));
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" )", target));
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_rrsig(ARGS_FROMWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+
+ REQUIRE(type == 46);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ isc_buffer_activeregion(source, &sr);
+ /*
+ * type covered: 2
+ * algorithm: 1
+ * labels: 1
+ * original ttl: 4
+ * signature expiration: 4
+ * time signed: 4
+ * key footprint: 2
+ */
+ if (sr.length < 18)
+ return (ISC_R_UNEXPECTEDEND);
+
+ isc_buffer_forward(source, 18);
+ RETERR(mem_tobuffer(target, sr.base, 18));
+
+ /*
+ * Signer.
+ */
+ dns_name_init(&name, NULL);
+ RETERR(dns_name_fromwire(&name, source, dctx, options, target));
+
+ /*
+ * Sig.
+ */
+ isc_buffer_activeregion(source, &sr);
+ isc_buffer_forward(source, sr.length);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline isc_result_t
+towire_rrsig(ARGS_TOWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+ dns_offsets_t offsets;
+
+ REQUIRE(rdata->type == 46);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ dns_rdata_toregion(rdata, &sr);
+ /*
+ * type covered: 2
+ * algorithm: 1
+ * labels: 1
+ * original ttl: 4
+ * signature expiration: 4
+ * time signed: 4
+ * key footprint: 2
+ */
+ RETERR(mem_tobuffer(target, sr.base, 18));
+ isc_region_consume(&sr, 18);
+
+ /*
+ * Signer.
+ */
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &sr);
+ isc_region_consume(&sr, name_length(&name));
+ RETERR(dns_name_towire(&name, cctx, target));
+
+ /*
+ * Signature.
+ */
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_rrsig(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 46);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_rrsig(ARGS_FROMSTRUCT) {
+ dns_rdata_rrsig_t *sig = source;
+
+ REQUIRE(type == 46);
+ REQUIRE(source != NULL);
+ REQUIRE(sig->common.rdtype == type);
+ REQUIRE(sig->common.rdclass == rdclass);
+ REQUIRE(sig->signature != NULL || sig->siglen == 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ /*
+ * Type covered.
+ */
+ RETERR(uint16_tobuffer(sig->covered, target));
+
+ /*
+ * Algorithm.
+ */
+ RETERR(uint8_tobuffer(sig->algorithm, target));
+
+ /*
+ * Labels.
+ */
+ RETERR(uint8_tobuffer(sig->labels, target));
+
+ /*
+ * Original TTL.
+ */
+ RETERR(uint32_tobuffer(sig->originalttl, target));
+
+ /*
+ * Expire time.
+ */
+ RETERR(uint32_tobuffer(sig->timeexpire, target));
+
+ /*
+ * Time signed.
+ */
+ RETERR(uint32_tobuffer(sig->timesigned, target));
+
+ /*
+ * Key ID.
+ */
+ RETERR(uint16_tobuffer(sig->keyid, target));
+
+ /*
+ * Signer name.
+ */
+ RETERR(name_tobuffer(&sig->signer, target));
+
+ /*
+ * Signature.
+ */
+ return (mem_tobuffer(target, sig->signature, sig->siglen));
+}
+
+static inline isc_result_t
+tostruct_rrsig(ARGS_TOSTRUCT) {
+ isc_region_t sr;
+ dns_rdata_rrsig_t *sig = target;
+ dns_name_t signer;
+
+ REQUIRE(rdata->type == 46);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ sig->common.rdclass = rdata->rdclass;
+ sig->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&sig->common, link);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /*
+ * Type covered.
+ */
+ sig->covered = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /*
+ * Algorithm.
+ */
+ sig->algorithm = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ /*
+ * Labels.
+ */
+ sig->labels = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ /*
+ * Original TTL.
+ */
+ sig->originalttl = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Expire time.
+ */
+ sig->timeexpire = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Time signed.
+ */
+ sig->timesigned = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Key ID.
+ */
+ sig->keyid = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ dns_name_init(&signer, NULL);
+ dns_name_fromregion(&signer, &sr);
+ dns_name_init(&sig->signer, NULL);
+ RETERR(name_duporclone(&signer, mctx, &sig->signer));
+ isc_region_consume(&sr, name_length(&sig->signer));
+
+ /*
+ * Signature.
+ */
+ sig->siglen = sr.length;
+ sig->signature = mem_maybedup(mctx, sr.base, sig->siglen);
+ if (sig->signature == NULL)
+ goto cleanup;
+
+
+ sig->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL)
+ dns_name_free(&sig->signer, mctx);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_rrsig(ARGS_FREESTRUCT) {
+ dns_rdata_rrsig_t *sig = (dns_rdata_rrsig_t *) source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(sig->common.rdtype == 46);
+
+ if (sig->mctx == NULL)
+ return;
+
+ dns_name_free(&sig->signer, sig->mctx);
+ if (sig->signature != NULL)
+ isc_mem_free(sig->mctx, sig->signature);
+ sig->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_rrsig(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 46);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_rrsig(ARGS_DIGEST) {
+
+ REQUIRE(rdata->type == 46);
+
+ UNUSED(rdata);
+ UNUSED(digest);
+ UNUSED(arg);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline dns_rdatatype_t
+covers_rrsig(dns_rdata_t *rdata) {
+ dns_rdatatype_t type;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 46);
+
+ dns_rdata_toregion(rdata, &r);
+ type = uint16_fromregion(&r);
+
+ return (type);
+}
+
+static inline isc_boolean_t
+checkowner_rrsig(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 46);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_rrsig(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 46);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_RRSIG_46_C */
diff --git a/lib/dns/rdata/generic/rrsig_46.h b/lib/dns/rdata/generic/rrsig_46.h
new file mode 100644
index 0000000..b8b35a2
--- /dev/null
+++ b/lib/dns/rdata/generic/rrsig_46.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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.
+ */
+
+#ifndef GENERIC_DNSSIG_46_H
+#define GENERIC_DNSSIG_46_H 1
+
+/* $Id: rrsig_46.h,v 1.3.20.2 2005/04/29 00:16:39 marka Exp $ */
+
+/*!
+ * \brief Per RFC2535 */
+typedef struct dns_rdata_rrsig {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ dns_rdatatype_t covered;
+ dns_secalg_t algorithm;
+ isc_uint8_t labels;
+ isc_uint32_t originalttl;
+ isc_uint32_t timeexpire;
+ isc_uint32_t timesigned;
+ isc_uint16_t keyid;
+ dns_name_t signer;
+ isc_uint16_t siglen;
+ unsigned char * signature;
+} dns_rdata_rrsig_t;
+
+
+#endif /* GENERIC_DNSSIG_46_H */
diff --git a/lib/dns/rdata/generic/rt_21.c b/lib/dns/rdata/generic/rt_21.c
new file mode 100644
index 0000000..6977e98
--- /dev/null
+++ b/lib/dns/rdata/generic/rt_21.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2004, 2005 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: rt_21.c,v 1.41.18.3 2005/04/27 05:01:52 sra Exp $ */
+
+/* reviewed: Thu Mar 16 15:02:31 PST 2000 by brister */
+
+/* RFC1183 */
+
+#ifndef RDATA_GENERIC_RT_21_C
+#define RDATA_GENERIC_RT_21_C
+
+#define RRTYPE_RT_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_rt(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ isc_boolean_t ok;
+
+ REQUIRE(type == 21);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ ok = ISC_TRUE;
+ if ((options & DNS_RDATA_CHECKNAMES) != 0)
+ ok = dns_name_ishostname(&name, ISC_FALSE);
+ if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0)
+ RETTOK(DNS_R_BADNAME);
+ if (!ok && callbacks != NULL)
+ warn_badname(&name, lexer, callbacks);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_rt(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+ char buf[sizeof("64000")];
+ unsigned short num;
+
+ REQUIRE(rdata->type == 21);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ num = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ sprintf(buf, "%u", num);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+ dns_name_fromregion(&name, &region);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_rt(ARGS_FROMWIRE) {
+ dns_name_t name;
+ isc_region_t sregion;
+ isc_region_t tregion;
+
+ REQUIRE(type == 21);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&name, NULL);
+
+ isc_buffer_activeregion(source, &sregion);
+ isc_buffer_availableregion(target, &tregion);
+ if (tregion.length < 2)
+ return (ISC_R_NOSPACE);
+ if (sregion.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ memcpy(tregion.base, sregion.base, 2);
+ isc_buffer_forward(source, 2);
+ isc_buffer_add(target, 2);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_rt(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+ isc_region_t tr;
+
+ REQUIRE(rdata->type == 21);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ isc_buffer_availableregion(target, &tr);
+ dns_rdata_toregion(rdata, &region);
+ if (tr.length < 2)
+ return (ISC_R_NOSPACE);
+ memcpy(tr.base, region.base, 2);
+ isc_region_consume(&region, 2);
+ isc_buffer_add(target, 2);
+
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_rt(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 21);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ order = memcmp(rdata1->data, rdata2->data, 2);
+ if (order != 0)
+ return (order < 0 ? -1 : 1);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ isc_region_consume(&region1, 2);
+ isc_region_consume(&region2, 2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_rt(ARGS_FROMSTRUCT) {
+ dns_rdata_rt_t *rt = source;
+ isc_region_t region;
+
+ REQUIRE(type == 21);
+ REQUIRE(source != NULL);
+ REQUIRE(rt->common.rdtype == type);
+ REQUIRE(rt->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint16_tobuffer(rt->preference, target));
+ dns_name_toregion(&rt->host, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_rt(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_rt_t *rt = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 21);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ rt->common.rdclass = rdata->rdclass;
+ rt->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&rt->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ rt->preference = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&rt->host, NULL);
+ RETERR(name_duporclone(&name, mctx, &rt->host));
+
+ rt->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_rt(ARGS_FREESTRUCT) {
+ dns_rdata_rt_t *rt = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(rt->common.rdtype == 21);
+
+ if (rt->mctx == NULL)
+ return;
+
+ dns_name_free(&rt->host, rt->mctx);
+ rt->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_rt(ARGS_ADDLDATA) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+ isc_result_t result;
+
+ REQUIRE(rdata->type == 21);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ isc_region_consume(&region, 2);
+ dns_name_fromregion(&name, &region);
+
+ result = (add)(arg, &name, dns_rdatatype_x25);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = (add)(arg, &name, dns_rdatatype_isdn);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ return ((add)(arg, &name, dns_rdatatype_a));
+}
+
+static inline isc_result_t
+digest_rt(ARGS_DIGEST) {
+ isc_region_t r1, r2;
+ isc_result_t result;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 21);
+
+ dns_rdata_toregion(rdata, &r1);
+ r2 = r1;
+ isc_region_consume(&r2, 2);
+ r1.length = 2;
+ result = (digest)(arg, &r1);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r2);
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_rt(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 21);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_rt(ARGS_CHECKNAMES) {
+ isc_region_t region;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 21);
+
+ UNUSED(owner);
+
+ dns_rdata_toregion(rdata, &region);
+ isc_region_consume(&region, 2);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ishostname(&name, ISC_FALSE)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_RT_21_C */
diff --git a/lib/dns/rdata/generic/rt_21.h b/lib/dns/rdata/generic/rt_21.h
new file mode 100644
index 0000000..b8ec969
--- /dev/null
+++ b/lib/dns/rdata/generic/rt_21.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_RT_21_H
+#define GENERIC_RT_21_H 1
+
+/* $Id: rt_21.h,v 1.17.18.2 2005/04/29 00:16:40 marka Exp $ */
+
+/*!
+ * \brief Per RFC1183 */
+
+typedef struct dns_rdata_rt {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t preference;
+ dns_name_t host;
+} dns_rdata_rt_t;
+
+#endif /* GENERIC_RT_21_H */
diff --git a/lib/dns/rdata/generic/sig_24.c b/lib/dns/rdata/generic/sig_24.c
new file mode 100644
index 0000000..9842953
--- /dev/null
+++ b/lib/dns/rdata/generic/sig_24.c
@@ -0,0 +1,578 @@
+/*
+ * Copyright (C) 2004, 2005 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: sig_24.c,v 1.62.18.2 2005/04/29 00:16:40 marka Exp $ */
+
+/* Reviewed: Fri Mar 17 09:05:02 PST 2000 by gson */
+
+/* RFC2535 */
+
+#ifndef RDATA_GENERIC_SIG_24_C
+#define RDATA_GENERIC_SIG_24_C
+
+#define RRTYPE_SIG_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_sig(ARGS_FROMTEXT) {
+ isc_token_t token;
+ unsigned char c;
+ long i;
+ dns_rdatatype_t covered;
+ char *e;
+ isc_result_t result;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ isc_uint32_t time_signed, time_expire;
+
+ REQUIRE(type == 24);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Type covered.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ result = dns_rdatatype_fromtext(&covered, &token.value.as_textregion);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
+ i = strtol(DNS_AS_STR(token), &e, 10);
+ if (i < 0 || i > 65535)
+ RETTOK(ISC_R_RANGE);
+ if (*e != 0)
+ RETTOK(result);
+ covered = (dns_rdatatype_t)i;
+ }
+ RETERR(uint16_tobuffer(covered, target));
+
+ /*
+ * Algorithm.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_secalg_fromtext(&c, &token.value.as_textregion));
+ RETERR(mem_tobuffer(target, &c, 1));
+
+ /*
+ * Labels.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffU)
+ RETTOK(ISC_R_RANGE);
+ c = (unsigned char)token.value.as_ulong;
+ RETERR(mem_tobuffer(target, &c, 1));
+
+ /*
+ * Original ttl.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ RETERR(uint32_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Signature expiration.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_expire));
+ RETERR(uint32_tobuffer(time_expire, target));
+
+ /*
+ * Time signed.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_signed));
+ RETERR(uint32_tobuffer(time_signed, target));
+
+ /*
+ * Key footprint.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Signer.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+
+ /*
+ * Sig.
+ */
+ return (isc_base64_tobuffer(lexer, target, -1));
+}
+
+static inline isc_result_t
+totext_sig(ARGS_TOTEXT) {
+ isc_region_t sr;
+ char buf[sizeof("4294967295")];
+ dns_rdatatype_t covered;
+ unsigned long ttl;
+ unsigned long when;
+ unsigned long exp;
+ unsigned long foot;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 24);
+ REQUIRE(rdata->length != 0);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /*
+ * Type covered.
+ */
+ covered = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ /*
+ * XXXAG We should have something like dns_rdatatype_isknown()
+ * that does the right thing with type 0.
+ */
+ if (dns_rdatatype_isknown(covered) && covered != 0) {
+ RETERR(dns_rdatatype_totext(covered, target));
+ } else {
+ char buf[sizeof("65535")];
+ sprintf(buf, "%u", covered);
+ RETERR(str_totext(buf, target));
+ }
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Algorithm.
+ */
+ sprintf(buf, "%u", sr.base[0]);
+ isc_region_consume(&sr, 1);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Labels.
+ */
+ sprintf(buf, "%u", sr.base[0]);
+ isc_region_consume(&sr, 1);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Ttl.
+ */
+ ttl = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+ sprintf(buf, "%lu", ttl);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Sig exp.
+ */
+ exp = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+ RETERR(dns_time32_totext(exp, target));
+
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+
+ /*
+ * Time signed.
+ */
+ when = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+ RETERR(dns_time32_totext(when, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Footprint.
+ */
+ foot = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%lu", foot);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Signer.
+ */
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+ dns_name_fromregion(&name, &sr);
+ isc_region_consume(&sr, name_length(&name));
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ RETERR(dns_name_totext(&prefix, sub, target));
+
+ /*
+ * Sig.
+ */
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_base64_totext(&sr, tctx->width - 2,
+ tctx->linebreak, target));
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" )", target));
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_sig(ARGS_FROMWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+
+ REQUIRE(type == 24);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ isc_buffer_activeregion(source, &sr);
+ /*
+ * type covered: 2
+ * algorithm: 1
+ * labels: 1
+ * original ttl: 4
+ * signature expiration: 4
+ * time signed: 4
+ * key footprint: 2
+ */
+ if (sr.length < 18)
+ return (ISC_R_UNEXPECTEDEND);
+
+ isc_buffer_forward(source, 18);
+ RETERR(mem_tobuffer(target, sr.base, 18));
+
+ /*
+ * Signer.
+ */
+ dns_name_init(&name, NULL);
+ RETERR(dns_name_fromwire(&name, source, dctx, options, target));
+
+ /*
+ * Sig.
+ */
+ isc_buffer_activeregion(source, &sr);
+ isc_buffer_forward(source, sr.length);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline isc_result_t
+towire_sig(ARGS_TOWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+ dns_offsets_t offsets;
+
+ REQUIRE(rdata->type == 24);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ dns_rdata_toregion(rdata, &sr);
+ /*
+ * type covered: 2
+ * algorithm: 1
+ * labels: 1
+ * original ttl: 4
+ * signature expiration: 4
+ * time signed: 4
+ * key footprint: 2
+ */
+ RETERR(mem_tobuffer(target, sr.base, 18));
+ isc_region_consume(&sr, 18);
+
+ /*
+ * Signer.
+ */
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &sr);
+ isc_region_consume(&sr, name_length(&name));
+ RETERR(dns_name_towire(&name, cctx, target));
+
+ /*
+ * Signature.
+ */
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_sig(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+ dns_name_t name1;
+ dns_name_t name2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 24);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+
+ INSIST(r1.length > 18);
+ INSIST(r2.length > 18);
+ r1.length = 18;
+ r2.length = 18;
+ order = isc_region_compare(&r1, &r2);
+ if (order != 0)
+ return (order);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ isc_region_consume(&r1, 18);
+ isc_region_consume(&r2, 18);
+ dns_name_fromregion(&name1, &r1);
+ dns_name_fromregion(&name2, &r2);
+ order = dns_name_rdatacompare(&name1, &name2);
+ if (order != 0)
+ return (order);
+
+ isc_region_consume(&r1, name_length(&name1));
+ isc_region_consume(&r2, name_length(&name2));
+
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_sig(ARGS_FROMSTRUCT) {
+ dns_rdata_sig_t *sig = source;
+
+ REQUIRE(type == 24);
+ REQUIRE(source != NULL);
+ REQUIRE(sig->common.rdtype == type);
+ REQUIRE(sig->common.rdclass == rdclass);
+ REQUIRE(sig->signature != NULL || sig->siglen == 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ /*
+ * Type covered.
+ */
+ RETERR(uint16_tobuffer(sig->covered, target));
+
+ /*
+ * Algorithm.
+ */
+ RETERR(uint8_tobuffer(sig->algorithm, target));
+
+ /*
+ * Labels.
+ */
+ RETERR(uint8_tobuffer(sig->labels, target));
+
+ /*
+ * Original TTL.
+ */
+ RETERR(uint32_tobuffer(sig->originalttl, target));
+
+ /*
+ * Expire time.
+ */
+ RETERR(uint32_tobuffer(sig->timeexpire, target));
+
+ /*
+ * Time signed.
+ */
+ RETERR(uint32_tobuffer(sig->timesigned, target));
+
+ /*
+ * Key ID.
+ */
+ RETERR(uint16_tobuffer(sig->keyid, target));
+
+ /*
+ * Signer name.
+ */
+ RETERR(name_tobuffer(&sig->signer, target));
+
+ /*
+ * Signature.
+ */
+ return (mem_tobuffer(target, sig->signature, sig->siglen));
+}
+
+static inline isc_result_t
+tostruct_sig(ARGS_TOSTRUCT) {
+ isc_region_t sr;
+ dns_rdata_sig_t *sig = target;
+ dns_name_t signer;
+
+ REQUIRE(rdata->type == 24);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ sig->common.rdclass = rdata->rdclass;
+ sig->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&sig->common, link);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /*
+ * Type covered.
+ */
+ sig->covered = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /*
+ * Algorithm.
+ */
+ sig->algorithm = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ /*
+ * Labels.
+ */
+ sig->labels = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ /*
+ * Original TTL.
+ */
+ sig->originalttl = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Expire time.
+ */
+ sig->timeexpire = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Time signed.
+ */
+ sig->timesigned = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Key ID.
+ */
+ sig->keyid = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ dns_name_init(&signer, NULL);
+ dns_name_fromregion(&signer, &sr);
+ dns_name_init(&sig->signer, NULL);
+ RETERR(name_duporclone(&signer, mctx, &sig->signer));
+ isc_region_consume(&sr, name_length(&sig->signer));
+
+ /*
+ * Signature.
+ */
+ sig->siglen = sr.length;
+ sig->signature = mem_maybedup(mctx, sr.base, sig->siglen);
+ if (sig->signature == NULL)
+ goto cleanup;
+
+
+ sig->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL)
+ dns_name_free(&sig->signer, mctx);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_sig(ARGS_FREESTRUCT) {
+ dns_rdata_sig_t *sig = (dns_rdata_sig_t *) source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(sig->common.rdtype == 24);
+
+ if (sig->mctx == NULL)
+ return;
+
+ dns_name_free(&sig->signer, sig->mctx);
+ if (sig->signature != NULL)
+ isc_mem_free(sig->mctx, sig->signature);
+ sig->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_sig(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 24);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_sig(ARGS_DIGEST) {
+
+ REQUIRE(rdata->type == 24);
+
+ UNUSED(rdata);
+ UNUSED(digest);
+ UNUSED(arg);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline dns_rdatatype_t
+covers_sig(dns_rdata_t *rdata) {
+ dns_rdatatype_t type;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 24);
+
+ dns_rdata_toregion(rdata, &r);
+ type = uint16_fromregion(&r);
+
+ return (type);
+}
+
+static inline isc_boolean_t
+checkowner_sig(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 24);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_sig(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 24);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_SIG_24_C */
diff --git a/lib/dns/rdata/generic/sig_24.h b/lib/dns/rdata/generic/sig_24.h
new file mode 100644
index 0000000..96ed767
--- /dev/null
+++ b/lib/dns/rdata/generic/sig_24.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_SIG_24_H
+#define GENERIC_SIG_24_H 1
+
+/* $Id: sig_24.h,v 1.22.18.2 2005/04/29 00:16:40 marka Exp $ */
+
+/*!
+ * \brief Per RFC2535 */
+
+typedef struct dns_rdata_sig_t {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ dns_rdatatype_t covered;
+ dns_secalg_t algorithm;
+ isc_uint8_t labels;
+ isc_uint32_t originalttl;
+ isc_uint32_t timeexpire;
+ isc_uint32_t timesigned;
+ isc_uint16_t keyid;
+ dns_name_t signer;
+ isc_uint16_t siglen;
+ unsigned char * signature;
+} dns_rdata_sig_t;
+
+
+#endif /* GENERIC_SIG_24_H */
diff --git a/lib/dns/rdata/generic/soa_6.c b/lib/dns/rdata/generic/soa_6.c
new file mode 100644
index 0000000..8de678c
--- /dev/null
+++ b/lib/dns/rdata/generic/soa_6.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: soa_6.c,v 1.59 2004/03/05 05:10:18 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 15:18:32 PST 2000 by explorer */
+
+#ifndef RDATA_GENERIC_SOA_6_C
+#define RDATA_GENERIC_SOA_6_C
+
+#define RRTYPE_SOA_ATTRIBUTES (DNS_RDATATYPEATTR_SINGLETON)
+
+static inline isc_result_t
+fromtext_soa(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ int i;
+ isc_uint32_t n;
+ isc_boolean_t ok;
+
+ REQUIRE(type == 6);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ origin = (origin != NULL) ? origin : dns_rootname;
+
+ for (i = 0; i < 2; i++) {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ RETTOK(dns_name_fromtext(&name, &buffer, origin,
+ options, target));
+ ok = ISC_TRUE;
+ if ((options & DNS_RDATA_CHECKNAMES) != 0)
+ switch (i) {
+ case 0:
+ ok = dns_name_ishostname(&name, ISC_FALSE);
+ break;
+ case 1:
+ ok = dns_name_ismailbox(&name);
+ break;
+
+ }
+ if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0)
+ RETTOK(DNS_R_BADNAME);
+ if (!ok && callbacks != NULL)
+ warn_badname(&name, lexer, callbacks);
+ }
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ RETERR(uint32_tobuffer(token.value.as_ulong, target));
+
+ for (i = 0; i < 4; i++) {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_counter_fromtext(&token.value.as_textregion, &n));
+ RETERR(uint32_tobuffer(n, target));
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static const char *soa_fieldnames[5] = {
+ "serial", "refresh", "retry", "expire", "minimum"
+};
+
+static inline isc_result_t
+totext_soa(ARGS_TOTEXT) {
+ isc_region_t dregion;
+ dns_name_t mname;
+ dns_name_t rname;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+ int i;
+ isc_boolean_t multiline;
+ isc_boolean_t comment;
+
+ REQUIRE(rdata->type == 6);
+ REQUIRE(rdata->length != 0);
+
+ multiline = ISC_TF((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0);
+ comment = ISC_TF((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0);
+
+ dns_name_init(&mname, NULL);
+ dns_name_init(&rname, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &dregion);
+
+ dns_name_fromregion(&mname, &dregion);
+ isc_region_consume(&dregion, name_length(&mname));
+
+ dns_name_fromregion(&rname, &dregion);
+ isc_region_consume(&dregion, name_length(&rname));
+
+ sub = name_prefix(&mname, tctx->origin, &prefix);
+ RETERR(dns_name_totext(&prefix, sub, target));
+
+ RETERR(str_totext(" ", target));
+
+ sub = name_prefix(&rname, tctx->origin, &prefix);
+ RETERR(dns_name_totext(&prefix, sub, target));
+
+ if (multiline)
+ RETERR(str_totext(" (" , target));
+ RETERR(str_totext(tctx->linebreak, target));
+
+ for (i = 0; i < 5; i++) {
+ char buf[sizeof("2147483647")];
+ unsigned long num;
+ unsigned int numlen;
+ num = uint32_fromregion(&dregion);
+ isc_region_consume(&dregion, 4);
+ numlen = sprintf(buf, "%lu", num);
+ INSIST(numlen > 0 && numlen < sizeof("2147483647"));
+ RETERR(str_totext(buf, target));
+ if (multiline && comment) {
+ RETERR(str_totext(" ; " + numlen, target));
+ RETERR(str_totext(soa_fieldnames[i], target));
+ /* Print times in week/day/hour/minute/second form */
+ if (i >= 1) {
+ RETERR(str_totext(" (", target));
+ RETERR(dns_ttl_totext(num, ISC_TRUE, target));
+ RETERR(str_totext(")", target));
+ }
+ RETERR(str_totext(tctx->linebreak, target));
+ } else if (i < 4) {
+ RETERR(str_totext(tctx->linebreak, target));
+ }
+ }
+
+ if (multiline)
+ RETERR(str_totext(")", target));
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_soa(ARGS_FROMWIRE) {
+ dns_name_t mname;
+ dns_name_t rname;
+ isc_region_t sregion;
+ isc_region_t tregion;
+
+ REQUIRE(type == 6);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&mname, NULL);
+ dns_name_init(&rname, NULL);
+
+ RETERR(dns_name_fromwire(&mname, source, dctx, options, target));
+ RETERR(dns_name_fromwire(&rname, source, dctx, options, target));
+
+ isc_buffer_activeregion(source, &sregion);
+ isc_buffer_availableregion(target, &tregion);
+
+ if (sregion.length < 20)
+ return (ISC_R_UNEXPECTEDEND);
+ if (tregion.length < 20)
+ return (ISC_R_NOSPACE);
+
+ memcpy(tregion.base, sregion.base, 20);
+ isc_buffer_forward(source, 20);
+ isc_buffer_add(target, 20);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_soa(ARGS_TOWIRE) {
+ isc_region_t sregion;
+ isc_region_t tregion;
+ dns_name_t mname;
+ dns_name_t rname;
+ dns_offsets_t moffsets;
+ dns_offsets_t roffsets;
+
+ REQUIRE(rdata->type == 6);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+
+ dns_name_init(&mname, moffsets);
+ dns_name_init(&rname, roffsets);
+
+ dns_rdata_toregion(rdata, &sregion);
+
+ dns_name_fromregion(&mname, &sregion);
+ isc_region_consume(&sregion, name_length(&mname));
+ RETERR(dns_name_towire(&mname, cctx, target));
+
+ dns_name_fromregion(&rname, &sregion);
+ isc_region_consume(&sregion, name_length(&rname));
+ RETERR(dns_name_towire(&rname, cctx, target));
+
+ isc_buffer_availableregion(target, &tregion);
+ if (tregion.length < 20)
+ return (ISC_R_NOSPACE);
+
+ memcpy(tregion.base, sregion.base, 20);
+ isc_buffer_add(target, 20);
+ return (ISC_R_SUCCESS);
+}
+
+static inline int
+compare_soa(ARGS_COMPARE) {
+ isc_region_t region1;
+ isc_region_t region2;
+ dns_name_t name1;
+ dns_name_t name2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 6);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ order = dns_name_rdatacompare(&name1, &name2);
+ if (order != 0)
+ return (order);
+
+ isc_region_consume(&region1, name_length(&name1));
+ isc_region_consume(&region2, name_length(&name2));
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ order = dns_name_rdatacompare(&name1, &name2);
+ if (order != 0)
+ return (order);
+
+ isc_region_consume(&region1, name_length(&name1));
+ isc_region_consume(&region2, name_length(&name2));
+
+ return (isc_region_compare(&region1, &region2));
+}
+
+static inline isc_result_t
+fromstruct_soa(ARGS_FROMSTRUCT) {
+ dns_rdata_soa_t *soa = source;
+ isc_region_t region;
+
+ REQUIRE(type == 6);
+ REQUIRE(source != NULL);
+ REQUIRE(soa->common.rdtype == type);
+ REQUIRE(soa->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&soa->origin, &region);
+ RETERR(isc_buffer_copyregion(target, &region));
+ dns_name_toregion(&soa->contact, &region);
+ RETERR(isc_buffer_copyregion(target, &region));
+ RETERR(uint32_tobuffer(soa->serial, target));
+ RETERR(uint32_tobuffer(soa->refresh, target));
+ RETERR(uint32_tobuffer(soa->retry, target));
+ RETERR(uint32_tobuffer(soa->expire, target));
+ return (uint32_tobuffer(soa->minimum, target));
+}
+
+static inline isc_result_t
+tostruct_soa(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_soa_t *soa = target;
+ dns_name_t name;
+ isc_result_t result;
+
+ REQUIRE(rdata->type == 6);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ soa->common.rdclass = rdata->rdclass;
+ soa->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&soa->common, link);
+
+
+ dns_rdata_toregion(rdata, &region);
+
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ isc_region_consume(&region, name_length(&name));
+ dns_name_init(&soa->origin, NULL);
+ RETERR(name_duporclone(&name, mctx, &soa->origin));
+
+ dns_name_fromregion(&name, &region);
+ isc_region_consume(&region, name_length(&name));
+ dns_name_init(&soa->contact, NULL);
+ result = name_duporclone(&name, mctx, &soa->contact);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ soa->serial = uint32_fromregion(&region);
+ isc_region_consume(&region, 4);
+
+ soa->refresh = uint32_fromregion(&region);
+ isc_region_consume(&region, 4);
+
+ soa->retry = uint32_fromregion(&region);
+ isc_region_consume(&region, 4);
+
+ soa->expire = uint32_fromregion(&region);
+ isc_region_consume(&region, 4);
+
+ soa->minimum = uint32_fromregion(&region);
+
+ soa->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL)
+ dns_name_free(&soa->origin, mctx);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_soa(ARGS_FREESTRUCT) {
+ dns_rdata_soa_t *soa = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(soa->common.rdtype == 6);
+
+ if (soa->mctx == NULL)
+ return;
+
+ dns_name_free(&soa->origin, soa->mctx);
+ dns_name_free(&soa->contact, soa->mctx);
+ soa->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_soa(ARGS_ADDLDATA) {
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ REQUIRE(rdata->type == 6);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_soa(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 6);
+
+ dns_rdata_toregion(rdata, &r);
+
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+ RETERR(dns_name_digest(&name, digest, arg));
+ isc_region_consume(&r, name_length(&name));
+
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+ RETERR(dns_name_digest(&name, digest, arg));
+ isc_region_consume(&r, name_length(&name));
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_soa(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 6);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_soa(ARGS_CHECKNAMES) {
+ isc_region_t region;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 6);
+
+ UNUSED(owner);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ishostname(&name, ISC_FALSE)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ isc_region_consume(&region, name_length(&name));
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ismailbox(&name)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_SOA_6_C */
diff --git a/lib/dns/rdata/generic/soa_6.h b/lib/dns/rdata/generic/soa_6.h
new file mode 100644
index 0000000..4211786
--- /dev/null
+++ b/lib/dns/rdata/generic/soa_6.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_SOA_6_H
+#define GENERIC_SOA_6_H 1
+
+/* $Id: soa_6.h,v 1.28.18.2 2005/04/29 00:16:40 marka Exp $ */
+
+typedef struct dns_rdata_soa {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t origin;
+ dns_name_t contact;
+ isc_uint32_t serial; /*%< host order */
+ isc_uint32_t refresh; /*%< host order */
+ isc_uint32_t retry; /*%< host order */
+ isc_uint32_t expire; /*%< host order */
+ isc_uint32_t minimum; /*%< host order */
+} dns_rdata_soa_t;
+
+
+#endif /* GENERIC_SOA_6_H */
diff --git a/lib/dns/rdata/generic/spf_99.c b/lib/dns/rdata/generic/spf_99.c
new file mode 100644
index 0000000..b65f580
--- /dev/null
+++ b/lib/dns/rdata/generic/spf_99.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: spf_99.c,v 1.1.2.2 2005/07/16 00:40:54 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 15:40:00 PST 2000 by bwelling */
+
+#ifndef RDATA_GENERIC_SPF_99_C
+#define RDATA_GENERIC_SPF_99_C
+
+#define RRTYPE_SPF_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_spf(ARGS_FROMTEXT) {
+ isc_token_t token;
+ int strings;
+
+ REQUIRE(type == 99);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ strings = 0;
+ for (;;) {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_qstring,
+ ISC_TRUE));
+ if (token.type != isc_tokentype_qstring &&
+ token.type != isc_tokentype_string)
+ break;
+ RETTOK(txt_fromtext(&token.value.as_textregion, target));
+ strings++;
+ }
+ /* Let upper layer handle eol/eof. */
+ isc_lex_ungettoken(lexer, &token);
+ return (strings == 0 ? ISC_R_UNEXPECTEDEND : ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_spf(ARGS_TOTEXT) {
+ isc_region_t region;
+
+ UNUSED(tctx);
+
+ REQUIRE(rdata->type == 99);
+
+ dns_rdata_toregion(rdata, &region);
+
+ while (region.length > 0) {
+ RETERR(txt_totext(&region, target));
+ if (region.length > 0)
+ RETERR(str_totext(" ", target));
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_spf(ARGS_FROMWIRE) {
+ isc_result_t result;
+
+ REQUIRE(type == 99);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(rdclass);
+ UNUSED(options);
+
+ do {
+ result = txt_fromwire(source, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } while (!buffer_empty(source));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_spf(ARGS_TOWIRE) {
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 99);
+
+ UNUSED(cctx);
+
+ isc_buffer_availableregion(target, &region);
+ if (region.length < rdata->length)
+ return (ISC_R_NOSPACE);
+
+ memcpy(region.base, rdata->data, rdata->length);
+ isc_buffer_add(target, rdata->length);
+ return (ISC_R_SUCCESS);
+}
+
+static inline int
+compare_spf(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 99);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_spf(ARGS_FROMSTRUCT) {
+ dns_rdata_spf_t *txt = source;
+ isc_region_t region;
+ isc_uint8_t length;
+
+ REQUIRE(type == 99);
+ REQUIRE(source != NULL);
+ REQUIRE(txt->common.rdtype == type);
+ REQUIRE(txt->common.rdclass == rdclass);
+ REQUIRE(txt->txt != NULL && txt->txt_len != 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ region.base = txt->txt;
+ region.length = txt->txt_len;
+ while (region.length > 0) {
+ length = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ if (region.length <= length)
+ return (ISC_R_UNEXPECTEDEND);
+ isc_region_consume(&region, length);
+ }
+
+ return (mem_tobuffer(target, txt->txt, txt->txt_len));
+}
+
+static inline isc_result_t
+tostruct_spf(ARGS_TOSTRUCT) {
+ dns_rdata_spf_t *txt = target;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 99);
+ REQUIRE(target != NULL);
+
+ txt->common.rdclass = rdata->rdclass;
+ txt->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&txt->common, link);
+
+ dns_rdata_toregion(rdata, &r);
+ txt->txt_len = r.length;
+ txt->txt = mem_maybedup(mctx, r.base, r.length);
+ if (txt->txt == NULL)
+ return (ISC_R_NOMEMORY);
+
+ txt->offset = 0;
+ txt->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_spf(ARGS_FREESTRUCT) {
+ dns_rdata_spf_t *txt = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(txt->common.rdtype == 99);
+
+ if (txt->mctx == NULL)
+ return;
+
+ if (txt->txt != NULL)
+ isc_mem_free(txt->mctx, txt->txt);
+ txt->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_spf(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 99);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_spf(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 99);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_spf(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 99);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_spf(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 99);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_SPF_99_C */
diff --git a/lib/dns/rdata/generic/spf_99.h b/lib/dns/rdata/generic/spf_99.h
new file mode 100644
index 0000000..afe77ec
--- /dev/null
+++ b/lib/dns/rdata/generic/spf_99.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+#ifndef GENERIC_SPF_99_H
+#define GENERIC_SPF_99_H 1
+
+/* $Id: spf_99.h,v 1.1.2.2 2005/07/16 00:40:54 marka Exp $ */
+
+typedef struct dns_rdata_spf_string {
+ isc_uint8_t length;
+ unsigned char *data;
+} dns_rdata_spf_string_t;
+
+typedef struct dns_rdata_spf {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ unsigned char *txt;
+ isc_uint16_t txt_len;
+ /* private */
+ isc_uint16_t offset;
+} dns_rdata_spf_t;
+
+/*
+ * ISC_LANG_BEGINDECLS and ISC_LANG_ENDDECLS are already done
+ * via rdatastructpre.h and rdatastructsuf.h.
+ */
+
+isc_result_t
+dns_rdata_spf_first(dns_rdata_spf_t *);
+
+isc_result_t
+dns_rdata_spf_next(dns_rdata_spf_t *);
+
+isc_result_t
+dns_rdata_spf_current(dns_rdata_spf_t *, dns_rdata_spf_string_t *);
+
+#endif /* GENERIC_SPF_99_H */
diff --git a/lib/dns/rdata/generic/sshfp_44.c b/lib/dns/rdata/generic/sshfp_44.c
new file mode 100644
index 0000000..64b51c7
--- /dev/null
+++ b/lib/dns/rdata/generic/sshfp_44.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: sshfp_44.c,v 1.3.18.1 2006/03/10 04:04:32 marka Exp $ */
+
+/* RFC 4255 */
+
+#ifndef RDATA_GENERIC_SSHFP_44_C
+#define RDATA_GENERIC_SSHFP_44_C
+
+#define RRTYPE_SSHFP_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_sshfp(ARGS_FROMTEXT) {
+ isc_token_t token;
+
+ REQUIRE(type == 44);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ /*
+ * Algorithm.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint8_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Digest type.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint8_tobuffer(token.value.as_ulong, target));
+ type = (isc_uint16_t) token.value.as_ulong;
+
+ /*
+ * Digest.
+ */
+ return (isc_hex_tobuffer(lexer, target, -1));
+}
+
+static inline isc_result_t
+totext_sshfp(ARGS_TOTEXT) {
+ isc_region_t sr;
+ char buf[sizeof("64000 ")];
+ unsigned int n;
+
+ REQUIRE(rdata->type == 44);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /*
+ * Algorithm.
+ */
+ n = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+ sprintf(buf, "%u ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Digest type.
+ */
+ n = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+ sprintf(buf, "%u", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Digest.
+ */
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_hex_totext(&sr, tctx->width - 2, tctx->linebreak, target));
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" )", target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_sshfp(ARGS_FROMWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(type == 44);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(dctx);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sr);
+ if (sr.length < 4)
+ return (ISC_R_UNEXPECTEDEND);
+
+ isc_buffer_forward(source, sr.length);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline isc_result_t
+towire_sshfp(ARGS_TOWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 44);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(cctx);
+
+ dns_rdata_toregion(rdata, &sr);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_sshfp(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 44);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_sshfp(ARGS_FROMSTRUCT) {
+ dns_rdata_sshfp_t *sshfp = source;
+
+ REQUIRE(type == 44);
+ REQUIRE(source != NULL);
+ REQUIRE(sshfp->common.rdtype == type);
+ REQUIRE(sshfp->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint8_tobuffer(sshfp->algorithm, target));
+ RETERR(uint8_tobuffer(sshfp->digest_type, target));
+
+ return (mem_tobuffer(target, sshfp->digest, sshfp->length));
+}
+
+static inline isc_result_t
+tostruct_sshfp(ARGS_TOSTRUCT) {
+ dns_rdata_sshfp_t *sshfp = target;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 44);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ sshfp->common.rdclass = rdata->rdclass;
+ sshfp->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&sshfp->common, link);
+
+ dns_rdata_toregion(rdata, &region);
+
+ sshfp->algorithm = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ sshfp->digest_type = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ sshfp->length = region.length;
+
+ sshfp->digest = mem_maybedup(mctx, region.base, region.length);
+ if (sshfp->digest == NULL)
+ return (ISC_R_NOMEMORY);
+
+ sshfp->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_sshfp(ARGS_FREESTRUCT) {
+ dns_rdata_sshfp_t *sshfp = source;
+
+ REQUIRE(sshfp != NULL);
+ REQUIRE(sshfp->common.rdtype == 44);
+
+ if (sshfp->mctx == NULL)
+ return;
+
+ if (sshfp->digest != NULL)
+ isc_mem_free(sshfp->mctx, sshfp->digest);
+ sshfp->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_sshfp(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 44);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_sshfp(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 44);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_sshfp(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 44);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_sshfp(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 44);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_SSHFP_44_C */
diff --git a/lib/dns/rdata/generic/sshfp_44.h b/lib/dns/rdata/generic/sshfp_44.h
new file mode 100644
index 0000000..513eeac
--- /dev/null
+++ b/lib/dns/rdata/generic/sshfp_44.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: sshfp_44.h,v 1.2.18.3 2006/03/10 04:04:32 marka Exp $ */
+
+/*!
+ * \brief Per RFC 4255 */
+
+#ifndef GENERIC_SSHFP_44_H
+#define GENERIC_SSHFP_44_H 1
+
+typedef struct dns_rdata_sshfp {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint8_t algorithm;
+ isc_uint8_t digest_type;
+ isc_uint16_t length;
+ unsigned char *digest;
+} dns_rdata_sshfp_t;
+
+#endif /* GENERIC_SSHFP_44_H */
diff --git a/lib/dns/rdata/generic/tkey_249.c b/lib/dns/rdata/generic/tkey_249.c
new file mode 100644
index 0000000..cee16ab
--- /dev/null
+++ b/lib/dns/rdata/generic/tkey_249.c
@@ -0,0 +1,555 @@
+/*
+ * 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: tkey_249.c,v 1.55 2004/03/05 05:10:18 marka Exp $ */
+
+/*
+ * Reviewed: Thu Mar 16 17:35:30 PST 2000 by halley.
+ */
+
+/* draft-ietf-dnsext-tkey-01.txt */
+
+#ifndef RDATA_GENERIC_TKEY_249_C
+#define RDATA_GENERIC_TKEY_249_C
+
+#define RRTYPE_TKEY_ATTRIBUTES (DNS_RDATATYPEATTR_META)
+
+static inline isc_result_t
+fromtext_tkey(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_rcode_t rcode;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ long i;
+ char *e;
+
+ REQUIRE(type == 249);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Algorithm.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+
+
+ /*
+ * Inception.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ RETERR(uint32_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Expiration.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ RETERR(uint32_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Mode.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Error.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ if (dns_tsigrcode_fromtext(&rcode, &token.value.as_textregion)
+ != ISC_R_SUCCESS)
+ {
+ i = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e != 0)
+ RETTOK(DNS_R_UNKNOWN);
+ if (i < 0 || i > 0xffff)
+ RETTOK(ISC_R_RANGE);
+ rcode = (dns_rcode_t)i;
+ }
+ RETERR(uint16_tobuffer(rcode, target));
+
+ /*
+ * Key Size.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Key Data.
+ */
+ RETERR(isc_base64_tobuffer(lexer, target, (int)token.value.as_ulong));
+
+ /*
+ * Other Size.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Other Data.
+ */
+ return (isc_base64_tobuffer(lexer, target, (int)token.value.as_ulong));
+}
+
+static inline isc_result_t
+totext_tkey(ARGS_TOTEXT) {
+ isc_region_t sr, dr;
+ char buf[sizeof("4294967295 ")];
+ unsigned long n;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 249);
+ REQUIRE(rdata->length != 0);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /*
+ * Algorithm.
+ */
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+ dns_name_fromregion(&name, &sr);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ RETERR(dns_name_totext(&prefix, sub, target));
+ RETERR(str_totext(" ", target));
+ isc_region_consume(&sr, name_length(&name));
+
+ /*
+ * Inception.
+ */
+ n = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+ sprintf(buf, "%lu ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Expiration.
+ */
+ n = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+ sprintf(buf, "%lu ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Mode.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%lu ", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Error.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ if (dns_tsigrcode_totext((dns_rcode_t)n, target) == ISC_R_SUCCESS)
+ RETERR(str_totext(" ", target));
+ else {
+ sprintf(buf, "%lu ", n);
+ RETERR(str_totext(buf, target));
+ }
+
+ /*
+ * Key Size.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%lu", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Key Data.
+ */
+ REQUIRE(n <= sr.length);
+ dr = sr;
+ dr.length = n;
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_base64_totext(&dr, tctx->width - 2,
+ tctx->linebreak, target));
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" ) ", target));
+ else
+ RETERR(str_totext(" ", target));
+ isc_region_consume(&sr, n);
+
+ /*
+ * Other Size.
+ */
+ n = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ sprintf(buf, "%lu", n);
+ RETERR(str_totext(buf, target));
+
+ /*
+ * Other Data.
+ */
+ REQUIRE(n <= sr.length);
+ if (n != 0U) {
+ dr = sr;
+ dr.length = n;
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" (", target));
+ RETERR(str_totext(tctx->linebreak, target));
+ RETERR(isc_base64_totext(&dr, tctx->width - 2,
+ tctx->linebreak, target));
+ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+ RETERR(str_totext(" )", target));
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_tkey(ARGS_FROMWIRE) {
+ isc_region_t sr;
+ unsigned long n;
+ dns_name_t name;
+
+ REQUIRE(type == 249);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ /*
+ * Algorithm.
+ */
+ dns_name_init(&name, NULL);
+ RETERR(dns_name_fromwire(&name, source, dctx, options, target));
+
+ /*
+ * Inception: 4
+ * Expiration: 4
+ * Mode: 2
+ * Error: 2
+ */
+ isc_buffer_activeregion(source, &sr);
+ if (sr.length < 12)
+ return (ISC_R_UNEXPECTEDEND);
+ RETERR(mem_tobuffer(target, sr.base, 12));
+ isc_region_consume(&sr, 12);
+ isc_buffer_forward(source, 12);
+
+ /*
+ * Key Length + Key Data.
+ */
+ if (sr.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ n = uint16_fromregion(&sr);
+ if (sr.length < n + 2)
+ return (ISC_R_UNEXPECTEDEND);
+ RETERR(mem_tobuffer(target, sr.base, n + 2));
+ isc_region_consume(&sr, n + 2);
+ isc_buffer_forward(source, n + 2);
+
+ /*
+ * Other Length + Other Data.
+ */
+ if (sr.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ n = uint16_fromregion(&sr);
+ if (sr.length < n + 2)
+ return (ISC_R_UNEXPECTEDEND);
+ isc_buffer_forward(source, n + 2);
+ return (mem_tobuffer(target, sr.base, n + 2));
+}
+
+static inline isc_result_t
+towire_tkey(ARGS_TOWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+ dns_offsets_t offsets;
+
+ REQUIRE(rdata->type == 249);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ /*
+ * Algorithm.
+ */
+ dns_rdata_toregion(rdata, &sr);
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &sr);
+ RETERR(dns_name_towire(&name, cctx, target));
+ isc_region_consume(&sr, name_length(&name));
+
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_tkey(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+ dns_name_t name1;
+ dns_name_t name2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 249);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ /*
+ * Algorithm.
+ */
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+ dns_name_fromregion(&name1, &r1);
+ dns_name_fromregion(&name2, &r2);
+ if ((order = dns_name_rdatacompare(&name1, &name2)) != 0)
+ return (order);
+ isc_region_consume(&r1, name_length(&name1));
+ isc_region_consume(&r2, name_length(&name2));
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_tkey(ARGS_FROMSTRUCT) {
+ dns_rdata_tkey_t *tkey = source;
+
+ REQUIRE(type == 249);
+ REQUIRE(source != NULL);
+ REQUIRE(tkey->common.rdtype == type);
+ REQUIRE(tkey->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ /*
+ * Algorithm Name.
+ */
+ RETERR(name_tobuffer(&tkey->algorithm, target));
+
+ /*
+ * Inception: 32 bits.
+ */
+ RETERR(uint32_tobuffer(tkey->inception, target));
+
+ /*
+ * Expire: 32 bits.
+ */
+ RETERR(uint32_tobuffer(tkey->expire, target));
+
+ /*
+ * Mode: 16 bits.
+ */
+ RETERR(uint16_tobuffer(tkey->mode, target));
+
+ /*
+ * Error: 16 bits.
+ */
+ RETERR(uint16_tobuffer(tkey->error, target));
+
+ /*
+ * Key size: 16 bits.
+ */
+ RETERR(uint16_tobuffer(tkey->keylen, target));
+
+ /*
+ * Key.
+ */
+ RETERR(mem_tobuffer(target, tkey->key, tkey->keylen));
+
+ /*
+ * Other size: 16 bits.
+ */
+ RETERR(uint16_tobuffer(tkey->otherlen, target));
+
+ /*
+ * Other data.
+ */
+ return (mem_tobuffer(target, tkey->other, tkey->otherlen));
+}
+
+static inline isc_result_t
+tostruct_tkey(ARGS_TOSTRUCT) {
+ dns_rdata_tkey_t *tkey = target;
+ dns_name_t alg;
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 249);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ tkey->common.rdclass = rdata->rdclass;
+ tkey->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&tkey->common, link);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ /*
+ * Algorithm Name.
+ */
+ dns_name_init(&alg, NULL);
+ dns_name_fromregion(&alg, &sr);
+ dns_name_init(&tkey->algorithm, NULL);
+ RETERR(name_duporclone(&alg, mctx, &tkey->algorithm));
+ isc_region_consume(&sr, name_length(&tkey->algorithm));
+
+ /*
+ * Inception.
+ */
+ tkey->inception = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Expire.
+ */
+ tkey->expire = uint32_fromregion(&sr);
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Mode.
+ */
+ tkey->mode = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /*
+ * Error.
+ */
+ tkey->error = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /*
+ * Key size.
+ */
+ tkey->keylen = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /*
+ * Key.
+ */
+ tkey->key = mem_maybedup(mctx, sr.base, tkey->keylen);
+ if (tkey->key == NULL)
+ goto cleanup;
+ isc_region_consume(&sr, tkey->keylen);
+
+ /*
+ * Other size.
+ */
+ tkey->otherlen = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ /*
+ * Other.
+ */
+ tkey->other = mem_maybedup(mctx, sr.base, tkey->otherlen);
+ if (tkey->other == NULL)
+ goto cleanup;
+
+ tkey->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL)
+ dns_name_free(&tkey->algorithm, mctx);
+ if (mctx != NULL && tkey->key != NULL)
+ isc_mem_free(mctx, tkey->key);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_tkey(ARGS_FREESTRUCT) {
+ dns_rdata_tkey_t *tkey = (dns_rdata_tkey_t *) source;
+
+ REQUIRE(source != NULL);
+
+ if (tkey->mctx == NULL)
+ return;
+
+ dns_name_free(&tkey->algorithm, tkey->mctx);
+ if (tkey->key != NULL)
+ isc_mem_free(tkey->mctx, tkey->key);
+ if (tkey->other != NULL)
+ isc_mem_free(tkey->mctx, tkey->other);
+ tkey->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_tkey(ARGS_ADDLDATA) {
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ REQUIRE(rdata->type == 249);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_tkey(ARGS_DIGEST) {
+ UNUSED(rdata);
+ UNUSED(digest);
+ UNUSED(arg);
+
+ REQUIRE(rdata->type == 249);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static inline isc_boolean_t
+checkowner_tkey(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 249);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_tkey(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 249);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_TKEY_249_C */
diff --git a/lib/dns/rdata/generic/tkey_249.h b/lib/dns/rdata/generic/tkey_249.h
new file mode 100644
index 0000000..c1d2f06
--- /dev/null
+++ b/lib/dns/rdata/generic/tkey_249.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_TKEY_249_H
+#define GENERIC_TKEY_249_H 1
+
+/* $Id: tkey_249.h,v 1.20.18.2 2005/04/29 00:16:40 marka Exp $ */
+
+/*!
+ * \brief Per draft-ietf-dnsind-tkey-00.txt */
+
+typedef struct dns_rdata_tkey {
+ dns_rdatacommon_t common;
+ isc_mem_t * mctx;
+ dns_name_t algorithm;
+ isc_uint32_t inception;
+ isc_uint32_t expire;
+ isc_uint16_t mode;
+ isc_uint16_t error;
+ isc_uint16_t keylen;
+ unsigned char * key;
+ isc_uint16_t otherlen;
+ unsigned char * other;
+} dns_rdata_tkey_t;
+
+
+#endif /* GENERIC_TKEY_249_H */
diff --git a/lib/dns/rdata/generic/txt_16.c b/lib/dns/rdata/generic/txt_16.c
new file mode 100644
index 0000000..fa3ffef
--- /dev/null
+++ b/lib/dns/rdata/generic/txt_16.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: txt_16.c,v 1.41 2004/03/05 05:10:18 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 15:40:00 PST 2000 by bwelling */
+
+#ifndef RDATA_GENERIC_TXT_16_C
+#define RDATA_GENERIC_TXT_16_C
+
+#define RRTYPE_TXT_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_txt(ARGS_FROMTEXT) {
+ isc_token_t token;
+ int strings;
+
+ REQUIRE(type == 16);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ strings = 0;
+ for (;;) {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_qstring,
+ ISC_TRUE));
+ if (token.type != isc_tokentype_qstring &&
+ token.type != isc_tokentype_string)
+ break;
+ RETTOK(txt_fromtext(&token.value.as_textregion, target));
+ strings++;
+ }
+ /* Let upper layer handle eol/eof. */
+ isc_lex_ungettoken(lexer, &token);
+ return (strings == 0 ? ISC_R_UNEXPECTEDEND : ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_txt(ARGS_TOTEXT) {
+ isc_region_t region;
+
+ UNUSED(tctx);
+
+ REQUIRE(rdata->type == 16);
+
+ dns_rdata_toregion(rdata, &region);
+
+ while (region.length > 0) {
+ RETERR(txt_totext(&region, target));
+ if (region.length > 0)
+ RETERR(str_totext(" ", target));
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_txt(ARGS_FROMWIRE) {
+ isc_result_t result;
+
+ REQUIRE(type == 16);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(rdclass);
+ UNUSED(options);
+
+ do {
+ result = txt_fromwire(source, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } while (!buffer_empty(source));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_txt(ARGS_TOWIRE) {
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 16);
+
+ UNUSED(cctx);
+
+ isc_buffer_availableregion(target, &region);
+ if (region.length < rdata->length)
+ return (ISC_R_NOSPACE);
+
+ memcpy(region.base, rdata->data, rdata->length);
+ isc_buffer_add(target, rdata->length);
+ return (ISC_R_SUCCESS);
+}
+
+static inline int
+compare_txt(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 16);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_txt(ARGS_FROMSTRUCT) {
+ dns_rdata_txt_t *txt = source;
+ isc_region_t region;
+ isc_uint8_t length;
+
+ REQUIRE(type == 16);
+ REQUIRE(source != NULL);
+ REQUIRE(txt->common.rdtype == type);
+ REQUIRE(txt->common.rdclass == rdclass);
+ REQUIRE(txt->txt != NULL && txt->txt_len != 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ region.base = txt->txt;
+ region.length = txt->txt_len;
+ while (region.length > 0) {
+ length = uint8_fromregion(&region);
+ isc_region_consume(&region, 1);
+ if (region.length <= length)
+ return (ISC_R_UNEXPECTEDEND);
+ isc_region_consume(&region, length);
+ }
+
+ return (mem_tobuffer(target, txt->txt, txt->txt_len));
+}
+
+static inline isc_result_t
+tostruct_txt(ARGS_TOSTRUCT) {
+ dns_rdata_txt_t *txt = target;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 16);
+ REQUIRE(target != NULL);
+
+ txt->common.rdclass = rdata->rdclass;
+ txt->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&txt->common, link);
+
+ dns_rdata_toregion(rdata, &r);
+ txt->txt_len = r.length;
+ txt->txt = mem_maybedup(mctx, r.base, r.length);
+ if (txt->txt == NULL)
+ return (ISC_R_NOMEMORY);
+
+ txt->offset = 0;
+ txt->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_txt(ARGS_FREESTRUCT) {
+ dns_rdata_txt_t *txt = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(txt->common.rdtype == 16);
+
+ if (txt->mctx == NULL)
+ return;
+
+ if (txt->txt != NULL)
+ isc_mem_free(txt->mctx, txt->txt);
+ txt->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_txt(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 16);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_txt(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 16);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_txt(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 16);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_txt(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 16);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_TXT_16_C */
diff --git a/lib/dns/rdata/generic/txt_16.h b/lib/dns/rdata/generic/txt_16.h
new file mode 100644
index 0000000..57d986a
--- /dev/null
+++ b/lib/dns/rdata/generic/txt_16.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef GENERIC_TXT_16_H
+#define GENERIC_TXT_16_H 1
+
+/* $Id: txt_16.h,v 1.24.18.2 2005/04/29 00:16:40 marka Exp $ */
+
+typedef struct dns_rdata_txt_string {
+ isc_uint8_t length;
+ unsigned char *data;
+} dns_rdata_txt_string_t;
+
+typedef struct dns_rdata_txt {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ unsigned char *txt;
+ isc_uint16_t txt_len;
+ /* private */
+ isc_uint16_t offset;
+} dns_rdata_txt_t;
+
+/*
+ * ISC_LANG_BEGINDECLS and ISC_LANG_ENDDECLS are already done
+ * via rdatastructpre.h and rdatastructsuf.h.
+ */
+
+isc_result_t
+dns_rdata_txt_first(dns_rdata_txt_t *);
+
+isc_result_t
+dns_rdata_txt_next(dns_rdata_txt_t *);
+
+isc_result_t
+dns_rdata_txt_current(dns_rdata_txt_t *, dns_rdata_txt_string_t *);
+
+#endif /* GENERIC_TXT_16_H */
diff --git a/lib/dns/rdata/generic/unspec_103.c b/lib/dns/rdata/generic/unspec_103.c
new file mode 100644
index 0000000..f316ad9
--- /dev/null
+++ b/lib/dns/rdata/generic/unspec_103.c
@@ -0,0 +1,189 @@
+/*
+ * 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: unspec_103.c,v 1.33 2004/03/05 05:10:18 marka Exp $ */
+
+#ifndef RDATA_GENERIC_UNSPEC_103_C
+#define RDATA_GENERIC_UNSPEC_103_C
+
+#define RRTYPE_UNSPEC_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_unspec(ARGS_FROMTEXT) {
+
+ REQUIRE(type == 103);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ return (atob_tobuffer(lexer, target));
+}
+
+static inline isc_result_t
+totext_unspec(ARGS_TOTEXT) {
+
+ REQUIRE(rdata->type == 103);
+
+ UNUSED(tctx);
+
+ return (btoa_totext(rdata->data, rdata->length, target));
+}
+
+static inline isc_result_t
+fromwire_unspec(ARGS_FROMWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(type == 103);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(dctx);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sr);
+ isc_buffer_forward(source, sr.length);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline isc_result_t
+towire_unspec(ARGS_TOWIRE) {
+
+ REQUIRE(rdata->type == 103);
+
+ UNUSED(cctx);
+
+ return (mem_tobuffer(target, rdata->data, rdata->length));
+}
+
+static inline int
+compare_unspec(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 103);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_unspec(ARGS_FROMSTRUCT) {
+ dns_rdata_unspec_t *unspec = source;
+
+ REQUIRE(type == 103);
+ REQUIRE(source != NULL);
+ REQUIRE(unspec->common.rdtype == type);
+ REQUIRE(unspec->common.rdclass == rdclass);
+ REQUIRE(unspec->data != NULL || unspec->datalen == 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ return (mem_tobuffer(target, unspec->data, unspec->datalen));
+}
+
+static inline isc_result_t
+tostruct_unspec(ARGS_TOSTRUCT) {
+ dns_rdata_unspec_t *unspec = target;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 103);
+ REQUIRE(target != NULL);
+
+ unspec->common.rdclass = rdata->rdclass;
+ unspec->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&unspec->common, link);
+
+ dns_rdata_toregion(rdata, &r);
+ unspec->datalen = r.length;
+ unspec->data = mem_maybedup(mctx, r.base, r.length);
+ if (unspec->data == NULL)
+ return (ISC_R_NOMEMORY);
+
+ unspec->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_unspec(ARGS_FREESTRUCT) {
+ dns_rdata_unspec_t *unspec = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(unspec->common.rdtype == 103);
+
+ if (unspec->mctx == NULL)
+ return;
+
+ if (unspec->data != NULL)
+ isc_mem_free(unspec->mctx, unspec->data);
+ unspec->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_unspec(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 103);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_unspec(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 103);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_unspec(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 103);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_unspec(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 103);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_UNSPEC_103_C */
diff --git a/lib/dns/rdata/generic/unspec_103.h b/lib/dns/rdata/generic/unspec_103.h
new file mode 100644
index 0000000..6575c1a
--- /dev/null
+++ b/lib/dns/rdata/generic/unspec_103.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+/* */
+#ifndef GENERIC_UNSPEC_103_H
+#define GENERIC_UNSPEC_103_H 1
+
+/* $Id: unspec_103.h,v 1.13.18.2 2005/04/29 00:16:40 marka Exp $ */
+
+typedef struct dns_rdata_unspec_t {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ unsigned char *data;
+ isc_uint16_t datalen;
+} dns_rdata_unspec_t;
+
+#endif /* GENERIC_UNSPEC_103_H */
diff --git a/lib/dns/rdata/generic/x25_19.c b/lib/dns/rdata/generic/x25_19.c
new file mode 100644
index 0000000..1199195
--- /dev/null
+++ b/lib/dns/rdata/generic/x25_19.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2004, 2005 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: x25_19.c,v 1.35.18.2 2005/04/29 00:16:40 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 16:15:57 PST 2000 by bwelling */
+
+/* RFC1183 */
+
+#ifndef RDATA_GENERIC_X25_19_C
+#define RDATA_GENERIC_X25_19_C
+
+#define RRTYPE_X25_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_x25(ARGS_FROMTEXT) {
+ isc_token_t token;
+ unsigned int i;
+
+ REQUIRE(type == 19);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
+ ISC_FALSE));
+ if (token.value.as_textregion.length < 4)
+ RETTOK(DNS_R_SYNTAX);
+ for (i = 0; i < token.value.as_textregion.length; i++)
+ if (!isdigit(token.value.as_textregion.base[i] & 0xff))
+ RETTOK(ISC_R_RANGE);
+ RETTOK(txt_fromtext(&token.value.as_textregion, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_x25(ARGS_TOTEXT) {
+ isc_region_t region;
+
+ UNUSED(tctx);
+
+ REQUIRE(rdata->type == 19);
+ REQUIRE(rdata->length != 0);
+
+ dns_rdata_toregion(rdata, &region);
+ return (txt_totext(&region, target));
+}
+
+static inline isc_result_t
+fromwire_x25(ARGS_FROMWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(type == 19);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(rdclass);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sr);
+ if (sr.length < 5)
+ return (DNS_R_FORMERR);
+ return (txt_fromwire(source, target));
+}
+
+static inline isc_result_t
+towire_x25(ARGS_TOWIRE) {
+ UNUSED(cctx);
+
+ REQUIRE(rdata->type == 19);
+ REQUIRE(rdata->length != 0);
+
+ return (mem_tobuffer(target, rdata->data, rdata->length));
+}
+
+static inline int
+compare_x25(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 19);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_x25(ARGS_FROMSTRUCT) {
+ dns_rdata_x25_t *x25 = source;
+ isc_uint8_t i;
+
+ REQUIRE(type == 19);
+ REQUIRE(source != NULL);
+ REQUIRE(x25->common.rdtype == type);
+ REQUIRE(x25->common.rdclass == rdclass);
+ REQUIRE(x25->x25 != NULL && x25->x25_len != 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ if (x25->x25_len < 4)
+ return (ISC_R_RANGE);
+
+ for (i = 0; i < x25->x25_len; i++)
+ if (!isdigit(x25->x25[i] & 0xff))
+ return (ISC_R_RANGE);
+
+ RETERR(uint8_tobuffer(x25->x25_len, target));
+ return (mem_tobuffer(target, x25->x25, x25->x25_len));
+}
+
+static inline isc_result_t
+tostruct_x25(ARGS_TOSTRUCT) {
+ dns_rdata_x25_t *x25 = target;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 19);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ x25->common.rdclass = rdata->rdclass;
+ x25->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&x25->common, link);
+
+ dns_rdata_toregion(rdata, &r);
+ x25->x25_len = uint8_fromregion(&r);
+ isc_region_consume(&r, 1);
+ x25->x25 = mem_maybedup(mctx, r.base, x25->x25_len);
+ if (x25->x25 == NULL)
+ return (ISC_R_NOMEMORY);
+
+ x25->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_x25(ARGS_FREESTRUCT) {
+ dns_rdata_x25_t *x25 = source;
+ REQUIRE(source != NULL);
+ REQUIRE(x25->common.rdtype == 19);
+
+ if (x25->mctx == NULL)
+ return;
+
+ if (x25->x25 != NULL)
+ isc_mem_free(x25->mctx, x25->x25);
+ x25->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_x25(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 19);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_x25(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 19);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_x25(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 19);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_x25(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 19);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_X25_19_C */
diff --git a/lib/dns/rdata/generic/x25_19.h b/lib/dns/rdata/generic/x25_19.h
new file mode 100644
index 0000000..32320d0
--- /dev/null
+++ b/lib/dns/rdata/generic/x25_19.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef GENERIC_X25_19_H
+#define GENERIC_X25_19_H 1
+
+/* $Id: x25_19.h,v 1.14.18.2 2005/04/29 00:16:40 marka Exp $ */
+
+/*!
+ * \brief Per RFC1183 */
+
+typedef struct dns_rdata_x25 {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ unsigned char *x25;
+ isc_uint8_t x25_len;
+} dns_rdata_x25_t;
+
+#endif /* GENERIC_X25_19_H */
diff --git a/lib/dns/rdata/hs_4/a_1.c b/lib/dns/rdata/hs_4/a_1.c
new file mode 100644
index 0000000..5d3ddae
--- /dev/null
+++ b/lib/dns/rdata/hs_4/a_1.c
@@ -0,0 +1,232 @@
+/*
+ * 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: a_1.c,v 1.29 2004/03/05 05:10:20 marka Exp $ */
+
+/* reviewed: Thu Mar 16 15:58:36 PST 2000 by brister */
+
+#ifndef RDATA_HS_4_A_1_C
+#define RDATA_HS_4_A_1_C
+
+#include <isc/net.h>
+
+#define RRTYPE_A_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_hs_a(ARGS_FROMTEXT) {
+ isc_token_t token;
+ struct in_addr addr;
+ isc_region_t region;
+
+ REQUIRE(type == 1);
+ REQUIRE(rdclass == 4);
+
+ UNUSED(type);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(rdclass);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ if (getquad(DNS_AS_STR(token), &addr, lexer, callbacks) != 1)
+ RETTOK(DNS_R_BADDOTTEDQUAD);
+ isc_buffer_availableregion(target, &region);
+ if (region.length < 4)
+ return (ISC_R_NOSPACE);
+ memcpy(region.base, &addr, 4);
+ isc_buffer_add(target, 4);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_hs_a(ARGS_TOTEXT) {
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 4);
+ REQUIRE(rdata->length == 4);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &region);
+ return (inet_totext(AF_INET, &region, target));
+}
+
+static inline isc_result_t
+fromwire_hs_a(ARGS_FROMWIRE) {
+ isc_region_t sregion;
+ isc_region_t tregion;
+
+ REQUIRE(type == 1);
+ REQUIRE(rdclass == 4);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(options);
+ UNUSED(rdclass);
+
+ isc_buffer_activeregion(source, &sregion);
+ isc_buffer_availableregion(target, &tregion);
+ if (sregion.length < 4)
+ return (ISC_R_UNEXPECTEDEND);
+ if (tregion.length < 4)
+ return (ISC_R_NOSPACE);
+
+ memcpy(tregion.base, sregion.base, 4);
+ isc_buffer_forward(source, 4);
+ isc_buffer_add(target, 4);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_hs_a(ARGS_TOWIRE) {
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 4);
+ REQUIRE(rdata->length == 4);
+
+ UNUSED(cctx);
+
+ isc_buffer_availableregion(target, &region);
+ if (region.length < rdata->length)
+ return (ISC_R_NOSPACE);
+ memcpy(region.base, rdata->data, rdata->length);
+ isc_buffer_add(target, 4);
+ return (ISC_R_SUCCESS);
+}
+
+static inline int
+compare_hs_a(ARGS_COMPARE) {
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 1);
+ REQUIRE(rdata1->rdclass == 4);
+ REQUIRE(rdata1->length == 4);
+ REQUIRE(rdata2->length == 4);
+
+ order = memcmp(rdata1->data, rdata2->data, 4);
+ if (order != 0)
+ order = (order < 0) ? -1 : 1;
+
+ return (order);
+}
+
+static inline isc_result_t
+fromstruct_hs_a(ARGS_FROMSTRUCT) {
+ dns_rdata_hs_a_t *a = source;
+ isc_uint32_t n;
+
+ REQUIRE(type == 1);
+ REQUIRE(rdclass == 4);
+ REQUIRE(source != NULL);
+ REQUIRE(a->common.rdtype == type);
+ REQUIRE(a->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ n = ntohl(a->in_addr.s_addr);
+
+ return (uint32_tobuffer(n, target));
+}
+
+static inline isc_result_t
+tostruct_hs_a(ARGS_TOSTRUCT) {
+ dns_rdata_hs_a_t *a = target;
+ isc_uint32_t n;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 4);
+ REQUIRE(rdata->length == 4);
+
+ UNUSED(mctx);
+
+ a->common.rdclass = rdata->rdclass;
+ a->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&a->common, link);
+
+ dns_rdata_toregion(rdata, &region);
+ n = uint32_fromregion(&region);
+ a->in_addr.s_addr = htonl(n);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_hs_a(ARGS_FREESTRUCT) {
+ UNUSED(source);
+
+ REQUIRE(source != NULL);
+}
+
+static inline isc_result_t
+additionaldata_hs_a(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 4);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_hs_a(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 4);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_hs_a(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 1);
+ REQUIRE(rdclass == 4);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_hs_a(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 4);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_HS_4_A_1_C */
diff --git a/lib/dns/rdata/hs_4/a_1.h b/lib/dns/rdata/hs_4/a_1.h
new file mode 100644
index 0000000..59f54b5
--- /dev/null
+++ b/lib/dns/rdata/hs_4/a_1.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+/* */
+#ifndef HS_4_A_1_H
+#define HS_4_A_1_H 1
+
+/* $Id: a_1.h,v 1.8.18.2 2005/04/29 00:16:41 marka Exp $ */
+
+typedef struct dns_rdata_hs_a {
+ dns_rdatacommon_t common;
+ struct in_addr in_addr;
+} dns_rdata_hs_a_t;
+
+#endif /* HS_4_A_1_H */
diff --git a/lib/dns/rdata/in_1/a6_38.c b/lib/dns/rdata/in_1/a6_38.c
new file mode 100644
index 0000000..50017e1
--- /dev/null
+++ b/lib/dns/rdata/in_1/a6_38.c
@@ -0,0 +1,461 @@
+/*
+ * 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: a6_38.c,v 1.52 2004/03/05 05:10:23 marka Exp $ */
+
+/* RFC2874 */
+
+#ifndef RDATA_IN_1_A6_28_C
+#define RDATA_IN_1_A6_28_C
+
+#include <isc/net.h>
+
+#define RRTYPE_A6_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_in_a6(ARGS_FROMTEXT) {
+ isc_token_t token;
+ unsigned char addr[16];
+ unsigned char prefixlen;
+ unsigned char octets;
+ unsigned char mask;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ isc_boolean_t ok;
+
+ REQUIRE(type == 38);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Prefix length.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 128U)
+ RETTOK(ISC_R_RANGE);
+
+ prefixlen = (unsigned char)token.value.as_ulong;
+ RETERR(mem_tobuffer(target, &prefixlen, 1));
+
+ /*
+ * Suffix.
+ */
+ if (prefixlen != 128) {
+ /*
+ * Prefix 0..127.
+ */
+ octets = prefixlen/8;
+ /*
+ * Octets 0..15.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string,
+ ISC_FALSE));
+ if (inet_pton(AF_INET6, DNS_AS_STR(token), addr) != 1)
+ RETTOK(DNS_R_BADAAAA);
+ mask = 0xff >> (prefixlen % 8);
+ addr[octets] &= mask;
+ RETERR(mem_tobuffer(target, &addr[octets], 16 - octets));
+ }
+
+ if (prefixlen == 0)
+ return (ISC_R_SUCCESS);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ ok = ISC_TRUE;
+ if ((options & DNS_RDATA_CHECKNAMES) != 0)
+ ok = dns_name_ishostname(&name, ISC_FALSE);
+ if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0)
+ RETTOK(DNS_R_BADNAME);
+ if (!ok && callbacks != NULL)
+ warn_badname(&name, lexer, callbacks);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_in_a6(ARGS_TOTEXT) {
+ isc_region_t sr, ar;
+ unsigned char addr[16];
+ unsigned char prefixlen;
+ unsigned char octets;
+ unsigned char mask;
+ char buf[sizeof("128")];
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 38);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_rdata_toregion(rdata, &sr);
+ prefixlen = sr.base[0];
+ INSIST(prefixlen <= 128);
+ isc_region_consume(&sr, 1);
+ sprintf(buf, "%u", prefixlen);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ if (prefixlen != 128) {
+ octets = prefixlen/8;
+ memset(addr, 0, sizeof(addr));
+ memcpy(&addr[octets], sr.base, 16 - octets);
+ mask = 0xff >> (prefixlen % 8);
+ addr[octets] &= mask;
+ ar.base = addr;
+ ar.length = sizeof(addr);
+ RETERR(inet_totext(AF_INET6, &ar, target));
+ isc_region_consume(&sr, 16 - octets);
+ }
+
+ if (prefixlen == 0)
+ return (ISC_R_SUCCESS);
+
+ RETERR(str_totext(" ", target));
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+ dns_name_fromregion(&name, &sr);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_in_a6(ARGS_FROMWIRE) {
+ isc_region_t sr;
+ unsigned char prefixlen;
+ unsigned char octets;
+ unsigned char mask;
+ dns_name_t name;
+
+ REQUIRE(type == 38);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ isc_buffer_activeregion(source, &sr);
+ /*
+ * Prefix length.
+ */
+ if (sr.length < 1)
+ return (ISC_R_UNEXPECTEDEND);
+ prefixlen = sr.base[0];
+ if (prefixlen > 128)
+ return (ISC_R_RANGE);
+ isc_region_consume(&sr, 1);
+ RETERR(mem_tobuffer(target, &prefixlen, 1));
+ isc_buffer_forward(source, 1);
+
+ /*
+ * Suffix.
+ */
+ if (prefixlen != 128) {
+ octets = 16 - prefixlen / 8;
+ if (sr.length < octets)
+ return (ISC_R_UNEXPECTEDEND);
+ mask = 0xff >> (prefixlen % 8);
+ sr.base[0] &= mask; /* Ensure pad bits are zero. */
+ RETERR(mem_tobuffer(target, sr.base, octets));
+ isc_buffer_forward(source, octets);
+ }
+
+ if (prefixlen == 0)
+ return (ISC_R_SUCCESS);
+
+ dns_name_init(&name, NULL);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_in_a6(ARGS_TOWIRE) {
+ isc_region_t sr;
+ dns_name_t name;
+ dns_offsets_t offsets;
+ unsigned char prefixlen;
+ unsigned char octets;
+
+ REQUIRE(rdata->type == 38);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ dns_rdata_toregion(rdata, &sr);
+ prefixlen = sr.base[0];
+ INSIST(prefixlen <= 128);
+
+ octets = 1 + 16 - prefixlen / 8;
+ RETERR(mem_tobuffer(target, sr.base, octets));
+ isc_region_consume(&sr, octets);
+
+ if (prefixlen == 0)
+ return (ISC_R_SUCCESS);
+
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &sr);
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_in_a6(ARGS_COMPARE) {
+ int order;
+ unsigned char prefixlen1, prefixlen2;
+ unsigned char octets;
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 38);
+ REQUIRE(rdata1->rdclass == 1);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+ prefixlen1 = region1.base[0];
+ prefixlen2 = region2.base[0];
+ isc_region_consume(&region1, 1);
+ isc_region_consume(&region2, 1);
+ if (prefixlen1 < prefixlen2)
+ return (-1);
+ else if (prefixlen1 > prefixlen2)
+ return (1);
+ /*
+ * Prefix lengths are equal.
+ */
+ octets = 16 - prefixlen1 / 8;
+
+ if (octets > 0) {
+ order = memcmp(region1.base, region2.base, octets);
+ if (order < 0)
+ return (-1);
+ else if (order > 0)
+ return (1);
+ /*
+ * Address suffixes are equal.
+ */
+ if (prefixlen1 == 0)
+ return (order);
+ isc_region_consume(&region1, octets);
+ isc_region_consume(&region2, octets);
+ }
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_in_a6(ARGS_FROMSTRUCT) {
+ dns_rdata_in_a6_t *a6 = source;
+ isc_region_t region;
+ int octets;
+ isc_uint8_t bits;
+ isc_uint8_t first;
+ isc_uint8_t mask;
+
+ REQUIRE(type == 38);
+ REQUIRE(rdclass == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(a6->common.rdtype == type);
+ REQUIRE(a6->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ if (a6->prefixlen > 128)
+ return (ISC_R_RANGE);
+
+ RETERR(uint8_tobuffer(a6->prefixlen, target));
+
+ /* Suffix */
+ if (a6->prefixlen != 128) {
+ octets = 16 - a6->prefixlen / 8;
+ bits = a6->prefixlen % 8;
+ if (bits != 0) {
+ mask = 0xffU >> bits;
+ first = a6->in6_addr.s6_addr[16 - octets] & mask;
+ RETERR(uint8_tobuffer(first, target));
+ octets--;
+ }
+ if (octets > 0)
+ RETERR(mem_tobuffer(target,
+ a6->in6_addr.s6_addr + 16 - octets,
+ octets));
+ }
+
+ if (a6->prefixlen == 0)
+ return (ISC_R_SUCCESS);
+ dns_name_toregion(&a6->prefix, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_in_a6(ARGS_TOSTRUCT) {
+ dns_rdata_in_a6_t *a6 = target;
+ unsigned char octets;
+ dns_name_t name;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 38);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ a6->common.rdclass = rdata->rdclass;
+ a6->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&a6->common, link);
+
+ dns_rdata_toregion(rdata, &r);
+
+ a6->prefixlen = uint8_fromregion(&r);
+ isc_region_consume(&r, 1);
+ memset(a6->in6_addr.s6_addr, 0, sizeof(a6->in6_addr.s6_addr));
+
+ /*
+ * Suffix.
+ */
+ if (a6->prefixlen != 128) {
+ octets = 16 - a6->prefixlen / 8;
+ INSIST(r.length >= octets);
+ memcpy(a6->in6_addr.s6_addr + 16 - octets, r.base, octets);
+ isc_region_consume(&r, octets);
+ }
+
+ /*
+ * Prefix.
+ */
+ dns_name_init(&a6->prefix, NULL);
+ if (a6->prefixlen != 0) {
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+ RETERR(name_duporclone(&name, mctx, &a6->prefix));
+ }
+ a6->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_in_a6(ARGS_FREESTRUCT) {
+ dns_rdata_in_a6_t *a6 = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(a6->common.rdclass == 1);
+ REQUIRE(a6->common.rdtype == 38);
+
+ if (a6->mctx == NULL)
+ return;
+
+ if (dns_name_dynamic(&a6->prefix))
+ dns_name_free(&a6->prefix, a6->mctx);
+ a6->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_in_a6(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 38);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_in_a6(ARGS_DIGEST) {
+ isc_region_t r1, r2;
+ unsigned char prefixlen, octets;
+ isc_result_t result;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 38);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_rdata_toregion(rdata, &r1);
+ r2 = r1;
+ prefixlen = r1.base[0];
+ octets = 1 + 16 - prefixlen / 8;
+
+ r1.length = octets;
+ result = (digest)(arg, &r1);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (prefixlen == 0)
+ return (ISC_R_SUCCESS);
+
+ isc_region_consume(&r2, octets);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r2);
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_in_a6(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 38);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ return (dns_name_ishostname(name, wildcard));
+}
+
+static inline isc_boolean_t
+checknames_in_a6(ARGS_CHECKNAMES) {
+ isc_region_t region;
+ dns_name_t name;
+ unsigned int prefixlen;
+
+ REQUIRE(rdata->type == 38);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(owner);
+
+ dns_rdata_toregion(rdata, &region);
+ prefixlen = uint8_fromregion(&region);
+ if (prefixlen == 0)
+ return (ISC_TRUE);
+ isc_region_consume(&region, 1 + 16 - prefixlen / 8);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ishostname(&name, ISC_FALSE)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_IN_1_A6_38_C */
diff --git a/lib/dns/rdata/in_1/a6_38.h b/lib/dns/rdata/in_1/a6_38.h
new file mode 100644
index 0000000..bb15dad
--- /dev/null
+++ b/lib/dns/rdata/in_1/a6_38.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef IN_1_A6_38_H
+#define IN_1_A6_38_H 1
+
+/* $Id: a6_38.h,v 1.20.18.2 2005/04/29 00:16:41 marka Exp $ */
+
+/*!
+ * \brief Per RFC2874 */
+
+typedef struct dns_rdata_in_a6 {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t prefix;
+ isc_uint8_t prefixlen;
+ struct in6_addr in6_addr;
+} dns_rdata_in_a6_t;
+
+#endif /* IN_1_A6_38_H */
diff --git a/lib/dns/rdata/in_1/a_1.c b/lib/dns/rdata/in_1/a_1.c
new file mode 100644
index 0000000..e8cb8ce
--- /dev/null
+++ b/lib/dns/rdata/in_1/a_1.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: a_1.c,v 1.51 2004/03/05 05:10:23 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */
+
+#ifndef RDATA_IN_1_A_1_C
+#define RDATA_IN_1_A_1_C
+
+#include <string.h>
+
+#include <isc/net.h>
+
+#define RRTYPE_A_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_in_a(ARGS_FROMTEXT) {
+ isc_token_t token;
+ struct in_addr addr;
+ isc_region_t region;
+
+ REQUIRE(type == 1);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(rdclass);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ if (getquad(DNS_AS_STR(token), &addr, lexer, callbacks) != 1)
+ RETTOK(DNS_R_BADDOTTEDQUAD);
+ isc_buffer_availableregion(target, &region);
+ if (region.length < 4)
+ return (ISC_R_NOSPACE);
+ memcpy(region.base, &addr, 4);
+ isc_buffer_add(target, 4);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_in_a(ARGS_TOTEXT) {
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length == 4);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &region);
+ return (inet_totext(AF_INET, &region, target));
+}
+
+static inline isc_result_t
+fromwire_in_a(ARGS_FROMWIRE) {
+ isc_region_t sregion;
+ isc_region_t tregion;
+
+ REQUIRE(type == 1);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(options);
+ UNUSED(rdclass);
+
+ isc_buffer_activeregion(source, &sregion);
+ isc_buffer_availableregion(target, &tregion);
+ if (sregion.length < 4)
+ return (ISC_R_UNEXPECTEDEND);
+ if (tregion.length < 4)
+ return (ISC_R_NOSPACE);
+
+ memcpy(tregion.base, sregion.base, 4);
+ isc_buffer_forward(source, 4);
+ isc_buffer_add(target, 4);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_in_a(ARGS_TOWIRE) {
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length == 4);
+
+ UNUSED(cctx);
+
+ isc_buffer_availableregion(target, &region);
+ if (region.length < rdata->length)
+ return (ISC_R_NOSPACE);
+ memcpy(region.base, rdata->data, rdata->length);
+ isc_buffer_add(target, 4);
+ return (ISC_R_SUCCESS);
+}
+
+static inline int
+compare_in_a(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 1);
+ REQUIRE(rdata1->rdclass == 1);
+ REQUIRE(rdata1->length == 4);
+ REQUIRE(rdata2->length == 4);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_in_a(ARGS_FROMSTRUCT) {
+ dns_rdata_in_a_t *a = source;
+ isc_uint32_t n;
+
+ REQUIRE(type == 1);
+ REQUIRE(rdclass == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(a->common.rdtype == type);
+ REQUIRE(a->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ n = ntohl(a->in_addr.s_addr);
+
+ return (uint32_tobuffer(n, target));
+}
+
+
+static inline isc_result_t
+tostruct_in_a(ARGS_TOSTRUCT) {
+ dns_rdata_in_a_t *a = target;
+ isc_uint32_t n;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length == 4);
+
+ UNUSED(mctx);
+
+ a->common.rdclass = rdata->rdclass;
+ a->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&a->common, link);
+
+ dns_rdata_toregion(rdata, &region);
+ n = uint32_fromregion(&region);
+ a->in_addr.s_addr = htonl(n);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_in_a(ARGS_FREESTRUCT) {
+ dns_rdata_in_a_t *a = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(a->common.rdtype == 1);
+ REQUIRE(a->common.rdclass == 1);
+
+ UNUSED(a);
+}
+
+static inline isc_result_t
+additionaldata_in_a(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_in_a(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_in_a(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 1);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ return (dns_name_ishostname(name, wildcard));
+}
+
+static inline isc_boolean_t
+checknames_in_a(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 1);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_IN_1_A_1_C */
diff --git a/lib/dns/rdata/in_1/a_1.h b/lib/dns/rdata/in_1/a_1.h
new file mode 100644
index 0000000..d92a973
--- /dev/null
+++ b/lib/dns/rdata/in_1/a_1.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.
+ */
+
+/* */
+#ifndef IN_1_A_1_H
+#define IN_1_A_1_H 1
+
+/* $Id: a_1.h,v 1.24.18.2 2005/04/29 00:16:41 marka Exp $ */
+
+typedef struct dns_rdata_in_a {
+ dns_rdatacommon_t common;
+ struct in_addr in_addr;
+} dns_rdata_in_a_t;
+
+#endif /* IN_1_A_1_H */
diff --git a/lib/dns/rdata/in_1/aaaa_28.c b/lib/dns/rdata/in_1/aaaa_28.c
new file mode 100644
index 0000000..1dd32cf
--- /dev/null
+++ b/lib/dns/rdata/in_1/aaaa_28.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2004, 2005 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: aaaa_28.c,v 1.41.18.2 2005/04/29 00:16:41 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */
+
+/* RFC1886 */
+
+#ifndef RDATA_IN_1_AAAA_28_C
+#define RDATA_IN_1_AAAA_28_C
+
+#include <isc/net.h>
+
+#define RRTYPE_AAAA_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_in_aaaa(ARGS_FROMTEXT) {
+ isc_token_t token;
+ unsigned char addr[16];
+ isc_region_t region;
+
+ REQUIRE(type == 28);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ if (inet_pton(AF_INET6, DNS_AS_STR(token), addr) != 1)
+ RETTOK(DNS_R_BADAAAA);
+ isc_buffer_availableregion(target, &region);
+ if (region.length < 16)
+ return (ISC_R_NOSPACE);
+ memcpy(region.base, addr, 16);
+ isc_buffer_add(target, 16);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_in_aaaa(ARGS_TOTEXT) {
+ isc_region_t region;
+
+ UNUSED(tctx);
+
+ REQUIRE(rdata->type == 28);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length == 16);
+
+ dns_rdata_toregion(rdata, &region);
+ return (inet_totext(AF_INET6, &region, target));
+}
+
+static inline isc_result_t
+fromwire_in_aaaa(ARGS_FROMWIRE) {
+ isc_region_t sregion;
+ isc_region_t tregion;
+
+ REQUIRE(type == 28);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(options);
+ UNUSED(rdclass);
+
+ isc_buffer_activeregion(source, &sregion);
+ isc_buffer_availableregion(target, &tregion);
+ if (sregion.length < 16)
+ return (ISC_R_UNEXPECTEDEND);
+ if (tregion.length < 16)
+ return (ISC_R_NOSPACE);
+
+ memcpy(tregion.base, sregion.base, 16);
+ isc_buffer_forward(source, 16);
+ isc_buffer_add(target, 16);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_in_aaaa(ARGS_TOWIRE) {
+ isc_region_t region;
+
+ UNUSED(cctx);
+
+ REQUIRE(rdata->type == 28);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length == 16);
+
+ isc_buffer_availableregion(target, &region);
+ if (region.length < rdata->length)
+ return (ISC_R_NOSPACE);
+ memcpy(region.base, rdata->data, rdata->length);
+ isc_buffer_add(target, 16);
+ return (ISC_R_SUCCESS);
+}
+
+static inline int
+compare_in_aaaa(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 28);
+ REQUIRE(rdata1->rdclass == 1);
+ REQUIRE(rdata1->length == 16);
+ REQUIRE(rdata2->length == 16);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_in_aaaa(ARGS_FROMSTRUCT) {
+ dns_rdata_in_aaaa_t *aaaa = source;
+
+ REQUIRE(type == 28);
+ REQUIRE(rdclass == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(aaaa->common.rdtype == type);
+ REQUIRE(aaaa->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ return (mem_tobuffer(target, aaaa->in6_addr.s6_addr, 16));
+}
+
+static inline isc_result_t
+tostruct_in_aaaa(ARGS_TOSTRUCT) {
+ dns_rdata_in_aaaa_t *aaaa = target;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 28);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length == 16);
+
+ UNUSED(mctx);
+
+ aaaa->common.rdclass = rdata->rdclass;
+ aaaa->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&aaaa->common, link);
+
+ dns_rdata_toregion(rdata, &r);
+ INSIST(r.length == 16);
+ memcpy(aaaa->in6_addr.s6_addr, r.base, 16);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_in_aaaa(ARGS_FREESTRUCT) {
+ dns_rdata_in_aaaa_t *aaaa = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(aaaa->common.rdclass == 1);
+ REQUIRE(aaaa->common.rdtype == 28);
+
+ UNUSED(aaaa);
+}
+
+static inline isc_result_t
+additionaldata_in_aaaa(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 28);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_in_aaaa(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 28);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_in_aaaa(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 28);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ return (dns_name_ishostname(name, wildcard));
+}
+
+static inline isc_boolean_t
+checknames_in_aaaa(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 28);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_IN_1_AAAA_28_C */
diff --git a/lib/dns/rdata/in_1/aaaa_28.h b/lib/dns/rdata/in_1/aaaa_28.h
new file mode 100644
index 0000000..31ad6a6
--- /dev/null
+++ b/lib/dns/rdata/in_1/aaaa_28.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef IN_1_AAAA_28_H
+#define IN_1_AAAA_28_H 1
+
+/* $Id: aaaa_28.h,v 1.17.18.2 2005/04/29 00:16:42 marka Exp $ */
+
+/*!
+ * \brief Per RFC1886 */
+
+typedef struct dns_rdata_in_aaaa {
+ dns_rdatacommon_t common;
+ struct in6_addr in6_addr;
+} dns_rdata_in_aaaa_t;
+
+#endif /* IN_1_AAAA_28_H */
diff --git a/lib/dns/rdata/in_1/apl_42.c b/lib/dns/rdata/in_1/apl_42.c
new file mode 100644
index 0000000..42b2e7f
--- /dev/null
+++ b/lib/dns/rdata/in_1/apl_42.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: apl_42.c,v 1.8.18.2 2005/04/29 00:16:42 marka Exp $ */
+
+/* RFC3123 */
+
+#ifndef RDATA_IN_1_APL_42_C
+#define RDATA_IN_1_APL_42_C
+
+#define RRTYPE_APL_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_in_apl(ARGS_FROMTEXT) {
+ isc_token_t token;
+ unsigned char addr[16];
+ unsigned long afi;
+ isc_uint8_t prefix;
+ isc_uint8_t len;
+ isc_boolean_t neg;
+ char *cp, *ap, *slash;
+ int n;
+
+ REQUIRE(type == 42);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(callbacks);
+
+ do {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string, ISC_TRUE));
+ if (token.type != isc_tokentype_string)
+ break;
+
+ cp = DNS_AS_STR(token);
+ neg = ISC_TF(*cp == '!');
+ if (neg)
+ cp++;
+ afi = strtoul(cp, &ap, 10);
+ if (*ap++ != ':' || cp == ap)
+ RETTOK(DNS_R_SYNTAX);
+ if (afi > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ slash = strchr(ap, '/');
+ if (slash == NULL || slash == ap)
+ RETTOK(DNS_R_SYNTAX);
+ RETTOK(isc_parse_uint8(&prefix, slash + 1, 10));
+ switch (afi) {
+ case 1:
+ *slash = '\0';
+ n = inet_pton(AF_INET, ap, addr);
+ *slash = '/';
+ if (n != 1)
+ RETTOK(DNS_R_BADDOTTEDQUAD);
+ if (prefix > 32)
+ RETTOK(ISC_R_RANGE);
+ for (len = 4; len > 0; len--)
+ if (addr[len - 1] != 0)
+ break;
+ break;
+
+ case 2:
+ *slash = '\0';
+ n = inet_pton(AF_INET6, ap, addr);
+ *slash = '/';
+ if (n != 1)
+ RETTOK(DNS_R_BADAAAA);
+ if (prefix > 128)
+ RETTOK(ISC_R_RANGE);
+ for (len = 16; len > 0; len--)
+ if (addr[len - 1] != 0)
+ break;
+ break;
+
+ default:
+ RETTOK(ISC_R_NOTIMPLEMENTED);
+ }
+ RETERR(uint16_tobuffer(afi, target));
+ RETERR(uint8_tobuffer(prefix, target));
+ RETERR(uint8_tobuffer(len | ((neg) ? 0x80 : 0), target));
+ RETERR(mem_tobuffer(target, addr, len));
+ } while (1);
+
+ /*
+ * Let upper layer handle eol/eof.
+ */
+ isc_lex_ungettoken(lexer, &token);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_in_apl(ARGS_TOTEXT) {
+ isc_region_t sr;
+ isc_region_t ir;
+ isc_uint16_t afi;
+ isc_uint8_t prefix;
+ isc_uint8_t len;
+ isc_boolean_t neg;
+ unsigned char buf[16];
+ char txt[sizeof(" !64000")];
+ const char *sep = "";
+ int n;
+
+ REQUIRE(rdata->type == 42);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &sr);
+ ir.base = buf;
+ ir.length = sizeof(buf);
+
+ while (sr.length > 0) {
+ INSIST(sr.length >= 4);
+ afi = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ prefix = *sr.base;
+ isc_region_consume(&sr, 1);
+ len = (*sr.base & 0x7f);
+ neg = ISC_TF((*sr.base & 0x80) != 0);
+ isc_region_consume(&sr, 1);
+ INSIST(len <= sr.length);
+ n = snprintf(txt, sizeof(txt), "%s%s%u:", sep,
+ neg ? "!": "", afi);
+ INSIST(n < (int)sizeof(txt));
+ RETERR(str_totext(txt, target));
+ switch (afi) {
+ case 1:
+ INSIST(len <= 4);
+ INSIST(prefix <= 32);
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, sr.base, len);
+ RETERR(inet_totext(AF_INET, &ir, target));
+ break;
+
+ case 2:
+ INSIST(len <= 16);
+ INSIST(prefix <= 128);
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, sr.base, len);
+ RETERR(inet_totext(AF_INET6, &ir, target));
+ break;
+
+ default:
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+ n = snprintf(txt, sizeof(txt), "/%u", prefix);
+ INSIST(n < (int)sizeof(txt));
+ RETERR(str_totext(txt, target));
+ isc_region_consume(&sr, len);
+ sep = " ";
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_in_apl(ARGS_FROMWIRE) {
+ isc_region_t sr, sr2;
+ isc_region_t tr;
+ isc_uint16_t afi;
+ isc_uint8_t prefix;
+ isc_uint8_t len;
+
+ REQUIRE(type == 42);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(rdclass);
+ UNUSED(options);
+
+ isc_buffer_activeregion(source, &sr);
+ isc_buffer_availableregion(target, &tr);
+ if (sr.length > tr.length)
+ return (ISC_R_NOSPACE);
+ sr2 = sr;
+
+ /* Zero or more items */
+ while (sr.length > 0) {
+ if (sr.length < 4)
+ return (ISC_R_UNEXPECTEDEND);
+ afi = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+ prefix = *sr.base;
+ isc_region_consume(&sr, 1);
+ len = (*sr.base & 0x7f);
+ isc_region_consume(&sr, 1);
+ if (len > sr.length)
+ return (ISC_R_UNEXPECTEDEND);
+ switch (afi) {
+ case 1:
+ if (prefix > 32 || len > 4)
+ return (ISC_R_RANGE);
+ break;
+ case 2:
+ if (prefix > 128 || len > 16)
+ return (ISC_R_RANGE);
+ }
+ if (len > 0 && sr.base[len - 1] == 0)
+ return (DNS_R_FORMERR);
+ isc_region_consume(&sr, len);
+ }
+ isc_buffer_forward(source, sr2.length);
+ return (mem_tobuffer(target, sr2.base, sr2.length));
+}
+
+static inline isc_result_t
+towire_in_apl(ARGS_TOWIRE) {
+ UNUSED(cctx);
+
+ REQUIRE(rdata->type == 42);
+ REQUIRE(rdata->rdclass == 1);
+
+ return (mem_tobuffer(target, rdata->data, rdata->length));
+}
+
+static inline int
+compare_in_apl(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 42);
+ REQUIRE(rdata1->rdclass == 1);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_in_apl(ARGS_FROMSTRUCT) {
+ dns_rdata_in_apl_t *apl = source;
+ isc_buffer_t b;
+
+ REQUIRE(type == 42);
+ REQUIRE(rdclass == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(apl->common.rdtype == type);
+ REQUIRE(apl->common.rdclass == rdclass);
+ REQUIRE(apl->apl != NULL || apl->apl_len == 0);
+
+ isc_buffer_init(&b, apl->apl, apl->apl_len);
+ isc_buffer_add(&b, apl->apl_len);
+ isc_buffer_setactive(&b, apl->apl_len);
+ return(fromwire_in_apl(rdclass, type, &b, NULL, ISC_FALSE, target));
+}
+
+static inline isc_result_t
+tostruct_in_apl(ARGS_TOSTRUCT) {
+ dns_rdata_in_apl_t *apl = target;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 42);
+ REQUIRE(rdata->rdclass == 1);
+
+ apl->common.rdclass = rdata->rdclass;
+ apl->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&apl->common, link);
+
+ dns_rdata_toregion(rdata, &r);
+ apl->apl_len = r.length;
+ apl->apl = mem_maybedup(mctx, r.base, r.length);
+ if (apl->apl == NULL)
+ return (ISC_R_NOMEMORY);
+
+ apl->offset = 0;
+ apl->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_in_apl(ARGS_FREESTRUCT) {
+ dns_rdata_in_apl_t *apl = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(apl->common.rdtype == 42);
+ REQUIRE(apl->common.rdclass == 1);
+
+ if (apl->mctx == NULL)
+ return;
+ if (apl->apl != NULL)
+ isc_mem_free(apl->mctx, apl->apl);
+ apl->mctx = NULL;
+}
+
+isc_result_t
+dns_rdata_apl_first(dns_rdata_in_apl_t *apl) {
+ REQUIRE(apl->common.rdtype == 42);
+ REQUIRE(apl->common.rdclass == 1);
+ REQUIRE(apl->apl != NULL || apl->apl_len == 0);
+
+ apl->offset = 0;
+ return ((apl->apl_len != 0) ? ISC_R_SUCCESS : ISC_R_NOMORE);
+}
+
+isc_result_t
+dns_rdata_apl_next(dns_rdata_in_apl_t *apl) {
+ REQUIRE(apl->common.rdtype == 42);
+ REQUIRE(apl->common.rdclass == 1);
+ REQUIRE(apl->apl != NULL || apl->apl_len == 0);
+
+ if (apl->offset + 3 < apl->apl_len)
+ return (ISC_R_NOMORE);
+ apl->offset += apl->apl[apl->offset + 3] & 0x7f;
+ return ((apl->offset >= apl->apl_len) ? ISC_R_SUCCESS : ISC_R_NOMORE);
+}
+
+isc_result_t
+dns_rdata_apl_current(dns_rdata_in_apl_t *apl, dns_rdata_apl_ent_t *ent) {
+
+ REQUIRE(apl->common.rdtype == 42);
+ REQUIRE(apl->common.rdclass == 1);
+ REQUIRE(ent != NULL);
+ REQUIRE(apl->apl != NULL || apl->apl_len == 0);
+
+ if (apl->offset >= apl->apl_len)
+ return (ISC_R_NOMORE);
+
+ ent->family = (apl->apl[apl->offset] << 8) + apl->apl[apl->offset + 1];
+ ent->prefix = apl->apl[apl->offset + 2];
+ ent->length = apl->apl[apl->offset + 3] & 0x7f;
+ ent->negative = ISC_TF((apl->apl[apl->offset + 3] & 0x80) != 0);
+ if (ent->length != 0)
+ ent->data = &apl->apl[apl->offset + 4];
+ else
+ ent->data = NULL;
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+additionaldata_in_apl(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 42);
+ REQUIRE(rdata->rdclass == 1);
+
+ (void)add;
+ (void)arg;
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_in_apl(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 42);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_in_apl(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 42);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+
+static inline isc_boolean_t
+checknames_in_apl(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 42);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_IN_1_APL_42_C */
diff --git a/lib/dns/rdata/in_1/apl_42.h b/lib/dns/rdata/in_1/apl_42.h
new file mode 100644
index 0000000..d434ace
--- /dev/null
+++ b/lib/dns/rdata/in_1/apl_42.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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.
+ */
+
+/* */
+#ifndef IN_1_APL_42_H
+#define IN_1_APL_42_H 1
+
+/* $Id: apl_42.h,v 1.2.18.2 2005/04/29 00:16:42 marka Exp $ */
+
+typedef struct dns_rdata_apl_ent {
+ isc_boolean_t negative;
+ isc_uint16_t family;
+ isc_uint8_t prefix;
+ isc_uint8_t length;
+ unsigned char *data;
+} dns_rdata_apl_ent_t;
+
+typedef struct dns_rdata_in_apl {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ /* type & class specific elements */
+ unsigned char *apl;
+ isc_uint16_t apl_len;
+ /* private */
+ isc_uint16_t offset;
+} dns_rdata_in_apl_t;
+
+/*
+ * ISC_LANG_BEGINDECLS and ISC_LANG_ENDDECLS are already done
+ * via rdatastructpre.h and rdatastructsuf.h.
+ */
+
+isc_result_t
+dns_rdata_apl_first(dns_rdata_in_apl_t *);
+
+isc_result_t
+dns_rdata_apl_next(dns_rdata_in_apl_t *);
+
+isc_result_t
+dns_rdata_apl_current(dns_rdata_in_apl_t *, dns_rdata_apl_ent_t *);
+
+#endif /* IN_1_APL_42_H */
diff --git a/lib/dns/rdata/in_1/kx_36.c b/lib/dns/rdata/in_1/kx_36.c
new file mode 100644
index 0000000..8a64aac
--- /dev/null
+++ b/lib/dns/rdata/in_1/kx_36.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2004, 2005 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: kx_36.c,v 1.41.18.2 2005/04/29 00:16:42 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 17:24:54 PST 2000 by explorer */
+
+/* RFC2230 */
+
+#ifndef RDATA_IN_1_KX_36_C
+#define RDATA_IN_1_KX_36_C
+
+#define RRTYPE_KX_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_in_kx(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 36);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_in_kx(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+ char buf[sizeof("64000")];
+ unsigned short num;
+
+ REQUIRE(rdata->type == 36);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ num = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ sprintf(buf, "%u", num);
+ RETERR(str_totext(buf, target));
+
+ RETERR(str_totext(" ", target));
+
+ dns_name_fromregion(&name, &region);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_in_kx(ARGS_FROMWIRE) {
+ dns_name_t name;
+ isc_region_t sregion;
+
+ REQUIRE(type == 36);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&name, NULL);
+
+ isc_buffer_activeregion(source, &sregion);
+ if (sregion.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ RETERR(mem_tobuffer(target, sregion.base, 2));
+ isc_buffer_forward(source, 2);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_in_kx(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 36);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ dns_rdata_toregion(rdata, &region);
+ RETERR(mem_tobuffer(target, region.base, 2));
+ isc_region_consume(&region, 2);
+
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_in_kx(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 36);
+ REQUIRE(rdata1->rdclass == 1);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ order = memcmp(rdata1->data, rdata2->data, 2);
+ if (order != 0)
+ return (order < 0 ? -1 : 1);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ isc_region_consume(&region1, 2);
+ isc_region_consume(&region2, 2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_in_kx(ARGS_FROMSTRUCT) {
+ dns_rdata_in_kx_t *kx = source;
+ isc_region_t region;
+
+ REQUIRE(type == 36);
+ REQUIRE(rdclass == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(kx->common.rdtype == type);
+ REQUIRE(kx->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint16_tobuffer(kx->preference, target));
+ dns_name_toregion(&kx->exchange, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_in_kx(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_in_kx_t *kx = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 36);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ kx->common.rdclass = rdata->rdclass;
+ kx->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&kx->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+
+ kx->preference = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&kx->exchange, NULL);
+ RETERR(name_duporclone(&name, mctx, &kx->exchange));
+ kx->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_in_kx(ARGS_FREESTRUCT) {
+ dns_rdata_in_kx_t *kx = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(kx->common.rdclass == 1);
+ REQUIRE(kx->common.rdtype == 36);
+
+ if (kx->mctx == NULL)
+ return;
+
+ dns_name_free(&kx->exchange, kx->mctx);
+ kx->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_in_kx(ARGS_ADDLDATA) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 36);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ isc_region_consume(&region, 2);
+ dns_name_fromregion(&name, &region);
+
+ return ((add)(arg, &name, dns_rdatatype_a));
+}
+
+static inline isc_result_t
+digest_in_kx(ARGS_DIGEST) {
+ isc_region_t r1, r2;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 36);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_rdata_toregion(rdata, &r1);
+ r2 = r1;
+ isc_region_consume(&r2, 2);
+ r1.length = 2;
+ RETERR((digest)(arg, &r1));
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r2);
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_in_kx(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 36);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_in_kx(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 36);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_IN_1_KX_36_C */
diff --git a/lib/dns/rdata/in_1/kx_36.h b/lib/dns/rdata/in_1/kx_36.h
new file mode 100644
index 0000000..c44883d
--- /dev/null
+++ b/lib/dns/rdata/in_1/kx_36.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef IN_1_KX_36_H
+#define IN_1_KX_36_H 1
+
+/* $Id: kx_36.h,v 1.16.18.2 2005/04/29 00:16:42 marka Exp $ */
+
+/*!
+ * \brief Per RFC2230 */
+
+typedef struct dns_rdata_in_kx {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t preference;
+ dns_name_t exchange;
+} dns_rdata_in_kx_t;
+
+#endif /* IN_1_KX_36_H */
diff --git a/lib/dns/rdata/in_1/naptr_35.c b/lib/dns/rdata/in_1/naptr_35.c
new file mode 100644
index 0000000..0e5961a
--- /dev/null
+++ b/lib/dns/rdata/in_1/naptr_35.c
@@ -0,0 +1,578 @@
+/*
+ * Copyright (C) 2004, 2005 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: naptr_35.c,v 1.47.18.2 2005/04/29 00:16:42 marka Exp $ */
+
+/* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */
+
+/* RFC2915 */
+
+#ifndef RDATA_IN_1_NAPTR_35_C
+#define RDATA_IN_1_NAPTR_35_C
+
+#define RRTYPE_NAPTR_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_in_naptr(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 35);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Order.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Preference.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Flags.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
+ ISC_FALSE));
+ RETTOK(txt_fromtext(&token.value.as_textregion, target));
+
+ /*
+ * Service.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
+ ISC_FALSE));
+ RETTOK(txt_fromtext(&token.value.as_textregion, target));
+
+ /*
+ * Regexp.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
+ ISC_FALSE));
+ RETTOK(txt_fromtext(&token.value.as_textregion, target));
+
+ /*
+ * Replacement.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_in_naptr(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+ char buf[sizeof("64000")];
+ unsigned short num;
+
+ REQUIRE(rdata->type == 35);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+
+ /*
+ * Order.
+ */
+ num = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ sprintf(buf, "%u", num);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Preference.
+ */
+ num = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ sprintf(buf, "%u", num);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Flags.
+ */
+ RETERR(txt_totext(&region, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Service.
+ */
+ RETERR(txt_totext(&region, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Regexp.
+ */
+ RETERR(txt_totext(&region, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Replacement.
+ */
+ dns_name_fromregion(&name, &region);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_in_naptr(ARGS_FROMWIRE) {
+ dns_name_t name;
+ isc_region_t sr;
+
+ REQUIRE(type == 35);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&name, NULL);
+
+ /*
+ * Order, preference.
+ */
+ isc_buffer_activeregion(source, &sr);
+ if (sr.length < 4)
+ return (ISC_R_UNEXPECTEDEND);
+ RETERR(mem_tobuffer(target, sr.base, 4));
+ isc_buffer_forward(source, 4);
+
+ /*
+ * Flags.
+ */
+ RETERR(txt_fromwire(source, target));
+
+ /*
+ * Service.
+ */
+ RETERR(txt_fromwire(source, target));
+
+ /*
+ * Regexp.
+ */
+ RETERR(txt_fromwire(source, target));
+
+ /*
+ * Replacement.
+ */
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_in_naptr(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 35);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ /*
+ * Order, preference.
+ */
+ dns_rdata_toregion(rdata, &sr);
+ RETERR(mem_tobuffer(target, sr.base, 4));
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Flags.
+ */
+ RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1));
+ isc_region_consume(&sr, sr.base[0] + 1);
+
+ /*
+ * Service.
+ */
+ RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1));
+ isc_region_consume(&sr, sr.base[0] + 1);
+
+ /*
+ * Regexp.
+ */
+ RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1));
+ isc_region_consume(&sr, sr.base[0] + 1);
+
+ /*
+ * Replacement.
+ */
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &sr);
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_in_naptr(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+ int order, len;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 35);
+ REQUIRE(rdata1->rdclass == 1);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ /*
+ * Order, preference.
+ */
+ order = memcmp(region1.base, region2.base, 4);
+ if (order != 0)
+ return (order < 0 ? -1 : 1);
+ isc_region_consume(&region1, 4);
+ isc_region_consume(&region2, 4);
+
+ /*
+ * Flags.
+ */
+ len = ISC_MIN(region1.base[0], region2.base[0]);
+ order = memcmp(region1.base, region2.base, len + 1);
+ if (order != 0)
+ return (order < 0 ? -1 : 1);
+ isc_region_consume(&region1, region1.base[0] + 1);
+ isc_region_consume(&region2, region2.base[0] + 1);
+
+ /*
+ * Service.
+ */
+ len = ISC_MIN(region1.base[0], region2.base[0]);
+ order = memcmp(region1.base, region2.base, len + 1);
+ if (order != 0)
+ return (order < 0 ? -1 : 1);
+ isc_region_consume(&region1, region1.base[0] + 1);
+ isc_region_consume(&region2, region2.base[0] + 1);
+
+ /*
+ * Regexp.
+ */
+ len = ISC_MIN(region1.base[0], region2.base[0]);
+ order = memcmp(region1.base, region2.base, len + 1);
+ if (order != 0)
+ return (order < 0 ? -1 : 1);
+ isc_region_consume(&region1, region1.base[0] + 1);
+ isc_region_consume(&region2, region2.base[0] + 1);
+
+ /*
+ * Replacement.
+ */
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_in_naptr(ARGS_FROMSTRUCT) {
+ dns_rdata_in_naptr_t *naptr = source;
+ isc_region_t region;
+
+ REQUIRE(type == 35);
+ REQUIRE(rdclass == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(naptr->common.rdtype == type);
+ REQUIRE(naptr->common.rdclass == rdclass);
+ REQUIRE(naptr->flags != NULL || naptr->flags_len == 0);
+ REQUIRE(naptr->service != NULL && naptr->service_len == 0);
+ REQUIRE(naptr->regexp != NULL && naptr->regexp_len == 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint16_tobuffer(naptr->order, target));
+ RETERR(uint16_tobuffer(naptr->preference, target));
+ RETERR(uint8_tobuffer(naptr->flags_len, target));
+ RETERR(mem_tobuffer(target, naptr->flags, naptr->flags_len));
+ RETERR(uint8_tobuffer(naptr->service_len, target));
+ RETERR(mem_tobuffer(target, naptr->service, naptr->service_len));
+ RETERR(uint8_tobuffer(naptr->regexp_len, target));
+ RETERR(mem_tobuffer(target, naptr->regexp, naptr->regexp_len));
+ dns_name_toregion(&naptr->replacement, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_in_naptr(ARGS_TOSTRUCT) {
+ dns_rdata_in_naptr_t *naptr = target;
+ isc_region_t r;
+ isc_result_t result;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 35);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ naptr->common.rdclass = rdata->rdclass;
+ naptr->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&naptr->common, link);
+
+ naptr->flags = NULL;
+ naptr->service = NULL;
+ naptr->regexp = NULL;
+
+ dns_rdata_toregion(rdata, &r);
+
+ naptr->order = uint16_fromregion(&r);
+ isc_region_consume(&r, 2);
+
+ naptr->preference = uint16_fromregion(&r);
+ isc_region_consume(&r, 2);
+
+ naptr->flags_len = uint8_fromregion(&r);
+ isc_region_consume(&r, 1);
+ INSIST(naptr->flags_len <= r.length);
+ naptr->flags = mem_maybedup(mctx, r.base, naptr->flags_len);
+ if (naptr->flags == NULL)
+ goto cleanup;
+ isc_region_consume(&r, naptr->flags_len);
+
+ naptr->service_len = uint8_fromregion(&r);
+ isc_region_consume(&r, 1);
+ INSIST(naptr->service_len <= r.length);
+ naptr->service = mem_maybedup(mctx, r.base, naptr->service_len);
+ if (naptr->service == NULL)
+ goto cleanup;
+ isc_region_consume(&r, naptr->service_len);
+
+ naptr->regexp_len = uint8_fromregion(&r);
+ isc_region_consume(&r, 1);
+ INSIST(naptr->regexp_len <= r.length);
+ naptr->regexp = mem_maybedup(mctx, r.base, naptr->regexp_len);
+ if (naptr->regexp == NULL)
+ goto cleanup;
+ isc_region_consume(&r, naptr->regexp_len);
+
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+ dns_name_init(&naptr->replacement, NULL);
+ result = name_duporclone(&name, mctx, &naptr->replacement);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ naptr->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (mctx != NULL && naptr->flags != NULL)
+ isc_mem_free(mctx, naptr->flags);
+ if (mctx != NULL && naptr->service != NULL)
+ isc_mem_free(mctx, naptr->service);
+ if (mctx != NULL && naptr->regexp != NULL)
+ isc_mem_free(mctx, naptr->regexp);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_in_naptr(ARGS_FREESTRUCT) {
+ dns_rdata_in_naptr_t *naptr = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(naptr->common.rdclass == 1);
+ REQUIRE(naptr->common.rdtype == 35);
+
+ if (naptr->mctx == NULL)
+ return;
+
+ if (naptr->flags != NULL)
+ isc_mem_free(naptr->mctx, naptr->flags);
+ if (naptr->service != NULL)
+ isc_mem_free(naptr->mctx, naptr->service);
+ if (naptr->regexp != NULL)
+ isc_mem_free(naptr->mctx, naptr->regexp);
+ dns_name_free(&naptr->replacement, naptr->mctx);
+ naptr->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_in_naptr(ARGS_ADDLDATA) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t sr;
+ dns_rdatatype_t atype;
+ unsigned int i, flagslen;
+ char *cp;
+
+ REQUIRE(rdata->type == 35);
+ REQUIRE(rdata->rdclass == 1);
+
+ /*
+ * Order, preference.
+ */
+ dns_rdata_toregion(rdata, &sr);
+ isc_region_consume(&sr, 4);
+
+ /*
+ * Flags.
+ */
+ atype = 0;
+ flagslen = sr.base[0];
+ cp = (char *)&sr.base[1];
+ for (i = 0; i < flagslen; i++, cp++) {
+ if (*cp == 'S' || *cp == 's') {
+ atype = dns_rdatatype_srv;
+ break;
+ }
+ if (*cp == 'A' || *cp == 'a') {
+ atype = dns_rdatatype_a;
+ break;
+ }
+ }
+ isc_region_consume(&sr, flagslen + 1);
+
+ /*
+ * Service.
+ */
+ isc_region_consume(&sr, sr.base[0] + 1);
+
+ /*
+ * Regexp.
+ */
+ isc_region_consume(&sr, sr.base[0] + 1);
+
+ /*
+ * Replacement.
+ */
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &sr);
+
+ if (atype != 0)
+ return ((add)(arg, &name, atype));
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_in_naptr(ARGS_DIGEST) {
+ isc_region_t r1, r2;
+ unsigned int length, n;
+ isc_result_t result;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 35);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_rdata_toregion(rdata, &r1);
+ r2 = r1;
+ length = 0;
+
+ /*
+ * Order, preference.
+ */
+ length += 4;
+ isc_region_consume(&r2, 4);
+
+ /*
+ * Flags.
+ */
+ n = r2.base[0] + 1;
+ length += n;
+ isc_region_consume(&r2, n);
+
+ /*
+ * Service.
+ */
+ n = r2.base[0] + 1;
+ length += n;
+ isc_region_consume(&r2, n);
+
+ /*
+ * Regexp.
+ */
+ n = r2.base[0] + 1;
+ length += n;
+ isc_region_consume(&r2, n);
+
+ /*
+ * Digest the RR up to the replacement name.
+ */
+ r1.length = length;
+ result = (digest)(arg, &r1);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Replacement.
+ */
+
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r2);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_in_naptr(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 35);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_in_naptr(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 35);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_IN_1_NAPTR_35_C */
diff --git a/lib/dns/rdata/in_1/naptr_35.h b/lib/dns/rdata/in_1/naptr_35.h
new file mode 100644
index 0000000..2578b48
--- /dev/null
+++ b/lib/dns/rdata/in_1/naptr_35.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef IN_1_NAPTR_35_H
+#define IN_1_NAPTR_35_H 1
+
+/* $Id: naptr_35.h,v 1.19.18.2 2005/04/29 00:16:42 marka Exp $ */
+
+/*!
+ * \brief Per RFC2915 */
+
+typedef struct dns_rdata_in_naptr {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t order;
+ isc_uint16_t preference;
+ char *flags;
+ isc_uint8_t flags_len;
+ char *service;
+ isc_uint8_t service_len;
+ char *regexp;
+ isc_uint8_t regexp_len;
+ dns_name_t replacement;
+} dns_rdata_in_naptr_t;
+
+#endif /* IN_1_NAPTR_35_H */
diff --git a/lib/dns/rdata/in_1/nsap-ptr_23.c b/lib/dns/rdata/in_1/nsap-ptr_23.c
new file mode 100644
index 0000000..1a65cbe
--- /dev/null
+++ b/lib/dns/rdata/in_1/nsap-ptr_23.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2004, 2005 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: nsap-ptr_23.c,v 1.34.18.2 2005/04/29 00:16:42 marka Exp $ */
+
+/* Reviewed: Fri Mar 17 10:16:02 PST 2000 by gson */
+
+/* RFC1348. Obsoleted in RFC 1706 - use PTR instead. */
+
+#ifndef RDATA_IN_1_NSAP_PTR_23_C
+#define RDATA_IN_1_NSAP_PTR_23_C
+
+#define RRTYPE_NSAP_PTR_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_in_nsap_ptr(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 23);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_in_nsap_ptr(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+
+ REQUIRE(rdata->type == 23);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ sub = name_prefix(&name, tctx->origin, &prefix);
+
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_in_nsap_ptr(ARGS_FROMWIRE) {
+ dns_name_t name;
+
+ REQUIRE(type == 23);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&name, NULL);
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_in_nsap_ptr(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 23);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_in_nsap_ptr(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 23);
+ REQUIRE(rdata1->rdclass == 1);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_in_nsap_ptr(ARGS_FROMSTRUCT) {
+ dns_rdata_in_nsap_ptr_t *nsap_ptr = source;
+ isc_region_t region;
+
+ REQUIRE(type == 23);
+ REQUIRE(rdclass == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(nsap_ptr->common.rdtype == type);
+ REQUIRE(nsap_ptr->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_name_toregion(&nsap_ptr->owner, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_in_nsap_ptr(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_in_nsap_ptr_t *nsap_ptr = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 23);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ nsap_ptr->common.rdclass = rdata->rdclass;
+ nsap_ptr->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&nsap_ptr->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&nsap_ptr->owner, NULL);
+ RETERR(name_duporclone(&name, mctx, &nsap_ptr->owner));
+ nsap_ptr->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_in_nsap_ptr(ARGS_FREESTRUCT) {
+ dns_rdata_in_nsap_ptr_t *nsap_ptr = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(nsap_ptr->common.rdclass == 1);
+ REQUIRE(nsap_ptr->common.rdtype == 23);
+
+ if (nsap_ptr->mctx == NULL)
+ return;
+
+ dns_name_free(&nsap_ptr->owner, nsap_ptr->mctx);
+ nsap_ptr->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_in_nsap_ptr(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 23);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_in_nsap_ptr(ARGS_DIGEST) {
+ isc_region_t r;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 23);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_rdata_toregion(rdata, &r);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_in_nsap_ptr(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 23);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_in_nsap_ptr(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 23);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_IN_1_NSAP_PTR_23_C */
diff --git a/lib/dns/rdata/in_1/nsap-ptr_23.h b/lib/dns/rdata/in_1/nsap-ptr_23.h
new file mode 100644
index 0000000..bd8e025
--- /dev/null
+++ b/lib/dns/rdata/in_1/nsap-ptr_23.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef IN_1_NSAP_PTR_23_H
+#define IN_1_NSAP_PTR_23_H 1
+
+/* $Id: nsap-ptr_23.h,v 1.15.18.2 2005/04/29 00:16:43 marka Exp $ */
+
+/*!
+ * \brief Per RFC1348. Obsoleted in RFC 1706 - use PTR instead. */
+
+typedef struct dns_rdata_in_nsap_ptr {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_name_t owner;
+} dns_rdata_in_nsap_ptr_t;
+
+#endif /* IN_1_NSAP_PTR_23_H */
diff --git a/lib/dns/rdata/in_1/nsap_22.c b/lib/dns/rdata/in_1/nsap_22.c
new file mode 100644
index 0000000..a348a30
--- /dev/null
+++ b/lib/dns/rdata/in_1/nsap_22.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2004, 2005 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: nsap_22.c,v 1.38.18.2 2005/04/29 00:16:43 marka Exp $ */
+
+/* Reviewed: Fri Mar 17 10:41:07 PST 2000 by gson */
+
+/* RFC1706 */
+
+#ifndef RDATA_IN_1_NSAP_22_C
+#define RDATA_IN_1_NSAP_22_C
+
+#define RRTYPE_NSAP_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_in_nsap(ARGS_FROMTEXT) {
+ isc_token_t token;
+ isc_textregion_t *sr;
+ int n;
+ int digits;
+ unsigned char c = 0;
+
+ REQUIRE(type == 22);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /* 0x<hex.string.with.periods> */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ sr = &token.value.as_textregion;
+ if (sr->length < 2)
+ RETTOK(ISC_R_UNEXPECTEDEND);
+ if (sr->base[0] != '0' || (sr->base[1] != 'x' && sr->base[1] != 'X'))
+ RETTOK(DNS_R_SYNTAX);
+ isc_textregion_consume(sr, 2);
+ digits = 0;
+ n = 0;
+ while (sr->length > 0) {
+ if (sr->base[0] == '.') {
+ isc_textregion_consume(sr, 1);
+ continue;
+ }
+ if ((n = hexvalue(sr->base[0])) == -1)
+ RETTOK(DNS_R_SYNTAX);
+ c <<= 4;
+ c += n;
+ if (++digits == 2) {
+ RETERR(mem_tobuffer(target, &c, 1));
+ digits = 0;
+ }
+ isc_textregion_consume(sr, 1);
+ }
+ if (digits)
+ RETTOK(ISC_R_UNEXPECTEDEND);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_in_nsap(ARGS_TOTEXT) {
+ isc_region_t region;
+ char buf[sizeof("xx")];
+
+ REQUIRE(rdata->type == 22);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &region);
+ RETERR(str_totext("0x", target));
+ while (region.length != 0) {
+ sprintf(buf, "%02x", region.base[0]);
+ isc_region_consume(&region, 1);
+ RETERR(str_totext(buf, target));
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_in_nsap(ARGS_FROMWIRE) {
+ isc_region_t region;
+
+ REQUIRE(type == 22);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(options);
+ UNUSED(rdclass);
+
+ isc_buffer_activeregion(source, &region);
+ if (region.length < 1)
+ return (ISC_R_UNEXPECTEDEND);
+
+ RETERR(mem_tobuffer(target, region.base, region.length));
+ isc_buffer_forward(source, region.length);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_in_nsap(ARGS_TOWIRE) {
+ REQUIRE(rdata->type == 22);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(cctx);
+
+ return (mem_tobuffer(target, rdata->data, rdata->length));
+}
+
+static inline int
+compare_in_nsap(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 22);
+ REQUIRE(rdata1->rdclass == 1);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_in_nsap(ARGS_FROMSTRUCT) {
+ dns_rdata_in_nsap_t *nsap = source;
+
+ REQUIRE(type == 22);
+ REQUIRE(rdclass == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(nsap->common.rdtype == type);
+ REQUIRE(nsap->common.rdclass == rdclass);
+ REQUIRE(nsap->nsap != NULL || nsap->nsap_len == 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ return (mem_tobuffer(target, nsap->nsap, nsap->nsap_len));
+}
+
+static inline isc_result_t
+tostruct_in_nsap(ARGS_TOSTRUCT) {
+ dns_rdata_in_nsap_t *nsap = target;
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 22);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ nsap->common.rdclass = rdata->rdclass;
+ nsap->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&nsap->common, link);
+
+ dns_rdata_toregion(rdata, &r);
+ nsap->nsap_len = r.length;
+ nsap->nsap = mem_maybedup(mctx, r.base, r.length);
+ if (nsap->nsap == NULL)
+ return (ISC_R_NOMEMORY);
+
+ nsap->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_in_nsap(ARGS_FREESTRUCT) {
+ dns_rdata_in_nsap_t *nsap = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(nsap->common.rdclass == 1);
+ REQUIRE(nsap->common.rdtype == 22);
+
+ if (nsap->mctx == NULL)
+ return;
+
+ if (nsap->nsap != NULL)
+ isc_mem_free(nsap->mctx, nsap->nsap);
+ nsap->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_in_nsap(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 22);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_in_nsap(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 22);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_in_nsap(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 22);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_in_nsap(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 22);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_IN_1_NSAP_22_C */
diff --git a/lib/dns/rdata/in_1/nsap_22.h b/lib/dns/rdata/in_1/nsap_22.h
new file mode 100644
index 0000000..583fbac
--- /dev/null
+++ b/lib/dns/rdata/in_1/nsap_22.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef IN_1_NSAP_22_H
+#define IN_1_NSAP_22_H 1
+
+/* $Id: nsap_22.h,v 1.14.18.2 2005/04/29 00:16:43 marka Exp $ */
+
+/*!
+ * \brief Per RFC1706 */
+
+typedef struct dns_rdata_in_nsap {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ unsigned char *nsap;
+ isc_uint16_t nsap_len;
+} dns_rdata_in_nsap_t;
+
+#endif /* IN_1_NSAP_22_H */
diff --git a/lib/dns/rdata/in_1/px_26.c b/lib/dns/rdata/in_1/px_26.c
new file mode 100644
index 0000000..3df9b99
--- /dev/null
+++ b/lib/dns/rdata/in_1/px_26.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2004, 2005 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: px_26.c,v 1.39.18.2 2005/04/29 00:16:43 marka Exp $ */
+
+/* Reviewed: Mon Mar 20 10:44:27 PST 2000 */
+
+/* RFC2163 */
+
+#ifndef RDATA_IN_1_PX_26_C
+#define RDATA_IN_1_PX_26_C
+
+#define RRTYPE_PX_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_in_px(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+
+ REQUIRE(type == 26);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Preference.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * MAP822.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+
+ /*
+ * MAPX400.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_in_px(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+ char buf[sizeof("64000")];
+ unsigned short num;
+
+ REQUIRE(rdata->type == 26);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ /*
+ * Preference.
+ */
+ dns_rdata_toregion(rdata, &region);
+ num = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ sprintf(buf, "%u", num);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * MAP822.
+ */
+ dns_name_fromregion(&name, &region);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ isc_region_consume(&region, name_length(&name));
+ RETERR(dns_name_totext(&prefix, sub, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * MAPX400.
+ */
+ dns_name_fromregion(&name, &region);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ return(dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_in_px(ARGS_FROMWIRE) {
+ dns_name_t name;
+ isc_region_t sregion;
+
+ REQUIRE(type == 26);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&name, NULL);
+
+ /*
+ * Preference.
+ */
+ isc_buffer_activeregion(source, &sregion);
+ if (sregion.length < 2)
+ return (ISC_R_UNEXPECTEDEND);
+ RETERR(mem_tobuffer(target, sregion.base, 2));
+ isc_buffer_forward(source, 2);
+
+ /*
+ * MAP822.
+ */
+ RETERR(dns_name_fromwire(&name, source, dctx, options, target));
+
+ /*
+ * MAPX400.
+ */
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_in_px(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 26);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ /*
+ * Preference.
+ */
+ dns_rdata_toregion(rdata, &region);
+ RETERR(mem_tobuffer(target, region.base, 2));
+ isc_region_consume(&region, 2);
+
+ /*
+ * MAP822.
+ */
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &region);
+ RETERR(dns_name_towire(&name, cctx, target));
+ isc_region_consume(&region, name_length(&name));
+
+ /*
+ * MAPX400.
+ */
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &region);
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_in_px(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 26);
+ REQUIRE(rdata1->rdclass == 1);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ order = memcmp(rdata1->data, rdata2->data, 2);
+ if (order != 0)
+ return (order < 0 ? -1 : 1);
+
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ isc_region_consume(&region1, 2);
+ isc_region_consume(&region2, 2);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ order = dns_name_rdatacompare(&name1, &name2);
+ if (order != 0)
+ return (order);
+
+ isc_region_consume(&region1, name_length(&name1));
+ isc_region_consume(&region2, name_length(&name2));
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_in_px(ARGS_FROMSTRUCT) {
+ dns_rdata_in_px_t *px = source;
+ isc_region_t region;
+
+ REQUIRE(type == 26);
+ REQUIRE(rdclass == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(px->common.rdtype == type);
+ REQUIRE(px->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint16_tobuffer(px->preference, target));
+ dns_name_toregion(&px->map822, &region);
+ RETERR(isc_buffer_copyregion(target, &region));
+ dns_name_toregion(&px->mapx400, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_in_px(ARGS_TOSTRUCT) {
+ dns_rdata_in_px_t *px = target;
+ dns_name_t name;
+ isc_region_t region;
+ isc_result_t result;
+
+ REQUIRE(rdata->type == 26);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ px->common.rdclass = rdata->rdclass;
+ px->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&px->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+
+ px->preference = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+
+ dns_name_fromregion(&name, &region);
+
+ dns_name_init(&px->map822, NULL);
+ RETERR(name_duporclone(&name, mctx, &px->map822));
+ isc_region_consume(&region, name_length(&px->map822));
+
+ dns_name_init(&px->mapx400, NULL);
+ result = name_duporclone(&name, mctx, &px->mapx400);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ px->mctx = mctx;
+ return (result);
+
+ cleanup:
+ dns_name_free(&px->map822, mctx);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_in_px(ARGS_FREESTRUCT) {
+ dns_rdata_in_px_t *px = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(px->common.rdclass == 1);
+ REQUIRE(px->common.rdtype == 26);
+
+ if (px->mctx == NULL)
+ return;
+
+ dns_name_free(&px->map822, px->mctx);
+ dns_name_free(&px->mapx400, px->mctx);
+ px->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_in_px(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 26);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_in_px(ARGS_DIGEST) {
+ isc_region_t r1, r2;
+ dns_name_t name;
+ isc_result_t result;
+
+ REQUIRE(rdata->type == 26);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_rdata_toregion(rdata, &r1);
+ r2 = r1;
+ isc_region_consume(&r2, 2);
+ r1.length = 2;
+ result = (digest)(arg, &r1);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r2);
+ result = dns_name_digest(&name, digest, arg);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_region_consume(&r2, name_length(&name));
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r2);
+
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_in_px(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 26);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_in_px(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 26);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_IN_1_PX_26_C */
diff --git a/lib/dns/rdata/in_1/px_26.h b/lib/dns/rdata/in_1/px_26.h
new file mode 100644
index 0000000..a38d5f81
--- /dev/null
+++ b/lib/dns/rdata/in_1/px_26.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef IN_1_PX_26_H
+#define IN_1_PX_26_H 1
+
+/* $Id: px_26.h,v 1.15.18.2 2005/04/29 00:16:43 marka Exp $ */
+
+/*!
+ * \brief Per RFC2163 */
+
+typedef struct dns_rdata_in_px {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t preference;
+ dns_name_t map822;
+ dns_name_t mapx400;
+} dns_rdata_in_px_t;
+
+#endif /* IN_1_PX_26_H */
diff --git a/lib/dns/rdata/in_1/srv_33.c b/lib/dns/rdata/in_1/srv_33.c
new file mode 100644
index 0000000..2925a77
--- /dev/null
+++ b/lib/dns/rdata/in_1/srv_33.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2004, 2005 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: srv_33.c,v 1.41.18.2 2005/04/29 00:16:43 marka Exp $ */
+
+/* Reviewed: Fri Mar 17 13:01:00 PST 2000 by bwelling */
+
+/* RFC2782 */
+
+#ifndef RDATA_IN_1_SRV_33_C
+#define RDATA_IN_1_SRV_33_C
+
+#define RRTYPE_SRV_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_in_srv(ARGS_FROMTEXT) {
+ isc_token_t token;
+ dns_name_t name;
+ isc_buffer_t buffer;
+ isc_boolean_t ok;
+
+ REQUIRE(type == 33);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+
+ /*
+ * Priority.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Weight.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Port.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /*
+ * Target.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ dns_name_init(&name, NULL);
+ buffer_fromregion(&buffer, &token.value.as_region);
+ origin = (origin != NULL) ? origin : dns_rootname;
+ RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
+ ok = ISC_TRUE;
+ if ((options & DNS_RDATA_CHECKNAMES) != 0)
+ ok = dns_name_ishostname(&name, ISC_FALSE);
+ if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0)
+ RETTOK(DNS_R_BADNAME);
+ if (!ok && callbacks != NULL)
+ warn_badname(&name, lexer, callbacks);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_in_srv(ARGS_TOTEXT) {
+ isc_region_t region;
+ dns_name_t name;
+ dns_name_t prefix;
+ isc_boolean_t sub;
+ char buf[sizeof("64000")];
+ unsigned short num;
+
+ REQUIRE(rdata->type == 33);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_name_init(&name, NULL);
+ dns_name_init(&prefix, NULL);
+
+ /*
+ * Priority.
+ */
+ dns_rdata_toregion(rdata, &region);
+ num = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ sprintf(buf, "%u", num);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Weight.
+ */
+ num = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ sprintf(buf, "%u", num);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Port.
+ */
+ num = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ sprintf(buf, "%u", num);
+ RETERR(str_totext(buf, target));
+ RETERR(str_totext(" ", target));
+
+ /*
+ * Target.
+ */
+ dns_name_fromregion(&name, &region);
+ sub = name_prefix(&name, tctx->origin, &prefix);
+ return (dns_name_totext(&prefix, sub, target));
+}
+
+static inline isc_result_t
+fromwire_in_srv(ARGS_FROMWIRE) {
+ dns_name_t name;
+ isc_region_t sr;
+
+ REQUIRE(type == 33);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
+
+ dns_name_init(&name, NULL);
+
+ /*
+ * Priority, weight, port.
+ */
+ isc_buffer_activeregion(source, &sr);
+ if (sr.length < 6)
+ return (ISC_R_UNEXPECTEDEND);
+ RETERR(mem_tobuffer(target, sr.base, 6));
+ isc_buffer_forward(source, 6);
+
+ /*
+ * Target.
+ */
+ return (dns_name_fromwire(&name, source, dctx, options, target));
+}
+
+static inline isc_result_t
+towire_in_srv(ARGS_TOWIRE) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 33);
+ REQUIRE(rdata->length != 0);
+
+ dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
+ /*
+ * Priority, weight, port.
+ */
+ dns_rdata_toregion(rdata, &sr);
+ RETERR(mem_tobuffer(target, sr.base, 6));
+ isc_region_consume(&sr, 6);
+
+ /*
+ * Target.
+ */
+ dns_name_init(&name, offsets);
+ dns_name_fromregion(&name, &sr);
+ return (dns_name_towire(&name, cctx, target));
+}
+
+static inline int
+compare_in_srv(ARGS_COMPARE) {
+ dns_name_t name1;
+ dns_name_t name2;
+ isc_region_t region1;
+ isc_region_t region2;
+ int order;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 33);
+ REQUIRE(rdata1->rdclass == 1);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ /*
+ * Priority, weight, port.
+ */
+ order = memcmp(rdata1->data, rdata2->data, 6);
+ if (order != 0)
+ return (order < 0 ? -1 : 1);
+
+ /*
+ * Target.
+ */
+ dns_name_init(&name1, NULL);
+ dns_name_init(&name2, NULL);
+
+ dns_rdata_toregion(rdata1, &region1);
+ dns_rdata_toregion(rdata2, &region2);
+
+ isc_region_consume(&region1, 6);
+ isc_region_consume(&region2, 6);
+
+ dns_name_fromregion(&name1, &region1);
+ dns_name_fromregion(&name2, &region2);
+
+ return (dns_name_rdatacompare(&name1, &name2));
+}
+
+static inline isc_result_t
+fromstruct_in_srv(ARGS_FROMSTRUCT) {
+ dns_rdata_in_srv_t *srv = source;
+ isc_region_t region;
+
+ REQUIRE(type == 33);
+ REQUIRE(rdclass == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(srv->common.rdtype == type);
+ REQUIRE(srv->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint16_tobuffer(srv->priority, target));
+ RETERR(uint16_tobuffer(srv->weight, target));
+ RETERR(uint16_tobuffer(srv->port, target));
+ dns_name_toregion(&srv->target, &region);
+ return (isc_buffer_copyregion(target, &region));
+}
+
+static inline isc_result_t
+tostruct_in_srv(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_in_srv_t *srv = target;
+ dns_name_t name;
+
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->type == 33);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ srv->common.rdclass = rdata->rdclass;
+ srv->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&srv->common, link);
+
+ dns_name_init(&name, NULL);
+ dns_rdata_toregion(rdata, &region);
+ srv->priority = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ srv->weight = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ srv->port = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ dns_name_fromregion(&name, &region);
+ dns_name_init(&srv->target, NULL);
+ RETERR(name_duporclone(&name, mctx, &srv->target));
+ srv->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_in_srv(ARGS_FREESTRUCT) {
+ dns_rdata_in_srv_t *srv = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(srv->common.rdclass == 1);
+ REQUIRE(srv->common.rdtype == 33);
+
+ if (srv->mctx == NULL)
+ return;
+
+ dns_name_free(&srv->target, srv->mctx);
+ srv->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_in_srv(ARGS_ADDLDATA) {
+ dns_name_t name;
+ dns_offsets_t offsets;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 33);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_name_init(&name, offsets);
+ dns_rdata_toregion(rdata, &region);
+ isc_region_consume(&region, 6);
+ dns_name_fromregion(&name, &region);
+
+ return ((add)(arg, &name, dns_rdatatype_a));
+}
+
+static inline isc_result_t
+digest_in_srv(ARGS_DIGEST) {
+ isc_region_t r1, r2;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 33);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_rdata_toregion(rdata, &r1);
+ r2 = r1;
+ isc_region_consume(&r2, 6);
+ r1.length = 6;
+ RETERR((digest)(arg, &r1));
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &r2);
+ return (dns_name_digest(&name, digest, arg));
+}
+
+static inline isc_boolean_t
+checkowner_in_srv(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 33);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_in_srv(ARGS_CHECKNAMES) {
+ isc_region_t region;
+ dns_name_t name;
+
+ REQUIRE(rdata->type == 33);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(owner);
+
+ dns_rdata_toregion(rdata, &region);
+ isc_region_consume(&region, 6);
+ dns_name_init(&name, NULL);
+ dns_name_fromregion(&name, &region);
+ if (!dns_name_ishostname(&name, ISC_FALSE)) {
+ if (bad != NULL)
+ dns_name_clone(&name, bad);
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_IN_1_SRV_33_C */
diff --git a/lib/dns/rdata/in_1/srv_33.h b/lib/dns/rdata/in_1/srv_33.h
new file mode 100644
index 0000000..7d9fef6
--- /dev/null
+++ b/lib/dns/rdata/in_1/srv_33.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+#ifndef IN_1_SRV_33_H
+#define IN_1_SRV_33_H 1
+
+/* $Id: srv_33.h,v 1.15.18.2 2005/04/29 00:16:43 marka Exp $ */
+
+/* Reviewed: Fri Mar 17 13:01:00 PST 2000 by bwelling */
+
+/*!
+ * \brief Per RFC2782 */
+
+typedef struct dns_rdata_in_srv {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ isc_uint16_t priority;
+ isc_uint16_t weight;
+ isc_uint16_t port;
+ dns_name_t target;
+} dns_rdata_in_srv_t;
+
+#endif /* IN_1_SRV_33_H */
diff --git a/lib/dns/rdata/in_1/wks_11.c b/lib/dns/rdata/in_1/wks_11.c
new file mode 100644
index 0000000..749b8fd
--- /dev/null
+++ b/lib/dns/rdata/in_1/wks_11.c
@@ -0,0 +1,349 @@
+/*
+ * 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: wks_11.c,v 1.51.18.1 2004/09/16 01:02:19 marka Exp $ */
+
+/* Reviewed: Fri Mar 17 15:01:49 PST 2000 by explorer */
+
+#ifndef RDATA_IN_1_WKS_11_C
+#define RDATA_IN_1_WKS_11_C
+
+#include <limits.h>
+#include <stdlib.h>
+
+#include <isc/net.h>
+#include <isc/netdb.h>
+
+#define RRTYPE_WKS_ATTRIBUTES (0)
+
+static inline isc_result_t
+fromtext_in_wks(ARGS_FROMTEXT) {
+ isc_token_t token;
+ isc_region_t region;
+ struct in_addr addr;
+ struct protoent *pe;
+ struct servent *se;
+ char *e;
+ long proto;
+ unsigned char bm[8*1024]; /* 64k bits */
+ long port;
+ long maxport = -1;
+ const char *ps = NULL;
+ unsigned int n;
+ char service[32];
+ int i;
+
+ REQUIRE(type == 11);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(origin);
+ UNUSED(options);
+ UNUSED(rdclass);
+
+ /*
+ * IPv4 dotted quad.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ isc_buffer_availableregion(target, &region);
+ if (getquad(DNS_AS_STR(token), &addr, lexer, callbacks) != 1)
+ RETTOK(DNS_R_BADDOTTEDQUAD);
+ if (region.length < 4)
+ return (ISC_R_NOSPACE);
+ memcpy(region.base, &addr, 4);
+ isc_buffer_add(target, 4);
+
+ /*
+ * Protocol.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+
+ proto = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e == 0)
+ ;
+ else if ((pe = getprotobyname(DNS_AS_STR(token))) != NULL)
+ proto = pe->p_proto;
+ else
+ RETTOK(DNS_R_UNKNOWNPROTO);
+ if (proto < 0 || proto > 0xff)
+ RETTOK(ISC_R_RANGE);
+
+ if (proto == IPPROTO_TCP)
+ ps = "tcp";
+ else if (proto == IPPROTO_UDP)
+ ps = "udp";
+
+ RETERR(uint8_tobuffer(proto, target));
+
+ memset(bm, 0, sizeof(bm));
+ do {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string, ISC_TRUE));
+ if (token.type != isc_tokentype_string)
+ break;
+
+ /*
+ * Lowercase the service string as some getservbyname() are
+ * case sensitive and the database is usually in lowercase.
+ */
+ strncpy(service, DNS_AS_STR(token), sizeof(service));
+ service[sizeof(service)-1] = '\0';
+ for (i = strlen(service) - 1; i >= 0; i--)
+ if (isupper(service[i]&0xff))
+ service[i] = tolower(service[i]&0xff);
+
+ port = strtol(DNS_AS_STR(token), &e, 10);
+ if (*e == 0)
+ ;
+ else if ((se = getservbyname(service, ps)) != NULL)
+ port = ntohs(se->s_port);
+ else if ((se = getservbyname(DNS_AS_STR(token), ps))
+ != NULL)
+ port = ntohs(se->s_port);
+ else
+ RETTOK(DNS_R_UNKNOWNSERVICE);
+ if (port < 0 || port > 0xffff)
+ RETTOK(ISC_R_RANGE);
+ if (port > maxport)
+ maxport = port;
+ bm[port / 8] |= (0x80 >> (port % 8));
+ } while (1);
+
+ /*
+ * Let upper layer handle eol/eof.
+ */
+ isc_lex_ungettoken(lexer, &token);
+
+ n = (maxport + 8) / 8;
+ return (mem_tobuffer(target, bm, n));
+}
+
+static inline isc_result_t
+totext_in_wks(ARGS_TOTEXT) {
+ isc_region_t sr;
+ unsigned short proto;
+ char buf[sizeof("65535")];
+ unsigned int i, j;
+
+ UNUSED(tctx);
+
+ REQUIRE(rdata->type == 11);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length >= 5);
+
+ dns_rdata_toregion(rdata, &sr);
+ RETERR(inet_totext(AF_INET, &sr, target));
+ isc_region_consume(&sr, 4);
+
+ proto = uint8_fromregion(&sr);
+ sprintf(buf, "%u", proto);
+ RETERR(str_totext(" ", target));
+ RETERR(str_totext(buf, target));
+ isc_region_consume(&sr, 1);
+
+ for (i = 0; i < sr.length; i++) {
+ if (sr.base[i] != 0)
+ for (j = 0; j < 8; j++)
+ if ((sr.base[i] & (0x80 >> j)) != 0) {
+ sprintf(buf, "%u", i * 8 + j);
+ RETERR(str_totext(" ", target));
+ RETERR(str_totext(buf, target));
+ }
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_in_wks(ARGS_FROMWIRE) {
+ isc_region_t sr;
+ isc_region_t tr;
+
+ REQUIRE(type == 11);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(dctx);
+ UNUSED(options);
+ UNUSED(rdclass);
+
+ isc_buffer_activeregion(source, &sr);
+ isc_buffer_availableregion(target, &tr);
+
+ if (sr.length < 5)
+ return (ISC_R_UNEXPECTEDEND);
+ if (sr.length > 8 * 1024 + 5)
+ return (DNS_R_EXTRADATA);
+ if (tr.length < sr.length)
+ return (ISC_R_NOSPACE);
+
+ memcpy(tr.base, sr.base, sr.length);
+ isc_buffer_add(target, sr.length);
+ isc_buffer_forward(source, sr.length);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_in_wks(ARGS_TOWIRE) {
+ isc_region_t sr;
+
+ UNUSED(cctx);
+
+ REQUIRE(rdata->type == 11);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ dns_rdata_toregion(rdata, &sr);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_in_wks(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 11);
+ REQUIRE(rdata1->rdclass == 1);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_in_wks(ARGS_FROMSTRUCT) {
+ dns_rdata_in_wks_t *wks = source;
+ isc_uint32_t a;
+
+ REQUIRE(type == 11);
+ REQUIRE(rdclass == 1);
+ REQUIRE(source != NULL);
+ REQUIRE(wks->common.rdtype == type);
+ REQUIRE(wks->common.rdclass == rdclass);
+ REQUIRE(wks->map != NULL || wks->map_len == 0);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ a = ntohl(wks->in_addr.s_addr);
+ RETERR(uint32_tobuffer(a, target));
+ RETERR(uint16_tobuffer(wks->protocol, target));
+ return (mem_tobuffer(target, wks->map, wks->map_len));
+}
+
+static inline isc_result_t
+tostruct_in_wks(ARGS_TOSTRUCT) {
+ dns_rdata_in_wks_t *wks = target;
+ isc_uint32_t n;
+ isc_region_t region;
+
+ REQUIRE(rdata->type == 11);
+ REQUIRE(rdata->rdclass == 1);
+ REQUIRE(rdata->length != 0);
+
+ wks->common.rdclass = rdata->rdclass;
+ wks->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&wks->common, link);
+
+ dns_rdata_toregion(rdata, &region);
+ n = uint32_fromregion(&region);
+ wks->in_addr.s_addr = htonl(n);
+ isc_region_consume(&region, 4);
+ wks->protocol = uint16_fromregion(&region);
+ isc_region_consume(&region, 2);
+ wks->map_len = region.length;
+ wks->map = mem_maybedup(mctx, region.base, region.length);
+ if (wks->map == NULL)
+ return (ISC_R_NOMEMORY);
+ wks->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_in_wks(ARGS_FREESTRUCT) {
+ dns_rdata_in_wks_t *wks = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(wks->common.rdtype == 11);
+ REQUIRE(wks->common.rdclass == 1);
+
+ if (wks->mctx == NULL)
+ return;
+
+ if (wks->map != NULL)
+ isc_mem_free(wks->mctx, wks->map);
+ wks->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_in_wks(ARGS_ADDLDATA) {
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ REQUIRE(rdata->type == 11);
+ REQUIRE(rdata->rdclass == 1);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_in_wks(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 11);
+ REQUIRE(rdata->rdclass == 1);
+
+ dns_rdata_toregion(rdata, &r);
+
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_in_wks(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 11);
+ REQUIRE(rdclass == 1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ return (dns_name_ishostname(name, wildcard));
+}
+
+static inline isc_boolean_t
+checknames_in_wks(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 11);
+ REQUIRE(rdata->rdclass == 1);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_IN_1_WKS_11_C */
diff --git a/lib/dns/rdata/in_1/wks_11.h b/lib/dns/rdata/in_1/wks_11.h
new file mode 100644
index 0000000..a0093b9
--- /dev/null
+++ b/lib/dns/rdata/in_1/wks_11.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.
+ */
+
+#ifndef IN_1_WKS_11_H
+#define IN_1_WKS_11_H 1
+
+/* $Id: wks_11.h,v 1.20 2004/03/05 05:10:25 marka Exp $ */
+
+typedef struct dns_rdata_in_wks {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ struct in_addr in_addr;
+ isc_uint16_t protocol;
+ unsigned char *map;
+ isc_uint16_t map_len;
+} dns_rdata_in_wks_t;
+
+#endif /* IN_1_WKS_11_H */
diff --git a/lib/dns/rdata/rdatastructpre.h b/lib/dns/rdata/rdatastructpre.h
new file mode 100644
index 0000000..d641ef5
--- /dev/null
+++ b/lib/dns/rdata/rdatastructpre.h
@@ -0,0 +1,42 @@
+/*
+ * 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: rdatastructpre.h,v 1.14 2004/03/05 05:10:04 marka Exp $ */
+
+#ifndef DNS_RDATASTRUCT_H
+#define DNS_RDATASTRUCT_H 1
+
+#include <isc/lang.h>
+#include <isc/sockaddr.h>
+
+#include <dns/name.h>
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef struct dns_rdatacommon {
+ dns_rdataclass_t rdclass;
+ dns_rdatatype_t rdtype;
+ ISC_LINK(struct dns_rdatacommon) link;
+} dns_rdatacommon_t;
+
+#define DNS_RDATACOMMON_INIT(_data, _rdtype, _rdclass) \
+ do { \
+ (_data)->common.rdtype = (_rdtype); \
+ (_data)->common.rdclass = (_rdclass); \
+ ISC_LINK_INIT(&(_data)->common, link); \
+ } while (0)
diff --git a/lib/dns/rdata/rdatastructsuf.h b/lib/dns/rdata/rdatastructsuf.h
new file mode 100644
index 0000000..1ab1b0a
--- /dev/null
+++ b/lib/dns/rdata/rdatastructsuf.h
@@ -0,0 +1,22 @@
+/*
+ * 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: rdatastructsuf.h,v 1.8 2004/03/05 05:10:04 marka Exp $ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RDATASTRUCT_H */
diff --git a/lib/dns/rdatalist.c b/lib/dns/rdatalist.c
new file mode 100644
index 0000000..7229fa3
--- /dev/null
+++ b/lib/dns/rdatalist.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2004, 2005 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: rdatalist.c,v 1.28.18.3 2005/04/29 00:16:02 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/util.h>
+
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+
+#include "rdatalist_p.h"
+
+static dns_rdatasetmethods_t methods = {
+ isc__rdatalist_disassociate,
+ isc__rdatalist_first,
+ isc__rdatalist_next,
+ isc__rdatalist_current,
+ isc__rdatalist_clone,
+ isc__rdatalist_count,
+ isc__rdatalist_addnoqname,
+ isc__rdatalist_getnoqname,
+ NULL,
+ NULL,
+ NULL
+};
+
+void
+dns_rdatalist_init(dns_rdatalist_t *rdatalist) {
+
+ /*
+ * Initialize rdatalist.
+ */
+
+ rdatalist->rdclass = 0;
+ rdatalist->type = 0;
+ rdatalist->covers = 0;
+ rdatalist->ttl = 0;
+ ISC_LIST_INIT(rdatalist->rdata);
+ ISC_LINK_INIT(rdatalist, link);
+}
+
+isc_result_t
+dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist,
+ dns_rdataset_t *rdataset) {
+
+ /*
+ * Make 'rdataset' refer to the rdata in 'rdatalist'.
+ */
+
+ REQUIRE(rdatalist != NULL);
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(! dns_rdataset_isassociated(rdataset));
+
+ rdataset->methods = &methods;
+ rdataset->rdclass = rdatalist->rdclass;
+ rdataset->type = rdatalist->type;
+ rdataset->covers = rdatalist->covers;
+ rdataset->ttl = rdatalist->ttl;
+ rdataset->trust = 0;
+ rdataset->private1 = rdatalist;
+ rdataset->private2 = NULL;
+ rdataset->private3 = NULL;
+ rdataset->privateuint4 = 0;
+ rdataset->private5 = NULL;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc__rdatalist_disassociate(dns_rdataset_t *rdataset) {
+ UNUSED(rdataset);
+}
+
+isc_result_t
+isc__rdatalist_first(dns_rdataset_t *rdataset) {
+ dns_rdatalist_t *rdatalist;
+
+ rdatalist = rdataset->private1;
+ rdataset->private2 = ISC_LIST_HEAD(rdatalist->rdata);
+
+ if (rdataset->private2 == NULL)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__rdatalist_next(dns_rdataset_t *rdataset) {
+ dns_rdata_t *rdata;
+
+ rdata = rdataset->private2;
+ if (rdata == NULL)
+ return (ISC_R_NOMORE);
+
+ rdataset->private2 = ISC_LIST_NEXT(rdata, link);
+
+ if (rdataset->private2 == NULL)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc__rdatalist_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
+ dns_rdata_t *list_rdata;
+
+ list_rdata = rdataset->private2;
+ INSIST(list_rdata != NULL);
+
+ dns_rdata_clone(list_rdata, rdata);
+}
+
+void
+isc__rdatalist_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
+ *target = *source;
+
+ /*
+ * Reset iterator state.
+ */
+ target->private2 = NULL;
+}
+
+unsigned int
+isc__rdatalist_count(dns_rdataset_t *rdataset) {
+ dns_rdatalist_t *rdatalist;
+ dns_rdata_t *rdata;
+ unsigned int count;
+
+ rdatalist = rdataset->private1;
+
+ count = 0;
+ for (rdata = ISC_LIST_HEAD(rdatalist->rdata);
+ rdata != NULL;
+ rdata = ISC_LIST_NEXT(rdata, link))
+ count++;
+
+ return (count);
+}
+
+isc_result_t
+isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
+ dns_rdataset_t *nsec = NULL;
+ dns_rdataset_t *nsecsig = NULL;
+ dns_rdataset_t *rdset;
+ dns_ttl_t ttl;
+
+ for (rdset = ISC_LIST_HEAD(name->list);
+ rdset != NULL;
+ rdset = ISC_LIST_NEXT(rdset, link))
+ {
+ if (rdset->rdclass != rdataset->rdclass)
+ continue;
+ if (rdset->type == dns_rdatatype_nsec)
+ nsec = rdset;
+ if (rdset->type == dns_rdatatype_rrsig &&
+ rdset->covers == dns_rdatatype_nsec)
+ nsecsig = rdset;
+ }
+
+ if (nsec == NULL || nsecsig == NULL)
+ return (ISC_R_NOTFOUND);
+ /*
+ * Minimise ttl.
+ */
+ ttl = rdataset->ttl;
+ if (nsec->ttl < ttl)
+ ttl = nsec->ttl;
+ if (nsecsig->ttl < ttl)
+ ttl = nsecsig->ttl;
+ rdataset->ttl = nsec->ttl = nsecsig->ttl = ttl;
+ rdataset->attributes |= DNS_RDATASETATTR_NOQNAME;
+ rdataset->private6 = name;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
+ dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
+{
+ dns_rdataclass_t rdclass = rdataset->rdclass;
+ dns_rdataset_t *tnsec = NULL;
+ dns_rdataset_t *tnsecsig = NULL;
+ dns_name_t *noqname = rdataset->private6;
+
+ REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0);
+ (void)dns_name_dynamic(noqname); /* Sanity Check. */
+
+ for (rdataset = ISC_LIST_HEAD(noqname->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link))
+ {
+ if (rdataset->rdclass != rdclass)
+ continue;
+ if (rdataset->type == dns_rdatatype_nsec)
+ tnsec = rdataset;
+ if (rdataset->type == dns_rdatatype_rrsig &&
+ rdataset->covers == dns_rdatatype_nsec)
+ tnsecsig = rdataset;
+ }
+ if (tnsec == NULL || tnsecsig == NULL)
+ return (ISC_R_NOTFOUND);
+
+ dns_name_clone(noqname, name);
+ dns_rdataset_clone(tnsec, nsec);
+ dns_rdataset_clone(tnsecsig, nsecsig);
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/dns/rdatalist_p.h b/lib/dns/rdatalist_p.h
new file mode 100644
index 0000000..d697fec
--- /dev/null
+++ b/lib/dns/rdatalist_p.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2004, 2005 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: rdatalist_p.h,v 1.5.18.2 2005/04/29 00:16:03 marka Exp $ */
+
+#ifndef DNS_RDATALIST_P_H
+#define DNS_RDATALIST_P_H
+
+/*! \file */
+
+#include <isc/result.h>
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+void
+isc__rdatalist_disassociate(dns_rdataset_t *rdatasetp);
+
+isc_result_t
+isc__rdatalist_first(dns_rdataset_t *rdataset);
+
+isc_result_t
+isc__rdatalist_next(dns_rdataset_t *rdataset);
+
+void
+isc__rdatalist_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
+
+void
+isc__rdatalist_clone(dns_rdataset_t *source, dns_rdataset_t *target);
+
+unsigned int
+isc__rdatalist_count(dns_rdataset_t *rdataset);
+
+isc_result_t
+isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name);
+
+isc_result_t
+isc__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
+ dns_rdataset_t *nsec, dns_rdataset_t *nsecsig);
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_RDATALIST_P_H */
diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c
new file mode 100644
index 0000000..c86b3c5
--- /dev/null
+++ b/lib/dns/rdataset.c
@@ -0,0 +1,709 @@
+/*
+ * Copyright (C) 2004-2006 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: rdataset.c,v 1.72.18.5 2006/03/02 00:37:21 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/mem.h>
+#include <isc/random.h>
+#include <isc/util.h>
+
+#include <dns/name.h>
+#include <dns/ncache.h>
+#include <dns/rdata.h>
+#include <dns/rdataset.h>
+#include <dns/compress.h>
+
+void
+dns_rdataset_init(dns_rdataset_t *rdataset) {
+
+ /*
+ * Make 'rdataset' a valid, disassociated rdataset.
+ */
+
+ REQUIRE(rdataset != NULL);
+
+ rdataset->magic = DNS_RDATASET_MAGIC;
+ rdataset->methods = NULL;
+ ISC_LINK_INIT(rdataset, link);
+ rdataset->rdclass = 0;
+ rdataset->type = 0;
+ rdataset->ttl = 0;
+ rdataset->trust = 0;
+ rdataset->covers = 0;
+ rdataset->attributes = 0;
+ rdataset->count = ISC_UINT32_MAX;
+ rdataset->private1 = NULL;
+ rdataset->private2 = NULL;
+ rdataset->private3 = NULL;
+ rdataset->privateuint4 = 0;
+ rdataset->private5 = NULL;
+ rdataset->private6 = NULL;
+}
+
+void
+dns_rdataset_invalidate(dns_rdataset_t *rdataset) {
+
+ /*
+ * Invalidate 'rdataset'.
+ */
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods == NULL);
+
+ rdataset->magic = 0;
+ ISC_LINK_INIT(rdataset, link);
+ rdataset->rdclass = 0;
+ rdataset->type = 0;
+ rdataset->ttl = 0;
+ rdataset->trust = 0;
+ rdataset->covers = 0;
+ rdataset->attributes = 0;
+ rdataset->count = ISC_UINT32_MAX;
+ rdataset->private1 = NULL;
+ rdataset->private2 = NULL;
+ rdataset->private3 = NULL;
+ rdataset->privateuint4 = 0;
+ rdataset->private5 = NULL;
+}
+
+void
+dns_rdataset_disassociate(dns_rdataset_t *rdataset) {
+
+ /*
+ * Disassociate 'rdataset' from its rdata, allowing it to be reused.
+ */
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+
+ (rdataset->methods->disassociate)(rdataset);
+ rdataset->methods = NULL;
+ ISC_LINK_INIT(rdataset, link);
+ rdataset->rdclass = 0;
+ rdataset->type = 0;
+ rdataset->ttl = 0;
+ rdataset->trust = 0;
+ rdataset->covers = 0;
+ rdataset->attributes = 0;
+ rdataset->count = ISC_UINT32_MAX;
+ rdataset->private1 = NULL;
+ rdataset->private2 = NULL;
+ rdataset->private3 = NULL;
+ rdataset->privateuint4 = 0;
+ rdataset->private5 = NULL;
+ rdataset->private6 = NULL;
+}
+
+isc_boolean_t
+dns_rdataset_isassociated(dns_rdataset_t *rdataset) {
+ /*
+ * Is 'rdataset' associated?
+ */
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+
+ if (rdataset->methods != NULL)
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+}
+
+static void
+question_disassociate(dns_rdataset_t *rdataset) {
+ UNUSED(rdataset);
+}
+
+static isc_result_t
+question_cursor(dns_rdataset_t *rdataset) {
+ UNUSED(rdataset);
+
+ return (ISC_R_NOMORE);
+}
+
+static void
+question_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
+ /*
+ * This routine should never be called.
+ */
+ UNUSED(rdataset);
+ UNUSED(rdata);
+
+ REQUIRE(0);
+}
+
+static void
+question_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
+ *target = *source;
+}
+
+static unsigned int
+question_count(dns_rdataset_t *rdataset) {
+ /*
+ * This routine should never be called.
+ */
+ UNUSED(rdataset);
+ REQUIRE(0);
+
+ return (0);
+}
+
+static dns_rdatasetmethods_t question_methods = {
+ question_disassociate,
+ question_cursor,
+ question_cursor,
+ question_current,
+ question_clone,
+ question_count,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+void
+dns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type)
+{
+
+ /*
+ * Make 'rdataset' a valid, associated, question rdataset, with a
+ * question class of 'rdclass' and type 'type'.
+ */
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods == NULL);
+
+ rdataset->methods = &question_methods;
+ rdataset->rdclass = rdclass;
+ rdataset->type = type;
+ rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
+}
+
+unsigned int
+dns_rdataset_count(dns_rdataset_t *rdataset) {
+
+ /*
+ * Return the number of records in 'rdataset'.
+ */
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+
+ return ((rdataset->methods->count)(rdataset));
+}
+
+void
+dns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
+
+ /*
+ * Make 'target' refer to the same rdataset as 'source'.
+ */
+
+ REQUIRE(DNS_RDATASET_VALID(source));
+ REQUIRE(source->methods != NULL);
+ REQUIRE(DNS_RDATASET_VALID(target));
+ REQUIRE(target->methods == NULL);
+
+ (source->methods->clone)(source, target);
+}
+
+isc_result_t
+dns_rdataset_first(dns_rdataset_t *rdataset) {
+
+ /*
+ * Move the rdata cursor to the first rdata in the rdataset (if any).
+ */
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+
+ return ((rdataset->methods->first)(rdataset));
+}
+
+isc_result_t
+dns_rdataset_next(dns_rdataset_t *rdataset) {
+
+ /*
+ * Move the rdata cursor to the next rdata in the rdataset (if any).
+ */
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+
+ return ((rdataset->methods->next)(rdataset));
+}
+
+void
+dns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
+
+ /*
+ * Make 'rdata' refer to the current rdata.
+ */
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+
+ (rdataset->methods->current)(rdataset, rdata);
+}
+
+#define MAX_SHUFFLE 32
+#define WANT_FIXED(r) (((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
+#define WANT_RANDOM(r) (((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
+
+struct towire_sort {
+ int key;
+ dns_rdata_t *rdata;
+};
+
+static int
+towire_compare(const void *av, const void *bv) {
+ const struct towire_sort *a = (const struct towire_sort *) av;
+ const struct towire_sort *b = (const struct towire_sort *) bv;
+ return (a->key - b->key);
+}
+
+static isc_result_t
+towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
+ dns_compress_t *cctx, isc_buffer_t *target,
+ dns_rdatasetorderfunc_t order, const void *order_arg,
+ isc_boolean_t partial, unsigned int options,
+ unsigned int *countp, void **state)
+{
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_region_t r;
+ isc_result_t result;
+ unsigned int i, count, added, choice;
+ isc_buffer_t savedbuffer, rdlen, rrbuffer;
+ unsigned int headlen;
+ isc_boolean_t question = ISC_FALSE;
+ isc_boolean_t shuffle = ISC_FALSE;
+ dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE];
+ struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE];
+
+ UNUSED(state);
+
+ /*
+ * Convert 'rdataset' to wire format, compressing names as specified
+ * in cctx, and storing the result in 'target'.
+ */
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(countp != NULL);
+ REQUIRE((order == NULL) == (order_arg == NULL));
+ REQUIRE(cctx != NULL && cctx->mctx != NULL);
+
+ count = 0;
+ if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
+ question = ISC_TRUE;
+ count = 1;
+ result = dns_rdataset_first(rdataset);
+ INSIST(result == ISC_R_NOMORE);
+ } else if (rdataset->type == 0) {
+ /*
+ * This is a negative caching rdataset.
+ */
+ unsigned int ncache_opts = 0;
+ if ((options & DNS_RDATASETTOWIRE_OMITDNSSEC) != 0)
+ ncache_opts |= DNS_NCACHETOWIRE_OMITDNSSEC;
+ return (dns_ncache_towire(rdataset, cctx, target, ncache_opts,
+ countp));
+ } else {
+ count = (rdataset->methods->count)(rdataset);
+ result = dns_rdataset_first(rdataset);
+ if (result == ISC_R_NOMORE)
+ return (ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ /*
+ * Do we want to shuffle this anwer?
+ */
+ if (!question && count > 1 &&
+ (!WANT_FIXED(rdataset) || order != NULL) &&
+ rdataset->type != dns_rdatatype_rrsig)
+ shuffle = ISC_TRUE;
+
+ if (shuffle && count > MAX_SHUFFLE) {
+ shuffled = isc_mem_get(cctx->mctx, count * sizeof(*shuffled));
+ sorted = isc_mem_get(cctx->mctx, count * sizeof(*sorted));
+ if (shuffled == NULL || sorted == NULL)
+ shuffle = ISC_FALSE;
+ } else {
+ shuffled = shuffled_fixed;
+ sorted = sorted_fixed;
+ }
+
+ if (shuffle) {
+ /*
+ * First we get handles to all of the rdata.
+ */
+ i = 0;
+ do {
+ INSIST(i < count);
+ dns_rdata_init(&shuffled[i]);
+ dns_rdataset_current(rdataset, &shuffled[i]);
+ i++;
+ result = dns_rdataset_next(rdataset);
+ } while (result == ISC_R_SUCCESS);
+ if (result != ISC_R_NOMORE)
+ goto cleanup;
+ INSIST(i == count);
+
+ /*
+ * Now we shuffle.
+ */
+ if (WANT_FIXED(rdataset)) {
+ /*
+ * 'Fixed' order.
+ */
+ INSIST(order != NULL);
+ for (i = 0; i < count; i++) {
+ sorted[i].key = (*order)(&shuffled[i],
+ order_arg);
+ sorted[i].rdata = &shuffled[i];
+ }
+ } else if (WANT_RANDOM(rdataset)) {
+ /*
+ * 'Random' order.
+ */
+ for (i = 0; i < count; i++) {
+ dns_rdata_t rdata;
+ isc_uint32_t val;
+
+ isc_random_get(&val);
+ choice = i + (val % (count - i));
+ rdata = shuffled[i];
+ shuffled[i] = shuffled[choice];
+ shuffled[choice] = rdata;
+ if (order != NULL)
+ sorted[i].key = (*order)(&shuffled[i],
+ order_arg);
+ else
+ sorted[i].key = 0; /* Unused */
+ sorted[i].rdata = &shuffled[i];
+ }
+ } else {
+ /*
+ * "Cyclic" order.
+ */
+ isc_uint32_t val;
+ unsigned int j;
+
+ val = rdataset->count;
+ if (val == ISC_UINT32_MAX)
+ isc_random_get(&val);
+ j = val % count;
+ for (i = 0; i < count; i++) {
+ if (order != NULL)
+ sorted[j].key = (*order)(&shuffled[i],
+ order_arg);
+ else
+ sorted[j].key = 0; /* Unused */
+ sorted[j].rdata = &shuffled[i];
+ j++;
+ if (j == count)
+ j = 0; /* Wrap around. */
+ }
+ }
+
+ /*
+ * Sorted order.
+ */
+ if (order != NULL)
+ qsort(sorted, count, sizeof(sorted[0]),
+ towire_compare);
+ }
+
+ savedbuffer = *target;
+ i = 0;
+ added = 0;
+
+ do {
+ /*
+ * Copy out the name, type, class, ttl.
+ */
+
+ rrbuffer = *target;
+ dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
+ result = dns_name_towire(owner_name, cctx, target);
+ if (result != ISC_R_SUCCESS)
+ goto rollback;
+ headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
+ if (!question)
+ headlen += sizeof(dns_ttl_t)
+ + 2; /* XXX 2 for rdata len */
+ isc_buffer_availableregion(target, &r);
+ if (r.length < headlen) {
+ result = ISC_R_NOSPACE;
+ goto rollback;
+ }
+ isc_buffer_putuint16(target, rdataset->type);
+ isc_buffer_putuint16(target, rdataset->rdclass);
+ if (!question) {
+ isc_buffer_putuint32(target, rdataset->ttl);
+
+ /*
+ * Save space for rdlen.
+ */
+ rdlen = *target;
+ isc_buffer_add(target, 2);
+
+ /*
+ * Copy out the rdata
+ */
+ if (shuffle)
+ rdata = *(sorted[i].rdata);
+ else {
+ dns_rdata_reset(&rdata);
+ dns_rdataset_current(rdataset, &rdata);
+ }
+ result = dns_rdata_towire(&rdata, cctx, target);
+ if (result != ISC_R_SUCCESS)
+ goto rollback;
+ INSIST((target->used >= rdlen.used + 2) &&
+ (target->used - rdlen.used - 2 < 65536));
+ isc_buffer_putuint16(&rdlen,
+ (isc_uint16_t)(target->used -
+ rdlen.used - 2));
+ added++;
+ }
+
+ if (shuffle) {
+ i++;
+ if (i == count)
+ result = ISC_R_NOMORE;
+ else
+ result = ISC_R_SUCCESS;
+ } else {
+ result = dns_rdataset_next(rdataset);
+ }
+ } while (result == ISC_R_SUCCESS);
+
+ if (result != ISC_R_NOMORE)
+ goto rollback;
+
+ *countp += count;
+
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+
+ rollback:
+ if (partial && result == ISC_R_NOSPACE) {
+ INSIST(rrbuffer.used < 65536);
+ dns_compress_rollback(cctx, (isc_uint16_t)rrbuffer.used);
+ *countp += added;
+ *target = rrbuffer;
+ goto cleanup;
+ }
+ INSIST(savedbuffer.used < 65536);
+ dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
+ *countp = 0;
+ *target = savedbuffer;
+
+ cleanup:
+ if (sorted != NULL && sorted != sorted_fixed)
+ isc_mem_put(cctx->mctx, sorted, count * sizeof(*sorted));
+ if (shuffled != NULL && shuffled != shuffled_fixed)
+ isc_mem_put(cctx->mctx, shuffled, count * sizeof(*shuffled));
+ return (result);
+}
+
+isc_result_t
+dns_rdataset_towiresorted(dns_rdataset_t *rdataset,
+ const dns_name_t *owner_name,
+ dns_compress_t *cctx,
+ isc_buffer_t *target,
+ dns_rdatasetorderfunc_t order,
+ const void *order_arg,
+ unsigned int options,
+ unsigned int *countp)
+{
+ return (towiresorted(rdataset, owner_name, cctx, target,
+ order, order_arg, ISC_FALSE, options,
+ countp, NULL));
+}
+
+isc_result_t
+dns_rdataset_towirepartial(dns_rdataset_t *rdataset,
+ const dns_name_t *owner_name,
+ dns_compress_t *cctx,
+ isc_buffer_t *target,
+ dns_rdatasetorderfunc_t order,
+ const void *order_arg,
+ unsigned int options,
+ unsigned int *countp,
+ void **state)
+{
+ REQUIRE(state == NULL); /* XXX remove when implemented */
+ return (towiresorted(rdataset, owner_name, cctx, target,
+ order, order_arg, ISC_TRUE, options,
+ countp, state));
+}
+
+isc_result_t
+dns_rdataset_towire(dns_rdataset_t *rdataset,
+ dns_name_t *owner_name,
+ dns_compress_t *cctx,
+ isc_buffer_t *target,
+ unsigned int options,
+ unsigned int *countp)
+{
+ return (towiresorted(rdataset, owner_name, cctx, target,
+ NULL, NULL, ISC_FALSE, options, countp, NULL));
+}
+
+isc_result_t
+dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
+ dns_additionaldatafunc_t add, void *arg)
+{
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_result_t result;
+
+ /*
+ * For each rdata in rdataset, call 'add' for each name and type in the
+ * rdata which is subject to additional section processing.
+ */
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
+
+ result = dns_rdataset_first(rdataset);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ do {
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_additionaldata(&rdata, add, arg);
+ if (result == ISC_R_SUCCESS)
+ result = dns_rdataset_next(rdataset);
+ dns_rdata_reset(&rdata);
+ } while (result == ISC_R_SUCCESS);
+
+ if (result != ISC_R_NOMORE)
+ return (result);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+ if (rdataset->methods->addnoqname == NULL)
+ return (ISC_R_NOTIMPLEMENTED);
+ return((rdataset->methods->addnoqname)(rdataset, name));
+}
+
+isc_result_t
+dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
+ dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
+{
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+
+ if (rdataset->methods->getnoqname == NULL)
+ return (ISC_R_NOTIMPLEMENTED);
+ return((rdataset->methods->getnoqname)(rdataset, name, nsec, nsecsig));
+}
+
+/*
+ * Additional cache stuff
+ */
+isc_result_t
+dns_rdataset_getadditional(dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype,
+ dns_acache_t *acache,
+ dns_zone_t **zonep,
+ dns_db_t **dbp,
+ dns_dbversion_t **versionp,
+ dns_dbnode_t **nodep,
+ dns_name_t *fname,
+ dns_message_t *msg,
+ isc_stdtime_t now)
+{
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+ REQUIRE(zonep == NULL || *zonep == NULL);
+ REQUIRE(dbp != NULL && *dbp == NULL);
+ REQUIRE(versionp != NULL && *versionp == NULL);
+ REQUIRE(nodep != NULL && *nodep == NULL);
+ REQUIRE(fname != NULL);
+ REQUIRE(msg != NULL);
+
+ if (acache != NULL && rdataset->methods->getadditional != NULL) {
+ return ((rdataset->methods->getadditional)(rdataset, type,
+ qtype, acache,
+ zonep, dbp,
+ versionp, nodep,
+ fname, msg, now));
+ }
+
+ return (ISC_R_FAILURE);
+}
+
+isc_result_t
+dns_rdataset_setadditional(dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype,
+ dns_acache_t *acache,
+ dns_zone_t *zone,
+ dns_db_t *db,
+ dns_dbversion_t *version,
+ dns_dbnode_t *node,
+ dns_name_t *fname)
+{
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+
+ if (acache != NULL && rdataset->methods->setadditional != NULL) {
+ return ((rdataset->methods->setadditional)(rdataset, type,
+ qtype, acache, zone,
+ db, version,
+ node, fname));
+ }
+
+ return (ISC_R_FAILURE);
+}
+
+isc_result_t
+dns_rdataset_putadditional(dns_acache_t *acache,
+ dns_rdataset_t *rdataset,
+ dns_rdatasetadditional_t type,
+ dns_rdatatype_t qtype)
+{
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+
+ if (acache != NULL && rdataset->methods->putadditional != NULL) {
+ return ((rdataset->methods->putadditional)(acache, rdataset,
+ type, qtype));
+ }
+
+ return (ISC_R_FAILURE);
+}
+
diff --git a/lib/dns/rdatasetiter.c b/lib/dns/rdatasetiter.c
new file mode 100644
index 0000000..8089e04
--- /dev/null
+++ b/lib/dns/rdatasetiter.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2004, 2005 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: rdatasetiter.c,v 1.12.18.2 2005/04/29 00:16:03 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/util.h>
+
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+
+void
+dns_rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
+ /*
+ * Destroy '*iteratorp'.
+ */
+
+ REQUIRE(iteratorp != NULL);
+ REQUIRE(DNS_RDATASETITER_VALID(*iteratorp));
+
+ (*iteratorp)->methods->destroy(iteratorp);
+
+ ENSURE(*iteratorp == NULL);
+}
+
+isc_result_t
+dns_rdatasetiter_first(dns_rdatasetiter_t *iterator) {
+ /*
+ * Move the rdataset cursor to the first rdataset at the node (if any).
+ */
+
+ REQUIRE(DNS_RDATASETITER_VALID(iterator));
+
+ return (iterator->methods->first(iterator));
+}
+
+isc_result_t
+dns_rdatasetiter_next(dns_rdatasetiter_t *iterator) {
+ /*
+ * Move the rdataset cursor to the next rdataset at the node (if any).
+ */
+
+ REQUIRE(DNS_RDATASETITER_VALID(iterator));
+
+ return (iterator->methods->next(iterator));
+}
+
+void
+dns_rdatasetiter_current(dns_rdatasetiter_t *iterator,
+ dns_rdataset_t *rdataset)
+{
+ /*
+ * Return the current rdataset.
+ */
+
+ REQUIRE(DNS_RDATASETITER_VALID(iterator));
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(! dns_rdataset_isassociated(rdataset));
+
+ iterator->methods->current(iterator, rdataset);
+}
diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c
new file mode 100644
index 0000000..5d89d01
--- /dev/null
+++ b/lib/dns/rdataslab.c
@@ -0,0 +1,1045 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: rdataslab.c,v 1.35.18.8 2007/08/28 07:20:05 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <isc/mem.h>
+#include <isc/region.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/util.h>
+
+#include <dns/result.h>
+#include <dns/rdata.h>
+#include <dns/rdataset.h>
+#include <dns/rdataslab.h>
+
+#ifndef DNS_RDATASET_FIXED
+#define DNS_RDATASET_FIXED 1
+#endif
+
+/*
+ * The rdataslab structure allows iteration to occur in both load order
+ * and DNSSEC order. The structure is as follows:
+ *
+ * header (reservelen bytes)
+ * record count (2 bytes)
+ * offset table (4 x record count bytes in load order)
+ * data records
+ * data length (2 bytes)
+ * order (2 bytes)
+ * data (data length bytes)
+ *
+ * If DNS_RDATASET_FIXED is defined to be zero (0) the format of a
+ * rdataslab is as follows:
+ *
+ * header (reservelen bytes)
+ * record count (2 bytes)
+ * data records
+ * data length (2 bytes)
+ * data (data length bytes)
+ *
+ * Offsets are from the end of the header.
+ *
+ * Load order traversal is performed by walking the offset table to find
+ * the start of the record (DNS_RDATASET_FIXED = 1).
+ *
+ * DNSSEC order traversal is performed by walking the data records.
+ *
+ * The order is stored with record to allow for efficient reconstuction of
+ * of the offset table following a merge or subtraction.
+ *
+ * The iterator methods here currently only support DNSSEC order iteration.
+ *
+ * The iterator methods in rbtdb support both load order and DNSSEC order
+ * iteration.
+ *
+ * WARNING:
+ * rbtdb.c directly interacts with the slab's raw structures. If the
+ * structure changes then rbtdb.c also needs to be updated to reflect
+ * the changes. See the areas tagged with "RDATASLAB".
+ */
+
+struct xrdata {
+ dns_rdata_t rdata;
+ unsigned int order;
+};
+
+/*% Note: the "const void *" are just to make qsort happy. */
+static int
+compare_rdata(const void *p1, const void *p2) {
+ const struct xrdata *x1 = p1;
+ const struct xrdata *x2 = p2;
+ return (dns_rdata_compare(&x1->rdata, &x2->rdata));
+}
+
+#if DNS_RDATASET_FIXED
+static void
+fillin_offsets(unsigned char *offsetbase, unsigned int *offsettable,
+ unsigned length)
+{
+ unsigned int i, j;
+ unsigned char *raw;
+
+ for (i = 0, j = 0; i < length; i++) {
+
+ if (offsettable[i] == 0)
+ continue;
+
+ /*
+ * Fill in offset table.
+ */
+ raw = &offsetbase[j*4 + 2];
+ *raw++ = (offsettable[i] & 0xff000000) >> 24;
+ *raw++ = (offsettable[i] & 0xff0000) >> 16;
+ *raw++ = (offsettable[i] & 0xff00) >> 8;
+ *raw = offsettable[i] & 0xff;
+
+ /*
+ * Fill in table index.
+ */
+ raw = offsetbase + offsettable[i] + 2;
+ *raw++ = (j & 0xff00) >> 8;
+ *raw = j++ & 0xff;
+ }
+}
+#endif
+
+isc_result_t
+dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
+ isc_region_t *region, unsigned int reservelen)
+{
+ struct xrdata *x;
+ unsigned char *rawbuf;
+#if DNS_RDATASET_FIXED
+ unsigned char *offsetbase;
+#endif
+ unsigned int buflen;
+ isc_result_t result;
+ unsigned int nitems;
+ unsigned int nalloc;
+ unsigned int i;
+#if DNS_RDATASET_FIXED
+ unsigned int *offsettable;
+#endif
+
+ buflen = reservelen + 2;
+
+ nalloc = dns_rdataset_count(rdataset);
+ nitems = nalloc;
+ if (nitems == 0)
+ return (ISC_R_FAILURE);
+
+ if (nalloc > 0xffff)
+ return (ISC_R_NOSPACE);
+
+ x = isc_mem_get(mctx, nalloc * sizeof(struct xrdata));
+ if (x == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /*
+ * Save all of the rdata members into an array.
+ */
+ result = dns_rdataset_first(rdataset);
+ if (result != ISC_R_SUCCESS)
+ goto free_rdatas;
+ for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) {
+ INSIST(result == ISC_R_SUCCESS);
+ dns_rdata_init(&x[i].rdata);
+ dns_rdataset_current(rdataset, &x[i].rdata);
+#if DNS_RDATASET_FIXED
+ x[i].order = i;
+#endif
+ result = dns_rdataset_next(rdataset);
+ }
+ if (result != ISC_R_NOMORE)
+ goto free_rdatas;
+ if (i != nalloc) {
+ /*
+ * Somehow we iterated over fewer rdatas than
+ * dns_rdataset_count() said there were!
+ */
+ result = ISC_R_FAILURE;
+ goto free_rdatas;
+ }
+
+ /*
+ * Put into DNSSEC order.
+ */
+ qsort(x, nalloc, sizeof(struct xrdata), compare_rdata);
+
+ /*
+ * Remove duplicates and compute the total storage required.
+ *
+ * If an rdata is not a duplicate, accumulate the storage size
+ * required for the rdata. We do not store the class, type, etc,
+ * just the rdata, so our overhead is 2 bytes for the number of
+ * records, and 8 for each rdata, (length(2), offset(4) and order(2))
+ * and then the rdata itself.
+ */
+ for (i = 1; i < nalloc; i++) {
+ if (compare_rdata(&x[i-1].rdata, &x[i].rdata) == 0) {
+ x[i-1].rdata.data = NULL;
+ x[i-1].rdata.length = 0;
+#if DNS_RDATASET_FIXED
+ /*
+ * Preserve the least order so A, B, A -> A, B
+ * after duplicate removal.
+ */
+ if (x[i-1].order < x[i].order)
+ x[i].order = x[i-1].order;
+#endif
+ nitems--;
+ } else
+#if DNS_RDATASET_FIXED
+ buflen += (8 + x[i-1].rdata.length);
+#else
+ buflen += (2 + x[i-1].rdata.length);
+#endif
+ }
+ /*
+ * Don't forget the last item!
+ */
+#if DNS_RDATASET_FIXED
+ buflen += (8 + x[i-1].rdata.length);
+#else
+ buflen += (2 + x[i-1].rdata.length);
+#endif
+
+ /*
+ * Ensure that singleton types are actually singletons.
+ */
+ if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) {
+ /*
+ * We have a singleton type, but there's more than one
+ * RR in the rdataset.
+ */
+ result = DNS_R_SINGLETON;
+ goto free_rdatas;
+ }
+
+ /*
+ * Allocate the memory, set up a buffer, start copying in
+ * data.
+ */
+ rawbuf = isc_mem_get(mctx, buflen);
+ if (rawbuf == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto free_rdatas;
+ }
+
+#if DNS_RDATASET_FIXED
+ /* Allocate temporary offset table. */
+ offsettable = isc_mem_get(mctx, nalloc * sizeof(unsigned int));
+ if (offsettable == NULL) {
+ isc_mem_put(mctx, rawbuf, buflen);
+ result = ISC_R_NOMEMORY;
+ goto free_rdatas;
+ }
+ memset(offsettable, 0, nalloc * sizeof(unsigned int));
+#endif
+
+ region->base = rawbuf;
+ region->length = buflen;
+
+ rawbuf += reservelen;
+#if DNS_RDATASET_FIXED
+ offsetbase = rawbuf;
+#endif
+
+ *rawbuf++ = (nitems & 0xff00) >> 8;
+ *rawbuf++ = (nitems & 0x00ff);
+
+#if DNS_RDATASET_FIXED
+ /* Skip load order table. Filled in later. */
+ rawbuf += nitems * 4;
+#endif
+
+ for (i = 0; i < nalloc; i++) {
+ if (x[i].rdata.data == NULL)
+ continue;
+#if DNS_RDATASET_FIXED
+ offsettable[x[i].order] = rawbuf - offsetbase;
+#endif
+ *rawbuf++ = (x[i].rdata.length & 0xff00) >> 8;
+ *rawbuf++ = (x[i].rdata.length & 0x00ff);
+#if DNS_RDATASET_FIXED
+ rawbuf += 2; /* filled in later */
+#endif
+ memcpy(rawbuf, x[i].rdata.data, x[i].rdata.length);
+ rawbuf += x[i].rdata.length;
+ }
+
+#if DNS_RDATASET_FIXED
+ fillin_offsets(offsetbase, offsettable, nalloc);
+ isc_mem_put(mctx, offsettable, nalloc * sizeof(unsigned int));
+#endif
+
+ result = ISC_R_SUCCESS;
+
+ free_rdatas:
+ isc_mem_put(mctx, x, nalloc * sizeof(struct xrdata));
+ return (result);
+}
+
+static void
+rdataset_disassociate(dns_rdataset_t *rdataset) {
+ UNUSED(rdataset);
+}
+
+static isc_result_t
+rdataset_first(dns_rdataset_t *rdataset) {
+ unsigned char *raw = rdataset->private3;
+ unsigned int count;
+
+ count = raw[0] * 256 + raw[1];
+ if (count == 0) {
+ rdataset->private5 = NULL;
+ return (ISC_R_NOMORE);
+ }
+#if DNS_RDATASET_FIXED
+ raw += 2 + (4 * count);
+#else
+ raw += 2;
+#endif
+ /*
+ * The privateuint4 field is the number of rdata beyond the cursor
+ * position, so we decrement the total count by one before storing
+ * it.
+ */
+ count--;
+ rdataset->privateuint4 = count;
+ rdataset->private5 = raw;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+rdataset_next(dns_rdataset_t *rdataset) {
+ unsigned int count;
+ unsigned int length;
+ unsigned char *raw;
+
+ count = rdataset->privateuint4;
+ if (count == 0)
+ return (ISC_R_NOMORE);
+ count--;
+ rdataset->privateuint4 = count;
+ raw = rdataset->private5;
+ length = raw[0] * 256 + raw[1];
+#if DNS_RDATASET_FIXED
+ raw += length + 4;
+#else
+ raw += length + 2;
+#endif
+ rdataset->private5 = raw;
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
+ unsigned char *raw = rdataset->private5;
+ isc_region_t r;
+
+ REQUIRE(raw != NULL);
+
+ r.length = raw[0] * 256 + raw[1];
+#if DNS_RDATASET_FIXED
+ raw += 4;
+#else
+ raw += 2;
+#endif
+ r.base = raw;
+ dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
+}
+
+static void
+rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
+ *target = *source;
+
+ /*
+ * Reset iterator state.
+ */
+ target->privateuint4 = 0;
+ target->private5 = NULL;
+}
+
+static unsigned int
+rdataset_count(dns_rdataset_t *rdataset) {
+ unsigned char *raw = rdataset->private3;
+ unsigned int count;
+
+ count = raw[0] * 256 + raw[1];
+
+ return (count);
+}
+
+static dns_rdatasetmethods_t rdataset_methods = {
+ rdataset_disassociate,
+ rdataset_first,
+ rdataset_next,
+ rdataset_current,
+ rdataset_clone,
+ rdataset_count,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+void
+dns_rdataslab_tordataset(unsigned char *slab, unsigned int reservelen,
+ dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
+ dns_rdatatype_t covers, dns_ttl_t ttl,
+ dns_rdataset_t *rdataset)
+{
+ REQUIRE(slab != NULL);
+ REQUIRE(!dns_rdataset_isassociated(rdataset));
+
+ rdataset->methods = &rdataset_methods;
+ rdataset->rdclass = rdclass;
+ rdataset->type = rdtype;
+ rdataset->covers = covers;
+ rdataset->ttl = ttl;
+ rdataset->trust = 0;
+ rdataset->private1 = NULL;
+ rdataset->private2 = NULL;
+ rdataset->private3 = slab + reservelen;
+
+ /*
+ * Reset iterator state.
+ */
+ rdataset->privateuint4 = 0;
+ rdataset->private5 = NULL;
+}
+
+unsigned int
+dns_rdataslab_size(unsigned char *slab, unsigned int reservelen) {
+ unsigned int count, length;
+ unsigned char *current;
+
+ REQUIRE(slab != NULL);
+
+ current = slab + reservelen;
+ count = *current++ * 256;
+ count += *current++;
+#if DNS_RDATASET_FIXED
+ current += (4 * count);
+#endif
+ while (count > 0) {
+ count--;
+ length = *current++ * 256;
+ length += *current++;
+#if DNS_RDATASET_FIXED
+ current += length + 2;
+#else
+ current += length;
+#endif
+ }
+
+ return ((unsigned int)(current - slab));
+}
+
+/*
+ * Make the dns_rdata_t 'rdata' refer to the slab item
+ * beginning at '*current', which is part of a slab of type
+ * 'type' and class 'rdclass', and advance '*current' to
+ * point to the next item in the slab.
+ */
+static inline void
+rdata_from_slab(unsigned char **current,
+ dns_rdataclass_t rdclass, dns_rdatatype_t type,
+ dns_rdata_t *rdata)
+{
+ unsigned char *tcurrent = *current;
+ isc_region_t region;
+
+ region.length = *tcurrent++ * 256;
+ region.length += *tcurrent++;
+#if DNS_RDATASET_FIXED
+ tcurrent += 2;
+#endif
+ region.base = tcurrent;
+ tcurrent += region.length;
+ dns_rdata_fromregion(rdata, rdclass, type, &region);
+ *current = tcurrent;
+}
+
+/*
+ * Return true iff 'slab' (slab data of type 'type' and class 'rdclass')
+ * contains an rdata identical to 'rdata'. This does case insensitive
+ * comparisons per DNSSEC.
+ */
+static inline isc_boolean_t
+rdata_in_slab(unsigned char *slab, unsigned int reservelen,
+ dns_rdataclass_t rdclass, dns_rdatatype_t type,
+ dns_rdata_t *rdata)
+{
+ unsigned int count, i;
+ unsigned char *current;
+ dns_rdata_t trdata = DNS_RDATA_INIT;
+ int n;
+
+ current = slab + reservelen;
+ count = *current++ * 256;
+ count += *current++;
+
+#if DNS_RDATASET_FIXED
+ current += (4 * count);
+#endif
+
+ for (i = 0; i < count; i++) {
+ rdata_from_slab(&current, rdclass, type, &trdata);
+
+ n = dns_rdata_compare(&trdata, rdata);
+ if (n == 0)
+ return (ISC_TRUE);
+ if (n > 0) /* In DNSSEC order. */
+ break;
+ dns_rdata_reset(&trdata);
+ }
+ return (ISC_FALSE);
+}
+
+isc_result_t
+dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
+ unsigned int reservelen, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_rdatatype_t type,
+ unsigned int flags, unsigned char **tslabp)
+{
+ unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent;
+ unsigned int ocount, ncount, count, olength, tlength, tcount, length;
+ isc_region_t nregion;
+ dns_rdata_t ordata = DNS_RDATA_INIT;
+ dns_rdata_t nrdata = DNS_RDATA_INIT;
+ isc_boolean_t added_something = ISC_FALSE;
+ unsigned int oadded = 0;
+ unsigned int nadded = 0;
+ unsigned int nncount = 0;
+#if DNS_RDATASET_FIXED
+ unsigned int oncount;
+ unsigned int norder = 0;
+ unsigned int oorder = 0;
+ unsigned char *offsetbase;
+ unsigned int *offsettable;
+#endif
+
+ /*
+ * XXX Need parameter to allow "delete rdatasets in nslab" merge,
+ * or perhaps another merge routine for this purpose.
+ */
+
+ REQUIRE(tslabp != NULL && *tslabp == NULL);
+ REQUIRE(oslab != NULL && nslab != NULL);
+
+ ocurrent = oslab + reservelen;
+ ocount = *ocurrent++ * 256;
+ ocount += *ocurrent++;
+#if DNS_RDATASET_FIXED
+ ocurrent += (4 * ocount);
+#endif
+ ostart = ocurrent;
+ ncurrent = nslab + reservelen;
+ ncount = *ncurrent++ * 256;
+ ncount += *ncurrent++;
+#if DNS_RDATASET_FIXED
+ ncurrent += (4 * ncount);
+#endif
+ INSIST(ocount > 0 && ncount > 0);
+
+#if DNS_RDATASET_FIXED
+ oncount = ncount;
+#endif
+
+ /*
+ * Yes, this is inefficient!
+ */
+
+ /*
+ * Figure out the length of the old slab's data.
+ */
+ olength = 0;
+ for (count = 0; count < ocount; count++) {
+ length = *ocurrent++ * 256;
+ length += *ocurrent++;
+#if DNS_RDATASET_FIXED
+ olength += length + 8;
+ ocurrent += length + 2;
+#else
+ olength += length + 2;
+ ocurrent += length;
+#endif
+ }
+
+ /*
+ * Start figuring out the target length and count.
+ */
+ tlength = reservelen + 2 + olength;
+ tcount = ocount;
+
+ /*
+ * Add in the length of rdata in the new slab that aren't in
+ * the old slab.
+ */
+ do {
+ nregion.length = *ncurrent++ * 256;
+ nregion.length += *ncurrent++;
+#if DNS_RDATASET_FIXED
+ ncurrent += 2; /* Skip order. */
+#endif
+ nregion.base = ncurrent;
+ dns_rdata_init(&nrdata);
+ dns_rdata_fromregion(&nrdata, rdclass, type, &nregion);
+ if (!rdata_in_slab(oslab, reservelen, rdclass, type, &nrdata))
+ {
+ /*
+ * This rdata isn't in the old slab.
+ */
+#if DNS_RDATASET_FIXED
+ tlength += nregion.length + 8;
+#else
+ tlength += nregion.length + 2;
+#endif
+ tcount++;
+ nncount++;
+ added_something = ISC_TRUE;
+ }
+ ncurrent += nregion.length;
+ ncount--;
+ } while (ncount > 0);
+ ncount = nncount;
+
+ if (((flags & DNS_RDATASLAB_EXACT) != 0) &&
+ (tcount != ncount + ocount))
+ return (DNS_R_NOTEXACT);
+
+ if (!added_something && (flags & DNS_RDATASLAB_FORCE) == 0)
+ return (DNS_R_UNCHANGED);
+
+ /*
+ * Ensure that singleton types are actually singletons.
+ */
+ if (tcount > 1 && dns_rdatatype_issingleton(type)) {
+ /*
+ * We have a singleton type, but there's more than one
+ * RR in the rdataset.
+ */
+ return (DNS_R_SINGLETON);
+ }
+
+ if (tcount > 0xffff)
+ return (ISC_R_NOSPACE);
+
+ /*
+ * Copy the reserved area from the new slab.
+ */
+ tstart = isc_mem_get(mctx, tlength);
+ if (tstart == NULL)
+ return (ISC_R_NOMEMORY);
+ memcpy(tstart, nslab, reservelen);
+ tcurrent = tstart + reservelen;
+#if DNS_RDATASET_FIXED
+ offsetbase = tcurrent;
+#endif
+
+ /*
+ * Write the new count.
+ */
+ *tcurrent++ = (tcount & 0xff00) >> 8;
+ *tcurrent++ = (tcount & 0x00ff);
+
+#if DNS_RDATASET_FIXED
+ /*
+ * Skip offset table.
+ */
+ tcurrent += (tcount * 4);
+
+ offsettable = isc_mem_get(mctx,
+ (ocount + oncount) * sizeof(unsigned int));
+ if (offsettable == NULL) {
+ isc_mem_put(mctx, tstart, tlength);
+ return (ISC_R_NOMEMORY);
+ }
+ memset(offsettable, 0, (ocount + oncount) * sizeof(unsigned int));
+#endif
+
+ /*
+ * Merge the two slabs.
+ */
+ ocurrent = ostart;
+ INSIST(ocount != 0);
+#if DNS_RDATASET_FIXED
+ oorder = ocurrent[2] * 256 + ocurrent[3];
+ INSIST(oorder < ocount);
+#endif
+ rdata_from_slab(&ocurrent, rdclass, type, &ordata);
+
+ ncurrent = nslab + reservelen + 2;
+#if DNS_RDATASET_FIXED
+ ncurrent += (4 * oncount);
+#endif
+
+ if (ncount > 0) {
+ do {
+ dns_rdata_reset(&nrdata);
+#if DNS_RDATASET_FIXED
+ norder = ncurrent[2] * 256 + ncurrent[3];
+
+ INSIST(norder < oncount);
+#endif
+ rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
+ } while (rdata_in_slab(oslab, reservelen, rdclass,
+ type, &nrdata));
+ }
+
+ while (oadded < ocount || nadded < ncount) {
+ isc_boolean_t fromold;
+ if (oadded == ocount)
+ fromold = ISC_FALSE;
+ else if (nadded == ncount)
+ fromold = ISC_TRUE;
+ else
+ fromold = ISC_TF(compare_rdata(&ordata, &nrdata) < 0);
+ if (fromold) {
+#if DNS_RDATASET_FIXED
+ offsettable[oorder] = tcurrent - offsetbase;
+#endif
+ length = ordata.length;
+ *tcurrent++ = (length & 0xff00) >> 8;
+ *tcurrent++ = (length & 0x00ff);
+#if DNS_RDATASET_FIXED
+ tcurrent += 2; /* fill in later */
+#endif
+ memcpy(tcurrent, ordata.data, length);
+ tcurrent += length;
+ oadded++;
+ if (oadded < ocount) {
+ dns_rdata_reset(&ordata);
+#if DNS_RDATASET_FIXED
+ oorder = ocurrent[2] * 256 + ocurrent[3];
+ INSIST(oorder < ocount);
+#endif
+ rdata_from_slab(&ocurrent, rdclass, type,
+ &ordata);
+ }
+ } else {
+#if DNS_RDATASET_FIXED
+ offsettable[ocount + norder] = tcurrent - offsetbase;
+#endif
+ length = nrdata.length;
+ *tcurrent++ = (length & 0xff00) >> 8;
+ *tcurrent++ = (length & 0x00ff);
+#if DNS_RDATASET_FIXED
+ tcurrent += 2; /* fill in later */
+#endif
+ memcpy(tcurrent, nrdata.data, length);
+ tcurrent += length;
+ nadded++;
+ if (nadded < ncount) {
+ do {
+ dns_rdata_reset(&nrdata);
+#if DNS_RDATASET_FIXED
+ norder = ncurrent[2] * 256 + ncurrent[3];
+ INSIST(norder < oncount);
+#endif
+ rdata_from_slab(&ncurrent, rdclass,
+ type, &nrdata);
+ } while (rdata_in_slab(oslab, reservelen,
+ rdclass, type,
+ &nrdata));
+ }
+ }
+ }
+
+#if DNS_RDATASET_FIXED
+ fillin_offsets(offsetbase, offsettable, ocount + oncount);
+
+ isc_mem_put(mctx, offsettable,
+ (ocount + oncount) * sizeof(unsigned int));
+#endif
+
+ INSIST(tcurrent == tstart + tlength);
+
+ *tslabp = tstart;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab,
+ unsigned int reservelen, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_rdatatype_t type,
+ unsigned int flags, unsigned char **tslabp)
+{
+ unsigned char *mcurrent, *sstart, *scurrent, *tstart, *tcurrent;
+ unsigned int mcount, scount, rcount ,count, tlength, tcount, i;
+ dns_rdata_t srdata = DNS_RDATA_INIT;
+ dns_rdata_t mrdata = DNS_RDATA_INIT;
+#if DNS_RDATASET_FIXED
+ unsigned char *offsetbase;
+ unsigned int *offsettable;
+#endif
+ unsigned int order;
+
+ REQUIRE(tslabp != NULL && *tslabp == NULL);
+ REQUIRE(mslab != NULL && sslab != NULL);
+
+ mcurrent = mslab + reservelen;
+ mcount = *mcurrent++ * 256;
+ mcount += *mcurrent++;
+ scurrent = sslab + reservelen;
+ scount = *scurrent++ * 256;
+ scount += *scurrent++;
+ INSIST(mcount > 0 && scount > 0);
+
+ /*
+ * Yes, this is inefficient!
+ */
+
+ /*
+ * Start figuring out the target length and count.
+ */
+ tlength = reservelen + 2;
+ tcount = 0;
+ rcount = 0;
+
+#if DNS_RDATASET_FIXED
+ mcurrent += 4 * mcount;
+ scurrent += 4 * scount;
+#endif
+ sstart = scurrent;
+
+ /*
+ * Add in the length of rdata in the mslab that aren't in
+ * the sslab.
+ */
+ for (i = 0; i < mcount; i++) {
+ unsigned char *mrdatabegin = mcurrent;
+ rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
+ scurrent = sstart;
+ for (count = 0; count < scount; count++) {
+ dns_rdata_reset(&srdata);
+ rdata_from_slab(&scurrent, rdclass, type, &srdata);
+ if (dns_rdata_compare(&mrdata, &srdata) == 0)
+ break;
+ }
+ if (count == scount) {
+ /*
+ * This rdata isn't in the sslab, and thus isn't
+ * being subtracted.
+ */
+ tlength += mcurrent - mrdatabegin;
+ tcount++;
+ } else
+ rcount++;
+ dns_rdata_reset(&mrdata);
+ }
+
+#if DNS_RDATASET_FIXED
+ tlength += (4 * tcount);
+#endif
+
+ /*
+ * Check that all the records originally existed. The numeric
+ * check only works as rdataslabs do not contain duplicates.
+ */
+ if (((flags & DNS_RDATASLAB_EXACT) != 0) && (rcount != scount))
+ return (DNS_R_NOTEXACT);
+
+ /*
+ * Don't continue if the new rdataslab would be empty.
+ */
+ if (tcount == 0)
+ return (DNS_R_NXRRSET);
+
+ /*
+ * If nothing is going to change, we can stop.
+ */
+ if (rcount == 0)
+ return (DNS_R_UNCHANGED);
+
+ /*
+ * Copy the reserved area from the mslab.
+ */
+ tstart = isc_mem_get(mctx, tlength);
+ if (tstart == NULL)
+ return (ISC_R_NOMEMORY);
+ memcpy(tstart, mslab, reservelen);
+ tcurrent = tstart + reservelen;
+#if DNS_RDATASET_FIXED
+ offsetbase = tcurrent;
+
+ offsettable = isc_mem_get(mctx, mcount * sizeof(unsigned int));
+ if (offsettable == NULL) {
+ isc_mem_put(mctx, tstart, tlength);
+ return (ISC_R_NOMEMORY);
+ }
+ memset(offsettable, 0, mcount * sizeof(unsigned int));
+#endif
+
+ /*
+ * Write the new count.
+ */
+ *tcurrent++ = (tcount & 0xff00) >> 8;
+ *tcurrent++ = (tcount & 0x00ff);
+
+#if DNS_RDATASET_FIXED
+ tcurrent += (4 * tcount);
+#endif
+
+ /*
+ * Copy the parts of mslab not in sslab.
+ */
+ mcurrent = mslab + reservelen;
+ mcount = *mcurrent++ * 256;
+ mcount += *mcurrent++;
+#if DNS_RDATASET_FIXED
+ mcurrent += (4 * mcount);
+#endif
+ for (i = 0; i < mcount; i++) {
+ unsigned char *mrdatabegin = mcurrent;
+#if DNS_RDATASET_FIXED
+ order = mcurrent[2] * 256 + mcurrent[3];
+ INSIST(order < mcount);
+#endif
+ rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
+ scurrent = sstart;
+ for (count = 0; count < scount; count++) {
+ dns_rdata_reset(&srdata);
+ rdata_from_slab(&scurrent, rdclass, type, &srdata);
+ if (dns_rdata_compare(&mrdata, &srdata) == 0)
+ break;
+ }
+ if (count == scount) {
+ /*
+ * This rdata isn't in the sslab, and thus should be
+ * copied to the tslab.
+ */
+ unsigned int length = mcurrent - mrdatabegin;
+#if DNS_RDATASET_FIXED
+ offsettable[order] = tcurrent - offsetbase;
+#endif
+ memcpy(tcurrent, mrdatabegin, length);
+ tcurrent += length;
+ }
+ dns_rdata_reset(&mrdata);
+ }
+
+#if DNS_RDATASET_FIXED
+ fillin_offsets(offsetbase, offsettable, mcount);
+
+ isc_mem_put(mctx, offsettable, mcount * sizeof(unsigned int));
+#endif
+
+ INSIST(tcurrent == tstart + tlength);
+
+ *tslabp = tstart;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_boolean_t
+dns_rdataslab_equal(unsigned char *slab1, unsigned char *slab2,
+ unsigned int reservelen)
+{
+ unsigned char *current1, *current2;
+ unsigned int count1, count2;
+ unsigned int length1, length2;
+
+ current1 = slab1 + reservelen;
+ count1 = *current1++ * 256;
+ count1 += *current1++;
+
+ current2 = slab2 + reservelen;
+ count2 = *current2++ * 256;
+ count2 += *current2++;
+
+ if (count1 != count2)
+ return (ISC_FALSE);
+
+#if DNS_RDATASET_FIXED
+ current1 += (4 * count1);
+ current2 += (4 * count2);
+#endif
+
+ while (count1 > 0) {
+ length1 = *current1++ * 256;
+ length1 += *current1++;
+
+ length2 = *current2++ * 256;
+ length2 += *current2++;
+
+#if DNS_RDATASET_FIXED
+ current1 += 2;
+ current2 += 2;
+#endif
+
+ if (length1 != length2 ||
+ memcmp(current1, current2, length1) != 0)
+ return (ISC_FALSE);
+
+ current1 += length1;
+ current2 += length1;
+
+ count1--;
+ }
+ return (ISC_TRUE);
+}
+
+isc_boolean_t
+dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2,
+ unsigned int reservelen, dns_rdataclass_t rdclass,
+ dns_rdatatype_t type)
+{
+ unsigned char *current1, *current2;
+ unsigned int count1, count2;
+ dns_rdata_t rdata1 = DNS_RDATA_INIT;
+ dns_rdata_t rdata2 = DNS_RDATA_INIT;
+
+ current1 = slab1 + reservelen;
+ count1 = *current1++ * 256;
+ count1 += *current1++;
+
+ current2 = slab2 + reservelen;
+ count2 = *current2++ * 256;
+ count2 += *current2++;
+
+ if (count1 != count2)
+ return (ISC_FALSE);
+
+#if DNS_RDATASET_FIXED
+ current1 += (4 * count1);
+ current2 += (4 * count2);
+#endif
+
+ while (count1-- > 0) {
+ rdata_from_slab(&current1, rdclass, type, &rdata1);
+ rdata_from_slab(&current2, rdclass, type, &rdata2);
+ if (dns_rdata_compare(&rdata1, &rdata2) != 0)
+ return (ISC_FALSE);
+ dns_rdata_reset(&rdata1);
+ dns_rdata_reset(&rdata2);
+ }
+ return (ISC_TRUE);
+}
diff --git a/lib/dns/request.c b/lib/dns/request.c
new file mode 100644
index 0000000..be8f93d
--- /dev/null
+++ b/lib/dns/request.c
@@ -0,0 +1,1461 @@
+/*
+ * Copyright (C) 2004-2006 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: request.c,v 1.72.18.5 2006/08/21 00:40:53 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/acl.h>
+#include <dns/compress.h>
+#include <dns/dispatch.h>
+#include <dns/events.h>
+#include <dns/log.h>
+#include <dns/message.h>
+#include <dns/rdata.h>
+#include <dns/rdatastruct.h>
+#include <dns/request.h>
+#include <dns/result.h>
+#include <dns/tsig.h>
+
+#define REQUESTMGR_MAGIC ISC_MAGIC('R', 'q', 'u', 'M')
+#define VALID_REQUESTMGR(mgr) ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC)
+
+#define REQUEST_MAGIC ISC_MAGIC('R', 'q', 'u', '!')
+#define VALID_REQUEST(request) ISC_MAGIC_VALID(request, REQUEST_MAGIC)
+
+typedef ISC_LIST(dns_request_t) dns_requestlist_t;
+
+#define DNS_REQUEST_NLOCKS 7
+
+struct dns_requestmgr {
+ unsigned int magic;
+ isc_mutex_t lock;
+ isc_mem_t *mctx;
+
+ /* locked */
+ isc_int32_t eref;
+ isc_int32_t iref;
+ isc_timermgr_t *timermgr;
+ isc_socketmgr_t *socketmgr;
+ isc_taskmgr_t *taskmgr;
+ dns_dispatchmgr_t *dispatchmgr;
+ dns_dispatch_t *dispatchv4;
+ dns_dispatch_t *dispatchv6;
+ isc_boolean_t exiting;
+ isc_eventlist_t whenshutdown;
+ unsigned int hash;
+ isc_mutex_t locks[DNS_REQUEST_NLOCKS];
+ dns_requestlist_t requests;
+};
+
+struct dns_request {
+ unsigned int magic;
+ unsigned int hash;
+ isc_mem_t *mctx;
+ isc_int32_t flags;
+ ISC_LINK(dns_request_t) link;
+ isc_buffer_t *query;
+ isc_buffer_t *answer;
+ dns_requestevent_t *event;
+ dns_dispatch_t *dispatch;
+ dns_dispentry_t *dispentry;
+ isc_timer_t *timer;
+ dns_requestmgr_t *requestmgr;
+ isc_buffer_t *tsig;
+ dns_tsigkey_t *tsigkey;
+ isc_event_t ctlevent;
+ isc_boolean_t canceling; /* ctlevent outstanding */
+ isc_sockaddr_t destaddr;
+ unsigned int udpcount;
+};
+
+#define DNS_REQUEST_F_CONNECTING 0x0001
+#define DNS_REQUEST_F_SENDING 0x0002
+#define DNS_REQUEST_F_CANCELED 0x0004 /*%< ctlevent received, or otherwise
+ synchronously canceled */
+#define DNS_REQUEST_F_TIMEDOUT 0x0008 /*%< cancelled due to a timeout */
+#define DNS_REQUEST_F_TCP 0x0010 /*%< This request used TCP */
+#define DNS_REQUEST_CANCELED(r) \
+ (((r)->flags & DNS_REQUEST_F_CANCELED) != 0)
+#define DNS_REQUEST_CONNECTING(r) \
+ (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0)
+#define DNS_REQUEST_SENDING(r) \
+ (((r)->flags & DNS_REQUEST_F_SENDING) != 0)
+#define DNS_REQUEST_TIMEDOUT(r) \
+ (((r)->flags & DNS_REQUEST_F_TIMEDOUT) != 0)
+
+
+/***
+ *** Forward
+ ***/
+
+static void mgr_destroy(dns_requestmgr_t *requestmgr);
+static void mgr_shutdown(dns_requestmgr_t *requestmgr);
+static unsigned int mgr_gethash(dns_requestmgr_t *requestmgr);
+static void send_shutdown_events(dns_requestmgr_t *requestmgr);
+
+static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer,
+ unsigned int options, isc_mem_t *mctx);
+static void req_senddone(isc_task_t *task, isc_event_t *event);
+static void req_response(isc_task_t *task, isc_event_t *event);
+static void req_timeout(isc_task_t *task, isc_event_t *event);
+static void req_connected(isc_task_t *task, isc_event_t *event);
+static void req_sendevent(dns_request_t *request, isc_result_t result);
+static void req_cancel(dns_request_t *request);
+static void req_destroy(dns_request_t *request);
+static void req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
+static void do_cancel(isc_task_t *task, isc_event_t *event);
+
+/***
+ *** Public
+ ***/
+
+isc_result_t
+dns_requestmgr_create(isc_mem_t *mctx,
+ isc_timermgr_t *timermgr,
+ isc_socketmgr_t *socketmgr,
+ isc_taskmgr_t *taskmgr,
+ dns_dispatchmgr_t *dispatchmgr,
+ dns_dispatch_t *dispatchv4,
+ dns_dispatch_t *dispatchv6,
+ dns_requestmgr_t **requestmgrp)
+{
+ dns_requestmgr_t *requestmgr;
+ isc_socket_t *socket;
+ isc_result_t result;
+ int i;
+
+ req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
+
+ REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
+ REQUIRE(timermgr != NULL);
+ REQUIRE(socketmgr != NULL);
+ REQUIRE(taskmgr != NULL);
+ REQUIRE(dispatchmgr != NULL);
+ if (dispatchv4 != NULL) {
+ socket = dns_dispatch_getsocket(dispatchv4);
+ REQUIRE(isc_socket_gettype(socket) == isc_sockettype_udp);
+ }
+ if (dispatchv6 != NULL) {
+ socket = dns_dispatch_getsocket(dispatchv6);
+ REQUIRE(isc_socket_gettype(socket) == isc_sockettype_udp);
+ }
+
+ requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
+ if (requestmgr == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = isc_mutex_init(&requestmgr->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
+ return (result);
+ }
+ for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
+ result = isc_mutex_init(&requestmgr->locks[i]);
+ if (result != ISC_R_SUCCESS) {
+ while (--i >= 0)
+ DESTROYLOCK(&requestmgr->locks[i]);
+ DESTROYLOCK(&requestmgr->lock);
+ isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
+ return (result);
+ }
+ }
+ requestmgr->timermgr = timermgr;
+ requestmgr->socketmgr = socketmgr;
+ requestmgr->taskmgr = taskmgr;
+ requestmgr->dispatchmgr = dispatchmgr;
+ requestmgr->dispatchv4 = NULL;
+ if (dispatchv4 != NULL)
+ dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4);
+ requestmgr->dispatchv6 = NULL;
+ if (dispatchv6 != NULL)
+ dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6);
+ requestmgr->mctx = NULL;
+ isc_mem_attach(mctx, &requestmgr->mctx);
+ requestmgr->eref = 1; /* implict attach */
+ requestmgr->iref = 0;
+ ISC_LIST_INIT(requestmgr->whenshutdown);
+ ISC_LIST_INIT(requestmgr->requests);
+ requestmgr->exiting = ISC_FALSE;
+ requestmgr->hash = 0;
+ requestmgr->magic = REQUESTMGR_MAGIC;
+
+ req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr);
+
+ *requestmgrp = requestmgr;
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task,
+ isc_event_t **eventp)
+{
+ isc_task_t *clone;
+ isc_event_t *event;
+
+ req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_whenshutdown");
+
+ REQUIRE(VALID_REQUESTMGR(requestmgr));
+ REQUIRE(eventp != NULL);
+
+ event = *eventp;
+ *eventp = NULL;
+
+ LOCK(&requestmgr->lock);
+
+ if (requestmgr->exiting) {
+ /*
+ * We're already shutdown. Send the event.
+ */
+ event->ev_sender = requestmgr;
+ isc_task_send(task, &event);
+ } else {
+ clone = NULL;
+ isc_task_attach(task, &clone);
+ event->ev_sender = clone;
+ ISC_LIST_APPEND(requestmgr->whenshutdown, event, ev_link);
+ }
+ UNLOCK(&requestmgr->lock);
+}
+
+void
+dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
+
+ REQUIRE(VALID_REQUESTMGR(requestmgr));
+
+ req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr);
+
+ LOCK(&requestmgr->lock);
+ mgr_shutdown(requestmgr);
+ UNLOCK(&requestmgr->lock);
+}
+
+static void
+mgr_shutdown(dns_requestmgr_t *requestmgr) {
+ dns_request_t *request;
+
+ /*
+ * Caller holds lock.
+ */
+ if (!requestmgr->exiting) {
+ requestmgr->exiting = ISC_TRUE;
+ for (request = ISC_LIST_HEAD(requestmgr->requests);
+ request != NULL;
+ request = ISC_LIST_NEXT(request, link)) {
+ dns_request_cancel(request);
+ }
+ if (requestmgr->iref == 0) {
+ INSIST(ISC_LIST_EMPTY(requestmgr->requests));
+ send_shutdown_events(requestmgr);
+ }
+ }
+}
+
+static void
+requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
+
+ /*
+ * Locked by caller.
+ */
+
+ REQUIRE(VALID_REQUESTMGR(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ REQUIRE(!source->exiting);
+
+ source->iref++;
+ *targetp = source;
+
+ req_log(ISC_LOG_DEBUG(3), "requestmgr_attach: %p: eref %d iref %d",
+ source, source->eref, source->iref);
+}
+
+static void
+requestmgr_detach(dns_requestmgr_t **requestmgrp) {
+ dns_requestmgr_t *requestmgr;
+ isc_boolean_t need_destroy = ISC_FALSE;
+
+ REQUIRE(requestmgrp != NULL);
+ requestmgr = *requestmgrp;
+ REQUIRE(VALID_REQUESTMGR(requestmgr));
+
+ *requestmgrp = NULL;
+ LOCK(&requestmgr->lock);
+ INSIST(requestmgr->iref > 0);
+ requestmgr->iref--;
+
+ req_log(ISC_LOG_DEBUG(3), "requestmgr_detach: %p: eref %d iref %d",
+ requestmgr, requestmgr->eref, requestmgr->iref);
+
+ if (requestmgr->iref == 0 && requestmgr->exiting) {
+ INSIST(ISC_LIST_HEAD(requestmgr->requests) == NULL);
+ send_shutdown_events(requestmgr);
+ if (requestmgr->eref == 0)
+ need_destroy = ISC_TRUE;
+ }
+ UNLOCK(&requestmgr->lock);
+
+ if (need_destroy)
+ mgr_destroy(requestmgr);
+}
+
+void
+dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
+
+ REQUIRE(VALID_REQUESTMGR(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+ REQUIRE(!source->exiting);
+
+ LOCK(&source->lock);
+ source->eref++;
+ *targetp = source;
+ UNLOCK(&source->lock);
+
+ req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: eref %d iref %d",
+ source, source->eref, source->iref);
+}
+
+void
+dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) {
+ dns_requestmgr_t *requestmgr;
+ isc_boolean_t need_destroy = ISC_FALSE;
+
+ REQUIRE(requestmgrp != NULL);
+ requestmgr = *requestmgrp;
+ REQUIRE(VALID_REQUESTMGR(requestmgr));
+
+ LOCK(&requestmgr->lock);
+ INSIST(requestmgr->eref > 0);
+ requestmgr->eref--;
+
+ req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: eref %d iref %d",
+ requestmgr, requestmgr->eref, requestmgr->iref);
+
+ if (requestmgr->eref == 0 && requestmgr->iref == 0) {
+ INSIST(requestmgr->exiting &&
+ ISC_LIST_HEAD(requestmgr->requests) == NULL);
+ need_destroy = ISC_TRUE;
+ }
+ UNLOCK(&requestmgr->lock);
+
+ if (need_destroy)
+ mgr_destroy(requestmgr);
+
+ *requestmgrp = NULL;
+}
+
+static void
+send_shutdown_events(dns_requestmgr_t *requestmgr) {
+ isc_event_t *event, *next_event;
+ isc_task_t *etask;
+
+ req_log(ISC_LOG_DEBUG(3), "send_shutdown_events: %p", requestmgr);
+
+ /*
+ * Caller must be holding the manager lock.
+ */
+ for (event = ISC_LIST_HEAD(requestmgr->whenshutdown);
+ event != NULL;
+ event = next_event) {
+ next_event = ISC_LIST_NEXT(event, ev_link);
+ ISC_LIST_UNLINK(requestmgr->whenshutdown, event, ev_link);
+ etask = event->ev_sender;
+ event->ev_sender = requestmgr;
+ isc_task_sendanddetach(&etask, &event);
+ }
+}
+
+static void
+mgr_destroy(dns_requestmgr_t *requestmgr) {
+ int i;
+ isc_mem_t *mctx;
+
+ req_log(ISC_LOG_DEBUG(3), "mgr_destroy");
+
+ REQUIRE(requestmgr->eref == 0);
+ REQUIRE(requestmgr->iref == 0);
+
+ DESTROYLOCK(&requestmgr->lock);
+ for (i = 0; i < DNS_REQUEST_NLOCKS; i++)
+ DESTROYLOCK(&requestmgr->locks[i]);
+ if (requestmgr->dispatchv4 != NULL)
+ dns_dispatch_detach(&requestmgr->dispatchv4);
+ if (requestmgr->dispatchv6 != NULL)
+ dns_dispatch_detach(&requestmgr->dispatchv6);
+ requestmgr->magic = 0;
+ mctx = requestmgr->mctx;
+ isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
+ isc_mem_detach(&mctx);
+}
+
+static unsigned int
+mgr_gethash(dns_requestmgr_t *requestmgr) {
+ req_log(ISC_LOG_DEBUG(3), "mgr_gethash");
+ /*
+ * Locked by caller.
+ */
+ requestmgr->hash++;
+ return (requestmgr->hash % DNS_REQUEST_NLOCKS);
+}
+
+static inline isc_result_t
+req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) {
+ isc_region_t r;
+ isc_socket_t *socket;
+ isc_result_t result;
+
+ req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
+
+ REQUIRE(VALID_REQUEST(request));
+ socket = dns_dispatch_getsocket(request->dispatch);
+ isc_buffer_usedregion(request->query, &r);
+ result = isc_socket_sendto(socket, &r, task, req_senddone,
+ request, address, NULL);
+ if (result == ISC_R_SUCCESS)
+ request->flags |= DNS_REQUEST_F_SENDING;
+ return (result);
+}
+
+static isc_result_t
+new_request(isc_mem_t *mctx, dns_request_t **requestp) {
+ dns_request_t *request;
+
+ request = isc_mem_get(mctx, sizeof(*request));
+ if (request == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /*
+ * Zero structure.
+ */
+ request->magic = 0;
+ request->mctx = NULL;
+ request->flags = 0;
+ ISC_LINK_INIT(request, link);
+ request->query = NULL;
+ request->answer = NULL;
+ request->event = NULL;
+ request->dispatch = NULL;
+ request->dispentry = NULL;
+ request->timer = NULL;
+ request->requestmgr = NULL;
+ request->tsig = NULL;
+ request->tsigkey = NULL;
+ ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL,
+ DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL,
+ NULL, NULL);
+ request->canceling = ISC_FALSE;
+ request->udpcount = 0;
+
+ isc_mem_attach(mctx, &request->mctx);
+
+ request->magic = REQUEST_MAGIC;
+ *requestp = request;
+ return (ISC_R_SUCCESS);
+}
+
+
+static isc_boolean_t
+isblackholed(dns_dispatchmgr_t *dispatchmgr, isc_sockaddr_t *destaddr) {
+ dns_acl_t *blackhole;
+ isc_netaddr_t netaddr;
+ int match;
+ isc_boolean_t drop = ISC_FALSE;
+ char netaddrstr[ISC_NETADDR_FORMATSIZE];
+
+ blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
+ if (blackhole != NULL) {
+ isc_netaddr_fromsockaddr(&netaddr, destaddr);
+ if (dns_acl_match(&netaddr, NULL, blackhole,
+ NULL, &match, NULL) == ISC_R_SUCCESS &&
+ match > 0)
+ drop = ISC_TRUE;
+ }
+ if (drop) {
+ isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
+ req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
+ }
+ return (drop);
+}
+
+static isc_result_t
+create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
+ isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
+{
+ isc_result_t result;
+ isc_socket_t *socket = NULL;
+ isc_sockaddr_t src;
+ unsigned int attrs;
+ isc_sockaddr_t bind_any;
+
+ result = isc_socket_create(requestmgr->socketmgr,
+ isc_sockaddr_pf(destaddr),
+ isc_sockettype_tcp, &socket);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
+ if (srcaddr == NULL) {
+ isc_sockaddr_anyofpf(&bind_any,
+ isc_sockaddr_pf(destaddr));
+ result = isc_socket_bind(socket, &bind_any);
+ } else {
+ src = *srcaddr;
+ isc_sockaddr_setport(&src, 0);
+ result = isc_socket_bind(socket, &src);
+ }
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+#endif
+ attrs = 0;
+ attrs |= DNS_DISPATCHATTR_TCP;
+ attrs |= DNS_DISPATCHATTR_PRIVATE;
+ if (isc_sockaddr_pf(destaddr) == AF_INET)
+ attrs |= DNS_DISPATCHATTR_IPV4;
+ else
+ attrs |= DNS_DISPATCHATTR_IPV6;
+ attrs |= DNS_DISPATCHATTR_MAKEQUERY;
+ result = dns_dispatch_createtcp(requestmgr->dispatchmgr,
+ socket, requestmgr->taskmgr,
+ 4096, 2, 1, 1, 3, attrs,
+ dispatchp);
+cleanup:
+ isc_socket_detach(&socket);
+ return (result);
+}
+
+static isc_result_t
+find_udp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
+ isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
+{
+ dns_dispatch_t *disp = NULL;
+ unsigned int attrs, attrmask;
+
+ if (srcaddr == NULL) {
+ switch (isc_sockaddr_pf(destaddr)) {
+ case PF_INET:
+ disp = requestmgr->dispatchv4;
+ break;
+
+ case PF_INET6:
+ disp = requestmgr->dispatchv6;
+ break;
+
+ default:
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+ if (disp == NULL)
+ return (ISC_R_FAMILYNOSUPPORT);
+ dns_dispatch_attach(disp, dispatchp);
+ return (ISC_R_SUCCESS);
+ }
+ attrs = 0;
+ attrs |= DNS_DISPATCHATTR_UDP;
+ switch (isc_sockaddr_pf(srcaddr)) {
+ case PF_INET:
+ attrs |= DNS_DISPATCHATTR_IPV4;
+ break;
+
+ case PF_INET6:
+ attrs |= DNS_DISPATCHATTR_IPV6;
+ break;
+
+ default:
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+ attrmask = 0;
+ attrmask |= DNS_DISPATCHATTR_UDP;
+ attrmask |= DNS_DISPATCHATTR_TCP;
+ attrmask |= DNS_DISPATCHATTR_IPV4;
+ attrmask |= DNS_DISPATCHATTR_IPV6;
+ return (dns_dispatch_getudp(requestmgr->dispatchmgr,
+ requestmgr->socketmgr,
+ requestmgr->taskmgr,
+ srcaddr, 4096,
+ 1000, 32768, 16411, 16433,
+ attrs, attrmask,
+ dispatchp));
+}
+
+static isc_result_t
+get_dispatch(isc_boolean_t tcp, dns_requestmgr_t *requestmgr,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ dns_dispatch_t **dispatchp)
+{
+ isc_result_t result;
+ if (tcp)
+ result = create_tcp_dispatch(requestmgr, srcaddr,
+ destaddr, dispatchp);
+ else
+ result = find_udp_dispatch(requestmgr, srcaddr,
+ destaddr, dispatchp);
+ return (result);
+}
+
+static isc_result_t
+set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) {
+ isc_time_t expires;
+ isc_interval_t interval;
+ isc_result_t result;
+ isc_timertype_t timertype;
+
+ isc_interval_set(&interval, timeout, 0);
+ result = isc_time_nowplusinterval(&expires, &interval);
+ isc_interval_set(&interval, udpresend, 0);
+
+ timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once;
+ if (result == ISC_R_SUCCESS)
+ result = isc_timer_reset(timer, timertype, &expires,
+ &interval, ISC_FALSE);
+ return (result);
+}
+
+isc_result_t
+dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, unsigned int timeout,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_request_t **requestp)
+{
+ return(dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
+ options, timeout, 0, 0, task, action,
+ arg, requestp));
+}
+
+isc_result_t
+dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, unsigned int timeout,
+ unsigned int udptimeout, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_request_t **requestp)
+{
+ unsigned int udpretries = 0;
+
+ if (udptimeout != 0)
+ udpretries = timeout / udptimeout;
+
+ return (dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr,
+ options, timeout, udptimeout,
+ udpretries, task, action, arg,
+ requestp));
+}
+
+isc_result_t
+dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, unsigned int timeout,
+ unsigned int udptimeout, unsigned int udpretries,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_request_t **requestp)
+{
+ dns_request_t *request = NULL;
+ isc_task_t *tclone = NULL;
+ isc_socket_t *socket = NULL;
+ isc_result_t result;
+ isc_mem_t *mctx;
+ dns_messageid_t id;
+ isc_boolean_t tcp = ISC_FALSE;
+ isc_region_t r;
+
+ REQUIRE(VALID_REQUESTMGR(requestmgr));
+ REQUIRE(msgbuf != NULL);
+ REQUIRE(destaddr != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+ REQUIRE(requestp != NULL && *requestp == NULL);
+ REQUIRE(timeout > 0);
+ if (srcaddr != NULL)
+ REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
+
+ mctx = requestmgr->mctx;
+
+ req_log(ISC_LOG_DEBUG(3), "dns_request_createraw");
+
+ if (isblackholed(requestmgr->dispatchmgr, destaddr))
+ return (DNS_R_BLACKHOLED);
+
+ request = NULL;
+ result = new_request(mctx, &request);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (udptimeout == 0 && udpretries != 0) {
+ udptimeout = timeout / (udpretries + 1);
+ if (udptimeout == 0)
+ udptimeout = 1;
+ }
+ request->udpcount = udpretries;
+
+ /*
+ * Create timer now. We will set it below once.
+ */
+ result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
+ NULL, NULL, task, req_timeout, request,
+ &request->timer);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ request->event = (dns_requestevent_t *)
+ isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
+ action, arg, sizeof(dns_requestevent_t));
+ if (request->event == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ isc_task_attach(task, &tclone);
+ request->event->ev_sender = task;
+ request->event->request = request;
+ request->event->result = ISC_R_FAILURE;
+
+ isc_buffer_usedregion(msgbuf, &r);
+ if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
+ result = DNS_R_FORMERR;
+ goto cleanup;
+ }
+
+ if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512)
+ tcp = ISC_TRUE;
+
+ result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
+ &request->dispatch);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ socket = dns_dispatch_getsocket(request->dispatch);
+ INSIST(socket != NULL);
+ result = dns_dispatch_addresponse(request->dispatch, destaddr, task,
+ req_response, request, &id,
+ &request->dispentry);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = isc_buffer_allocate(mctx, &request->query,
+ r.length + (tcp ? 2 : 0));
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ if (tcp)
+ isc_buffer_putuint16(request->query, (isc_uint16_t)r.length);
+ result = isc_buffer_copyregion(request->query, &r);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ /* Add message ID. */
+ isc_buffer_usedregion(request->query, &r);
+ if (tcp)
+ isc_region_consume(&r, 2);
+ r.base[0] = (id>>8) & 0xff;
+ r.base[1] = id & 0xff;
+
+ LOCK(&requestmgr->lock);
+ if (requestmgr->exiting) {
+ UNLOCK(&requestmgr->lock);
+ result = ISC_R_SHUTTINGDOWN;
+ goto cleanup;
+ }
+ requestmgr_attach(requestmgr, &request->requestmgr);
+ request->hash = mgr_gethash(requestmgr);
+ ISC_LIST_APPEND(requestmgr->requests, request, link);
+ UNLOCK(&requestmgr->lock);
+
+ result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
+ if (result != ISC_R_SUCCESS)
+ goto unlink;
+
+ request->destaddr = *destaddr;
+ if (tcp) {
+ result = isc_socket_connect(socket, destaddr, task,
+ req_connected, request);
+ if (result != ISC_R_SUCCESS)
+ goto unlink;
+ request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
+ } else {
+ result = req_send(request, task, destaddr);
+ if (result != ISC_R_SUCCESS)
+ goto unlink;
+ }
+
+ req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p",
+ request);
+ *requestp = request;
+ return (ISC_R_SUCCESS);
+
+ unlink:
+ LOCK(&requestmgr->lock);
+ ISC_LIST_UNLINK(requestmgr->requests, request, link);
+ UNLOCK(&requestmgr->lock);
+
+ cleanup:
+ if (tclone != NULL)
+ isc_task_detach(&tclone);
+ req_destroy(request);
+ req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
+ dns_result_totext(result));
+ return (result);
+}
+
+isc_result_t
+dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
+ isc_sockaddr_t *address, unsigned int options,
+ dns_tsigkey_t *key,
+ unsigned int timeout, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_request_t **requestp)
+{
+ return (dns_request_createvia3(requestmgr, message, NULL, address,
+ options, key, timeout, 0, 0, task,
+ action, arg, requestp));
+}
+
+isc_result_t
+dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, dns_tsigkey_t *key,
+ unsigned int timeout, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_request_t **requestp)
+{
+ return(dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
+ options, key, timeout, 0, 0, task,
+ action, arg, requestp));
+}
+
+isc_result_t
+dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, dns_tsigkey_t *key,
+ unsigned int timeout, unsigned int udptimeout,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_request_t **requestp)
+{
+ unsigned int udpretries = 0;
+
+ if (udptimeout != 0)
+ udpretries = timeout / udptimeout;
+ return (dns_request_createvia3(requestmgr, message, srcaddr, destaddr,
+ options, key, timeout, udptimeout,
+ udpretries, task, action, arg,
+ requestp));
+}
+
+isc_result_t
+dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ unsigned int options, dns_tsigkey_t *key,
+ unsigned int timeout, unsigned int udptimeout,
+ unsigned int udpretries, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_request_t **requestp)
+{
+ dns_request_t *request = NULL;
+ isc_task_t *tclone = NULL;
+ isc_socket_t *socket = NULL;
+ isc_result_t result;
+ isc_mem_t *mctx;
+ dns_messageid_t id;
+ isc_boolean_t tcp;
+ isc_boolean_t setkey = ISC_TRUE;
+
+ REQUIRE(VALID_REQUESTMGR(requestmgr));
+ REQUIRE(message != NULL);
+ REQUIRE(destaddr != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+ REQUIRE(requestp != NULL && *requestp == NULL);
+ REQUIRE(timeout > 0);
+ if (srcaddr != NULL)
+ REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
+
+ mctx = requestmgr->mctx;
+
+ req_log(ISC_LOG_DEBUG(3), "dns_request_createvia");
+
+ if (isblackholed(requestmgr->dispatchmgr, destaddr))
+ return (DNS_R_BLACKHOLED);
+
+ request = NULL;
+ result = new_request(mctx, &request);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (udptimeout == 0 && udpretries != 0) {
+ udptimeout = timeout / (udpretries + 1);
+ if (udptimeout == 0)
+ udptimeout = 1;
+ }
+ request->udpcount = udpretries;
+
+ /*
+ * Create timer now. We will set it below once.
+ */
+ result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
+ NULL, NULL, task, req_timeout, request,
+ &request->timer);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ request->event = (dns_requestevent_t *)
+ isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
+ action, arg, sizeof(dns_requestevent_t));
+ if (request->event == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ isc_task_attach(task, &tclone);
+ request->event->ev_sender = task;
+ request->event->request = request;
+ request->event->result = ISC_R_FAILURE;
+ if (key != NULL)
+ dns_tsigkey_attach(key, &request->tsigkey);
+
+ use_tcp:
+ tcp = ISC_TF((options & DNS_REQUESTOPT_TCP) != 0);
+ result = get_dispatch(tcp, requestmgr, srcaddr, destaddr,
+ &request->dispatch);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ socket = dns_dispatch_getsocket(request->dispatch);
+ INSIST(socket != NULL);
+ result = dns_dispatch_addresponse(request->dispatch, destaddr, task,
+ req_response, request, &id,
+ &request->dispentry);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ message->id = id;
+ if (setkey) {
+ result = dns_message_settsigkey(message, request->tsigkey);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ }
+ result = req_render(message, &request->query, options, mctx);
+ if (result == DNS_R_USETCP &&
+ (options & DNS_REQUESTOPT_TCP) == 0) {
+ /*
+ * Try again using TCP.
+ */
+ dns_message_renderreset(message);
+ dns_dispatch_removeresponse(&request->dispentry, NULL);
+ dns_dispatch_detach(&request->dispatch);
+ socket = NULL;
+ options |= DNS_REQUESTOPT_TCP;
+ setkey = ISC_FALSE;
+ goto use_tcp;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = dns_message_getquerytsig(message, mctx, &request->tsig);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ LOCK(&requestmgr->lock);
+ if (requestmgr->exiting) {
+ UNLOCK(&requestmgr->lock);
+ result = ISC_R_SHUTTINGDOWN;
+ goto cleanup;
+ }
+ requestmgr_attach(requestmgr, &request->requestmgr);
+ request->hash = mgr_gethash(requestmgr);
+ ISC_LIST_APPEND(requestmgr->requests, request, link);
+ UNLOCK(&requestmgr->lock);
+
+ result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
+ if (result != ISC_R_SUCCESS)
+ goto unlink;
+
+ request->destaddr = *destaddr;
+ if (tcp) {
+ result = isc_socket_connect(socket, destaddr, task,
+ req_connected, request);
+ if (result != ISC_R_SUCCESS)
+ goto unlink;
+ request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
+ } else {
+ result = req_send(request, task, destaddr);
+ if (result != ISC_R_SUCCESS)
+ goto unlink;
+ }
+
+ req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p",
+ request);
+ *requestp = request;
+ return (ISC_R_SUCCESS);
+
+ unlink:
+ LOCK(&requestmgr->lock);
+ ISC_LIST_UNLINK(requestmgr->requests, request, link);
+ UNLOCK(&requestmgr->lock);
+
+ cleanup:
+ if (tclone != NULL)
+ isc_task_detach(&tclone);
+ req_destroy(request);
+ req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s",
+ dns_result_totext(result));
+ return (result);
+}
+
+static isc_result_t
+req_render(dns_message_t *message, isc_buffer_t **bufferp,
+ unsigned int options, isc_mem_t *mctx)
+{
+ isc_buffer_t *buf1 = NULL;
+ isc_buffer_t *buf2 = NULL;
+ isc_result_t result;
+ isc_region_t r;
+ isc_boolean_t tcp = ISC_FALSE;
+ dns_compress_t cctx;
+ isc_boolean_t cleanup_cctx = ISC_FALSE;
+
+ REQUIRE(bufferp != NULL && *bufferp == NULL);
+
+ req_log(ISC_LOG_DEBUG(3), "request_render");
+
+ /*
+ * Create buffer able to hold largest possible message.
+ */
+ result = isc_buffer_allocate(mctx, &buf1, 65535);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_compress_init(&cctx, -1, mctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ cleanup_cctx = ISC_TRUE;
+
+ /*
+ * Render message.
+ */
+ result = dns_message_renderbegin(message, &cctx, buf1);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_message_renderend(message);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ dns_compress_invalidate(&cctx);
+ cleanup_cctx = ISC_FALSE;
+
+ /*
+ * Copy rendered message to exact sized buffer.
+ */
+ isc_buffer_usedregion(buf1, &r);
+ if ((options & DNS_REQUESTOPT_TCP) != 0) {
+ tcp = ISC_TRUE;
+ } else if (r.length > 512) {
+ result = DNS_R_USETCP;
+ goto cleanup;
+ }
+ result = isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0));
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ if (tcp)
+ isc_buffer_putuint16(buf2, (isc_uint16_t)r.length);
+ result = isc_buffer_copyregion(buf2, &r);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ /*
+ * Cleanup and return.
+ */
+ isc_buffer_free(&buf1);
+ *bufferp = buf2;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ dns_message_renderreset(message);
+ if (buf1 != NULL)
+ isc_buffer_free(&buf1);
+ if (buf2 != NULL)
+ isc_buffer_free(&buf2);
+ if (cleanup_cctx)
+ dns_compress_invalidate(&cctx);
+ return (result);
+}
+
+
+/*
+ * If this request is no longer waiting for events,
+ * send the completion event. This will ultimately
+ * cause the request to be destroyed.
+ *
+ * Requires:
+ * 'request' is locked by the caller.
+ */
+static void
+send_if_done(dns_request_t *request, isc_result_t result) {
+ if (!DNS_REQUEST_CONNECTING(request) &&
+ !DNS_REQUEST_SENDING(request) &&
+ !request->canceling)
+ req_sendevent(request, result);
+}
+
+/*
+ * Handle the control event.
+ */
+static void
+do_cancel(isc_task_t *task, isc_event_t *event) {
+ dns_request_t *request = event->ev_arg;
+ UNUSED(task);
+ INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL);
+ LOCK(&request->requestmgr->locks[request->hash]);
+ request->canceling = ISC_FALSE;
+ if (!DNS_REQUEST_CANCELED(request))
+ req_cancel(request);
+ send_if_done(request, ISC_R_CANCELED);
+ UNLOCK(&request->requestmgr->locks[request->hash]);
+}
+
+void
+dns_request_cancel(dns_request_t *request) {
+ REQUIRE(VALID_REQUEST(request));
+
+ req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request);
+
+ REQUIRE(VALID_REQUEST(request));
+
+ LOCK(&request->requestmgr->locks[request->hash]);
+ if (!request->canceling && !DNS_REQUEST_CANCELED(request)) {
+ isc_event_t *ev = &request->ctlevent;
+ isc_task_send(request->event->ev_sender, &ev);
+ request->canceling = ISC_TRUE;
+ }
+ UNLOCK(&request->requestmgr->locks[request->hash]);
+}
+
+isc_result_t
+dns_request_getresponse(dns_request_t *request, dns_message_t *message,
+ unsigned int options)
+{
+ isc_result_t result;
+
+ REQUIRE(VALID_REQUEST(request));
+ REQUIRE(request->answer != NULL);
+
+ req_log(ISC_LOG_DEBUG(3), "dns_request_getresponse: request %p",
+ request);
+
+ result = dns_message_setquerytsig(message, request->tsig);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dns_message_settsigkey(message, request->tsigkey);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dns_message_parse(message, request->answer, options);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (request->tsigkey != NULL)
+ result = dns_tsig_verify(request->answer, message, NULL, NULL);
+ return (result);
+}
+
+isc_boolean_t
+dns_request_usedtcp(dns_request_t *request) {
+ REQUIRE(VALID_REQUEST(request));
+
+ return (ISC_TF((request->flags & DNS_REQUEST_F_TCP) != 0));
+}
+
+void
+dns_request_destroy(dns_request_t **requestp) {
+ dns_request_t *request;
+
+ REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
+
+ request = *requestp;
+
+ req_log(ISC_LOG_DEBUG(3), "dns_request_destroy: request %p", request);
+
+ LOCK(&request->requestmgr->lock);
+ LOCK(&request->requestmgr->locks[request->hash]);
+ ISC_LIST_UNLINK(request->requestmgr->requests, request, link);
+ INSIST(!DNS_REQUEST_CONNECTING(request));
+ INSIST(!DNS_REQUEST_SENDING(request));
+ UNLOCK(&request->requestmgr->locks[request->hash]);
+ UNLOCK(&request->requestmgr->lock);
+
+ /*
+ * These should have been cleaned up by req_cancel() before
+ * the completion event was sent.
+ */
+ INSIST(!ISC_LINK_LINKED(request, link));
+ INSIST(request->dispentry == NULL);
+ INSIST(request->dispatch == NULL);
+ INSIST(request->timer == NULL);
+
+ req_destroy(request);
+
+ *requestp = NULL;
+}
+
+/***
+ *** Private: request.
+ ***/
+
+static void
+req_connected(isc_task_t *task, isc_event_t *event) {
+ isc_socketevent_t *sevent = (isc_socketevent_t *)event;
+ isc_result_t result;
+ dns_request_t *request = event->ev_arg;
+
+ REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
+ REQUIRE(VALID_REQUEST(request));
+ REQUIRE(DNS_REQUEST_CONNECTING(request));
+
+ req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request);
+
+ LOCK(&request->requestmgr->locks[request->hash]);
+ request->flags &= ~DNS_REQUEST_F_CONNECTING;
+
+ if (DNS_REQUEST_CANCELED(request)) {
+ /*
+ * Send delayed event.
+ */
+ if (DNS_REQUEST_TIMEDOUT(request))
+ send_if_done(request, ISC_R_TIMEDOUT);
+ else
+ send_if_done(request, ISC_R_CANCELED);
+ } else {
+ dns_dispatch_starttcp(request->dispatch);
+ result = sevent->result;
+ if (result == ISC_R_SUCCESS)
+ result = req_send(request, task, NULL);
+
+ if (result != ISC_R_SUCCESS) {
+ req_cancel(request);
+ send_if_done(request, ISC_R_CANCELED);
+ }
+ }
+ UNLOCK(&request->requestmgr->locks[request->hash]);
+ isc_event_free(&event);
+}
+
+static void
+req_senddone(isc_task_t *task, isc_event_t *event) {
+ isc_socketevent_t *sevent = (isc_socketevent_t *)event;
+ dns_request_t *request = event->ev_arg;
+
+ REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
+ REQUIRE(VALID_REQUEST(request));
+ REQUIRE(DNS_REQUEST_SENDING(request));
+
+ req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request);
+
+ UNUSED(task);
+
+ LOCK(&request->requestmgr->locks[request->hash]);
+ request->flags &= ~DNS_REQUEST_F_SENDING;
+
+ if (DNS_REQUEST_CANCELED(request)) {
+ /*
+ * Send delayed event.
+ */
+ if (DNS_REQUEST_TIMEDOUT(request))
+ send_if_done(request, ISC_R_TIMEDOUT);
+ else
+ send_if_done(request, ISC_R_CANCELED);
+ } else if (sevent->result != ISC_R_SUCCESS) {
+ req_cancel(request);
+ send_if_done(request, ISC_R_CANCELED);
+ }
+ UNLOCK(&request->requestmgr->locks[request->hash]);
+
+ isc_event_free(&event);
+}
+
+static void
+req_response(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ dns_request_t *request = event->ev_arg;
+ dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
+ isc_region_t r;
+
+ REQUIRE(VALID_REQUEST(request));
+ REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
+
+ UNUSED(task);
+
+ req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request,
+ dns_result_totext(devent->result));
+
+ LOCK(&request->requestmgr->locks[request->hash]);
+ result = devent->result;
+ if (result != ISC_R_SUCCESS)
+ goto done;
+
+ /*
+ * Copy buffer to request.
+ */
+ isc_buffer_usedregion(&devent->buffer, &r);
+ result = isc_buffer_allocate(request->mctx, &request->answer,
+ r.length);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ result = isc_buffer_copyregion(request->answer, &r);
+ if (result != ISC_R_SUCCESS)
+ isc_buffer_free(&request->answer);
+ done:
+ /*
+ * Cleanup.
+ */
+ dns_dispatch_removeresponse(&request->dispentry, &devent);
+ req_cancel(request);
+ /*
+ * Send completion event.
+ */
+ send_if_done(request, result);
+ UNLOCK(&request->requestmgr->locks[request->hash]);
+}
+
+static void
+req_timeout(isc_task_t *task, isc_event_t *event) {
+ dns_request_t *request = event->ev_arg;
+ isc_result_t result;
+
+ REQUIRE(VALID_REQUEST(request));
+
+ req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request);
+
+ UNUSED(task);
+ LOCK(&request->requestmgr->locks[request->hash]);
+ if (event->ev_type == ISC_TIMEREVENT_TICK &&
+ request->udpcount-- != 0) {
+ if (! DNS_REQUEST_SENDING(request)) {
+ result = req_send(request, task, &request->destaddr);
+ if (result != ISC_R_SUCCESS) {
+ req_cancel(request);
+ send_if_done(request, result);
+ }
+ }
+ } else {
+ request->flags |= DNS_REQUEST_F_TIMEDOUT;
+ req_cancel(request);
+ send_if_done(request, ISC_R_TIMEDOUT);
+ }
+ UNLOCK(&request->requestmgr->locks[request->hash]);
+ isc_event_free(&event);
+}
+
+static void
+req_sendevent(dns_request_t *request, isc_result_t result) {
+ isc_task_t *task;
+
+ REQUIRE(VALID_REQUEST(request));
+
+ req_log(ISC_LOG_DEBUG(3), "req_sendevent: request %p", request);
+
+ /*
+ * Lock held by caller.
+ */
+ task = request->event->ev_sender;
+ request->event->ev_sender = request;
+ request->event->result = result;
+ isc_task_sendanddetach(&task, (isc_event_t **)&request->event);
+}
+
+static void
+req_destroy(dns_request_t *request) {
+ isc_mem_t *mctx;
+
+ REQUIRE(VALID_REQUEST(request));
+
+ req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request);
+
+ request->magic = 0;
+ if (request->query != NULL)
+ isc_buffer_free(&request->query);
+ if (request->answer != NULL)
+ isc_buffer_free(&request->answer);
+ if (request->event != NULL)
+ isc_event_free((isc_event_t **)&request->event);
+ if (request->dispentry != NULL)
+ dns_dispatch_removeresponse(&request->dispentry, NULL);
+ if (request->dispatch != NULL)
+ dns_dispatch_detach(&request->dispatch);
+ if (request->timer != NULL)
+ isc_timer_detach(&request->timer);
+ if (request->tsig != NULL)
+ isc_buffer_free(&request->tsig);
+ if (request->tsigkey != NULL)
+ dns_tsigkey_detach(&request->tsigkey);
+ if (request->requestmgr != NULL)
+ requestmgr_detach(&request->requestmgr);
+ mctx = request->mctx;
+ isc_mem_put(mctx, request, sizeof(*request));
+ isc_mem_detach(&mctx);
+}
+
+/*
+ * Stop the current request. Must be called from the request's task.
+ */
+static void
+req_cancel(dns_request_t *request) {
+ isc_socket_t *socket;
+
+ REQUIRE(VALID_REQUEST(request));
+
+ req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request);
+
+ /*
+ * Lock held by caller.
+ */
+ request->flags |= DNS_REQUEST_F_CANCELED;
+
+ if (request->timer != NULL)
+ isc_timer_detach(&request->timer);
+ if (request->dispentry != NULL)
+ dns_dispatch_removeresponse(&request->dispentry, NULL);
+ if (DNS_REQUEST_CONNECTING(request)) {
+ socket = dns_dispatch_getsocket(request->dispatch);
+ isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
+ }
+ if (DNS_REQUEST_SENDING(request)) {
+ socket = dns_dispatch_getsocket(request->dispatch);
+ isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
+ }
+ dns_dispatch_detach(&request->dispatch);
+}
+
+static void
+req_log(int level, const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_REQUEST, level, fmt, ap);
+ va_end(ap);
+}
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
new file mode 100644
index 0000000..5b57005
--- /dev/null
+++ b/lib/dns/resolver.c
@@ -0,0 +1,7181 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: resolver.c,v 1.284.18.66 2007/11/01 13:53:27 shane Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/acl.h>
+#include <dns/adb.h>
+#include <dns/cache.h>
+#include <dns/db.h>
+#include <dns/dispatch.h>
+#include <dns/ds.h>
+#include <dns/events.h>
+#include <dns/forward.h>
+#include <dns/keytable.h>
+#include <dns/log.h>
+#include <dns/message.h>
+#include <dns/ncache.h>
+#include <dns/opcode.h>
+#include <dns/peer.h>
+#include <dns/rbt.h>
+#include <dns/rcode.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/rdatatype.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+#include <dns/rootns.h>
+#include <dns/tsig.h>
+#include <dns/validator.h>
+
+#define DNS_RESOLVER_TRACE
+#ifdef DNS_RESOLVER_TRACE
+#define RTRACE(m) isc_log_write(dns_lctx, \
+ DNS_LOGCATEGORY_RESOLVER, \
+ DNS_LOGMODULE_RESOLVER, \
+ ISC_LOG_DEBUG(3), \
+ "res %p: %s", res, (m))
+#define RRTRACE(r, m) isc_log_write(dns_lctx, \
+ DNS_LOGCATEGORY_RESOLVER, \
+ DNS_LOGMODULE_RESOLVER, \
+ ISC_LOG_DEBUG(3), \
+ "res %p: %s", (r), (m))
+#define FCTXTRACE(m) isc_log_write(dns_lctx, \
+ DNS_LOGCATEGORY_RESOLVER, \
+ DNS_LOGMODULE_RESOLVER, \
+ ISC_LOG_DEBUG(3), \
+ "fctx %p(%s'): %s", fctx, fctx->info, (m))
+#define FCTXTRACE2(m1, m2) \
+ isc_log_write(dns_lctx, \
+ DNS_LOGCATEGORY_RESOLVER, \
+ DNS_LOGMODULE_RESOLVER, \
+ ISC_LOG_DEBUG(3), \
+ "fctx %p(%s): %s %s", \
+ fctx, fctx->info, (m1), (m2))
+#define FTRACE(m) isc_log_write(dns_lctx, \
+ DNS_LOGCATEGORY_RESOLVER, \
+ DNS_LOGMODULE_RESOLVER, \
+ ISC_LOG_DEBUG(3), \
+ "fetch %p (fctx %p(%s)): %s", \
+ fetch, fetch->private, \
+ fetch->private->info, (m))
+#define QTRACE(m) isc_log_write(dns_lctx, \
+ DNS_LOGCATEGORY_RESOLVER, \
+ DNS_LOGMODULE_RESOLVER, \
+ ISC_LOG_DEBUG(3), \
+ "resquery %p (fctx %p(%s)): %s", \
+ query, query->fctx, \
+ query->fctx->info, (m))
+#else
+#define RTRACE(m)
+#define RRTRACE(r, m)
+#define FCTXTRACE(m)
+#define FTRACE(m)
+#define QTRACE(m)
+#endif
+
+/*%
+ * Maximum EDNS0 input packet size.
+ */
+#define RECV_BUFFER_SIZE 4096 /* XXXRTH Constant. */
+
+/*%
+ * This defines the maximum number of timeouts we will permit before we
+ * disable EDNS0 on the query.
+ */
+#define MAX_EDNS0_TIMEOUTS 3
+
+typedef struct fetchctx fetchctx_t;
+
+typedef struct query {
+ /* Locked by task event serialization. */
+ unsigned int magic;
+ fetchctx_t * fctx;
+ isc_mem_t * mctx;
+ dns_dispatchmgr_t * dispatchmgr;
+ dns_dispatch_t * dispatch;
+ dns_adbaddrinfo_t * addrinfo;
+ isc_socket_t * tcpsocket;
+ isc_time_t start;
+ dns_messageid_t id;
+ dns_dispentry_t * dispentry;
+ ISC_LINK(struct query) link;
+ isc_buffer_t buffer;
+ isc_buffer_t *tsig;
+ dns_tsigkey_t *tsigkey;
+ unsigned int options;
+ unsigned int attributes;
+ unsigned int sends;
+ unsigned int connects;
+ unsigned char data[512];
+} resquery_t;
+
+#define QUERY_MAGIC ISC_MAGIC('Q', '!', '!', '!')
+#define VALID_QUERY(query) ISC_MAGIC_VALID(query, QUERY_MAGIC)
+
+#define RESQUERY_ATTR_CANCELED 0x02
+
+#define RESQUERY_CONNECTING(q) ((q)->connects > 0)
+#define RESQUERY_CANCELED(q) (((q)->attributes & \
+ RESQUERY_ATTR_CANCELED) != 0)
+#define RESQUERY_SENDING(q) ((q)->sends > 0)
+
+typedef enum {
+ fetchstate_init = 0, /*%< Start event has not run yet. */
+ fetchstate_active,
+ fetchstate_done /*%< FETCHDONE events posted. */
+} fetchstate;
+
+struct fetchctx {
+ /*% Not locked. */
+ unsigned int magic;
+ dns_resolver_t * res;
+ dns_name_t name;
+ dns_rdatatype_t type;
+ unsigned int options;
+ unsigned int bucketnum;
+ char * info;
+ /*% Locked by appropriate bucket lock. */
+ fetchstate state;
+ isc_boolean_t want_shutdown;
+ isc_boolean_t cloned;
+ isc_boolean_t spilled;
+ unsigned int references;
+ isc_event_t control_event;
+ ISC_LINK(struct fetchctx) link;
+ ISC_LIST(dns_fetchevent_t) events;
+ /*% Locked by task event serialization. */
+ dns_name_t domain;
+ dns_rdataset_t nameservers;
+ unsigned int attributes;
+ isc_timer_t * timer;
+ isc_time_t expires;
+ isc_interval_t interval;
+ dns_message_t * qmessage;
+ dns_message_t * rmessage;
+ ISC_LIST(resquery_t) queries;
+ dns_adbfindlist_t finds;
+ dns_adbfind_t * find;
+ dns_adbfindlist_t altfinds;
+ dns_adbfind_t * altfind;
+ dns_adbaddrinfolist_t forwaddrs;
+ dns_adbaddrinfolist_t altaddrs;
+ isc_sockaddrlist_t forwarders;
+ dns_fwdpolicy_t fwdpolicy;
+ isc_sockaddrlist_t bad;
+ isc_sockaddrlist_t edns;
+ isc_sockaddrlist_t edns512;
+ dns_validator_t *validator;
+ ISC_LIST(dns_validator_t) validators;
+ dns_db_t * cache;
+ dns_adb_t * adb;
+
+ /*%
+ * The number of events we're waiting for.
+ */
+ unsigned int pending;
+
+ /*%
+ * The number of times we've "restarted" the current
+ * nameserver set. This acts as a failsafe to prevent
+ * us from pounding constantly on a particular set of
+ * servers that, for whatever reason, are not giving
+ * us useful responses, but are responding in such a
+ * way that they are not marked "bad".
+ */
+ unsigned int restarts;
+
+ /*%
+ * The number of timeouts that have occurred since we
+ * last successfully received a response packet. This
+ * is used for EDNS0 black hole detection.
+ */
+ unsigned int timeouts;
+ /*%
+ * Look aside state for DS lookups.
+ */
+ dns_name_t nsname;
+ dns_fetch_t * nsfetch;
+ dns_rdataset_t nsrrset;
+
+ /*%
+ * Number of queries that reference this context.
+ */
+ unsigned int nqueries;
+};
+
+#define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!')
+#define VALID_FCTX(fctx) ISC_MAGIC_VALID(fctx, FCTX_MAGIC)
+
+#define FCTX_ATTR_HAVEANSWER 0x0001
+#define FCTX_ATTR_GLUING 0x0002
+#define FCTX_ATTR_ADDRWAIT 0x0004
+#define FCTX_ATTR_SHUTTINGDOWN 0x0008
+#define FCTX_ATTR_WANTCACHE 0x0010
+#define FCTX_ATTR_WANTNCACHE 0x0020
+#define FCTX_ATTR_NEEDEDNS0 0x0040
+#define FCTX_ATTR_TRIEDFIND 0x0080
+#define FCTX_ATTR_TRIEDALT 0x0100
+
+#define HAVE_ANSWER(f) (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \
+ 0)
+#define GLUING(f) (((f)->attributes & FCTX_ATTR_GLUING) != \
+ 0)
+#define ADDRWAIT(f) (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
+ 0)
+#define SHUTTINGDOWN(f) (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
+ != 0)
+#define WANTCACHE(f) (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
+#define WANTNCACHE(f) (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
+#define NEEDEDNS0(f) (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0)
+#define TRIEDFIND(f) (((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0)
+#define TRIEDALT(f) (((f)->attributes & FCTX_ATTR_TRIEDALT) != 0)
+
+typedef struct {
+ dns_adbaddrinfo_t * addrinfo;
+ fetchctx_t * fctx;
+} dns_valarg_t;
+
+struct dns_fetch {
+ unsigned int magic;
+ fetchctx_t * private;
+};
+
+#define DNS_FETCH_MAGIC ISC_MAGIC('F', 't', 'c', 'h')
+#define DNS_FETCH_VALID(fetch) ISC_MAGIC_VALID(fetch, DNS_FETCH_MAGIC)
+
+typedef struct fctxbucket {
+ isc_task_t * task;
+ isc_mutex_t lock;
+ ISC_LIST(fetchctx_t) fctxs;
+ isc_boolean_t exiting;
+ isc_mem_t * mctx;
+} fctxbucket_t;
+
+typedef struct alternate {
+ isc_boolean_t isaddress;
+ union {
+ isc_sockaddr_t addr;
+ struct {
+ dns_name_t name;
+ in_port_t port;
+ } _n;
+ } _u;
+ ISC_LINK(struct alternate) link;
+} alternate_t;
+
+struct dns_resolver {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ isc_mutex_t lock;
+ isc_mutex_t nlock;
+ isc_mutex_t primelock;
+ dns_rdataclass_t rdclass;
+ isc_socketmgr_t * socketmgr;
+ isc_timermgr_t * timermgr;
+ isc_taskmgr_t * taskmgr;
+ dns_view_t * view;
+ isc_boolean_t frozen;
+ unsigned int options;
+ dns_dispatchmgr_t * dispatchmgr;
+ dns_dispatch_t * dispatchv4;
+ dns_dispatch_t * dispatchv6;
+ unsigned int nbuckets;
+ fctxbucket_t * buckets;
+ isc_uint32_t lame_ttl;
+ ISC_LIST(alternate_t) alternates;
+ isc_uint16_t udpsize;
+#if USE_ALGLOCK
+ isc_rwlock_t alglock;
+#endif
+ dns_rbt_t * algorithms;
+#if USE_MBSLOCK
+ isc_rwlock_t mbslock;
+#endif
+ dns_rbt_t * mustbesecure;
+ unsigned int spillatmax;
+ unsigned int spillatmin;
+ isc_timer_t * spillattimer;
+ isc_boolean_t zero_no_soa_ttl;
+ /* Locked by lock. */
+ unsigned int references;
+ isc_boolean_t exiting;
+ isc_eventlist_t whenshutdown;
+ unsigned int activebuckets;
+ isc_boolean_t priming;
+ unsigned int spillat;
+ /* Locked by primelock. */
+ dns_fetch_t * primefetch;
+ /* Locked by nlock. */
+ unsigned int nfctx;
+};
+
+#define RES_MAGIC ISC_MAGIC('R', 'e', 's', '!')
+#define VALID_RESOLVER(res) ISC_MAGIC_VALID(res, RES_MAGIC)
+
+/*%
+ * Private addrinfo flags. These must not conflict with DNS_FETCHOPT_NOEDNS0,
+ * which we also use as an addrinfo flag.
+ */
+#define FCTX_ADDRINFO_MARK 0x0001
+#define FCTX_ADDRINFO_FORWARDER 0x1000
+#define UNMARKED(a) (((a)->flags & FCTX_ADDRINFO_MARK) \
+ == 0)
+#define ISFORWARDER(a) (((a)->flags & \
+ FCTX_ADDRINFO_FORWARDER) != 0)
+
+#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
+
+#define dns_db_transfernode(a,b,c) do { (*c) = (*b); (*b) = NULL; } while (0)
+
+static void destroy(dns_resolver_t *res);
+static void empty_bucket(dns_resolver_t *res);
+static isc_result_t resquery_send(resquery_t *query);
+static void resquery_response(isc_task_t *task, isc_event_t *event);
+static void resquery_connected(isc_task_t *task, isc_event_t *event);
+static void fctx_try(fetchctx_t *fctx);
+static isc_boolean_t fctx_destroy(fetchctx_t *fctx);
+static isc_result_t ncache_adderesult(dns_message_t *message,
+ dns_db_t *cache, dns_dbnode_t *node,
+ dns_rdatatype_t covers,
+ isc_stdtime_t now, dns_ttl_t maxttl,
+ dns_rdataset_t *ardataset,
+ isc_result_t *eresultp);
+static void validated(isc_task_t *task, isc_event_t *event);
+static void maybe_destroy(fetchctx_t *fctx);
+
+static isc_result_t
+valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
+ dns_rdatatype_t type, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset, unsigned int valoptions,
+ isc_task_t *task)
+{
+ dns_validator_t *validator = NULL;
+ dns_valarg_t *valarg;
+ isc_result_t result;
+
+ valarg = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
+ sizeof(*valarg));
+ if (valarg == NULL)
+ return (ISC_R_NOMEMORY);
+
+ valarg->fctx = fctx;
+ valarg->addrinfo = addrinfo;
+
+ if (!ISC_LIST_EMPTY(fctx->validators))
+ INSIST((valoptions & DNS_VALIDATOR_DEFER) != 0);
+
+ result = dns_validator_create(fctx->res->view, name, type, rdataset,
+ sigrdataset, fctx->rmessage,
+ valoptions, task, validated, valarg,
+ &validator);
+ if (result == ISC_R_SUCCESS) {
+ if ((valoptions & DNS_VALIDATOR_DEFER) == 0) {
+ INSIST(fctx->validator == NULL);
+ fctx->validator = validator;
+ }
+ ISC_LIST_APPEND(fctx->validators, validator, link);
+ } else
+ isc_mem_put(fctx->res->buckets[fctx->bucketnum].mctx,
+ valarg, sizeof(*valarg));
+ return (result);
+}
+
+static isc_boolean_t
+fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) {
+ dns_name_t *name;
+ dns_name_t *domain = &fctx->domain;
+ dns_rdataset_t *rdataset;
+ dns_rdatatype_t type;
+ isc_result_t result;
+ isc_boolean_t keep_auth = ISC_FALSE;
+
+ if (message->rcode == dns_rcode_nxdomain)
+ return (ISC_FALSE);
+
+ /*
+ * Look for BIND 8 style delegations.
+ * Also look for answers to ANY queries where the duplicate NS RRset
+ * may have been stripped from the authority section.
+ */
+ if (message->counts[DNS_SECTION_ANSWER] != 0 &&
+ (fctx->type == dns_rdatatype_ns ||
+ fctx->type == dns_rdatatype_any)) {
+ result = dns_message_firstname(message, DNS_SECTION_ANSWER);
+ while (result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_ANSWER,
+ &name);
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ type = rdataset->type;
+ if (type != dns_rdatatype_ns)
+ continue;
+ if (dns_name_issubdomain(name, domain))
+ return (ISC_FALSE);
+ }
+ result = dns_message_nextname(message,
+ DNS_SECTION_ANSWER);
+ }
+ }
+
+ /* Look for referral. */
+ if (message->counts[DNS_SECTION_AUTHORITY] == 0)
+ goto munge;
+
+ result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+ while (result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ type = rdataset->type;
+ if (type == dns_rdatatype_soa &&
+ dns_name_equal(name, domain))
+ keep_auth = ISC_TRUE;
+ if (type != dns_rdatatype_ns &&
+ type != dns_rdatatype_soa)
+ continue;
+ if (dns_name_equal(name, domain))
+ goto munge;
+ if (dns_name_issubdomain(name, domain))
+ return (ISC_FALSE);
+ }
+ result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
+ }
+
+ munge:
+ message->rcode = dns_rcode_nxdomain;
+ message->counts[DNS_SECTION_ANSWER] = 0;
+ if (!keep_auth)
+ message->counts[DNS_SECTION_AUTHORITY] = 0;
+ message->counts[DNS_SECTION_ADDITIONAL] = 0;
+ return (ISC_TRUE);
+}
+
+static inline isc_result_t
+fctx_starttimer(fetchctx_t *fctx) {
+ /*
+ * Start the lifetime timer for fctx.
+ *
+ * This is also used for stopping the idle timer; in that
+ * case we must purge events already posted to ensure that
+ * no further idle events are delivered.
+ */
+ return (isc_timer_reset(fctx->timer, isc_timertype_once,
+ &fctx->expires, NULL, ISC_TRUE));
+}
+
+static inline void
+fctx_stoptimer(fetchctx_t *fctx) {
+ isc_result_t result;
+
+ /*
+ * We don't return a result if resetting the timer to inactive fails
+ * since there's nothing to be done about it. Resetting to inactive
+ * should never fail anyway, since the code as currently written
+ * cannot fail in that case.
+ */
+ result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
+ NULL, NULL, ISC_TRUE);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_timer_reset(): %s",
+ isc_result_totext(result));
+ }
+}
+
+
+static inline isc_result_t
+fctx_startidletimer(fetchctx_t *fctx) {
+ /*
+ * Start the idle timer for fctx. The lifetime timer continues
+ * to be in effect.
+ */
+ return (isc_timer_reset(fctx->timer, isc_timertype_once,
+ &fctx->expires, &fctx->interval,
+ ISC_FALSE));
+}
+
+/*
+ * Stopping the idle timer is equivalent to calling fctx_starttimer(), but
+ * we use fctx_stopidletimer for readability in the code below.
+ */
+#define fctx_stopidletimer fctx_starttimer
+
+
+static inline void
+resquery_destroy(resquery_t **queryp) {
+ resquery_t *query;
+
+ REQUIRE(queryp != NULL);
+ query = *queryp;
+ REQUIRE(!ISC_LINK_LINKED(query, link));
+
+ INSIST(query->tcpsocket == NULL);
+
+ query->fctx->nqueries--;
+ if (SHUTTINGDOWN(query->fctx))
+ maybe_destroy(query->fctx); /* Locks bucket. */
+ query->magic = 0;
+ isc_mem_put(query->mctx, query, sizeof(*query));
+ *queryp = NULL;
+}
+
+static void
+fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
+ isc_time_t *finish, isc_boolean_t no_response)
+{
+ fetchctx_t *fctx;
+ resquery_t *query;
+ unsigned int rtt;
+ unsigned int factor;
+ dns_adbfind_t *find;
+ dns_adbaddrinfo_t *addrinfo;
+
+ query = *queryp;
+ fctx = query->fctx;
+
+ FCTXTRACE("cancelquery");
+
+ REQUIRE(!RESQUERY_CANCELED(query));
+
+ query->attributes |= RESQUERY_ATTR_CANCELED;
+
+ /*
+ * Should we update the RTT?
+ */
+ if (finish != NULL || no_response) {
+ if (finish != NULL) {
+ /*
+ * We have both the start and finish times for this
+ * packet, so we can compute a real RTT.
+ */
+ rtt = (unsigned int)isc_time_microdiff(finish,
+ &query->start);
+ factor = DNS_ADB_RTTADJDEFAULT;
+ } else {
+ /*
+ * We don't have an RTT for this query. Maybe the
+ * packet was lost, or maybe this server is very
+ * slow. We don't know. Increase the RTT.
+ */
+ INSIST(no_response);
+ rtt = query->addrinfo->srtt + 200000;
+ if (rtt > 10000000)
+ rtt = 10000000;
+ /*
+ * Replace the current RTT with our value.
+ */
+ factor = DNS_ADB_RTTADJREPLACE;
+ }
+ dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor);
+ }
+
+ /*
+ * Age RTTs of servers not tried.
+ */
+ factor = DNS_ADB_RTTADJAGE;
+ if (finish != NULL)
+ for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink))
+ if (UNMARKED(addrinfo))
+ dns_adb_adjustsrtt(fctx->adb, addrinfo,
+ 0, factor);
+
+ if (finish != NULL && TRIEDFIND(fctx))
+ for (find = ISC_LIST_HEAD(fctx->finds);
+ find != NULL;
+ find = ISC_LIST_NEXT(find, publink))
+ for (addrinfo = ISC_LIST_HEAD(find->list);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink))
+ if (UNMARKED(addrinfo))
+ dns_adb_adjustsrtt(fctx->adb, addrinfo,
+ 0, factor);
+
+ if (finish != NULL && TRIEDALT(fctx)) {
+ for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink))
+ if (UNMARKED(addrinfo))
+ dns_adb_adjustsrtt(fctx->adb, addrinfo,
+ 0, factor);
+ for (find = ISC_LIST_HEAD(fctx->altfinds);
+ find != NULL;
+ find = ISC_LIST_NEXT(find, publink))
+ for (addrinfo = ISC_LIST_HEAD(find->list);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink))
+ if (UNMARKED(addrinfo))
+ dns_adb_adjustsrtt(fctx->adb, addrinfo,
+ 0, factor);
+ }
+
+ if (query->dispentry != NULL)
+ dns_dispatch_removeresponse(&query->dispentry, deventp);
+
+ ISC_LIST_UNLINK(fctx->queries, query, link);
+
+ if (query->tsig != NULL)
+ isc_buffer_free(&query->tsig);
+
+ if (query->tsigkey != NULL)
+ dns_tsigkey_detach(&query->tsigkey);
+
+ /*
+ * Check for any outstanding socket events. If they exist, cancel
+ * them and let the event handlers finish the cleanup. The resolver
+ * only needs to worry about managing the connect and send events;
+ * the dispatcher manages the recv events.
+ */
+ if (RESQUERY_CONNECTING(query))
+ /*
+ * Cancel the connect.
+ */
+ isc_socket_cancel(query->tcpsocket, NULL,
+ ISC_SOCKCANCEL_CONNECT);
+ else if (RESQUERY_SENDING(query))
+ /*
+ * Cancel the pending send.
+ */
+ isc_socket_cancel(dns_dispatch_getsocket(query->dispatch),
+ NULL, ISC_SOCKCANCEL_SEND);
+
+ if (query->dispatch != NULL)
+ dns_dispatch_detach(&query->dispatch);
+
+ if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query)))
+ /*
+ * It's safe to destroy the query now.
+ */
+ resquery_destroy(&query);
+}
+
+static void
+fctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) {
+ resquery_t *query, *next_query;
+
+ FCTXTRACE("cancelqueries");
+
+ for (query = ISC_LIST_HEAD(fctx->queries);
+ query != NULL;
+ query = next_query) {
+ next_query = ISC_LIST_NEXT(query, link);
+ fctx_cancelquery(&query, NULL, NULL, no_response);
+ }
+}
+
+static void
+fctx_cleanupfinds(fetchctx_t *fctx) {
+ dns_adbfind_t *find, *next_find;
+
+ REQUIRE(ISC_LIST_EMPTY(fctx->queries));
+
+ for (find = ISC_LIST_HEAD(fctx->finds);
+ find != NULL;
+ find = next_find) {
+ next_find = ISC_LIST_NEXT(find, publink);
+ ISC_LIST_UNLINK(fctx->finds, find, publink);
+ dns_adb_destroyfind(&find);
+ }
+ fctx->find = NULL;
+}
+
+static void
+fctx_cleanupaltfinds(fetchctx_t *fctx) {
+ dns_adbfind_t *find, *next_find;
+
+ REQUIRE(ISC_LIST_EMPTY(fctx->queries));
+
+ for (find = ISC_LIST_HEAD(fctx->altfinds);
+ find != NULL;
+ find = next_find) {
+ next_find = ISC_LIST_NEXT(find, publink);
+ ISC_LIST_UNLINK(fctx->altfinds, find, publink);
+ dns_adb_destroyfind(&find);
+ }
+ fctx->altfind = NULL;
+}
+
+static void
+fctx_cleanupforwaddrs(fetchctx_t *fctx) {
+ dns_adbaddrinfo_t *addr, *next_addr;
+
+ REQUIRE(ISC_LIST_EMPTY(fctx->queries));
+
+ for (addr = ISC_LIST_HEAD(fctx->forwaddrs);
+ addr != NULL;
+ addr = next_addr) {
+ next_addr = ISC_LIST_NEXT(addr, publink);
+ ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink);
+ dns_adb_freeaddrinfo(fctx->adb, &addr);
+ }
+}
+
+static void
+fctx_cleanupaltaddrs(fetchctx_t *fctx) {
+ dns_adbaddrinfo_t *addr, *next_addr;
+
+ REQUIRE(ISC_LIST_EMPTY(fctx->queries));
+
+ for (addr = ISC_LIST_HEAD(fctx->altaddrs);
+ addr != NULL;
+ addr = next_addr) {
+ next_addr = ISC_LIST_NEXT(addr, publink);
+ ISC_LIST_UNLINK(fctx->altaddrs, addr, publink);
+ dns_adb_freeaddrinfo(fctx->adb, &addr);
+ }
+}
+
+static inline void
+fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) {
+ FCTXTRACE("stopeverything");
+ fctx_cancelqueries(fctx, no_response);
+ fctx_cleanupfinds(fctx);
+ fctx_cleanupaltfinds(fctx);
+ fctx_cleanupforwaddrs(fctx);
+ fctx_cleanupaltaddrs(fctx);
+ fctx_stoptimer(fctx);
+}
+
+static inline void
+fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
+ dns_fetchevent_t *event, *next_event;
+ isc_task_t *task;
+ unsigned int count = 0;
+ isc_interval_t i;
+ isc_boolean_t logit = ISC_FALSE;
+
+ /*
+ * Caller must be holding the appropriate bucket lock.
+ */
+ REQUIRE(fctx->state == fetchstate_done);
+
+ FCTXTRACE("sendevents");
+
+ for (event = ISC_LIST_HEAD(fctx->events);
+ event != NULL;
+ event = next_event) {
+ next_event = ISC_LIST_NEXT(event, ev_link);
+ ISC_LIST_UNLINK(fctx->events, event, ev_link);
+ task = event->ev_sender;
+ event->ev_sender = fctx;
+ if (!HAVE_ANSWER(fctx))
+ event->result = result;
+
+ INSIST(result != ISC_R_SUCCESS ||
+ dns_rdataset_isassociated(event->rdataset) ||
+ fctx->type == dns_rdatatype_any ||
+ fctx->type == dns_rdatatype_rrsig ||
+ fctx->type == dns_rdatatype_sig);
+
+ /*
+ * Negative results must be indicated in event->result.
+ */
+ if (dns_rdataset_isassociated(event->rdataset) &&
+ event->rdataset->type == dns_rdatatype_none) {
+ INSIST(event->result == DNS_R_NCACHENXDOMAIN ||
+ event->result == DNS_R_NCACHENXRRSET);
+ }
+
+ isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event));
+ count++;
+ }
+
+ if ((fctx->attributes & FCTX_ATTR_HAVEANSWER) != 0 &&
+ fctx->spilled &&
+ (count < fctx->res->spillatmax || fctx->res->spillatmax == 0)) {
+ LOCK(&fctx->res->lock);
+ if (count == fctx->res->spillat && !fctx->res->exiting) {
+ fctx->res->spillat += 5;
+ if (fctx->res->spillat > fctx->res->spillatmax &&
+ fctx->res->spillatmax != 0)
+ fctx->res->spillat = fctx->res->spillatmax;
+ logit = ISC_TRUE;
+ isc_interval_set(&i, 20 * 60, 0);
+ result = isc_timer_reset(fctx->res->spillattimer,
+ isc_timertype_ticker, NULL,
+ &i, ISC_TRUE);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ }
+ UNLOCK(&fctx->res->lock);
+ if (logit)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+ "clients-per-query increased to %u",
+ count + 1);
+ }
+}
+
+static void
+fctx_done(fetchctx_t *fctx, isc_result_t result) {
+ dns_resolver_t *res;
+ isc_boolean_t no_response;
+
+ FCTXTRACE("done");
+
+ res = fctx->res;
+
+ if (result == ISC_R_SUCCESS)
+ no_response = ISC_TRUE;
+ else
+ no_response = ISC_FALSE;
+ fctx_stopeverything(fctx, no_response);
+
+ LOCK(&res->buckets[fctx->bucketnum].lock);
+
+ fctx->state = fetchstate_done;
+ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+ fctx_sendevents(fctx, result);
+
+ UNLOCK(&res->buckets[fctx->bucketnum].lock);
+}
+
+static void
+resquery_senddone(isc_task_t *task, isc_event_t *event) {
+ isc_socketevent_t *sevent = (isc_socketevent_t *)event;
+ resquery_t *query = event->ev_arg;
+ isc_boolean_t retry = ISC_FALSE;
+ isc_result_t result;
+ fetchctx_t *fctx;
+
+ REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
+
+ QTRACE("senddone");
+
+ /*
+ * XXXRTH
+ *
+ * Currently we don't wait for the senddone event before retrying
+ * a query. This means that if we get really behind, we may end
+ * up doing extra work!
+ */
+
+ UNUSED(task);
+
+ INSIST(RESQUERY_SENDING(query));
+
+ query->sends--;
+ fctx = query->fctx;
+
+ if (RESQUERY_CANCELED(query)) {
+ if (query->sends == 0) {
+ /*
+ * This query was canceled while the
+ * isc_socket_sendto() was in progress.
+ */
+ if (query->tcpsocket != NULL)
+ isc_socket_detach(&query->tcpsocket);
+ resquery_destroy(&query);
+ }
+ } else
+ switch (sevent->result) {
+ case ISC_R_SUCCESS:
+ break;
+
+ case ISC_R_HOSTUNREACH:
+ case ISC_R_NETUNREACH:
+ case ISC_R_NOPERM:
+ case ISC_R_ADDRNOTAVAIL:
+ case ISC_R_CONNREFUSED:
+
+ /*
+ * No route to remote.
+ */
+ fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
+ retry = ISC_TRUE;
+ break;
+
+ default:
+ fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
+ break;
+ }
+
+ isc_event_free(&event);
+
+ if (retry) {
+ /*
+ * Behave as if the idle timer has expired. For TCP
+ * this may not actually reflect the latest timer.
+ */
+ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+ result = fctx_stopidletimer(fctx);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ else
+ fctx_try(fctx);
+ }
+}
+
+static inline isc_result_t
+fctx_addopt(dns_message_t *message, unsigned int version, isc_uint16_t udpsize)
+{
+ dns_rdataset_t *rdataset;
+ dns_rdatalist_t *rdatalist;
+ dns_rdata_t *rdata;
+ isc_result_t result;
+
+ rdatalist = NULL;
+ result = dns_message_gettemprdatalist(message, &rdatalist);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ rdata = NULL;
+ result = dns_message_gettemprdata(message, &rdata);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ rdataset = NULL;
+ result = dns_message_gettemprdataset(message, &rdataset);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_rdataset_init(rdataset);
+
+ rdatalist->type = dns_rdatatype_opt;
+ rdatalist->covers = 0;
+
+ /*
+ * Set Maximum UDP buffer size.
+ */
+ rdatalist->rdclass = udpsize;
+
+ /*
+ * Set EXTENDED-RCODE and Z to 0, DO to 1.
+ */
+ rdatalist->ttl = (version << 16);
+ rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO;
+
+ /*
+ * No EDNS options.
+ */
+ rdata->data = NULL;
+ rdata->length = 0;
+ rdata->rdclass = rdatalist->rdclass;
+ rdata->type = rdatalist->type;
+ rdata->flags = 0;
+
+ ISC_LIST_INIT(rdatalist->rdata);
+ ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
+ RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS);
+
+ return (dns_message_setopt(message, rdataset));
+}
+
+static inline void
+fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) {
+ unsigned int seconds;
+ unsigned int us;
+
+ /*
+ * We retry every .5 seconds the first two times through the address
+ * list, and then we do exponential back-off.
+ */
+ if (fctx->restarts < 3)
+ us = 500000;
+ else
+ us = (500000 << (fctx->restarts - 2));
+
+ /*
+ * Double the round-trip time.
+ */
+ rtt *= 2;
+
+ /*
+ * Always wait for at least the doubled round-trip time.
+ */
+ if (us < rtt)
+ us = rtt;
+
+ /*
+ * But don't ever wait for more than 10 seconds.
+ */
+ if (us > 10000000)
+ us = 10000000;
+
+ seconds = us / 1000000;
+ us -= seconds * 1000000;
+ isc_interval_set(&fctx->interval, seconds, us * 1000);
+}
+
+static isc_result_t
+fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
+ unsigned int options)
+{
+ dns_resolver_t *res;
+ isc_task_t *task;
+ isc_result_t result;
+ resquery_t *query;
+ isc_sockaddr_t addr;
+ isc_boolean_t have_addr = ISC_FALSE;
+
+ FCTXTRACE("query");
+
+ res = fctx->res;
+ task = res->buckets[fctx->bucketnum].task;
+
+ fctx_setretryinterval(fctx, addrinfo->srtt);
+ result = fctx_startidletimer(fctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ INSIST(ISC_LIST_EMPTY(fctx->validators));
+
+ dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
+
+ query = isc_mem_get(res->buckets[fctx->bucketnum].mctx,
+ sizeof(*query));
+ if (query == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto stop_idle_timer;
+ }
+ query->mctx = res->buckets[fctx->bucketnum].mctx;
+ query->options = options;
+ query->attributes = 0;
+ query->sends = 0;
+ query->connects = 0;
+ /*
+ * Note that the caller MUST guarantee that 'addrinfo' will remain
+ * valid until this query is canceled.
+ */
+ query->addrinfo = addrinfo;
+ TIME_NOW(&query->start);
+
+ /*
+ * If this is a TCP query, then we need to make a socket and
+ * a dispatch for it here. Otherwise we use the resolver's
+ * shared dispatch.
+ */
+ query->dispatchmgr = res->dispatchmgr;
+ query->dispatch = NULL;
+ query->tcpsocket = NULL;
+ if (res->view->peers != NULL) {
+ dns_peer_t *peer = NULL;
+ isc_netaddr_t dstip;
+ isc_netaddr_fromsockaddr(&dstip, &addrinfo->sockaddr);
+ result = dns_peerlist_peerbyaddr(res->view->peers,
+ &dstip, &peer);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_peer_getquerysource(peer, &addr);
+ if (result == ISC_R_SUCCESS)
+ have_addr = ISC_TRUE;
+ }
+ }
+
+ if ((query->options & DNS_FETCHOPT_TCP) != 0) {
+ int pf;
+
+ pf = isc_sockaddr_pf(&addrinfo->sockaddr);
+ if (!have_addr) {
+ switch (pf) {
+ case PF_INET:
+ result =
+ dns_dispatch_getlocaladdress(res->dispatchv4,
+ &addr);
+ break;
+ case PF_INET6:
+ result =
+ dns_dispatch_getlocaladdress(res->dispatchv6,
+ &addr);
+ break;
+ default:
+ result = ISC_R_NOTIMPLEMENTED;
+ break;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_query;
+ }
+ isc_sockaddr_setport(&addr, 0);
+
+ result = isc_socket_create(res->socketmgr, pf,
+ isc_sockettype_tcp,
+ &query->tcpsocket);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_query;
+
+#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
+ result = isc_socket_bind(query->tcpsocket, &addr);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_socket;
+#endif
+
+ /*
+ * A dispatch will be created once the connect succeeds.
+ */
+ } else {
+ if (have_addr) {
+ unsigned int attrs, attrmask;
+ 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_query;
+ }
+ attrmask = DNS_DISPATCHATTR_UDP;
+ attrmask |= DNS_DISPATCHATTR_TCP;
+ attrmask |= DNS_DISPATCHATTR_IPV4;
+ attrmask |= DNS_DISPATCHATTR_IPV6;
+ result = dns_dispatch_getudp(res->dispatchmgr,
+ res->socketmgr,
+ res->taskmgr, &addr,
+ 4096, 1000, 32768, 16411,
+ 16433, attrs, attrmask,
+ &query->dispatch);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_query;
+ } else {
+ switch (isc_sockaddr_pf(&addrinfo->sockaddr)) {
+ case PF_INET:
+ dns_dispatch_attach(res->dispatchv4,
+ &query->dispatch);
+ break;
+ case PF_INET6:
+ dns_dispatch_attach(res->dispatchv6,
+ &query->dispatch);
+ break;
+ default:
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup_query;
+ }
+ }
+ /*
+ * We should always have a valid dispatcher here. If we
+ * don't support a protocol family, then its dispatcher
+ * will be NULL, but we shouldn't be finding addresses for
+ * protocol types we don't support, so the dispatcher
+ * we found should never be NULL.
+ */
+ INSIST(query->dispatch != NULL);
+ }
+
+ query->dispentry = NULL;
+ query->fctx = fctx;
+ query->tsig = NULL;
+ query->tsigkey = NULL;
+ ISC_LINK_INIT(query, link);
+ query->magic = QUERY_MAGIC;
+
+ if ((query->options & DNS_FETCHOPT_TCP) != 0) {
+ /*
+ * Connect to the remote server.
+ *
+ * XXXRTH Should we attach to the socket?
+ */
+ result = isc_socket_connect(query->tcpsocket,
+ &addrinfo->sockaddr, task,
+ resquery_connected, query);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_socket;
+ query->connects++;
+ QTRACE("connecting via TCP");
+ } else {
+ result = resquery_send(query);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_dispatch;
+ }
+
+ ISC_LIST_APPEND(fctx->queries, query, link);
+ query->fctx->nqueries++;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_socket:
+ isc_socket_detach(&query->tcpsocket);
+
+ cleanup_dispatch:
+ if (query->dispatch != NULL)
+ dns_dispatch_detach(&query->dispatch);
+
+ cleanup_query:
+ query->magic = 0;
+ isc_mem_put(res->buckets[fctx->bucketnum].mctx,
+ query, sizeof(*query));
+
+ stop_idle_timer:
+ RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS);
+
+ return (result);
+}
+
+static isc_boolean_t
+triededns(fetchctx_t *fctx, isc_sockaddr_t *address) {
+ isc_sockaddr_t *sa;
+
+ for (sa = ISC_LIST_HEAD(fctx->edns);
+ sa != NULL;
+ sa = ISC_LIST_NEXT(sa, link)) {
+ if (isc_sockaddr_equal(sa, address))
+ return (ISC_TRUE);
+ }
+
+ return (ISC_FALSE);
+}
+
+static void
+add_triededns(fetchctx_t *fctx, isc_sockaddr_t *address) {
+ isc_sockaddr_t *sa;
+
+ if (triededns(fctx, address))
+ return;
+
+ sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
+ sizeof(*sa));
+ if (sa == NULL)
+ return;
+
+ *sa = *address;
+ ISC_LIST_INITANDAPPEND(fctx->edns, sa, link);
+}
+
+static isc_boolean_t
+triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) {
+ isc_sockaddr_t *sa;
+
+ for (sa = ISC_LIST_HEAD(fctx->edns512);
+ sa != NULL;
+ sa = ISC_LIST_NEXT(sa, link)) {
+ if (isc_sockaddr_equal(sa, address))
+ return (ISC_TRUE);
+ }
+
+ return (ISC_FALSE);
+}
+
+static void
+add_triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) {
+ isc_sockaddr_t *sa;
+
+ if (triededns512(fctx, address))
+ return;
+
+ sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
+ sizeof(*sa));
+ if (sa == NULL)
+ return;
+
+ *sa = *address;
+ ISC_LIST_INITANDAPPEND(fctx->edns512, sa, link);
+}
+
+static isc_result_t
+resquery_send(resquery_t *query) {
+ fetchctx_t *fctx;
+ isc_result_t result;
+ dns_name_t *qname = NULL;
+ dns_rdataset_t *qrdataset = NULL;
+ isc_region_t r;
+ dns_resolver_t *res;
+ isc_task_t *task;
+ isc_socket_t *socket;
+ isc_buffer_t tcpbuffer;
+ isc_sockaddr_t *address;
+ isc_buffer_t *buffer;
+ isc_netaddr_t ipaddr;
+ dns_tsigkey_t *tsigkey = NULL;
+ dns_peer_t *peer = NULL;
+ isc_boolean_t useedns;
+ dns_compress_t cctx;
+ isc_boolean_t cleanup_cctx = ISC_FALSE;
+ isc_boolean_t secure_domain;
+
+ fctx = query->fctx;
+ QTRACE("send");
+
+ res = fctx->res;
+ task = res->buckets[fctx->bucketnum].task;
+ address = NULL;
+
+ if ((query->options & DNS_FETCHOPT_TCP) != 0) {
+ /*
+ * Reserve space for the TCP message length.
+ */
+ isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data));
+ isc_buffer_init(&query->buffer, query->data + 2,
+ sizeof(query->data) - 2);
+ buffer = &tcpbuffer;
+ } else {
+ isc_buffer_init(&query->buffer, query->data,
+ sizeof(query->data));
+ buffer = &query->buffer;
+ }
+
+ result = dns_message_gettempname(fctx->qmessage, &qname);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_temps;
+ result = dns_message_gettemprdataset(fctx->qmessage, &qrdataset);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_temps;
+
+ /*
+ * Get a query id from the dispatch.
+ */
+ result = dns_dispatch_addresponse(query->dispatch,
+ &query->addrinfo->sockaddr,
+ task,
+ resquery_response,
+ query,
+ &query->id,
+ &query->dispentry);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_temps;
+
+ fctx->qmessage->opcode = dns_opcode_query;
+
+ /*
+ * Set up question.
+ */
+ dns_name_init(qname, NULL);
+ dns_name_clone(&fctx->name, qname);
+ dns_rdataset_init(qrdataset);
+ dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type);
+ ISC_LIST_APPEND(qname->list, qrdataset, link);
+ dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION);
+ qname = NULL;
+ qrdataset = NULL;
+
+ /*
+ * Set RD if the client has requested that we do a recursive query,
+ * or if we're sending to a forwarder.
+ */
+ if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 ||
+ ISFORWARDER(query->addrinfo))
+ fctx->qmessage->flags |= DNS_MESSAGEFLAG_RD;
+
+ /*
+ * Set CD if the client says don't validate or the question is
+ * under a secure entry point.
+ */
+ if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0) {
+ fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
+ } else if (res->view->enablevalidation) {
+ result = dns_keytable_issecuredomain(res->view->secroots,
+ &fctx->name,
+ &secure_domain);
+ if (result != ISC_R_SUCCESS)
+ secure_domain = ISC_FALSE;
+ if (res->view->dlv != NULL)
+ secure_domain = ISC_TRUE;
+ if (secure_domain)
+ fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
+ }
+
+ /*
+ * We don't have to set opcode because it defaults to query.
+ */
+ fctx->qmessage->id = query->id;
+
+ /*
+ * Convert the question to wire format.
+ */
+ result = dns_compress_init(&cctx, -1, fctx->res->mctx);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_message;
+ cleanup_cctx = ISC_TRUE;
+
+ result = dns_message_renderbegin(fctx->qmessage, &cctx,
+ &query->buffer);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_message;
+
+ result = dns_message_rendersection(fctx->qmessage,
+ DNS_SECTION_QUESTION, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_message;
+
+ peer = NULL;
+ isc_netaddr_fromsockaddr(&ipaddr, &query->addrinfo->sockaddr);
+ (void) dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer);
+
+ /*
+ * The ADB does not know about servers with "edns no". Check this,
+ * and then inform the ADB for future use.
+ */
+ if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0 &&
+ peer != NULL &&
+ dns_peer_getsupportedns(peer, &useedns) == ISC_R_SUCCESS &&
+ !useedns)
+ {
+ query->options |= DNS_FETCHOPT_NOEDNS0;
+ dns_adb_changeflags(fctx->adb,
+ query->addrinfo,
+ DNS_FETCHOPT_NOEDNS0,
+ DNS_FETCHOPT_NOEDNS0);
+ }
+
+ /*
+ * Use EDNS0, unless the caller doesn't want it, or we know that
+ * the remote server doesn't like it.
+ */
+
+ if ((triededns512(fctx, &query->addrinfo->sockaddr) ||
+ fctx->timeouts >= (MAX_EDNS0_TIMEOUTS * 2)) &&
+ (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+ query->options |= DNS_FETCHOPT_NOEDNS0;
+ FCTXTRACE("too many timeouts, disabling EDNS0");
+ } else if ((triededns(fctx, &query->addrinfo->sockaddr) ||
+ fctx->timeouts >= MAX_EDNS0_TIMEOUTS) &&
+ (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+ query->options |= DNS_FETCHOPT_EDNS512;
+ FCTXTRACE("too many timeouts, setting EDNS size to 512");
+ }
+
+ if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+ if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) {
+ unsigned int version = 0; /* Default version. */
+ unsigned int flags;
+ isc_uint16_t udpsize = res->udpsize;
+
+ flags = query->addrinfo->flags;
+ if ((flags & DNS_FETCHOPT_EDNSVERSIONSET) != 0) {
+ version = flags & DNS_FETCHOPT_EDNSVERSIONMASK;
+ version >>= DNS_FETCHOPT_EDNSVERSIONSHIFT;
+ }
+ if ((query->options & DNS_FETCHOPT_EDNS512) != 0)
+ udpsize = 512;
+ else if (peer != NULL)
+ (void)dns_peer_getudpsize(peer, &udpsize);
+ result = fctx_addopt(fctx->qmessage, version, udpsize);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * We couldn't add the OPT, but we'll press on.
+ * We're not using EDNS0, so set the NOEDNS0
+ * bit.
+ */
+ query->options |= DNS_FETCHOPT_NOEDNS0;
+ }
+ } else {
+ /*
+ * We know this server doesn't like EDNS0, so we
+ * won't use it. Set the NOEDNS0 bit since we're
+ * not using EDNS0.
+ */
+ query->options |= DNS_FETCHOPT_NOEDNS0;
+ }
+ }
+
+ /*
+ * If we need EDNS0 to do this query and aren't using it, we lose.
+ */
+ if (NEEDEDNS0(fctx) && (query->options & DNS_FETCHOPT_NOEDNS0) != 0) {
+ result = DNS_R_SERVFAIL;
+ goto cleanup_message;
+ }
+
+ if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0)
+ add_triededns(fctx, &query->addrinfo->sockaddr);
+
+ if ((query->options & DNS_FETCHOPT_EDNS512) != 0)
+ add_triededns512(fctx, &query->addrinfo->sockaddr);
+
+ /*
+ * Clear CD if EDNS is not in use.
+ */
+ if ((query->options & DNS_FETCHOPT_NOEDNS0) != 0)
+ fctx->qmessage->flags &= ~DNS_MESSAGEFLAG_CD;
+
+ /*
+ * Add TSIG record tailored to the current recipient.
+ */
+ result = dns_view_getpeertsig(fctx->res->view, &ipaddr, &tsigkey);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
+ goto cleanup_message;
+
+ if (tsigkey != NULL) {
+ result = dns_message_settsigkey(fctx->qmessage, tsigkey);
+ dns_tsigkey_detach(&tsigkey);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_message;
+ }
+
+ result = dns_message_rendersection(fctx->qmessage,
+ DNS_SECTION_ADDITIONAL, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_message;
+
+ result = dns_message_renderend(fctx->qmessage);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_message;
+
+ dns_compress_invalidate(&cctx);
+ cleanup_cctx = ISC_FALSE;
+
+ if (dns_message_gettsigkey(fctx->qmessage) != NULL) {
+ dns_tsigkey_attach(dns_message_gettsigkey(fctx->qmessage),
+ &query->tsigkey);
+ result = dns_message_getquerytsig(fctx->qmessage,
+ fctx->res->mctx,
+ &query->tsig);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_message;
+ }
+
+ /*
+ * If using TCP, write the length of the message at the beginning
+ * of the buffer.
+ */
+ if ((query->options & DNS_FETCHOPT_TCP) != 0) {
+ isc_buffer_usedregion(&query->buffer, &r);
+ isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t)r.length);
+ isc_buffer_add(&tcpbuffer, r.length);
+ }
+
+ /*
+ * We're now done with the query message.
+ */
+ dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
+
+ socket = dns_dispatch_getsocket(query->dispatch);
+ /*
+ * Send the query!
+ */
+ if ((query->options & DNS_FETCHOPT_TCP) == 0)
+ address = &query->addrinfo->sockaddr;
+ isc_buffer_usedregion(buffer, &r);
+
+ /*
+ * XXXRTH Make sure we don't send to ourselves! We should probably
+ * prune out these addresses when we get them from the ADB.
+ */
+ result = isc_socket_sendto(socket, &r, task, resquery_senddone,
+ query, address, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_message;
+ query->sends++;
+ QTRACE("sent");
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_message:
+ if (cleanup_cctx)
+ dns_compress_invalidate(&cctx);
+
+ dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
+
+ /*
+ * Stop the dispatcher from listening.
+ */
+ dns_dispatch_removeresponse(&query->dispentry, NULL);
+
+ cleanup_temps:
+ if (qname != NULL)
+ dns_message_puttempname(fctx->qmessage, &qname);
+ if (qrdataset != NULL)
+ dns_message_puttemprdataset(fctx->qmessage, &qrdataset);
+
+ return (result);
+}
+
+static void
+resquery_connected(isc_task_t *task, isc_event_t *event) {
+ isc_socketevent_t *sevent = (isc_socketevent_t *)event;
+ resquery_t *query = event->ev_arg;
+ isc_boolean_t retry = ISC_FALSE;
+ isc_result_t result;
+ unsigned int attrs;
+ fetchctx_t *fctx;
+
+ REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
+ REQUIRE(VALID_QUERY(query));
+
+ QTRACE("connected");
+
+ UNUSED(task);
+
+ /*
+ * XXXRTH
+ *
+ * Currently we don't wait for the connect event before retrying
+ * a query. This means that if we get really behind, we may end
+ * up doing extra work!
+ */
+
+ query->connects--;
+ fctx = query->fctx;
+
+ if (RESQUERY_CANCELED(query)) {
+ /*
+ * This query was canceled while the connect() was in
+ * progress.
+ */
+ isc_socket_detach(&query->tcpsocket);
+ resquery_destroy(&query);
+ } else {
+ switch (sevent->result) {
+ case ISC_R_SUCCESS:
+ /*
+ * We are connected. Create a dispatcher and
+ * send the query.
+ */
+ attrs = 0;
+ attrs |= DNS_DISPATCHATTR_TCP;
+ attrs |= DNS_DISPATCHATTR_PRIVATE;
+ attrs |= DNS_DISPATCHATTR_CONNECTED;
+ if (isc_sockaddr_pf(&query->addrinfo->sockaddr) ==
+ AF_INET)
+ attrs |= DNS_DISPATCHATTR_IPV4;
+ else
+ attrs |= DNS_DISPATCHATTR_IPV6;
+ attrs |= DNS_DISPATCHATTR_MAKEQUERY;
+
+ result = dns_dispatch_createtcp(query->dispatchmgr,
+ query->tcpsocket,
+ query->fctx->res->taskmgr,
+ 4096, 2, 1, 1, 3, attrs,
+ &query->dispatch);
+
+ /*
+ * Regardless of whether dns_dispatch_create()
+ * succeeded or not, we don't need our reference
+ * to the socket anymore.
+ */
+ isc_socket_detach(&query->tcpsocket);
+
+ if (result == ISC_R_SUCCESS)
+ result = resquery_send(query);
+
+ if (result != ISC_R_SUCCESS) {
+ fctx_cancelquery(&query, NULL, NULL,
+ ISC_FALSE);
+ fctx_done(fctx, result);
+ }
+ break;
+
+ case ISC_R_NETUNREACH:
+ case ISC_R_HOSTUNREACH:
+ case ISC_R_CONNREFUSED:
+ case ISC_R_NOPERM:
+ case ISC_R_ADDRNOTAVAIL:
+ case ISC_R_CONNECTIONRESET:
+ /*
+ * No route to remote.
+ */
+ isc_socket_detach(&query->tcpsocket);
+ fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
+ retry = ISC_TRUE;
+ break;
+
+ default:
+ isc_socket_detach(&query->tcpsocket);
+ fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
+ break;
+ }
+ }
+
+ isc_event_free(&event);
+
+ if (retry) {
+ /*
+ * Behave as if the idle timer has expired. For TCP
+ * connections this may not actually reflect the latest timer.
+ */
+ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+ result = fctx_stopidletimer(fctx);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ else
+ fctx_try(fctx);
+ }
+}
+
+static void
+fctx_finddone(isc_task_t *task, isc_event_t *event) {
+ fetchctx_t *fctx;
+ dns_adbfind_t *find;
+ dns_resolver_t *res;
+ isc_boolean_t want_try = ISC_FALSE;
+ isc_boolean_t want_done = ISC_FALSE;
+ isc_boolean_t bucket_empty = ISC_FALSE;
+ unsigned int bucketnum;
+
+ find = event->ev_sender;
+ fctx = event->ev_arg;
+ REQUIRE(VALID_FCTX(fctx));
+ res = fctx->res;
+
+ UNUSED(task);
+
+ FCTXTRACE("finddone");
+
+ INSIST(fctx->pending > 0);
+ fctx->pending--;
+
+ if (ADDRWAIT(fctx)) {
+ /*
+ * The fetch is waiting for a name to be found.
+ */
+ INSIST(!SHUTTINGDOWN(fctx));
+ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+ if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES)
+ want_try = ISC_TRUE;
+ else if (fctx->pending == 0) {
+ /*
+ * We've got nothing else to wait for and don't
+ * know the answer. There's nothing to do but
+ * fail the fctx.
+ */
+ want_done = ISC_TRUE;
+ }
+ } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
+ fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) {
+ bucketnum = fctx->bucketnum;
+ LOCK(&res->buckets[bucketnum].lock);
+ /*
+ * Note that we had to wait until we had the lock before
+ * looking at fctx->references.
+ */
+ if (fctx->references == 0)
+ bucket_empty = fctx_destroy(fctx);
+ UNLOCK(&res->buckets[bucketnum].lock);
+ }
+
+ isc_event_free(&event);
+ dns_adb_destroyfind(&find);
+
+ if (want_try)
+ fctx_try(fctx);
+ else if (want_done)
+ fctx_done(fctx, ISC_R_FAILURE);
+ else if (bucket_empty)
+ empty_bucket(res);
+}
+
+
+static inline isc_boolean_t
+bad_server(fetchctx_t *fctx, isc_sockaddr_t *address) {
+ isc_sockaddr_t *sa;
+
+ for (sa = ISC_LIST_HEAD(fctx->bad);
+ sa != NULL;
+ sa = ISC_LIST_NEXT(sa, link)) {
+ if (isc_sockaddr_equal(sa, address))
+ return (ISC_TRUE);
+ }
+
+ return (ISC_FALSE);
+}
+
+static inline isc_boolean_t
+mark_bad(fetchctx_t *fctx) {
+ dns_adbfind_t *curr;
+ dns_adbaddrinfo_t *addrinfo;
+ isc_boolean_t all_bad = ISC_TRUE;
+
+ /*
+ * Mark all known bad servers, so we don't try to talk to them
+ * again.
+ */
+
+ /*
+ * Mark any bad nameservers.
+ */
+ for (curr = ISC_LIST_HEAD(fctx->finds);
+ curr != NULL;
+ curr = ISC_LIST_NEXT(curr, publink)) {
+ for (addrinfo = ISC_LIST_HEAD(curr->list);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+ if (bad_server(fctx, &addrinfo->sockaddr))
+ addrinfo->flags |= FCTX_ADDRINFO_MARK;
+ else
+ all_bad = ISC_FALSE;
+ }
+ }
+
+ /*
+ * Mark any bad forwarders.
+ */
+ for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+ if (bad_server(fctx, &addrinfo->sockaddr))
+ addrinfo->flags |= FCTX_ADDRINFO_MARK;
+ else
+ all_bad = ISC_FALSE;
+ }
+
+ /*
+ * Mark any bad alternates.
+ */
+ for (curr = ISC_LIST_HEAD(fctx->altfinds);
+ curr != NULL;
+ curr = ISC_LIST_NEXT(curr, publink)) {
+ for (addrinfo = ISC_LIST_HEAD(curr->list);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+ if (bad_server(fctx, &addrinfo->sockaddr))
+ addrinfo->flags |= FCTX_ADDRINFO_MARK;
+ else
+ all_bad = ISC_FALSE;
+ }
+ }
+
+ for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+ if (bad_server(fctx, &addrinfo->sockaddr))
+ addrinfo->flags |= FCTX_ADDRINFO_MARK;
+ else
+ all_bad = ISC_FALSE;
+ }
+
+ return (all_bad);
+}
+
+static void
+add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+ char classbuf[64];
+ char typebuf[64];
+ char code[64];
+ isc_buffer_t b;
+ isc_sockaddr_t *sa;
+ const char *sep1, *sep2;
+ isc_sockaddr_t *address = &addrinfo->sockaddr;
+
+ if (bad_server(fctx, address)) {
+ /*
+ * We already know this server is bad.
+ */
+ return;
+ }
+
+ FCTXTRACE("add_bad");
+
+ sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
+ sizeof(*sa));
+ if (sa == NULL)
+ return;
+ *sa = *address;
+ ISC_LIST_INITANDAPPEND(fctx->bad, sa, link);
+
+ if (reason == DNS_R_LAME) /* already logged */
+ return;
+
+ if (reason == DNS_R_UNEXPECTEDRCODE &&
+ fctx->rmessage->opcode == dns_rcode_servfail &&
+ ISFORWARDER(addrinfo))
+ return;
+
+ if (reason == DNS_R_UNEXPECTEDRCODE) {
+ isc_buffer_init(&b, code, sizeof(code) - 1);
+ dns_rcode_totext(fctx->rmessage->rcode, &b);
+ code[isc_buffer_usedlength(&b)] = '\0';
+ sep1 = "(";
+ sep2 = ") ";
+ } else if (reason == DNS_R_UNEXPECTEDOPCODE) {
+ isc_buffer_init(&b, code, sizeof(code) - 1);
+ dns_opcode_totext((dns_opcode_t)fctx->rmessage->opcode, &b);
+ code[isc_buffer_usedlength(&b)] = '\0';
+ sep1 = "(";
+ sep2 = ") ";
+ } else {
+ code[0] = '\0';
+ sep1 = "";
+ sep2 = "";
+ }
+ dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
+ dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
+ dns_rdataclass_format(fctx->res->rdclass, classbuf, sizeof(classbuf));
+ isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
+ "%s %s%s%sresolving '%s/%s/%s': %s",
+ dns_result_totext(reason), sep1, code, sep2,
+ namebuf, typebuf, classbuf, addrbuf);
+}
+
+static void
+sort_adbfind(dns_adbfind_t *find) {
+ dns_adbaddrinfo_t *best, *curr;
+ dns_adbaddrinfolist_t sorted;
+
+ /*
+ * Lame N^2 bubble sort.
+ */
+
+ ISC_LIST_INIT(sorted);
+ while (!ISC_LIST_EMPTY(find->list)) {
+ best = ISC_LIST_HEAD(find->list);
+ curr = ISC_LIST_NEXT(best, publink);
+ while (curr != NULL) {
+ if (curr->srtt < best->srtt)
+ best = curr;
+ curr = ISC_LIST_NEXT(curr, publink);
+ }
+ ISC_LIST_UNLINK(find->list, best, publink);
+ ISC_LIST_APPEND(sorted, best, publink);
+ }
+ find->list = sorted;
+}
+
+static void
+sort_finds(fetchctx_t *fctx) {
+ dns_adbfind_t *best, *curr;
+ dns_adbfindlist_t sorted;
+ dns_adbaddrinfo_t *addrinfo, *bestaddrinfo;
+
+ /*
+ * Lame N^2 bubble sort.
+ */
+
+ ISC_LIST_INIT(sorted);
+ while (!ISC_LIST_EMPTY(fctx->finds)) {
+ best = ISC_LIST_HEAD(fctx->finds);
+ bestaddrinfo = ISC_LIST_HEAD(best->list);
+ INSIST(bestaddrinfo != NULL);
+ curr = ISC_LIST_NEXT(best, publink);
+ while (curr != NULL) {
+ addrinfo = ISC_LIST_HEAD(curr->list);
+ INSIST(addrinfo != NULL);
+ if (addrinfo->srtt < bestaddrinfo->srtt) {
+ best = curr;
+ bestaddrinfo = addrinfo;
+ }
+ curr = ISC_LIST_NEXT(curr, publink);
+ }
+ ISC_LIST_UNLINK(fctx->finds, best, publink);
+ ISC_LIST_APPEND(sorted, best, publink);
+ }
+ fctx->finds = sorted;
+
+ ISC_LIST_INIT(sorted);
+ while (!ISC_LIST_EMPTY(fctx->altfinds)) {
+ best = ISC_LIST_HEAD(fctx->altfinds);
+ bestaddrinfo = ISC_LIST_HEAD(best->list);
+ INSIST(bestaddrinfo != NULL);
+ curr = ISC_LIST_NEXT(best, publink);
+ while (curr != NULL) {
+ addrinfo = ISC_LIST_HEAD(curr->list);
+ INSIST(addrinfo != NULL);
+ if (addrinfo->srtt < bestaddrinfo->srtt) {
+ best = curr;
+ bestaddrinfo = addrinfo;
+ }
+ curr = ISC_LIST_NEXT(curr, publink);
+ }
+ ISC_LIST_UNLINK(fctx->altfinds, best, publink);
+ ISC_LIST_APPEND(sorted, best, publink);
+ }
+ fctx->altfinds = sorted;
+}
+
+static void
+findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port,
+ unsigned int options, unsigned int flags, isc_stdtime_t now,
+ isc_boolean_t *need_alternate)
+{
+ dns_adbaddrinfo_t *ai;
+ dns_adbfind_t *find;
+ dns_resolver_t *res;
+ isc_boolean_t unshared;
+ isc_result_t result;
+
+ res = fctx->res;
+ unshared = ISC_TF((fctx->options | DNS_FETCHOPT_UNSHARED) != 0);
+ /*
+ * If this name is a subdomain of the query domain, tell
+ * the ADB to start looking using zone/hint data. This keeps us
+ * from getting stuck if the nameserver is beneath the zone cut
+ * and we don't know its address (e.g. because the A record has
+ * expired).
+ */
+ if (dns_name_issubdomain(name, &fctx->domain))
+ options |= DNS_ADBFIND_STARTATZONE;
+ options |= DNS_ADBFIND_GLUEOK;
+ options |= DNS_ADBFIND_HINTOK;
+
+ /*
+ * See what we know about this address.
+ */
+ find = NULL;
+ result = dns_adb_createfind(fctx->adb,
+ res->buckets[fctx->bucketnum].task,
+ fctx_finddone, fctx, name,
+ &fctx->name, fctx->type,
+ options, now, NULL,
+ res->view->dstport, &find);
+ if (result != ISC_R_SUCCESS) {
+ if (result == DNS_R_ALIAS) {
+ /*
+ * XXXRTH Follow the CNAME/DNAME chain?
+ */
+ dns_adb_destroyfind(&find);
+ }
+ } else if (!ISC_LIST_EMPTY(find->list)) {
+ /*
+ * We have at least some of the addresses for the
+ * name.
+ */
+ INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0);
+ sort_adbfind(find);
+ if (flags != 0 || port != 0) {
+ for (ai = ISC_LIST_HEAD(find->list);
+ ai != NULL;
+ ai = ISC_LIST_NEXT(ai, publink)) {
+ ai->flags |= flags;
+ if (port != 0)
+ isc_sockaddr_setport(&ai->sockaddr,
+ port);
+ }
+ }
+ if ((flags & FCTX_ADDRINFO_FORWARDER) != 0)
+ ISC_LIST_APPEND(fctx->altfinds, find, publink);
+ else
+ ISC_LIST_APPEND(fctx->finds, find, publink);
+ } else {
+ /*
+ * We don't know any of the addresses for this
+ * name.
+ */
+ if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) {
+ /*
+ * We're looking for them and will get an
+ * event about it later.
+ */
+ fctx->pending++;
+ /*
+ * Bootstrap.
+ */
+ if (need_alternate != NULL &&
+ !*need_alternate && unshared &&
+ ((res->dispatchv4 == NULL &&
+ find->result_v6 != DNS_R_NXDOMAIN) ||
+ (res->dispatchv6 == NULL &&
+ find->result_v4 != DNS_R_NXDOMAIN)))
+ *need_alternate = ISC_TRUE;
+ } else {
+ /*
+ * If we know there are no addresses for
+ * the family we are using then try to add
+ * an alternative server.
+ */
+ if (need_alternate != NULL && !*need_alternate &&
+ ((res->dispatchv4 == NULL &&
+ find->result_v6 == DNS_R_NXRRSET) ||
+ (res->dispatchv6 == NULL &&
+ find->result_v4 == DNS_R_NXRRSET)))
+ *need_alternate = ISC_TRUE;
+ dns_adb_destroyfind(&find);
+ }
+ }
+}
+
+static isc_result_t
+fctx_getaddresses(fetchctx_t *fctx) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_result_t result;
+ dns_resolver_t *res;
+ isc_stdtime_t now;
+ unsigned int stdoptions;
+ isc_sockaddr_t *sa;
+ dns_adbaddrinfo_t *ai;
+ isc_boolean_t all_bad;
+ dns_rdata_ns_t ns;
+ isc_boolean_t need_alternate = ISC_FALSE;
+
+ FCTXTRACE("getaddresses");
+
+ /*
+ * Don't pound on remote servers. (Failsafe!)
+ */
+ fctx->restarts++;
+ if (fctx->restarts > 10) {
+ FCTXTRACE("too many restarts");
+ return (DNS_R_SERVFAIL);
+ }
+
+ res = fctx->res;
+ stdoptions = 0; /* Keep compiler happy. */
+
+ /*
+ * Forwarders.
+ */
+
+ INSIST(ISC_LIST_EMPTY(fctx->forwaddrs));
+ INSIST(ISC_LIST_EMPTY(fctx->altaddrs));
+
+ /*
+ * If this fctx has forwarders, use them; otherwise use any
+ * selective forwarders specified in the view; otherwise use the
+ * resolver's forwarders (if any).
+ */
+ sa = ISC_LIST_HEAD(fctx->forwarders);
+ if (sa == NULL) {
+ dns_forwarders_t *forwarders = NULL;
+ dns_name_t *name = &fctx->name;
+ dns_name_t suffix;
+ unsigned int labels;
+
+ /*
+ * DS records are found in the parent server.
+ * Strip label to get the correct forwarder (if any).
+ */
+ if (fctx->type == dns_rdatatype_ds &&
+ dns_name_countlabels(name) > 1) {
+ dns_name_init(&suffix, NULL);
+ labels = dns_name_countlabels(name);
+ dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
+ name = &suffix;
+ }
+ result = dns_fwdtable_find(fctx->res->view->fwdtable, name,
+ &forwarders);
+ if (result == ISC_R_SUCCESS) {
+ sa = ISC_LIST_HEAD(forwarders->addrs);
+ fctx->fwdpolicy = forwarders->fwdpolicy;
+ }
+ }
+
+ while (sa != NULL) {
+ ai = NULL;
+ result = dns_adb_findaddrinfo(fctx->adb,
+ sa, &ai, 0); /* XXXMLG */
+ if (result == ISC_R_SUCCESS) {
+ dns_adbaddrinfo_t *cur;
+ ai->flags |= FCTX_ADDRINFO_FORWARDER;
+ cur = ISC_LIST_HEAD(fctx->forwaddrs);
+ while (cur != NULL && cur->srtt < ai->srtt)
+ cur = ISC_LIST_NEXT(cur, publink);
+ if (cur != NULL)
+ ISC_LIST_INSERTBEFORE(fctx->forwaddrs, cur,
+ ai, publink);
+ else
+ ISC_LIST_APPEND(fctx->forwaddrs, ai, publink);
+ }
+ sa = ISC_LIST_NEXT(sa, link);
+ }
+
+ /*
+ * If the forwarding policy is "only", we don't need the addresses
+ * of the nameservers.
+ */
+ if (fctx->fwdpolicy == dns_fwdpolicy_only)
+ goto out;
+
+ /*
+ * Normal nameservers.
+ */
+
+ stdoptions = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT;
+ if (fctx->restarts == 1) {
+ /*
+ * To avoid sending out a flood of queries likely to
+ * result in NXRRSET, we suppress fetches for address
+ * families we don't have the first time through,
+ * provided that we have addresses in some family we
+ * can use.
+ *
+ * We don't want to set this option all the time, since
+ * if fctx->restarts > 1, we've clearly been having trouble
+ * with the addresses we had, so getting more could help.
+ */
+ stdoptions |= DNS_ADBFIND_AVOIDFETCHES;
+ }
+ if (res->dispatchv4 != NULL)
+ stdoptions |= DNS_ADBFIND_INET;
+ if (res->dispatchv6 != NULL)
+ stdoptions |= DNS_ADBFIND_INET6;
+ isc_stdtime_get(&now);
+
+ INSIST(ISC_LIST_EMPTY(fctx->finds));
+ INSIST(ISC_LIST_EMPTY(fctx->altfinds));
+
+ for (result = dns_rdataset_first(&fctx->nameservers);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&fctx->nameservers))
+ {
+ dns_rdataset_current(&fctx->nameservers, &rdata);
+ /*
+ * Extract the name from the NS record.
+ */
+ result = dns_rdata_tostruct(&rdata, &ns, NULL);
+ if (result != ISC_R_SUCCESS)
+ continue;
+
+ findname(fctx, &ns.name, 0, stdoptions, 0, now,
+ &need_alternate);
+ dns_rdata_reset(&rdata);
+ dns_rdata_freestruct(&ns);
+ }
+ if (result != ISC_R_NOMORE)
+ return (result);
+
+ /*
+ * Do we need to use 6 to 4?
+ */
+ if (need_alternate) {
+ int family;
+ alternate_t *a;
+ family = (res->dispatchv6 != NULL) ? AF_INET6 : AF_INET;
+ for (a = ISC_LIST_HEAD(fctx->res->alternates);
+ a != NULL;
+ a = ISC_LIST_NEXT(a, link)) {
+ if (!a->isaddress) {
+ findname(fctx, &a->_u._n.name, a->_u._n.port,
+ stdoptions, FCTX_ADDRINFO_FORWARDER,
+ now, NULL);
+ continue;
+ }
+ if (isc_sockaddr_pf(&a->_u.addr) != family)
+ continue;
+ ai = NULL;
+ result = dns_adb_findaddrinfo(fctx->adb, &a->_u.addr,
+ &ai, 0);
+ if (result == ISC_R_SUCCESS) {
+ dns_adbaddrinfo_t *cur;
+ ai->flags |= FCTX_ADDRINFO_FORWARDER;
+ cur = ISC_LIST_HEAD(fctx->altaddrs);
+ while (cur != NULL && cur->srtt < ai->srtt)
+ cur = ISC_LIST_NEXT(cur, publink);
+ if (cur != NULL)
+ ISC_LIST_INSERTBEFORE(fctx->altaddrs,
+ cur, ai, publink);
+ else
+ ISC_LIST_APPEND(fctx->altaddrs, ai,
+ publink);
+ }
+ }
+ }
+
+ out:
+ /*
+ * Mark all known bad servers.
+ */
+ all_bad = mark_bad(fctx);
+
+ /*
+ * How are we doing?
+ */
+ if (all_bad) {
+ /*
+ * We've got no addresses.
+ */
+ if (fctx->pending > 0) {
+ /*
+ * We're fetching the addresses, but don't have any
+ * yet. Tell the caller to wait for an answer.
+ */
+ result = DNS_R_WAIT;
+ } else {
+ /*
+ * We've lost completely. We don't know any
+ * addresses, and the ADB has told us it can't get
+ * them.
+ */
+ FCTXTRACE("no addresses");
+ result = ISC_R_FAILURE;
+ }
+ } else {
+ /*
+ * We've found some addresses. We might still be looking
+ * for more addresses.
+ */
+ sort_finds(fctx);
+ result = ISC_R_SUCCESS;
+ }
+
+ return (result);
+}
+
+static inline void
+possibly_mark(fetchctx_t *fctx, dns_adbaddrinfo_t *addr)
+{
+ isc_netaddr_t na;
+ char buf[ISC_NETADDR_FORMATSIZE];
+ isc_sockaddr_t *sa;
+ isc_boolean_t aborted = ISC_FALSE;
+ isc_boolean_t bogus;
+ dns_acl_t *blackhole;
+ isc_netaddr_t ipaddr;
+ dns_peer_t *peer = NULL;
+ dns_resolver_t *res;
+ const char *msg = NULL;
+
+ sa = &addr->sockaddr;
+
+ res = fctx->res;
+ isc_netaddr_fromsockaddr(&ipaddr, sa);
+ blackhole = dns_dispatchmgr_getblackhole(res->dispatchmgr);
+ (void) dns_peerlist_peerbyaddr(res->view->peers, &ipaddr, &peer);
+
+ if (blackhole != NULL) {
+ int match;
+
+ if (dns_acl_match(&ipaddr, NULL, blackhole,
+ &res->view->aclenv,
+ &match, NULL) == ISC_R_SUCCESS &&
+ match > 0)
+ aborted = ISC_TRUE;
+ }
+
+ if (peer != NULL &&
+ dns_peer_getbogus(peer, &bogus) == ISC_R_SUCCESS &&
+ bogus)
+ aborted = ISC_TRUE;
+
+ if (aborted) {
+ addr->flags |= FCTX_ADDRINFO_MARK;
+ msg = "ignoring blackholed / bogus server: ";
+ } else if (isc_sockaddr_ismulticast(sa)) {
+ addr->flags |= FCTX_ADDRINFO_MARK;
+ msg = "ignoring multicast address: ";
+ } else if (isc_sockaddr_isexperimental(sa)) {
+ addr->flags |= FCTX_ADDRINFO_MARK;
+ msg = "ignoring experimental address: ";
+ } else if (sa->type.sa.sa_family != AF_INET6) {
+ return;
+ } else if (IN6_IS_ADDR_V4MAPPED(&sa->type.sin6.sin6_addr)) {
+ addr->flags |= FCTX_ADDRINFO_MARK;
+ msg = "ignoring IPv6 mapped IPV4 address: ";
+ } else if (IN6_IS_ADDR_V4COMPAT(&sa->type.sin6.sin6_addr)) {
+ addr->flags |= FCTX_ADDRINFO_MARK;
+ msg = "ignoring IPv6 compatibility IPV4 address: ";
+ } else
+ return;
+
+ if (!isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3)))
+ return;
+
+ isc_netaddr_fromsockaddr(&na, sa);
+ isc_netaddr_format(&na, buf, sizeof(buf));
+ FCTXTRACE2(msg, buf);
+}
+
+static inline dns_adbaddrinfo_t *
+fctx_nextaddress(fetchctx_t *fctx) {
+ dns_adbfind_t *find, *start;
+ dns_adbaddrinfo_t *addrinfo;
+ dns_adbaddrinfo_t *faddrinfo;
+
+ /*
+ * Return the next untried address, if any.
+ */
+
+ /*
+ * Find the first unmarked forwarder (if any).
+ */
+ for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+ if (!UNMARKED(addrinfo))
+ continue;
+ possibly_mark(fctx, addrinfo);
+ if (UNMARKED(addrinfo)) {
+ addrinfo->flags |= FCTX_ADDRINFO_MARK;
+ fctx->find = NULL;
+ return (addrinfo);
+ }
+ }
+
+ /*
+ * No forwarders. Move to the next find.
+ */
+
+ fctx->attributes |= FCTX_ATTR_TRIEDFIND;
+
+ find = fctx->find;
+ if (find == NULL)
+ find = ISC_LIST_HEAD(fctx->finds);
+ else {
+ find = ISC_LIST_NEXT(find, publink);
+ if (find == NULL)
+ find = ISC_LIST_HEAD(fctx->finds);
+ }
+
+ /*
+ * Find the first unmarked addrinfo.
+ */
+ addrinfo = NULL;
+ if (find != NULL) {
+ start = find;
+ do {
+ for (addrinfo = ISC_LIST_HEAD(find->list);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+ if (!UNMARKED(addrinfo))
+ continue;
+ possibly_mark(fctx, addrinfo);
+ if (UNMARKED(addrinfo)) {
+ addrinfo->flags |= FCTX_ADDRINFO_MARK;
+ break;
+ }
+ }
+ if (addrinfo != NULL)
+ break;
+ find = ISC_LIST_NEXT(find, publink);
+ if (find == NULL)
+ find = ISC_LIST_HEAD(fctx->finds);
+ } while (find != start);
+ }
+
+ fctx->find = find;
+ if (addrinfo != NULL)
+ return (addrinfo);
+
+ /*
+ * No nameservers left. Try alternates.
+ */
+
+ fctx->attributes |= FCTX_ATTR_TRIEDALT;
+
+ find = fctx->altfind;
+ if (find == NULL)
+ find = ISC_LIST_HEAD(fctx->altfinds);
+ else {
+ find = ISC_LIST_NEXT(find, publink);
+ if (find == NULL)
+ find = ISC_LIST_HEAD(fctx->altfinds);
+ }
+
+ /*
+ * Find the first unmarked addrinfo.
+ */
+ addrinfo = NULL;
+ if (find != NULL) {
+ start = find;
+ do {
+ for (addrinfo = ISC_LIST_HEAD(find->list);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+ if (!UNMARKED(addrinfo))
+ continue;
+ possibly_mark(fctx, addrinfo);
+ if (UNMARKED(addrinfo)) {
+ addrinfo->flags |= FCTX_ADDRINFO_MARK;
+ break;
+ }
+ }
+ if (addrinfo != NULL)
+ break;
+ find = ISC_LIST_NEXT(find, publink);
+ if (find == NULL)
+ find = ISC_LIST_HEAD(fctx->altfinds);
+ } while (find != start);
+ }
+
+ faddrinfo = addrinfo;
+
+ /*
+ * See if we have a better alternate server by address.
+ */
+
+ for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
+ addrinfo != NULL;
+ addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+ if (!UNMARKED(addrinfo))
+ continue;
+ possibly_mark(fctx, addrinfo);
+ if (UNMARKED(addrinfo) &&
+ (faddrinfo == NULL ||
+ addrinfo->srtt < faddrinfo->srtt)) {
+ if (faddrinfo != NULL)
+ faddrinfo->flags &= ~FCTX_ADDRINFO_MARK;
+ addrinfo->flags |= FCTX_ADDRINFO_MARK;
+ break;
+ }
+ }
+
+ if (addrinfo == NULL) {
+ addrinfo = faddrinfo;
+ fctx->altfind = find;
+ }
+
+ return (addrinfo);
+}
+
+static void
+fctx_try(fetchctx_t *fctx) {
+ isc_result_t result;
+ dns_adbaddrinfo_t *addrinfo;
+
+ FCTXTRACE("try");
+
+ REQUIRE(!ADDRWAIT(fctx));
+
+ addrinfo = fctx_nextaddress(fctx);
+ if (addrinfo == NULL) {
+ /*
+ * We have no more addresses. Start over.
+ */
+ fctx_cancelqueries(fctx, ISC_TRUE);
+ fctx_cleanupfinds(fctx);
+ fctx_cleanupaltfinds(fctx);
+ fctx_cleanupforwaddrs(fctx);
+ fctx_cleanupaltaddrs(fctx);
+ result = fctx_getaddresses(fctx);
+ if (result == DNS_R_WAIT) {
+ /*
+ * Sleep waiting for addresses.
+ */
+ FCTXTRACE("addrwait");
+ fctx->attributes |= FCTX_ATTR_ADDRWAIT;
+ return;
+ } else if (result != ISC_R_SUCCESS) {
+ /*
+ * Something bad happened.
+ */
+ fctx_done(fctx, result);
+ return;
+ }
+
+ addrinfo = fctx_nextaddress(fctx);
+ /*
+ * While we may have addresses from the ADB, they
+ * might be bad ones. In this case, return SERVFAIL.
+ */
+ if (addrinfo == NULL) {
+ fctx_done(fctx, DNS_R_SERVFAIL);
+ return;
+ }
+ }
+
+ result = fctx_query(fctx, addrinfo, fctx->options);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+}
+
+static isc_boolean_t
+fctx_destroy(fetchctx_t *fctx) {
+ dns_resolver_t *res;
+ unsigned int bucketnum;
+ isc_sockaddr_t *sa, *next_sa;
+
+ /*
+ * Caller must be holding the bucket lock.
+ */
+
+ REQUIRE(VALID_FCTX(fctx));
+ REQUIRE(fctx->state == fetchstate_done ||
+ fctx->state == fetchstate_init);
+ REQUIRE(ISC_LIST_EMPTY(fctx->events));
+ REQUIRE(ISC_LIST_EMPTY(fctx->queries));
+ REQUIRE(ISC_LIST_EMPTY(fctx->finds));
+ REQUIRE(ISC_LIST_EMPTY(fctx->altfinds));
+ REQUIRE(fctx->pending == 0);
+ REQUIRE(fctx->references == 0);
+ REQUIRE(ISC_LIST_EMPTY(fctx->validators));
+
+ FCTXTRACE("destroy");
+
+ res = fctx->res;
+ bucketnum = fctx->bucketnum;
+
+ ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link);
+
+ /*
+ * Free bad.
+ */
+ for (sa = ISC_LIST_HEAD(fctx->bad);
+ sa != NULL;
+ sa = next_sa) {
+ next_sa = ISC_LIST_NEXT(sa, link);
+ ISC_LIST_UNLINK(fctx->bad, sa, link);
+ isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
+ }
+
+ for (sa = ISC_LIST_HEAD(fctx->edns);
+ sa != NULL;
+ sa = next_sa) {
+ next_sa = ISC_LIST_NEXT(sa, link);
+ ISC_LIST_UNLINK(fctx->edns, sa, link);
+ isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
+ }
+
+ for (sa = ISC_LIST_HEAD(fctx->edns512);
+ sa != NULL;
+ sa = next_sa) {
+ next_sa = ISC_LIST_NEXT(sa, link);
+ ISC_LIST_UNLINK(fctx->edns512, sa, link);
+ isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
+ }
+
+ isc_timer_detach(&fctx->timer);
+ dns_message_destroy(&fctx->rmessage);
+ dns_message_destroy(&fctx->qmessage);
+ if (dns_name_countlabels(&fctx->domain) > 0)
+ dns_name_free(&fctx->domain, res->buckets[bucketnum].mctx);
+ if (dns_rdataset_isassociated(&fctx->nameservers))
+ dns_rdataset_disassociate(&fctx->nameservers);
+ dns_name_free(&fctx->name, res->buckets[bucketnum].mctx);
+ dns_db_detach(&fctx->cache);
+ dns_adb_detach(&fctx->adb);
+ isc_mem_free(res->buckets[bucketnum].mctx, fctx->info);
+ isc_mem_put(res->buckets[bucketnum].mctx, fctx, sizeof(*fctx));
+
+ LOCK(&res->nlock);
+ res->nfctx--;
+ UNLOCK(&res->nlock);
+
+ if (res->buckets[bucketnum].exiting &&
+ ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs))
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+}
+
+/*
+ * Fetch event handlers.
+ */
+
+static void
+fctx_timeout(isc_task_t *task, isc_event_t *event) {
+ fetchctx_t *fctx = event->ev_arg;
+
+ REQUIRE(VALID_FCTX(fctx));
+
+ UNUSED(task);
+
+ FCTXTRACE("timeout");
+
+ if (event->ev_type == ISC_TIMEREVENT_LIFE) {
+ fctx_done(fctx, ISC_R_TIMEDOUT);
+ } else {
+ isc_result_t result;
+
+ fctx->timeouts++;
+ /*
+ * We could cancel the running queries here, or we could let
+ * them keep going. Right now we choose the latter...
+ */
+ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+ /*
+ * Our timer has triggered. Reestablish the fctx lifetime
+ * timer.
+ */
+ result = fctx_starttimer(fctx);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ else
+ /*
+ * Keep trying.
+ */
+ fctx_try(fctx);
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+fctx_shutdown(fetchctx_t *fctx) {
+ isc_event_t *cevent;
+
+ /*
+ * Start the shutdown process for fctx, if it isn't already underway.
+ */
+
+ FCTXTRACE("shutdown");
+
+ /*
+ * The caller must be holding the appropriate bucket lock.
+ */
+
+ if (fctx->want_shutdown)
+ return;
+
+ fctx->want_shutdown = ISC_TRUE;
+
+ /*
+ * Unless we're still initializing (in which case the
+ * control event is still outstanding), we need to post
+ * the control event to tell the fetch we want it to
+ * exit.
+ */
+ if (fctx->state != fetchstate_init) {
+ cevent = &fctx->control_event;
+ isc_task_send(fctx->res->buckets[fctx->bucketnum].task,
+ &cevent);
+ }
+}
+
+static void
+fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
+ fetchctx_t *fctx = event->ev_arg;
+ isc_boolean_t bucket_empty = ISC_FALSE;
+ dns_resolver_t *res;
+ unsigned int bucketnum;
+ dns_validator_t *validator;
+
+ REQUIRE(VALID_FCTX(fctx));
+
+ UNUSED(task);
+
+ res = fctx->res;
+ bucketnum = fctx->bucketnum;
+
+ FCTXTRACE("doshutdown");
+
+ /*
+ * An fctx that is shutting down is no longer in ADDRWAIT mode.
+ */
+ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+
+ /*
+ * Cancel all pending validators. Note that this must be done
+ * without the bucket lock held, since that could cause deadlock.
+ */
+ validator = ISC_LIST_HEAD(fctx->validators);
+ while (validator != NULL) {
+ dns_validator_cancel(validator);
+ validator = ISC_LIST_NEXT(validator, link);
+ }
+
+ if (fctx->nsfetch != NULL)
+ dns_resolver_cancelfetch(fctx->nsfetch);
+
+ /*
+ * Shut down anything that is still running on behalf of this
+ * fetch. To avoid deadlock with the ADB, we must do this
+ * before we lock the bucket lock.
+ */
+ fctx_stopeverything(fctx, ISC_FALSE);
+
+ LOCK(&res->buckets[bucketnum].lock);
+
+ fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
+
+ INSIST(fctx->state == fetchstate_active ||
+ fctx->state == fetchstate_done);
+ INSIST(fctx->want_shutdown);
+
+ if (fctx->state != fetchstate_done) {
+ fctx->state = fetchstate_done;
+ fctx_sendevents(fctx, ISC_R_CANCELED);
+ }
+
+ if (fctx->references == 0 && fctx->pending == 0 &&
+ fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators))
+ bucket_empty = fctx_destroy(fctx);
+
+ UNLOCK(&res->buckets[bucketnum].lock);
+
+ if (bucket_empty)
+ empty_bucket(res);
+}
+
+static void
+fctx_start(isc_task_t *task, isc_event_t *event) {
+ fetchctx_t *fctx = event->ev_arg;
+ isc_boolean_t done = ISC_FALSE, bucket_empty = ISC_FALSE;
+ dns_resolver_t *res;
+ unsigned int bucketnum;
+
+ REQUIRE(VALID_FCTX(fctx));
+
+ UNUSED(task);
+
+ res = fctx->res;
+ bucketnum = fctx->bucketnum;
+
+ FCTXTRACE("start");
+
+ LOCK(&res->buckets[bucketnum].lock);
+
+ INSIST(fctx->state == fetchstate_init);
+ if (fctx->want_shutdown) {
+ /*
+ * We haven't started this fctx yet, and we've been requested
+ * to shut it down.
+ */
+ fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
+ fctx->state = fetchstate_done;
+ fctx_sendevents(fctx, ISC_R_CANCELED);
+ /*
+ * Since we haven't started, we INSIST that we have no
+ * pending ADB finds and no pending validations.
+ */
+ INSIST(fctx->pending == 0);
+ INSIST(fctx->nqueries == 0);
+ INSIST(ISC_LIST_EMPTY(fctx->validators));
+ if (fctx->references == 0) {
+ /*
+ * It's now safe to destroy this fctx.
+ */
+ bucket_empty = fctx_destroy(fctx);
+ }
+ done = ISC_TRUE;
+ } else {
+ /*
+ * Normal fctx startup.
+ */
+ fctx->state = fetchstate_active;
+ /*
+ * Reset the control event for later use in shutting down
+ * the fctx.
+ */
+ ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
+ DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx,
+ NULL, NULL, NULL);
+ }
+
+ UNLOCK(&res->buckets[bucketnum].lock);
+
+ if (!done) {
+ isc_result_t result;
+
+ /*
+ * All is well. Start working on the fetch.
+ */
+ result = fctx_starttimer(fctx);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ else
+ fctx_try(fctx);
+ } else if (bucket_empty)
+ empty_bucket(res);
+}
+
+/*
+ * Fetch Creation, Joining, and Cancelation.
+ */
+
+static inline isc_result_t
+fctx_join(fetchctx_t *fctx, isc_task_t *task, isc_sockaddr_t *client,
+ dns_messageid_t id, isc_taskaction_t action, void *arg,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
+ dns_fetch_t *fetch)
+{
+ isc_task_t *clone;
+ dns_fetchevent_t *event;
+
+ FCTXTRACE("join");
+
+ /*
+ * We store the task we're going to send this event to in the
+ * sender field. We'll make the fetch the sender when we actually
+ * send the event.
+ */
+ clone = NULL;
+ isc_task_attach(task, &clone);
+ event = (dns_fetchevent_t *)
+ isc_event_allocate(fctx->res->mctx, clone, DNS_EVENT_FETCHDONE,
+ action, arg, sizeof(*event));
+ if (event == NULL) {
+ isc_task_detach(&clone);
+ return (ISC_R_NOMEMORY);
+ }
+ event->result = DNS_R_SERVFAIL;
+ event->qtype = fctx->type;
+ event->db = NULL;
+ event->node = NULL;
+ event->rdataset = rdataset;
+ event->sigrdataset = sigrdataset;
+ event->fetch = fetch;
+ event->client = client;
+ event->id = id;
+ dns_fixedname_init(&event->foundname);
+
+ /*
+ * Make sure that we can store the sigrdataset in the
+ * first event if it is needed by any of the events.
+ */
+ if (event->sigrdataset != NULL)
+ ISC_LIST_PREPEND(fctx->events, event, ev_link);
+ else
+ ISC_LIST_APPEND(fctx->events, event, ev_link);
+ fctx->references++;
+
+ fetch->magic = DNS_FETCH_MAGIC;
+ fetch->private = fctx;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
+ dns_name_t *domain, dns_rdataset_t *nameservers,
+ unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp)
+{
+ fetchctx_t *fctx;
+ isc_result_t result;
+ isc_result_t iresult;
+ isc_interval_t interval;
+ dns_fixedname_t fixed;
+ unsigned int findoptions = 0;
+ char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE];
+ char typebuf[DNS_RDATATYPE_FORMATSIZE];
+ dns_name_t suffix;
+
+ /*
+ * Caller must be holding the lock for bucket number 'bucketnum'.
+ */
+ REQUIRE(fctxp != NULL && *fctxp == NULL);
+
+ fctx = isc_mem_get(res->buckets[bucketnum].mctx, sizeof(*fctx));
+ if (fctx == NULL)
+ return (ISC_R_NOMEMORY);
+ dns_name_format(name, buf, sizeof(buf));
+ dns_rdatatype_format(type, typebuf, sizeof(typebuf));
+ strcat(buf, "/"); /* checked */
+ strcat(buf, typebuf); /* checked */
+ fctx->info = isc_mem_strdup(res->buckets[bucketnum].mctx, buf);
+ if (fctx->info == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_fetch;
+ }
+ FCTXTRACE("create");
+ dns_name_init(&fctx->name, NULL);
+ result = dns_name_dup(name, res->buckets[bucketnum].mctx, &fctx->name);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_info;
+ dns_name_init(&fctx->domain, NULL);
+ dns_rdataset_init(&fctx->nameservers);
+
+ fctx->type = type;
+ fctx->options = options;
+ /*
+ * Note! We do not attach to the task. We are relying on the
+ * resolver to ensure that this task doesn't go away while we are
+ * using it.
+ */
+ fctx->res = res;
+ fctx->references = 0;
+ fctx->bucketnum = bucketnum;
+ fctx->state = fetchstate_init;
+ fctx->want_shutdown = ISC_FALSE;
+ fctx->cloned = ISC_FALSE;
+ ISC_LIST_INIT(fctx->queries);
+ ISC_LIST_INIT(fctx->finds);
+ ISC_LIST_INIT(fctx->altfinds);
+ ISC_LIST_INIT(fctx->forwaddrs);
+ ISC_LIST_INIT(fctx->altaddrs);
+ ISC_LIST_INIT(fctx->forwarders);
+ fctx->fwdpolicy = dns_fwdpolicy_none;
+ ISC_LIST_INIT(fctx->bad);
+ ISC_LIST_INIT(fctx->edns);
+ ISC_LIST_INIT(fctx->edns512);
+ ISC_LIST_INIT(fctx->validators);
+ fctx->validator = NULL;
+ fctx->find = NULL;
+ fctx->altfind = NULL;
+ fctx->pending = 0;
+ fctx->restarts = 0;
+ fctx->timeouts = 0;
+ fctx->attributes = 0;
+ fctx->spilled = ISC_FALSE;
+ fctx->nqueries = 0;
+
+ dns_name_init(&fctx->nsname, NULL);
+ fctx->nsfetch = NULL;
+ dns_rdataset_init(&fctx->nsrrset);
+
+ if (domain == NULL) {
+ dns_forwarders_t *forwarders = NULL;
+ unsigned int labels;
+
+ /*
+ * DS records are found in the parent server.
+ * Strip label to get the correct forwarder (if any).
+ */
+ if (fctx->type == dns_rdatatype_ds &&
+ dns_name_countlabels(name) > 1) {
+ dns_name_init(&suffix, NULL);
+ labels = dns_name_countlabels(name);
+ dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
+ name = &suffix;
+ }
+ dns_fixedname_init(&fixed);
+ domain = dns_fixedname_name(&fixed);
+ result = dns_fwdtable_find2(fctx->res->view->fwdtable, name,
+ domain, &forwarders);
+ if (result == ISC_R_SUCCESS)
+ fctx->fwdpolicy = forwarders->fwdpolicy;
+
+ if (fctx->fwdpolicy != dns_fwdpolicy_only) {
+ /*
+ * The caller didn't supply a query domain and
+ * nameservers, and we're not in forward-only mode,
+ * so find the best nameservers to use.
+ */
+ if (dns_rdatatype_atparent(type))
+ findoptions |= DNS_DBFIND_NOEXACT;
+ result = dns_view_findzonecut(res->view, name, domain,
+ 0, findoptions, ISC_TRUE,
+ &fctx->nameservers,
+ NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_name;
+ result = dns_name_dup(domain,
+ res->buckets[bucketnum].mctx,
+ &fctx->domain);
+ if (result != ISC_R_SUCCESS) {
+ dns_rdataset_disassociate(&fctx->nameservers);
+ goto cleanup_name;
+ }
+ } else {
+ /*
+ * We're in forward-only mode. Set the query domain.
+ */
+ result = dns_name_dup(domain,
+ res->buckets[bucketnum].mctx,
+ &fctx->domain);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_name;
+ }
+ } else {
+ result = dns_name_dup(domain,
+ res->buckets[bucketnum].mctx,
+ &fctx->domain);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_name;
+ dns_rdataset_clone(nameservers, &fctx->nameservers);
+ }
+
+ INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain));
+
+ fctx->qmessage = NULL;
+ result = dns_message_create(res->buckets[bucketnum].mctx,
+ DNS_MESSAGE_INTENTRENDER,
+ &fctx->qmessage);
+
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_domain;
+
+ fctx->rmessage = NULL;
+ result = dns_message_create(res->buckets[bucketnum].mctx,
+ DNS_MESSAGE_INTENTPARSE,
+ &fctx->rmessage);
+
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_qmessage;
+
+ /*
+ * Compute an expiration time for the entire fetch.
+ */
+ isc_interval_set(&interval, 30, 0); /* XXXRTH constant */
+ iresult = isc_time_nowplusinterval(&fctx->expires, &interval);
+ if (iresult != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_time_nowplusinterval: %s",
+ isc_result_totext(iresult));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_rmessage;
+ }
+
+ /*
+ * Default retry interval initialization. We set the interval now
+ * mostly so it won't be uninitialized. It will be set to the
+ * correct value before a query is issued.
+ */
+ isc_interval_set(&fctx->interval, 2, 0);
+
+ /*
+ * Create an inactive timer. It will be made active when the fetch
+ * is actually started.
+ */
+ fctx->timer = NULL;
+ iresult = isc_timer_create(res->timermgr, isc_timertype_inactive,
+ NULL, NULL,
+ res->buckets[bucketnum].task, fctx_timeout,
+ fctx, &fctx->timer);
+ if (iresult != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_timer_create: %s",
+ isc_result_totext(iresult));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_rmessage;
+ }
+
+ /*
+ * Attach to the view's cache and adb.
+ */
+ fctx->cache = NULL;
+ dns_db_attach(res->view->cachedb, &fctx->cache);
+ fctx->adb = NULL;
+ dns_adb_attach(res->view->adb, &fctx->adb);
+
+ ISC_LIST_INIT(fctx->events);
+ ISC_LINK_INIT(fctx, link);
+ fctx->magic = FCTX_MAGIC;
+
+ ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link);
+
+ LOCK(&res->nlock);
+ res->nfctx++;
+ UNLOCK(&res->nlock);
+
+ *fctxp = fctx;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_rmessage:
+ dns_message_destroy(&fctx->rmessage);
+
+ cleanup_qmessage:
+ dns_message_destroy(&fctx->qmessage);
+
+ cleanup_domain:
+ if (dns_name_countlabels(&fctx->domain) > 0)
+ dns_name_free(&fctx->domain, res->buckets[bucketnum].mctx);
+ if (dns_rdataset_isassociated(&fctx->nameservers))
+ dns_rdataset_disassociate(&fctx->nameservers);
+
+ cleanup_name:
+ dns_name_free(&fctx->name, res->buckets[bucketnum].mctx);
+
+ cleanup_info:
+ isc_mem_free(res->buckets[bucketnum].mctx, fctx->info);
+
+ cleanup_fetch:
+ isc_mem_put(res->buckets[bucketnum].mctx, fctx, sizeof(*fctx));
+
+ return (result);
+}
+
+/*
+ * Handle Responses
+ */
+static inline isc_boolean_t
+is_lame(fetchctx_t *fctx) {
+ dns_message_t *message = fctx->rmessage;
+ dns_name_t *name;
+ dns_rdataset_t *rdataset;
+ isc_result_t result;
+
+ if (message->rcode != dns_rcode_noerror &&
+ message->rcode != dns_rcode_nxdomain)
+ return (ISC_FALSE);
+
+ if (message->counts[DNS_SECTION_ANSWER] != 0)
+ return (ISC_FALSE);
+
+ if (message->counts[DNS_SECTION_AUTHORITY] == 0)
+ return (ISC_FALSE);
+
+ result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+ while (result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ dns_namereln_t namereln;
+ int order;
+ unsigned int labels;
+ if (rdataset->type != dns_rdatatype_ns)
+ continue;
+ namereln = dns_name_fullcompare(name, &fctx->domain,
+ &order, &labels);
+ if (namereln == dns_namereln_equal &&
+ (message->flags & DNS_MESSAGEFLAG_AA) != 0)
+ return (ISC_FALSE);
+ if (namereln == dns_namereln_subdomain)
+ return (ISC_FALSE);
+ return (ISC_TRUE);
+ }
+ result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
+ }
+
+ return (ISC_FALSE);
+}
+
+static inline void
+log_lame(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char domainbuf[DNS_NAME_FORMATSIZE];
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+
+ dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
+ dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
+ isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf));
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
+ "lame server resolving '%s' (in '%s'?): %s",
+ namebuf, domainbuf, addrbuf);
+}
+
+static inline isc_result_t
+same_question(fetchctx_t *fctx) {
+ isc_result_t result;
+ dns_message_t *message = fctx->rmessage;
+ dns_name_t *name;
+ dns_rdataset_t *rdataset;
+
+ /*
+ * Caller must be holding the fctx lock.
+ */
+
+ /*
+ * XXXRTH Currently we support only one question.
+ */
+ if (message->counts[DNS_SECTION_QUESTION] != 1)
+ return (DNS_R_FORMERR);
+
+ result = dns_message_firstname(message, DNS_SECTION_QUESTION);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_QUESTION, &name);
+ rdataset = ISC_LIST_HEAD(name->list);
+ INSIST(rdataset != NULL);
+ INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
+ if (fctx->type != rdataset->type ||
+ fctx->res->rdclass != rdataset->rdclass ||
+ !dns_name_equal(&fctx->name, name))
+ return (DNS_R_FORMERR);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+clone_results(fetchctx_t *fctx) {
+ dns_fetchevent_t *event, *hevent;
+ isc_result_t result;
+ dns_name_t *name, *hname;
+
+ FCTXTRACE("clone_results");
+
+ /*
+ * Set up any other events to have the same data as the first
+ * event.
+ *
+ * Caller must be holding the appropriate lock.
+ */
+
+ fctx->cloned = ISC_TRUE;
+ hevent = ISC_LIST_HEAD(fctx->events);
+ if (hevent == NULL)
+ return;
+ hname = dns_fixedname_name(&hevent->foundname);
+ for (event = ISC_LIST_NEXT(hevent, ev_link);
+ event != NULL;
+ event = ISC_LIST_NEXT(event, ev_link)) {
+ name = dns_fixedname_name(&event->foundname);
+ result = dns_name_copy(hname, name, NULL);
+ if (result != ISC_R_SUCCESS)
+ event->result = result;
+ else
+ event->result = hevent->result;
+ dns_db_attach(hevent->db, &event->db);
+ dns_db_attachnode(hevent->db, hevent->node, &event->node);
+ INSIST(hevent->rdataset != NULL);
+ INSIST(event->rdataset != NULL);
+ if (dns_rdataset_isassociated(hevent->rdataset))
+ dns_rdataset_clone(hevent->rdataset, event->rdataset);
+ INSIST(! (hevent->sigrdataset == NULL &&
+ event->sigrdataset != NULL));
+ if (hevent->sigrdataset != NULL &&
+ dns_rdataset_isassociated(hevent->sigrdataset) &&
+ event->sigrdataset != NULL)
+ dns_rdataset_clone(hevent->sigrdataset,
+ event->sigrdataset);
+ }
+}
+
+#define CACHE(r) (((r)->attributes & DNS_RDATASETATTR_CACHE) != 0)
+#define ANSWER(r) (((r)->attributes & DNS_RDATASETATTR_ANSWER) != 0)
+#define ANSWERSIG(r) (((r)->attributes & DNS_RDATASETATTR_ANSWERSIG) != 0)
+#define EXTERNAL(r) (((r)->attributes & DNS_RDATASETATTR_EXTERNAL) != 0)
+#define CHAINING(r) (((r)->attributes & DNS_RDATASETATTR_CHAINING) != 0)
+#define CHASE(r) (((r)->attributes & DNS_RDATASETATTR_CHASE) != 0)
+#define CHECKNAMES(r) (((r)->attributes & DNS_RDATASETATTR_CHECKNAMES) != 0)
+
+
+/*
+ * Destroy '*fctx' if it is ready to be destroyed (i.e., if it has
+ * no references and is no longer waiting for any events). If this
+ * was the last fctx in the resolver, destroy the resolver.
+ *
+ * Requires:
+ * '*fctx' is shutting down.
+ */
+static void
+maybe_destroy(fetchctx_t *fctx) {
+ unsigned int bucketnum;
+ isc_boolean_t bucket_empty = ISC_FALSE;
+ dns_resolver_t *res = fctx->res;
+ dns_validator_t *validator, *next_validator;
+
+ REQUIRE(SHUTTINGDOWN(fctx));
+
+ if (fctx->pending != 0 || fctx->nqueries != 0)
+ return;
+
+ for (validator = ISC_LIST_HEAD(fctx->validators);
+ validator != NULL; validator = next_validator) {
+ next_validator = ISC_LIST_NEXT(validator, link);
+ dns_validator_cancel(validator);
+ /*
+ * If this is a active validator wait for the cancel
+ * to complete before calling dns_validator_destroy().
+ */
+ if (validator == fctx->validator)
+ continue;
+ ISC_LIST_UNLINK(fctx->validators, validator, link);
+ dns_validator_destroy(&validator);
+ }
+
+ bucketnum = fctx->bucketnum;
+ LOCK(&res->buckets[bucketnum].lock);
+ if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators))
+ bucket_empty = fctx_destroy(fctx);
+ UNLOCK(&res->buckets[bucketnum].lock);
+
+ if (bucket_empty)
+ empty_bucket(res);
+}
+
+/*
+ * The validator has finished.
+ */
+static void
+validated(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t eresult = ISC_R_SUCCESS;
+ isc_stdtime_t now;
+ fetchctx_t *fctx;
+ dns_validatorevent_t *vevent;
+ dns_fetchevent_t *hevent;
+ dns_rdataset_t *ardataset = NULL;
+ dns_rdataset_t *asigrdataset = NULL;
+ dns_dbnode_t *node = NULL;
+ isc_boolean_t negative;
+ isc_boolean_t chaining;
+ isc_boolean_t sentresponse;
+ isc_uint32_t ttl;
+ dns_dbnode_t *nsnode = NULL;
+ dns_name_t *name;
+ dns_rdataset_t *rdataset;
+ dns_rdataset_t *sigrdataset;
+ dns_valarg_t *valarg;
+ dns_adbaddrinfo_t *addrinfo;
+
+ UNUSED(task); /* for now */
+
+ REQUIRE(event->ev_type == DNS_EVENT_VALIDATORDONE);
+ valarg = event->ev_arg;
+ fctx = valarg->fctx;
+ addrinfo = valarg->addrinfo;
+ REQUIRE(VALID_FCTX(fctx));
+ REQUIRE(!ISC_LIST_EMPTY(fctx->validators));
+
+ vevent = (dns_validatorevent_t *)event;
+
+ FCTXTRACE("received validation completion event");
+
+ ISC_LIST_UNLINK(fctx->validators, vevent->validator, link);
+ fctx->validator = NULL;
+
+ /*
+ * Destroy the validator early so that we can
+ * destroy the fctx if necessary.
+ */
+ dns_validator_destroy(&vevent->validator);
+ isc_mem_put(fctx->res->buckets[fctx->bucketnum].mctx,
+ valarg, sizeof(*valarg));
+
+ negative = ISC_TF(vevent->rdataset == NULL);
+
+ sentresponse = ISC_TF((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0);
+
+ /*
+ * If shutting down, ignore the results. Check to see if we're
+ * done waiting for validator completions and ADB pending events; if
+ * so, destroy the fctx.
+ */
+ if (SHUTTINGDOWN(fctx) && !sentresponse) {
+ maybe_destroy(fctx); /* Locks bucket. */
+ goto cleanup_event;
+ }
+
+ LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+
+ /*
+ * If chaining, we need to make sure that the right result code is
+ * returned, and that the rdatasets are bound.
+ */
+ if (vevent->result == ISC_R_SUCCESS &&
+ !negative &&
+ vevent->rdataset != NULL &&
+ CHAINING(vevent->rdataset))
+ {
+ if (vevent->rdataset->type == dns_rdatatype_cname)
+ eresult = DNS_R_CNAME;
+ else {
+ INSIST(vevent->rdataset->type == dns_rdatatype_dname);
+ eresult = DNS_R_DNAME;
+ }
+ chaining = ISC_TRUE;
+ } else
+ chaining = ISC_FALSE;
+
+ /*
+ * Either we're not shutting down, or we are shutting down but want
+ * to cache the result anyway (if this was a validation started by
+ * a query with cd set)
+ */
+
+ hevent = ISC_LIST_HEAD(fctx->events);
+ if (hevent != NULL) {
+ if (!negative && !chaining &&
+ (fctx->type == dns_rdatatype_any ||
+ fctx->type == dns_rdatatype_rrsig ||
+ fctx->type == dns_rdatatype_sig)) {
+ /*
+ * Don't bind rdatasets; the caller
+ * will iterate the node.
+ */
+ } else {
+ ardataset = hevent->rdataset;
+ asigrdataset = hevent->sigrdataset;
+ }
+ }
+
+ if (vevent->result != ISC_R_SUCCESS) {
+ FCTXTRACE("validation failed");
+ result = ISC_R_NOTFOUND;
+ if (vevent->rdataset != NULL)
+ result = dns_db_findnode(fctx->cache, vevent->name,
+ ISC_TRUE, &node);
+ if (result == ISC_R_SUCCESS)
+ (void)dns_db_deleterdataset(fctx->cache, node, NULL,
+ vevent->type, 0);
+ if (result == ISC_R_SUCCESS && vevent->sigrdataset != NULL)
+ (void)dns_db_deleterdataset(fctx->cache, node, NULL,
+ dns_rdatatype_rrsig,
+ vevent->type);
+ if (result == ISC_R_SUCCESS)
+ dns_db_detachnode(fctx->cache, &node);
+ result = vevent->result;
+ add_bad(fctx, addrinfo, result);
+ isc_event_free(&event);
+ UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ INSIST(fctx->validator == NULL);
+ fctx->validator = ISC_LIST_HEAD(fctx->validators);
+ if (fctx->validator != NULL) {
+ dns_validator_send(fctx->validator);
+ } else if (sentresponse)
+ fctx_done(fctx, result); /* Locks bucket. */
+ else
+ fctx_try(fctx); /* Locks bucket. */
+ return;
+ }
+
+ isc_stdtime_get(&now);
+
+ if (negative) {
+ dns_rdatatype_t covers;
+ FCTXTRACE("nonexistence validation OK");
+
+ if (fctx->rmessage->rcode == dns_rcode_nxdomain)
+ covers = dns_rdatatype_any;
+ else
+ covers = fctx->type;
+
+ result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE,
+ &node);
+ if (result != ISC_R_SUCCESS)
+ goto noanswer_response;
+
+ /*
+ * If we are asking for a SOA record set the cache time
+ * to zero to facilitate locating the containing zone of
+ * a arbitary zone.
+ */
+ ttl = fctx->res->view->maxncachettl;
+ if (fctx->type == dns_rdatatype_soa &&
+ covers == dns_rdatatype_any &&
+ fctx->res->zero_no_soa_ttl)
+ ttl = 0;
+
+ result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
+ covers, now, ttl,
+ ardataset, &eresult);
+ if (result != ISC_R_SUCCESS)
+ goto noanswer_response;
+ goto answer_response;
+ }
+
+ FCTXTRACE("validation OK");
+
+ if (vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF] != NULL) {
+
+ result = dns_rdataset_addnoqname(vevent->rdataset,
+ vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF]);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ INSIST(vevent->sigrdataset != NULL);
+ vevent->sigrdataset->ttl = vevent->rdataset->ttl;
+ }
+
+ /*
+ * The data was already cached as pending data.
+ * Re-cache it as secure and bind the cached
+ * rdatasets to the first event on the fetch
+ * event list.
+ */
+ result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto noanswer_response;
+
+ result = dns_db_addrdataset(fctx->cache, node, NULL, now,
+ vevent->rdataset, 0, ardataset);
+ if (result != ISC_R_SUCCESS &&
+ result != DNS_R_UNCHANGED)
+ goto noanswer_response;
+ if (ardataset != NULL && ardataset->type == 0) {
+ if (NXDOMAIN(ardataset))
+ eresult = DNS_R_NCACHENXDOMAIN;
+ else
+ eresult = DNS_R_NCACHENXRRSET;
+ } else if (vevent->sigrdataset != NULL) {
+ result = dns_db_addrdataset(fctx->cache, node, NULL, now,
+ vevent->sigrdataset, 0,
+ asigrdataset);
+ if (result != ISC_R_SUCCESS &&
+ result != DNS_R_UNCHANGED)
+ goto noanswer_response;
+ }
+
+ if (sentresponse) {
+ /*
+ * If we only deferred the destroy because we wanted to cache
+ * the data, destroy now.
+ */
+ dns_db_detachnode(fctx->cache, &node);
+ UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ if (SHUTTINGDOWN(fctx))
+ maybe_destroy(fctx); /* Locks bucket. */
+ goto cleanup_event;
+ }
+
+ if (!ISC_LIST_EMPTY(fctx->validators)) {
+ INSIST(!negative);
+ INSIST(fctx->type == dns_rdatatype_any ||
+ fctx->type == dns_rdatatype_rrsig ||
+ fctx->type == dns_rdatatype_sig);
+ /*
+ * Don't send a response yet - we have
+ * more rdatasets that still need to
+ * be validated.
+ */
+ dns_db_detachnode(fctx->cache, &node);
+ UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ dns_validator_send(ISC_LIST_HEAD(fctx->validators));
+ goto cleanup_event;
+ }
+
+ answer_response:
+ /*
+ * Cache any NS/NSEC records that happened to be validated.
+ */
+ result = dns_message_firstname(fctx->rmessage, DNS_SECTION_AUTHORITY);
+ while (result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(fctx->rmessage, DNS_SECTION_AUTHORITY,
+ &name);
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ if ((rdataset->type != dns_rdatatype_ns &&
+ rdataset->type != dns_rdatatype_nsec) ||
+ rdataset->trust != dns_trust_secure)
+ continue;
+ for (sigrdataset = ISC_LIST_HEAD(name->list);
+ sigrdataset != NULL;
+ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
+ if (sigrdataset->type != dns_rdatatype_rrsig ||
+ sigrdataset->covers != rdataset->type)
+ continue;
+ break;
+ }
+ if (sigrdataset == NULL ||
+ sigrdataset->trust != dns_trust_secure)
+ continue;
+ result = dns_db_findnode(fctx->cache, name, ISC_TRUE,
+ &nsnode);
+ if (result != ISC_R_SUCCESS)
+ continue;
+
+ result = dns_db_addrdataset(fctx->cache, nsnode, NULL,
+ now, rdataset, 0, NULL);
+ if (result == ISC_R_SUCCESS)
+ result = dns_db_addrdataset(fctx->cache, nsnode,
+ NULL, now,
+ sigrdataset, 0,
+ NULL);
+ dns_db_detachnode(fctx->cache, &nsnode);
+ }
+ result = dns_message_nextname(fctx->rmessage,
+ DNS_SECTION_AUTHORITY);
+ }
+
+ result = ISC_R_SUCCESS;
+
+ /*
+ * Respond with an answer, positive or negative,
+ * as opposed to an error. 'node' must be non-NULL.
+ */
+
+ fctx->attributes |= FCTX_ATTR_HAVEANSWER;
+
+ if (hevent != NULL) {
+ hevent->result = eresult;
+ RUNTIME_CHECK(dns_name_copy(vevent->name,
+ dns_fixedname_name(&hevent->foundname), NULL)
+ == ISC_R_SUCCESS);
+ dns_db_attach(fctx->cache, &hevent->db);
+ dns_db_transfernode(fctx->cache, &node, &hevent->node);
+ clone_results(fctx);
+ }
+
+ noanswer_response:
+ if (node != NULL)
+ dns_db_detachnode(fctx->cache, &node);
+
+ UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+
+ fctx_done(fctx, result); /* Locks bucket. */
+
+ cleanup_event:
+ INSIST(node == NULL);
+ isc_event_free(&event);
+}
+
+static inline isc_result_t
+cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
+ isc_stdtime_t now)
+{
+ dns_rdataset_t *rdataset, *sigrdataset;
+ dns_rdataset_t *addedrdataset, *ardataset, *asigrdataset;
+ dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL;
+ dns_dbnode_t *node, **anodep;
+ dns_db_t **adbp;
+ dns_name_t *aname;
+ dns_resolver_t *res;
+ isc_boolean_t need_validation, secure_domain, have_answer;
+ isc_result_t result, eresult;
+ dns_fetchevent_t *event;
+ unsigned int options;
+ isc_task_t *task;
+ isc_boolean_t fail;
+ unsigned int valoptions = 0;
+
+ /*
+ * The appropriate bucket lock must be held.
+ */
+
+ res = fctx->res;
+ need_validation = ISC_FALSE;
+ secure_domain = ISC_FALSE;
+ have_answer = ISC_FALSE;
+ eresult = ISC_R_SUCCESS;
+ task = res->buckets[fctx->bucketnum].task;
+
+ /*
+ * Is DNSSEC validation required for this name?
+ */
+ if (res->view->enablevalidation) {
+ result = dns_keytable_issecuredomain(res->view->secroots, name,
+ &secure_domain);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (!secure_domain && res->view->dlv != NULL) {
+ valoptions = DNS_VALIDATOR_DLV;
+ secure_domain = ISC_TRUE;
+ }
+ }
+
+ if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
+ need_validation = ISC_FALSE;
+ else
+ need_validation = secure_domain;
+
+ adbp = NULL;
+ aname = NULL;
+ anodep = NULL;
+ ardataset = NULL;
+ asigrdataset = NULL;
+ event = NULL;
+ if ((name->attributes & DNS_NAMEATTR_ANSWER) != 0 &&
+ !need_validation) {
+ have_answer = ISC_TRUE;
+ event = ISC_LIST_HEAD(fctx->events);
+ if (event != NULL) {
+ adbp = &event->db;
+ aname = dns_fixedname_name(&event->foundname);
+ result = dns_name_copy(name, aname, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ anodep = &event->node;
+ /*
+ * If this is an ANY, SIG or RRSIG query, we're not
+ * going to return any rdatasets, unless we encountered
+ * a CNAME or DNAME as "the answer". In this case,
+ * we're going to return DNS_R_CNAME or DNS_R_DNAME
+ * and we must set up the rdatasets.
+ */
+ if ((fctx->type != dns_rdatatype_any &&
+ fctx->type != dns_rdatatype_rrsig &&
+ fctx->type != dns_rdatatype_sig) ||
+ (name->attributes & DNS_NAMEATTR_CHAINING) != 0) {
+ ardataset = event->rdataset;
+ asigrdataset = event->sigrdataset;
+ }
+ }
+ }
+
+ /*
+ * Find or create the cache node.
+ */
+ node = NULL;
+ result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Cache or validate each cacheable rdataset.
+ */
+ fail = ISC_TF((fctx->res->options & DNS_RESOLVER_CHECKNAMESFAIL) != 0);
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ if (!CACHE(rdataset))
+ continue;
+ if (CHECKNAMES(rdataset)) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char typebuf[DNS_RDATATYPE_FORMATSIZE];
+ char classbuf[DNS_RDATATYPE_FORMATSIZE];
+
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ dns_rdatatype_format(rdataset->type, typebuf,
+ sizeof(typebuf));
+ dns_rdataclass_format(rdataset->rdclass, classbuf,
+ sizeof(classbuf));
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+ "check-names %s %s/%s/%s",
+ fail ? "failure" : "warning",
+ namebuf, typebuf, classbuf);
+ if (fail) {
+ if (ANSWER(rdataset)) {
+ dns_db_detachnode(fctx->cache, &node);
+ return (DNS_R_BADNAME);
+ }
+ continue;
+ }
+ }
+
+ /*
+ * Enforce the configure maximum cache TTL.
+ */
+ if (rdataset->ttl > res->view->maxcachettl)
+ rdataset->ttl = res->view->maxcachettl;
+
+ /*
+ * If this rrset is in a secure domain, do DNSSEC validation
+ * for it, unless it is glue.
+ */
+ if (secure_domain && rdataset->trust != dns_trust_glue) {
+ /*
+ * RRSIGs are validated as part of validating the
+ * type they cover.
+ */
+ if (rdataset->type == dns_rdatatype_rrsig)
+ continue;
+ /*
+ * Find the SIG for this rdataset, if we have it.
+ */
+ for (sigrdataset = ISC_LIST_HEAD(name->list);
+ sigrdataset != NULL;
+ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
+ if (sigrdataset->type == dns_rdatatype_rrsig &&
+ sigrdataset->covers == rdataset->type)
+ break;
+ }
+ if (sigrdataset == NULL) {
+ if (!ANSWER(rdataset) && need_validation) {
+ /*
+ * Ignore non-answer rdatasets that
+ * are missing signatures.
+ */
+ continue;
+ }
+ }
+
+ /*
+ * Normalize the rdataset and sigrdataset TTLs.
+ */
+ if (sigrdataset != NULL) {
+ rdataset->ttl = ISC_MIN(rdataset->ttl,
+ sigrdataset->ttl);
+ sigrdataset->ttl = rdataset->ttl;
+ }
+
+ /*
+ * Cache this rdataset/sigrdataset pair as
+ * pending data.
+ */
+ rdataset->trust = dns_trust_pending;
+ if (sigrdataset != NULL)
+ sigrdataset->trust = dns_trust_pending;
+ if (!need_validation)
+ addedrdataset = ardataset;
+ else
+ addedrdataset = NULL;
+ result = dns_db_addrdataset(fctx->cache, node, NULL,
+ now, rdataset, 0,
+ addedrdataset);
+ if (result == DNS_R_UNCHANGED) {
+ result = ISC_R_SUCCESS;
+ if (!need_validation &&
+ ardataset != NULL &&
+ ardataset->type == 0) {
+ /*
+ * The answer in the cache is better
+ * than the answer we found, and is
+ * a negative cache entry, so we
+ * must set eresult appropriately.
+ */
+ if (NXDOMAIN(ardataset))
+ eresult = DNS_R_NCACHENXDOMAIN;
+ else
+ eresult = DNS_R_NCACHENXRRSET;
+ /*
+ * We have a negative response from
+ * the cache so don't attempt to
+ * add the RRSIG rrset.
+ */
+ continue;
+ }
+ }
+ if (result != ISC_R_SUCCESS)
+ break;
+ if (sigrdataset != NULL) {
+ if (!need_validation)
+ addedrdataset = asigrdataset;
+ else
+ addedrdataset = NULL;
+ result = dns_db_addrdataset(fctx->cache,
+ node, NULL, now,
+ sigrdataset, 0,
+ addedrdataset);
+ if (result == DNS_R_UNCHANGED)
+ result = ISC_R_SUCCESS;
+ if (result != ISC_R_SUCCESS)
+ break;
+ } else if (!ANSWER(rdataset))
+ continue;
+
+ if (ANSWER(rdataset) && need_validation) {
+ if (fctx->type != dns_rdatatype_any &&
+ fctx->type != dns_rdatatype_rrsig &&
+ fctx->type != dns_rdatatype_sig) {
+ /*
+ * This is The Answer. We will
+ * validate it, but first we cache
+ * the rest of the response - it may
+ * contain useful keys.
+ */
+ INSIST(valrdataset == NULL &&
+ valsigrdataset == NULL);
+ valrdataset = rdataset;
+ valsigrdataset = sigrdataset;
+ } else {
+ /*
+ * This is one of (potentially)
+ * multiple answers to an ANY
+ * or SIG query. To keep things
+ * simple, we just start the
+ * validator right away rather
+ * than caching first and
+ * having to remember which
+ * rdatasets needed validation.
+ */
+ result = valcreate(fctx, addrinfo,
+ name, rdataset->type,
+ rdataset,
+ sigrdataset,
+ valoptions, task);
+ /*
+ * Defer any further validations.
+ * This prevents multiple validators
+ * from manipulating fctx->rmessage
+ * simultaniously.
+ */
+ valoptions |= DNS_VALIDATOR_DEFER;
+ }
+ } else if (CHAINING(rdataset)) {
+ if (rdataset->type == dns_rdatatype_cname)
+ eresult = DNS_R_CNAME;
+ else {
+ INSIST(rdataset->type ==
+ dns_rdatatype_dname);
+ eresult = DNS_R_DNAME;
+ }
+ }
+ } else if (!EXTERNAL(rdataset)) {
+ /*
+ * It's OK to cache this rdataset now.
+ */
+ if (ANSWER(rdataset))
+ addedrdataset = ardataset;
+ else if (ANSWERSIG(rdataset))
+ addedrdataset = asigrdataset;
+ else
+ addedrdataset = NULL;
+ if (CHAINING(rdataset)) {
+ if (rdataset->type == dns_rdatatype_cname)
+ eresult = DNS_R_CNAME;
+ else {
+ INSIST(rdataset->type ==
+ dns_rdatatype_dname);
+ eresult = DNS_R_DNAME;
+ }
+ }
+ if (rdataset->trust == dns_trust_glue &&
+ (rdataset->type == dns_rdatatype_ns ||
+ (rdataset->type == dns_rdatatype_rrsig &&
+ rdataset->covers == dns_rdatatype_ns))) {
+ /*
+ * If the trust level is 'dns_trust_glue'
+ * then we are adding data from a referral
+ * we got while executing the search algorithm.
+ * New referral data always takes precedence
+ * over the existing cache contents.
+ */
+ options = DNS_DBADD_FORCE;
+ } else
+ options = 0;
+ /*
+ * Now we can add the rdataset.
+ */
+ result = dns_db_addrdataset(fctx->cache,
+ node, NULL, now,
+ rdataset,
+ options,
+ addedrdataset);
+ if (result == DNS_R_UNCHANGED) {
+ if (ANSWER(rdataset) &&
+ ardataset != NULL &&
+ ardataset->type == 0) {
+ /*
+ * The answer in the cache is better
+ * than the answer we found, and is
+ * a negative cache entry, so we
+ * must set eresult appropriately.
+ */
+ if (NXDOMAIN(ardataset))
+ eresult = DNS_R_NCACHENXDOMAIN;
+ else
+ eresult = DNS_R_NCACHENXRRSET;
+ }
+ result = ISC_R_SUCCESS;
+ } else if (result != ISC_R_SUCCESS)
+ break;
+ }
+ }
+
+ if (valrdataset != NULL)
+ result = valcreate(fctx, addrinfo, name, fctx->type,
+ valrdataset, valsigrdataset, valoptions,
+ task);
+
+ if (result == ISC_R_SUCCESS && have_answer) {
+ fctx->attributes |= FCTX_ATTR_HAVEANSWER;
+ if (event != NULL) {
+ /*
+ * Negative results must be indicated in event->result.
+ */
+ if (dns_rdataset_isassociated(event->rdataset) &&
+ event->rdataset->type == dns_rdatatype_none) {
+ INSIST(eresult == DNS_R_NCACHENXDOMAIN ||
+ eresult == DNS_R_NCACHENXRRSET);
+ }
+ event->result = eresult;
+ dns_db_attach(fctx->cache, adbp);
+ dns_db_transfernode(fctx->cache, &node, anodep);
+ clone_results(fctx);
+ }
+ }
+
+ if (node != NULL)
+ dns_db_detachnode(fctx->cache, &node);
+
+ return (result);
+}
+
+static inline isc_result_t
+cache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now)
+{
+ isc_result_t result;
+ dns_section_t section;
+ dns_name_t *name;
+
+ FCTXTRACE("cache_message");
+
+ fctx->attributes &= ~FCTX_ATTR_WANTCACHE;
+
+ LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+
+ for (section = DNS_SECTION_ANSWER;
+ section <= DNS_SECTION_ADDITIONAL;
+ section++) {
+ result = dns_message_firstname(fctx->rmessage, section);
+ while (result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(fctx->rmessage, section,
+ &name);
+ if ((name->attributes & DNS_NAMEATTR_CACHE) != 0) {
+ result = cache_name(fctx, name, addrinfo, now);
+ if (result != ISC_R_SUCCESS)
+ break;
+ }
+ result = dns_message_nextname(fctx->rmessage, section);
+ }
+ if (result != ISC_R_NOMORE)
+ break;
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+
+ return (result);
+}
+
+/*
+ * Do what dns_ncache_add() does, and then compute an appropriate eresult.
+ */
+static isc_result_t
+ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
+ dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
+ dns_rdataset_t *ardataset,
+ isc_result_t *eresultp)
+{
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+
+ if (ardataset == NULL) {
+ dns_rdataset_init(&rdataset);
+ ardataset = &rdataset;
+ }
+ result = dns_ncache_add(message, cache, node, covers, now,
+ maxttl, ardataset);
+ if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) {
+ /*
+ * If the cache now contains a negative entry and we
+ * care about whether it is DNS_R_NCACHENXDOMAIN or
+ * DNS_R_NCACHENXRRSET then extract it.
+ */
+ if (ardataset->type == 0) {
+ /*
+ * The cache data is a negative cache entry.
+ */
+ if (NXDOMAIN(ardataset))
+ *eresultp = DNS_R_NCACHENXDOMAIN;
+ else
+ *eresultp = DNS_R_NCACHENXRRSET;
+ } else {
+ /*
+ * Either we don't care about the nature of the
+ * cache rdataset (because no fetch is interested
+ * in the outcome), or the cache rdataset is not
+ * a negative cache entry. Whichever case it is,
+ * we can return success.
+ *
+ * XXXRTH There's a CNAME/DNAME problem here.
+ */
+ *eresultp = ISC_R_SUCCESS;
+ }
+ result = ISC_R_SUCCESS;
+ }
+ if (ardataset == &rdataset && dns_rdataset_isassociated(ardataset))
+ dns_rdataset_disassociate(ardataset);
+
+ return (result);
+}
+
+static inline isc_result_t
+ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
+ dns_rdatatype_t covers, isc_stdtime_t now)
+{
+ isc_result_t result, eresult;
+ dns_name_t *name;
+ dns_resolver_t *res;
+ dns_db_t **adbp;
+ dns_dbnode_t *node, **anodep;
+ dns_rdataset_t *ardataset;
+ isc_boolean_t need_validation, secure_domain;
+ dns_name_t *aname;
+ dns_fetchevent_t *event;
+ isc_uint32_t ttl;
+ unsigned int valoptions = 0;
+
+ FCTXTRACE("ncache_message");
+
+ fctx->attributes &= ~FCTX_ATTR_WANTNCACHE;
+
+ res = fctx->res;
+ need_validation = ISC_FALSE;
+ secure_domain = ISC_FALSE;
+ eresult = ISC_R_SUCCESS;
+ name = &fctx->name;
+ node = NULL;
+
+ /*
+ * XXXMPA remove when we follow cnames and adjust the setting
+ * of FCTX_ATTR_WANTNCACHE in noanswer_response().
+ */
+ INSIST(fctx->rmessage->counts[DNS_SECTION_ANSWER] == 0);
+
+ /*
+ * Is DNSSEC validation required for this name?
+ */
+ if (fctx->res->view->enablevalidation) {
+ result = dns_keytable_issecuredomain(res->view->secroots, name,
+ &secure_domain);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (!secure_domain && res->view->dlv != NULL) {
+ valoptions = DNS_VALIDATOR_DLV;
+ secure_domain = ISC_TRUE;
+ }
+ }
+
+ if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
+ need_validation = ISC_FALSE;
+ else
+ need_validation = secure_domain;
+
+ if (secure_domain) {
+ /*
+ * Mark all rdatasets as pending.
+ */
+ dns_rdataset_t *trdataset;
+ dns_name_t *tname;
+
+ result = dns_message_firstname(fctx->rmessage,
+ DNS_SECTION_AUTHORITY);
+ while (result == ISC_R_SUCCESS) {
+ tname = NULL;
+ dns_message_currentname(fctx->rmessage,
+ DNS_SECTION_AUTHORITY,
+ &tname);
+ for (trdataset = ISC_LIST_HEAD(tname->list);
+ trdataset != NULL;
+ trdataset = ISC_LIST_NEXT(trdataset, link))
+ trdataset->trust = dns_trust_pending;
+ result = dns_message_nextname(fctx->rmessage,
+ DNS_SECTION_AUTHORITY);
+ }
+ if (result != ISC_R_NOMORE)
+ return (result);
+
+ }
+
+ if (need_validation) {
+ /*
+ * Do negative response validation.
+ */
+ result = valcreate(fctx, addrinfo, name, fctx->type,
+ NULL, NULL, valoptions,
+ res->buckets[fctx->bucketnum].task);
+ /*
+ * If validation is necessary, return now. Otherwise continue
+ * to process the message, letting the validation complete
+ * in its own good time.
+ */
+ return (result);
+ }
+
+ LOCK(&res->buckets[fctx->bucketnum].lock);
+
+ adbp = NULL;
+ aname = NULL;
+ anodep = NULL;
+ ardataset = NULL;
+ if (!HAVE_ANSWER(fctx)) {
+ event = ISC_LIST_HEAD(fctx->events);
+ if (event != NULL) {
+ adbp = &event->db;
+ aname = dns_fixedname_name(&event->foundname);
+ result = dns_name_copy(name, aname, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto unlock;
+ anodep = &event->node;
+ ardataset = event->rdataset;
+ }
+ } else
+ event = NULL;
+
+ result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto unlock;
+
+ /*
+ * If we are asking for a SOA record set the cache time
+ * to zero to facilitate locating the containing zone of
+ * a arbitary zone.
+ */
+ ttl = fctx->res->view->maxncachettl;
+ if (fctx->type == dns_rdatatype_soa &&
+ covers == dns_rdatatype_any)
+ ttl = 0;
+
+ result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
+ covers, now, ttl, ardataset, &eresult);
+ if (result != ISC_R_SUCCESS)
+ goto unlock;
+
+ if (!HAVE_ANSWER(fctx)) {
+ fctx->attributes |= FCTX_ATTR_HAVEANSWER;
+ if (event != NULL) {
+ event->result = eresult;
+ dns_db_attach(fctx->cache, adbp);
+ dns_db_transfernode(fctx->cache, &node, anodep);
+ clone_results(fctx);
+ }
+ }
+
+ unlock:
+ UNLOCK(&res->buckets[fctx->bucketnum].lock);
+
+ if (node != NULL)
+ dns_db_detachnode(fctx->cache, &node);
+
+ return (result);
+}
+
+static inline void
+mark_related(dns_name_t *name, dns_rdataset_t *rdataset,
+ isc_boolean_t external, isc_boolean_t gluing)
+{
+ name->attributes |= DNS_NAMEATTR_CACHE;
+ if (gluing) {
+ rdataset->trust = dns_trust_glue;
+ /*
+ * Glue with 0 TTL causes problems. We force the TTL to
+ * 1 second to prevent this.
+ */
+ if (rdataset->ttl == 0)
+ rdataset->ttl = 1;
+ } else
+ rdataset->trust = dns_trust_additional;
+ /*
+ * Avoid infinite loops by only marking new rdatasets.
+ */
+ if (!CACHE(rdataset)) {
+ name->attributes |= DNS_NAMEATTR_CHASE;
+ rdataset->attributes |= DNS_RDATASETATTR_CHASE;
+ }
+ rdataset->attributes |= DNS_RDATASETATTR_CACHE;
+ if (external)
+ rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL;
+}
+
+static isc_result_t
+check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) {
+ fetchctx_t *fctx = arg;
+ isc_result_t result;
+ dns_name_t *name;
+ dns_rdataset_t *rdataset;
+ isc_boolean_t external;
+ dns_rdatatype_t rtype;
+ isc_boolean_t gluing;
+
+ REQUIRE(VALID_FCTX(fctx));
+
+ if (GLUING(fctx))
+ gluing = ISC_TRUE;
+ else
+ gluing = ISC_FALSE;
+ name = NULL;
+ rdataset = NULL;
+ result = dns_message_findname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
+ addname, dns_rdatatype_any, 0, &name,
+ NULL);
+ if (result == ISC_R_SUCCESS) {
+ external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
+ if (type == dns_rdatatype_a) {
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ if (rdataset->type == dns_rdatatype_rrsig)
+ rtype = rdataset->covers;
+ else
+ rtype = rdataset->type;
+ if (rtype == dns_rdatatype_a ||
+ rtype == dns_rdatatype_aaaa)
+ mark_related(name, rdataset, external,
+ gluing);
+ }
+ } else {
+ result = dns_message_findtype(name, type, 0,
+ &rdataset);
+ if (result == ISC_R_SUCCESS) {
+ mark_related(name, rdataset, external, gluing);
+ /*
+ * Do we have its SIG too?
+ */
+ rdataset = NULL;
+ result = dns_message_findtype(name,
+ dns_rdatatype_rrsig,
+ type, &rdataset);
+ if (result == ISC_R_SUCCESS)
+ mark_related(name, rdataset, external,
+ gluing);
+ }
+ }
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+chase_additional(fetchctx_t *fctx) {
+ isc_boolean_t rescan;
+ dns_section_t section = DNS_SECTION_ADDITIONAL;
+ isc_result_t result;
+
+ again:
+ rescan = ISC_FALSE;
+
+ for (result = dns_message_firstname(fctx->rmessage, section);
+ result == ISC_R_SUCCESS;
+ result = dns_message_nextname(fctx->rmessage, section)) {
+ dns_name_t *name = NULL;
+ dns_rdataset_t *rdataset;
+ dns_message_currentname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
+ &name);
+ if ((name->attributes & DNS_NAMEATTR_CHASE) == 0)
+ continue;
+ name->attributes &= ~DNS_NAMEATTR_CHASE;
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ if (CHASE(rdataset)) {
+ rdataset->attributes &= ~DNS_RDATASETATTR_CHASE;
+ (void)dns_rdataset_additionaldata(rdataset,
+ check_related,
+ fctx);
+ rescan = ISC_TRUE;
+ }
+ }
+ }
+ if (rescan)
+ goto again;
+}
+
+static inline isc_result_t
+cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) {
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_cname_t cname;
+
+ result = dns_rdataset_first(rdataset);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &cname, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_name_init(tname, NULL);
+ dns_name_clone(&cname.cname, tname);
+ dns_rdata_freestruct(&cname);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname,
+ dns_fixedname_t *fixeddname)
+{
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned int nlabels;
+ int order;
+ dns_namereln_t namereln;
+ dns_rdata_dname_t dname;
+ dns_fixedname_t prefix;
+
+ /*
+ * Get the target name of the DNAME.
+ */
+
+ result = dns_rdataset_first(rdataset);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &dname, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Get the prefix of qname.
+ */
+ namereln = dns_name_fullcompare(qname, oname, &order, &nlabels);
+ if (namereln != dns_namereln_subdomain) {
+ dns_rdata_freestruct(&dname);
+ return (DNS_R_FORMERR);
+ }
+ dns_fixedname_init(&prefix);
+ dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL);
+ dns_fixedname_init(fixeddname);
+ result = dns_name_concatenate(dns_fixedname_name(&prefix),
+ &dname.dname,
+ dns_fixedname_name(fixeddname), NULL);
+ dns_rdata_freestruct(&dname);
+ return (result);
+}
+
+/*
+ * Handle a no-answer response (NXDOMAIN, NXRRSET, or referral).
+ * If bind8_ns_resp is ISC_TRUE, this is a suspected BIND 8
+ * response to an NS query that should be treated as a referral
+ * even though the NS records occur in the answer section
+ * rather than the authority section.
+ */
+static isc_result_t
+noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
+ isc_boolean_t bind8_ns_resp)
+{
+ isc_result_t result;
+ dns_message_t *message;
+ dns_name_t *name, *qname, *ns_name, *soa_name, *ds_name;
+ dns_rdataset_t *rdataset, *ns_rdataset;
+ isc_boolean_t aa, negative_response;
+ dns_rdatatype_t type;
+ dns_section_t section =
+ bind8_ns_resp ? DNS_SECTION_ANSWER : DNS_SECTION_AUTHORITY;
+
+ FCTXTRACE("noanswer_response");
+
+ message = fctx->rmessage;
+
+ /*
+ * Setup qname.
+ */
+ if (oqname == NULL) {
+ /*
+ * We have a normal, non-chained negative response or
+ * referral.
+ */
+ if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
+ aa = ISC_TRUE;
+ else
+ aa = ISC_FALSE;
+ qname = &fctx->name;
+ } else {
+ /*
+ * We're being invoked by answer_response() after it has
+ * followed a CNAME/DNAME chain.
+ */
+ qname = oqname;
+ aa = ISC_FALSE;
+ /*
+ * If the current qname is not a subdomain of the query
+ * domain, there's no point in looking at the authority
+ * section without doing DNSSEC validation.
+ *
+ * Until we do that validation, we'll just return success
+ * in this case.
+ */
+ if (!dns_name_issubdomain(qname, &fctx->domain))
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * We have to figure out if this is a negative response, or a
+ * referral.
+ */
+
+ /*
+ * Sometimes we can tell if its a negative response by looking at
+ * the message header.
+ */
+ negative_response = ISC_FALSE;
+ if (message->rcode == dns_rcode_nxdomain ||
+ (message->counts[DNS_SECTION_ANSWER] == 0 &&
+ message->counts[DNS_SECTION_AUTHORITY] == 0))
+ negative_response = ISC_TRUE;
+
+ /*
+ * Process the authority section.
+ */
+ ns_name = NULL;
+ ns_rdataset = NULL;
+ soa_name = NULL;
+ ds_name = NULL;
+ result = dns_message_firstname(message, section);
+ while (result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(message, section, &name);
+ if (dns_name_issubdomain(name, &fctx->domain)) {
+ /*
+ * Look for NS/SOA RRsets first.
+ */
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ type = rdataset->type;
+ if (type == dns_rdatatype_rrsig)
+ type = rdataset->covers;
+ if (((type == dns_rdatatype_ns ||
+ type == dns_rdatatype_soa) &&
+ !dns_name_issubdomain(qname, name)))
+ return (DNS_R_FORMERR);
+ if (type == dns_rdatatype_ns) {
+ /*
+ * NS or RRSIG NS.
+ *
+ * Only one set of NS RRs is allowed.
+ */
+ if (rdataset->type ==
+ dns_rdatatype_ns) {
+ if (ns_name != NULL &&
+ name != ns_name)
+ return (DNS_R_FORMERR);
+ ns_name = name;
+ ns_rdataset = rdataset;
+ }
+ name->attributes |=
+ DNS_NAMEATTR_CACHE;
+ rdataset->attributes |=
+ DNS_RDATASETATTR_CACHE;
+ rdataset->trust = dns_trust_glue;
+ }
+ if (type == dns_rdatatype_soa) {
+ /*
+ * SOA, or RRSIG SOA.
+ *
+ * Only one SOA is allowed.
+ */
+ if (rdataset->type ==
+ dns_rdatatype_soa) {
+ if (soa_name != NULL &&
+ name != soa_name)
+ return (DNS_R_FORMERR);
+ soa_name = name;
+ }
+ name->attributes |=
+ DNS_NAMEATTR_NCACHE;
+ rdataset->attributes |=
+ DNS_RDATASETATTR_NCACHE;
+ if (aa)
+ rdataset->trust =
+ dns_trust_authauthority;
+ else
+ rdataset->trust =
+ dns_trust_additional;
+ }
+ }
+ }
+ result = dns_message_nextname(message, section);
+ if (result == ISC_R_NOMORE)
+ break;
+ else if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ /*
+ * A negative response has a SOA record (Type 2)
+ * and a optional NS RRset (Type 1) or it has neither
+ * a SOA or a NS RRset (Type 3, handled above) or
+ * rcode is NXDOMAIN (handled above) in which case
+ * the NS RRset is allowed (Type 4).
+ */
+ if (soa_name != NULL)
+ negative_response = ISC_TRUE;
+
+ result = dns_message_firstname(message, section);
+ while (result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(message, section, &name);
+ if (dns_name_issubdomain(name, &fctx->domain)) {
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ type = rdataset->type;
+ if (type == dns_rdatatype_rrsig)
+ type = rdataset->covers;
+ if (type == dns_rdatatype_nsec) {
+ /*
+ * NSEC or RRSIG NSEC.
+ */
+ if (negative_response) {
+ name->attributes |=
+ DNS_NAMEATTR_NCACHE;
+ rdataset->attributes |=
+ DNS_RDATASETATTR_NCACHE;
+ } else {
+ name->attributes |=
+ DNS_NAMEATTR_CACHE;
+ rdataset->attributes |=
+ DNS_RDATASETATTR_CACHE;
+ }
+ if (aa)
+ rdataset->trust =
+ dns_trust_authauthority;
+ else
+ rdataset->trust =
+ dns_trust_additional;
+ /*
+ * No additional data needs to be
+ * marked.
+ */
+ } else if (type == dns_rdatatype_ds) {
+ /*
+ * DS or SIG DS.
+ *
+ * These should only be here if
+ * this is a referral, and there
+ * should only be one DS.
+ */
+ if (ns_name == NULL)
+ return (DNS_R_FORMERR);
+ if (rdataset->type ==
+ dns_rdatatype_ds) {
+ if (ds_name != NULL &&
+ name != ds_name)
+ return (DNS_R_FORMERR);
+ ds_name = name;
+ }
+ name->attributes |=
+ DNS_NAMEATTR_CACHE;
+ rdataset->attributes |=
+ DNS_RDATASETATTR_CACHE;
+ if (aa)
+ rdataset->trust =
+ dns_trust_authauthority;
+ else
+ rdataset->trust =
+ dns_trust_additional;
+ }
+ }
+ }
+ result = dns_message_nextname(message, section);
+ if (result == ISC_R_NOMORE)
+ break;
+ else if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ /*
+ * Trigger lookups for DNS nameservers.
+ */
+ if (negative_response && message->rcode == dns_rcode_noerror &&
+ fctx->type == dns_rdatatype_ds && soa_name != NULL &&
+ dns_name_equal(soa_name, qname) &&
+ !dns_name_equal(qname, dns_rootname))
+ return (DNS_R_CHASEDSSERVERS);
+
+ /*
+ * Did we find anything?
+ */
+ if (!negative_response && ns_name == NULL) {
+ /*
+ * Nope.
+ */
+ if (oqname != NULL) {
+ /*
+ * We've already got a partial CNAME/DNAME chain,
+ * and haven't found else anything useful here, but
+ * no error has occurred since we have an answer.
+ */
+ return (ISC_R_SUCCESS);
+ } else {
+ /*
+ * The responder is insane.
+ */
+ return (DNS_R_FORMERR);
+ }
+ }
+
+ /*
+ * If we found both NS and SOA, they should be the same name.
+ */
+ if (ns_name != NULL && soa_name != NULL && ns_name != soa_name)
+ return (DNS_R_FORMERR);
+
+ /*
+ * Do we have a referral? (We only want to follow a referral if
+ * we're not following a chain.)
+ */
+ if (!negative_response && ns_name != NULL && oqname == NULL) {
+ /*
+ * We already know ns_name is a subdomain of fctx->domain.
+ * If ns_name is equal to fctx->domain, we're not making
+ * progress. We return DNS_R_FORMERR so that we'll keep
+ * trying other servers.
+ */
+ if (dns_name_equal(ns_name, &fctx->domain))
+ return (DNS_R_FORMERR);
+
+ /*
+ * If the referral name is not a parent of the query
+ * name, consider the responder insane.
+ */
+ if (! dns_name_issubdomain(&fctx->name, ns_name)) {
+ FCTXTRACE("referral to non-parent");
+ return (DNS_R_FORMERR);
+ }
+
+ /*
+ * Mark any additional data related to this rdataset.
+ * It's important that we do this before we change the
+ * query domain.
+ */
+ INSIST(ns_rdataset != NULL);
+ fctx->attributes |= FCTX_ATTR_GLUING;
+ (void)dns_rdataset_additionaldata(ns_rdataset, check_related,
+ fctx);
+ fctx->attributes &= ~FCTX_ATTR_GLUING;
+ /*
+ * NS rdatasets with 0 TTL cause problems.
+ * dns_view_findzonecut() will not find them when we
+ * try to follow the referral, and we'll SERVFAIL
+ * because the best nameservers are now above QDOMAIN.
+ * We force the TTL to 1 second to prevent this.
+ */
+ if (ns_rdataset->ttl == 0)
+ ns_rdataset->ttl = 1;
+ /*
+ * Set the current query domain to the referral name.
+ *
+ * XXXRTH We should check if we're in forward-only mode, and
+ * if so we should bail out.
+ */
+ INSIST(dns_name_countlabels(&fctx->domain) > 0);
+ dns_name_free(&fctx->domain,
+ fctx->res->buckets[fctx->bucketnum].mctx);
+ if (dns_rdataset_isassociated(&fctx->nameservers))
+ dns_rdataset_disassociate(&fctx->nameservers);
+ dns_name_init(&fctx->domain, NULL);
+ result = dns_name_dup(ns_name,
+ fctx->res->buckets[fctx->bucketnum].mctx,
+ &fctx->domain);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ fctx->attributes |= FCTX_ATTR_WANTCACHE;
+ return (DNS_R_DELEGATION);
+ }
+
+ /*
+ * Since we're not doing a referral, we don't want to cache any
+ * NS RRs we may have found.
+ */
+ if (ns_name != NULL)
+ ns_name->attributes &= ~DNS_NAMEATTR_CACHE;
+
+ if (negative_response && oqname == NULL)
+ fctx->attributes |= FCTX_ATTR_WANTNCACHE;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+answer_response(fetchctx_t *fctx) {
+ isc_result_t result;
+ dns_message_t *message;
+ dns_name_t *name, *qname, tname;
+ dns_rdataset_t *rdataset;
+ isc_boolean_t done, external, chaining, aa, found, want_chaining;
+ isc_boolean_t have_answer, found_cname, found_type, wanted_chaining;
+ unsigned int aflag;
+ dns_rdatatype_t type;
+ dns_fixedname_t dname, fqname;
+
+ FCTXTRACE("answer_response");
+
+ message = fctx->rmessage;
+
+ /*
+ * Examine the answer section, marking those rdatasets which are
+ * part of the answer and should be cached.
+ */
+
+ done = ISC_FALSE;
+ found_cname = ISC_FALSE;
+ found_type = ISC_FALSE;
+ chaining = ISC_FALSE;
+ have_answer = ISC_FALSE;
+ want_chaining = ISC_FALSE;
+ if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
+ aa = ISC_TRUE;
+ else
+ aa = ISC_FALSE;
+ qname = &fctx->name;
+ type = fctx->type;
+ result = dns_message_firstname(message, DNS_SECTION_ANSWER);
+ while (!done && result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_ANSWER, &name);
+ external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
+ if (dns_name_equal(name, qname)) {
+ wanted_chaining = ISC_FALSE;
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ found = ISC_FALSE;
+ want_chaining = ISC_FALSE;
+ aflag = 0;
+ if (rdataset->type == type && !found_cname) {
+ /*
+ * We've found an ordinary answer.
+ */
+ found = ISC_TRUE;
+ found_type = ISC_TRUE;
+ done = ISC_TRUE;
+ aflag = DNS_RDATASETATTR_ANSWER;
+ } else if (type == dns_rdatatype_any) {
+ /*
+ * We've found an answer matching
+ * an ANY query. There may be
+ * more.
+ */
+ found = ISC_TRUE;
+ aflag = DNS_RDATASETATTR_ANSWER;
+ } else if (rdataset->type == dns_rdatatype_rrsig
+ && rdataset->covers == type
+ && !found_cname) {
+ /*
+ * We've found a signature that
+ * covers the type we're looking for.
+ */
+ found = ISC_TRUE;
+ found_type = ISC_TRUE;
+ aflag = DNS_RDATASETATTR_ANSWERSIG;
+ } else if (rdataset->type ==
+ dns_rdatatype_cname
+ && !found_type) {
+ /*
+ * We're looking for something else,
+ * but we found a CNAME.
+ *
+ * Getting a CNAME response for some
+ * query types is an error.
+ */
+ if (type == dns_rdatatype_rrsig ||
+ type == dns_rdatatype_dnskey ||
+ type == dns_rdatatype_nsec)
+ return (DNS_R_FORMERR);
+ found = ISC_TRUE;
+ found_cname = ISC_TRUE;
+ want_chaining = ISC_TRUE;
+ aflag = DNS_RDATASETATTR_ANSWER;
+ result = cname_target(rdataset,
+ &tname);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else if (rdataset->type == dns_rdatatype_rrsig
+ && rdataset->covers ==
+ dns_rdatatype_cname
+ && !found_type) {
+ /*
+ * We're looking for something else,
+ * but we found a SIG CNAME.
+ */
+ found = ISC_TRUE;
+ found_cname = ISC_TRUE;
+ aflag = DNS_RDATASETATTR_ANSWERSIG;
+ }
+
+ if (found) {
+ /*
+ * We've found an answer to our
+ * question.
+ */
+ name->attributes |=
+ DNS_NAMEATTR_CACHE;
+ rdataset->attributes |=
+ DNS_RDATASETATTR_CACHE;
+ rdataset->trust = dns_trust_answer;
+ if (!chaining) {
+ /*
+ * This data is "the" answer
+ * to our question only if
+ * we're not chaining (i.e.
+ * if we haven't followed
+ * a CNAME or DNAME).
+ */
+ INSIST(!external);
+ if (aflag ==
+ DNS_RDATASETATTR_ANSWER)
+ have_answer = ISC_TRUE;
+ name->attributes |=
+ DNS_NAMEATTR_ANSWER;
+ rdataset->attributes |= aflag;
+ if (aa)
+ rdataset->trust =
+ dns_trust_authanswer;
+ } else if (external) {
+ /*
+ * This data is outside of
+ * our query domain, and
+ * may only be cached if it
+ * comes from a secure zone
+ * and validates.
+ */
+ rdataset->attributes |=
+ DNS_RDATASETATTR_EXTERNAL;
+ }
+
+ /*
+ * Mark any additional data related
+ * to this rdataset.
+ */
+ (void)dns_rdataset_additionaldata(
+ rdataset,
+ check_related,
+ fctx);
+
+ /*
+ * CNAME chaining.
+ */
+ if (want_chaining) {
+ wanted_chaining = ISC_TRUE;
+ name->attributes |=
+ DNS_NAMEATTR_CHAINING;
+ rdataset->attributes |=
+ DNS_RDATASETATTR_CHAINING;
+ qname = &tname;
+ }
+ }
+ /*
+ * We could add an "else" clause here and
+ * log that we're ignoring this rdataset.
+ */
+ }
+ /*
+ * If wanted_chaining is true, we've done
+ * some chaining as the result of processing
+ * this node, and thus we need to set
+ * chaining to true.
+ *
+ * We don't set chaining inside of the
+ * rdataset loop because doing that would
+ * cause us to ignore the signatures of
+ * CNAMEs.
+ */
+ if (wanted_chaining)
+ chaining = ISC_TRUE;
+ } else {
+ /*
+ * Look for a DNAME (or its SIG). Anything else is
+ * ignored.
+ */
+ wanted_chaining = ISC_FALSE;
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ isc_boolean_t found_dname = ISC_FALSE;
+ found = ISC_FALSE;
+ aflag = 0;
+ if (rdataset->type == dns_rdatatype_dname) {
+ /*
+ * We're looking for something else,
+ * but we found a DNAME.
+ *
+ * If we're not chaining, then the
+ * DNAME should not be external.
+ */
+ if (!chaining && external)
+ return (DNS_R_FORMERR);
+ found = ISC_TRUE;
+ want_chaining = ISC_TRUE;
+ aflag = DNS_RDATASETATTR_ANSWER;
+ result = dname_target(rdataset,
+ qname, name,
+ &dname);
+ if (result == ISC_R_NOSPACE) {
+ /*
+ * We can't construct the
+ * DNAME target. Do not
+ * try to continue.
+ */
+ want_chaining = ISC_FALSE;
+ } else if (result != ISC_R_SUCCESS)
+ return (result);
+ else
+ found_dname = ISC_TRUE;
+ } else if (rdataset->type == dns_rdatatype_rrsig
+ && rdataset->covers ==
+ dns_rdatatype_dname) {
+ /*
+ * We've found a signature that
+ * covers the DNAME.
+ */
+ found = ISC_TRUE;
+ aflag = DNS_RDATASETATTR_ANSWERSIG;
+ }
+
+ if (found) {
+ /*
+ * We've found an answer to our
+ * question.
+ */
+ name->attributes |=
+ DNS_NAMEATTR_CACHE;
+ rdataset->attributes |=
+ DNS_RDATASETATTR_CACHE;
+ rdataset->trust = dns_trust_answer;
+ if (!chaining) {
+ /*
+ * This data is "the" answer
+ * to our question only if
+ * we're not chaining.
+ */
+ INSIST(!external);
+ if (aflag ==
+ DNS_RDATASETATTR_ANSWER)
+ have_answer = ISC_TRUE;
+ name->attributes |=
+ DNS_NAMEATTR_ANSWER;
+ rdataset->attributes |= aflag;
+ if (aa)
+ rdataset->trust =
+ dns_trust_authanswer;
+ } else if (external) {
+ rdataset->attributes |=
+ DNS_RDATASETATTR_EXTERNAL;
+ }
+
+ /*
+ * DNAME chaining.
+ */
+ if (found_dname) {
+ /*
+ * Copy the the dname into the
+ * qname fixed name.
+ *
+ * Although we check for
+ * failure of the copy
+ * operation, in practice it
+ * should never fail since
+ * we already know that the
+ * result fits in a fixedname.
+ */
+ dns_fixedname_init(&fqname);
+ result = dns_name_copy(
+ dns_fixedname_name(&dname),
+ dns_fixedname_name(&fqname),
+ NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ wanted_chaining = ISC_TRUE;
+ name->attributes |=
+ DNS_NAMEATTR_CHAINING;
+ rdataset->attributes |=
+ DNS_RDATASETATTR_CHAINING;
+ qname = dns_fixedname_name(
+ &fqname);
+ }
+ }
+ }
+ if (wanted_chaining)
+ chaining = ISC_TRUE;
+ }
+ result = dns_message_nextname(message, DNS_SECTION_ANSWER);
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * We should have found an answer.
+ */
+ if (!have_answer)
+ return (DNS_R_FORMERR);
+
+ /*
+ * This response is now potentially cacheable.
+ */
+ fctx->attributes |= FCTX_ATTR_WANTCACHE;
+
+ /*
+ * Did chaining end before we got the final answer?
+ */
+ if (chaining) {
+ /*
+ * Yes. This may be a negative reply, so hand off
+ * authority section processing to the noanswer code.
+ * If it isn't a noanswer response, no harm will be
+ * done.
+ */
+ return (noanswer_response(fctx, qname, ISC_FALSE));
+ }
+
+ /*
+ * We didn't end with an incomplete chain, so the rcode should be
+ * "no error".
+ */
+ if (message->rcode != dns_rcode_noerror)
+ return (DNS_R_FORMERR);
+
+ /*
+ * Examine the authority section (if there is one).
+ *
+ * We expect there to be only one owner name for all the rdatasets
+ * in this section, and we expect that it is not external.
+ */
+ done = ISC_FALSE;
+ result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+ while (!done && result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+ external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
+ if (!external) {
+ /*
+ * We expect to find NS or SIG NS rdatasets, and
+ * nothing else.
+ */
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ if (rdataset->type == dns_rdatatype_ns ||
+ (rdataset->type == dns_rdatatype_rrsig &&
+ rdataset->covers == dns_rdatatype_ns)) {
+ name->attributes |=
+ DNS_NAMEATTR_CACHE;
+ rdataset->attributes |=
+ DNS_RDATASETATTR_CACHE;
+ if (aa && !chaining)
+ rdataset->trust =
+ dns_trust_authauthority;
+ else
+ rdataset->trust =
+ dns_trust_additional;
+
+ /*
+ * Mark any additional data related
+ * to this rdataset.
+ */
+ (void)dns_rdataset_additionaldata(
+ rdataset,
+ check_related,
+ fctx);
+ done = ISC_TRUE;
+ }
+ }
+ }
+ result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ return (result);
+}
+
+static void
+resume_dslookup(isc_task_t *task, isc_event_t *event) {
+ dns_fetchevent_t *fevent;
+ dns_resolver_t *res;
+ fetchctx_t *fctx;
+ isc_result_t result;
+ isc_boolean_t bucket_empty = ISC_FALSE;
+ isc_boolean_t locked = ISC_FALSE;
+ unsigned int bucketnum;
+ dns_rdataset_t nameservers;
+ dns_fixedname_t fixed;
+ dns_name_t *domain;
+
+ REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
+ fevent = (dns_fetchevent_t *)event;
+ fctx = event->ev_arg;
+ REQUIRE(VALID_FCTX(fctx));
+ res = fctx->res;
+
+ UNUSED(task);
+ FCTXTRACE("resume_dslookup");
+
+ if (fevent->node != NULL)
+ dns_db_detachnode(fevent->db, &fevent->node);
+ if (fevent->db != NULL)
+ dns_db_detach(&fevent->db);
+
+ dns_rdataset_init(&nameservers);
+
+ bucketnum = fctx->bucketnum;
+ if (fevent->result == ISC_R_CANCELED) {
+ dns_resolver_destroyfetch(&fctx->nsfetch);
+ fctx_done(fctx, ISC_R_CANCELED);
+ } else if (fevent->result == ISC_R_SUCCESS) {
+
+ FCTXTRACE("resuming DS lookup");
+
+ dns_resolver_destroyfetch(&fctx->nsfetch);
+ if (dns_rdataset_isassociated(&fctx->nameservers))
+ dns_rdataset_disassociate(&fctx->nameservers);
+ dns_rdataset_clone(fevent->rdataset, &fctx->nameservers);
+ dns_name_free(&fctx->domain,
+ fctx->res->buckets[bucketnum].mctx);
+ dns_name_init(&fctx->domain, NULL);
+ result = dns_name_dup(&fctx->nsname,
+ fctx->res->buckets[bucketnum].mctx,
+ &fctx->domain);
+ if (result != ISC_R_SUCCESS) {
+ fctx_done(fctx, DNS_R_SERVFAIL);
+ goto cleanup;
+ }
+ /*
+ * Try again.
+ */
+ fctx_try(fctx);
+ } else {
+ unsigned int n;
+ dns_rdataset_t *nsrdataset = NULL;
+
+ /*
+ * Retrieve state from fctx->nsfetch before we destroy it.
+ */
+ dns_fixedname_init(&fixed);
+ domain = dns_fixedname_name(&fixed);
+ dns_name_copy(&fctx->nsfetch->private->domain, domain, NULL);
+ if (dns_name_equal(&fctx->nsname, domain)) {
+ fctx_done(fctx, DNS_R_SERVFAIL);
+ dns_resolver_destroyfetch(&fctx->nsfetch);
+ goto cleanup;
+ }
+ if (dns_rdataset_isassociated(
+ &fctx->nsfetch->private->nameservers)) {
+ dns_rdataset_clone(
+ &fctx->nsfetch->private->nameservers,
+ &nameservers);
+ nsrdataset = &nameservers;
+ } else
+ domain = NULL;
+ dns_resolver_destroyfetch(&fctx->nsfetch);
+ n = dns_name_countlabels(&fctx->nsname);
+ dns_name_getlabelsequence(&fctx->nsname, 1, n - 1,
+ &fctx->nsname);
+
+ if (dns_rdataset_isassociated(fevent->rdataset))
+ dns_rdataset_disassociate(fevent->rdataset);
+ FCTXTRACE("continuing to look for parent's NS records");
+ result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
+ dns_rdatatype_ns, domain,
+ nsrdataset, NULL, 0, task,
+ resume_dslookup, fctx,
+ &fctx->nsrrset, NULL,
+ &fctx->nsfetch);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ else {
+ LOCK(&res->buckets[bucketnum].lock);
+ locked = ISC_TRUE;
+ fctx->references++;
+ }
+ }
+
+ cleanup:
+ if (dns_rdataset_isassociated(&nameservers))
+ dns_rdataset_disassociate(&nameservers);
+ if (dns_rdataset_isassociated(fevent->rdataset))
+ dns_rdataset_disassociate(fevent->rdataset);
+ INSIST(fevent->sigrdataset == NULL);
+ isc_event_free(&event);
+ if (!locked)
+ LOCK(&res->buckets[bucketnum].lock);
+ fctx->references--;
+ if (fctx->references == 0)
+ bucket_empty = fctx_destroy(fctx);
+ UNLOCK(&res->buckets[bucketnum].lock);
+ if (bucket_empty)
+ empty_bucket(res);
+}
+
+static inline void
+checknamessection(dns_message_t *message, dns_section_t section) {
+ isc_result_t result;
+ dns_name_t *name;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t *rdataset;
+
+ for (result = dns_message_firstname(message, section);
+ result == ISC_R_SUCCESS;
+ result = dns_message_nextname(message, section))
+ {
+ name = NULL;
+ dns_message_currentname(message, section, &name);
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ for (result = dns_rdataset_first(rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(rdataset)) {
+ dns_rdataset_current(rdataset, &rdata);
+ if (!dns_rdata_checkowner(name, rdata.rdclass,
+ rdata.type,
+ ISC_FALSE) ||
+ !dns_rdata_checknames(&rdata, name, NULL))
+ {
+ rdataset->attributes |=
+ DNS_RDATASETATTR_CHECKNAMES;
+ }
+ dns_rdata_reset(&rdata);
+ }
+ }
+ }
+}
+
+static void
+checknames(dns_message_t *message) {
+
+ checknamessection(message, DNS_SECTION_ANSWER);
+ checknamessection(message, DNS_SECTION_AUTHORITY);
+ checknamessection(message, DNS_SECTION_ADDITIONAL);
+}
+
+static void
+log_packet(dns_message_t *message, int level, isc_mem_t *mctx) {
+ isc_buffer_t buffer;
+ char *buf = NULL;
+ int len = 1024;
+ isc_result_t result;
+
+ if (! isc_log_wouldlog(dns_lctx, level))
+ return;
+
+ /*
+ * Note that these are multiline debug messages. We want a newline
+ * to appear in the log after each message.
+ */
+
+ do {
+ buf = isc_mem_get(mctx, len);
+ if (buf == NULL)
+ break;
+ isc_buffer_init(&buffer, buf, len);
+ result = dns_message_totext(message, &dns_master_style_debug,
+ 0, &buffer);
+ if (result == ISC_R_NOSPACE) {
+ isc_mem_put(mctx, buf, len);
+ len += 1024;
+ } else if (result == ISC_R_SUCCESS)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, level,
+ "received packet:\n%.*s",
+ (int)isc_buffer_usedlength(&buffer),
+ buf);
+ } while (result == ISC_R_NOSPACE);
+
+ if (buf != NULL)
+ isc_mem_put(mctx, buf, len);
+}
+
+static void
+resquery_response(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result = ISC_R_SUCCESS;
+ resquery_t *query = event->ev_arg;
+ dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
+ isc_boolean_t keep_trying, get_nameservers, resend;
+ isc_boolean_t truncated;
+ dns_message_t *message;
+ fetchctx_t *fctx;
+ dns_name_t *fname;
+ dns_fixedname_t foundname;
+ isc_stdtime_t now;
+ isc_time_t tnow, *finish;
+ dns_adbaddrinfo_t *addrinfo;
+ unsigned int options;
+ unsigned int findoptions;
+ isc_result_t broken_server;
+
+ REQUIRE(VALID_QUERY(query));
+ fctx = query->fctx;
+ options = query->options;
+ REQUIRE(VALID_FCTX(fctx));
+ REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
+
+ QTRACE("response");
+
+ (void)isc_timer_touch(fctx->timer);
+
+ keep_trying = ISC_FALSE;
+ broken_server = ISC_R_SUCCESS;
+ get_nameservers = ISC_FALSE;
+ resend = ISC_FALSE;
+ truncated = ISC_FALSE;
+ finish = NULL;
+
+ if (fctx->res->exiting) {
+ result = ISC_R_SHUTTINGDOWN;
+ goto done;
+ }
+
+ fctx->timeouts = 0;
+
+ /*
+ * XXXRTH We should really get the current time just once. We
+ * need a routine to convert from an isc_time_t to an
+ * isc_stdtime_t.
+ */
+ TIME_NOW(&tnow);
+ finish = &tnow;
+ isc_stdtime_get(&now);
+
+ /*
+ * Did the dispatcher have a problem?
+ */
+ if (devent->result != ISC_R_SUCCESS) {
+ if (devent->result == ISC_R_EOF &&
+ (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+ /*
+ * The problem might be that they
+ * don't understand EDNS0. Turn it
+ * off and try again.
+ */
+ options |= DNS_FETCHOPT_NOEDNS0;
+ resend = ISC_TRUE;
+ /*
+ * Remember that they don't like EDNS0.
+ */
+ dns_adb_changeflags(fctx->adb,
+ query->addrinfo,
+ DNS_FETCHOPT_NOEDNS0,
+ DNS_FETCHOPT_NOEDNS0);
+ } else {
+ /*
+ * There's no hope for this query.
+ */
+ keep_trying = ISC_TRUE;
+ }
+ goto done;
+ }
+
+ message = fctx->rmessage;
+
+ if (query->tsig != NULL) {
+ result = dns_message_setquerytsig(message, query->tsig);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ }
+
+ if (query->tsigkey) {
+ result = dns_message_settsigkey(message, query->tsigkey);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ }
+
+ result = dns_message_parse(message, &devent->buffer, 0);
+ if (result != ISC_R_SUCCESS) {
+ switch (result) {
+ case ISC_R_UNEXPECTEDEND:
+ if (!message->question_ok ||
+ (message->flags & DNS_MESSAGEFLAG_TC) == 0 ||
+ (options & DNS_FETCHOPT_TCP) != 0) {
+ /*
+ * Either the message ended prematurely,
+ * and/or wasn't marked as being truncated,
+ * and/or this is a response to a query we
+ * sent over TCP. In all of these cases,
+ * something is wrong with the remote
+ * server and we don't want to retry using
+ * TCP.
+ */
+ if ((query->options & DNS_FETCHOPT_NOEDNS0)
+ == 0) {
+ /*
+ * The problem might be that they
+ * don't understand EDNS0. Turn it
+ * off and try again.
+ */
+ options |= DNS_FETCHOPT_NOEDNS0;
+ resend = ISC_TRUE;
+ /*
+ * Remember that they don't like EDNS0.
+ */
+ dns_adb_changeflags(
+ fctx->adb,
+ query->addrinfo,
+ DNS_FETCHOPT_NOEDNS0,
+ DNS_FETCHOPT_NOEDNS0);
+ } else {
+ broken_server = result;
+ keep_trying = ISC_TRUE;
+ }
+ goto done;
+ }
+ /*
+ * We defer retrying via TCP for a bit so we can
+ * check out this message further.
+ */
+ truncated = ISC_TRUE;
+ break;
+ case DNS_R_FORMERR:
+ if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+ /*
+ * The problem might be that they
+ * don't understand EDNS0. Turn it
+ * off and try again.
+ */
+ options |= DNS_FETCHOPT_NOEDNS0;
+ resend = ISC_TRUE;
+ /*
+ * Remember that they don't like EDNS0.
+ */
+ dns_adb_changeflags(fctx->adb,
+ query->addrinfo,
+ DNS_FETCHOPT_NOEDNS0,
+ DNS_FETCHOPT_NOEDNS0);
+ } else {
+ broken_server = DNS_R_UNEXPECTEDRCODE;
+ keep_trying = ISC_TRUE;
+ }
+ goto done;
+ default:
+ /*
+ * Something bad has happened.
+ */
+ goto done;
+ }
+ }
+
+ /*
+ * Log the incoming packet.
+ */
+ log_packet(message, ISC_LOG_DEBUG(10), fctx->res->mctx);
+
+ /*
+ * If the message is signed, check the signature. If not, this
+ * returns success anyway.
+ */
+ result = dns_message_checksig(message, fctx->res->view);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+
+ /*
+ * The dispatcher should ensure we only get responses with QR set.
+ */
+ INSIST((message->flags & DNS_MESSAGEFLAG_QR) != 0);
+ /*
+ * INSIST() that the message comes from the place we sent it to,
+ * since the dispatch code should ensure this.
+ *
+ * INSIST() that the message id is correct (this should also be
+ * ensured by the dispatch code).
+ */
+
+
+ /*
+ * Deal with truncated responses by retrying using TCP.
+ */
+ if ((message->flags & DNS_MESSAGEFLAG_TC) != 0)
+ truncated = ISC_TRUE;
+
+ if (truncated) {
+ if ((options & DNS_FETCHOPT_TCP) != 0) {
+ broken_server = DNS_R_TRUNCATEDTCP;
+ keep_trying = ISC_TRUE;
+ } else {
+ options |= DNS_FETCHOPT_TCP;
+ resend = ISC_TRUE;
+ }
+ goto done;
+ }
+
+ /*
+ * Is it a query response?
+ */
+ if (message->opcode != dns_opcode_query) {
+ /* XXXRTH Log */
+ broken_server = DNS_R_UNEXPECTEDOPCODE;
+ keep_trying = ISC_TRUE;
+ goto done;
+ }
+
+ /*
+ * Is the remote server broken, or does it dislike us?
+ */
+ if (message->rcode != dns_rcode_noerror &&
+ message->rcode != dns_rcode_nxdomain) {
+ if ((message->rcode == dns_rcode_formerr ||
+ message->rcode == dns_rcode_notimp ||
+ message->rcode == dns_rcode_servfail) &&
+ (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+ /*
+ * It's very likely they don't like EDNS0.
+ *
+ * XXXRTH We should check if the question
+ * we're asking requires EDNS0, and
+ * if so, we should bail out.
+ */
+ options |= DNS_FETCHOPT_NOEDNS0;
+ resend = ISC_TRUE;
+ /*
+ * Remember that they don't like EDNS0.
+ */
+ if (message->rcode != dns_rcode_servfail)
+ dns_adb_changeflags(fctx->adb, query->addrinfo,
+ DNS_FETCHOPT_NOEDNS0,
+ DNS_FETCHOPT_NOEDNS0);
+ } else if (message->rcode == dns_rcode_formerr) {
+ if (ISFORWARDER(query->addrinfo)) {
+ /*
+ * This forwarder doesn't understand us,
+ * but other forwarders might. Keep trying.
+ */
+ broken_server = DNS_R_REMOTEFORMERR;
+ keep_trying = ISC_TRUE;
+ } else {
+ /*
+ * The server doesn't understand us. Since
+ * all servers for a zone need similar
+ * capabilities, we assume that we will get
+ * FORMERR from all servers, and thus we
+ * cannot make any more progress with this
+ * fetch.
+ */
+ result = DNS_R_FORMERR;
+ }
+ } else if (message->rcode == dns_rcode_yxdomain) {
+ /*
+ * DNAME mapping failed because the new name
+ * was too long. There's no chance of success
+ * for this fetch.
+ */
+ result = DNS_R_YXDOMAIN;
+ } else if (message->rcode == dns_rcode_badvers) {
+ dns_rdataset_t *opt;
+ unsigned int flags, mask;
+ unsigned int version;
+
+ resend = ISC_TRUE;
+ opt = dns_message_getopt(message);
+ version = (opt->ttl >> 16) & 0xff;
+ flags = (version << DNS_FETCHOPT_EDNSVERSIONSHIFT) |
+ DNS_FETCHOPT_EDNSVERSIONSET;
+ mask = DNS_FETCHOPT_EDNSVERSIONMASK |
+ DNS_FETCHOPT_EDNSVERSIONSET;
+ switch (version) {
+ case 0:
+ dns_adb_changeflags(fctx->adb, query->addrinfo,
+ flags, mask);
+ break;
+ default:
+ broken_server = DNS_R_BADVERS;
+ keep_trying = ISC_TRUE;
+ break;
+ }
+ } else {
+ /*
+ * XXXRTH log.
+ */
+ broken_server = DNS_R_UNEXPECTEDRCODE;
+ INSIST(broken_server != ISC_R_SUCCESS);
+ keep_trying = ISC_TRUE;
+ }
+ goto done;
+ }
+
+ /*
+ * Is the question the same as the one we asked?
+ */
+ result = same_question(fctx);
+ if (result != ISC_R_SUCCESS) {
+ /* XXXRTH Log */
+ if (result == DNS_R_FORMERR)
+ keep_trying = ISC_TRUE;
+ goto done;
+ }
+
+ /*
+ * Is the server lame?
+ */
+ if (fctx->res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) &&
+ is_lame(fctx)) {
+ log_lame(fctx, query->addrinfo);
+ result = dns_adb_marklame(fctx->adb, query->addrinfo,
+ &fctx->name, fctx->type,
+ now + fctx->res->lame_ttl);
+ if (result != ISC_R_SUCCESS)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR,
+ "could not mark server as lame: %s",
+ isc_result_totext(result));
+ broken_server = DNS_R_LAME;
+ keep_trying = ISC_TRUE;
+ goto done;
+ }
+
+ /*
+ * Enforce delegations only zones like NET and COM.
+ */
+ if (!ISFORWARDER(query->addrinfo) &&
+ dns_view_isdelegationonly(fctx->res->view, &fctx->domain) &&
+ !dns_name_equal(&fctx->domain, &fctx->name) &&
+ fix_mustbedelegationornxdomain(message, fctx)) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char domainbuf[DNS_NAME_FORMATSIZE];
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+ char classbuf[64];
+ char typebuf[64];
+
+ dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
+ dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
+ dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
+ dns_rdataclass_format(fctx->res->rdclass, classbuf,
+ sizeof(classbuf));
+ isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
+ sizeof(addrbuf));
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DELEGATION_ONLY,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+ "enforced delegation-only for '%s' (%s/%s/%s) "
+ "from %s",
+ domainbuf, namebuf, typebuf, classbuf, addrbuf);
+ }
+
+ if ((fctx->res->options & DNS_RESOLVER_CHECKNAMES) != 0)
+ checknames(message);
+
+ /*
+ * Clear cache bits.
+ */
+ fctx->attributes &= ~(FCTX_ATTR_WANTNCACHE | FCTX_ATTR_WANTCACHE);
+
+ /*
+ * Did we get any answers?
+ */
+ if (message->counts[DNS_SECTION_ANSWER] > 0 &&
+ (message->rcode == dns_rcode_noerror ||
+ message->rcode == dns_rcode_nxdomain)) {
+ /*
+ * We've got answers. However, if we sent
+ * a BIND 8 server an NS query, it may have
+ * incorrectly responded with a non-authoritative
+ * answer instead of a referral. Since this
+ * answer lacks the SIGs necessary to do DNSSEC
+ * validation, we must invoke the following special
+ * kludge to treat it as a referral.
+ */
+ if (fctx->type == dns_rdatatype_ns &&
+ (message->flags & DNS_MESSAGEFLAG_AA) == 0 &&
+ !ISFORWARDER(query->addrinfo))
+ {
+ result = noanswer_response(fctx, NULL, ISC_TRUE);
+ if (result != DNS_R_DELEGATION) {
+ /*
+ * The answer section must have contained
+ * something other than the NS records
+ * we asked for. Since AA is not set
+ * and the server is not a forwarder,
+ * it is technically lame and it's easier
+ * to treat it as such than to figure out
+ * some more elaborate course of action.
+ */
+ broken_server = DNS_R_LAME;
+ keep_trying = ISC_TRUE;
+ goto done;
+ }
+ goto force_referral;
+ }
+ result = answer_response(fctx);
+ if (result != ISC_R_SUCCESS) {
+ if (result == DNS_R_FORMERR)
+ keep_trying = ISC_TRUE;
+ goto done;
+ }
+ } else if (message->counts[DNS_SECTION_AUTHORITY] > 0 ||
+ message->rcode == dns_rcode_noerror ||
+ message->rcode == dns_rcode_nxdomain) {
+ /*
+ * NXDOMAIN, NXRDATASET, or referral.
+ */
+ result = noanswer_response(fctx, NULL, ISC_FALSE);
+ if (result == DNS_R_CHASEDSSERVERS) {
+ } else if (result == DNS_R_DELEGATION) {
+ force_referral:
+ /*
+ * We don't have the answer, but we know a better
+ * place to look.
+ */
+ get_nameservers = ISC_TRUE;
+ keep_trying = ISC_TRUE;
+ /*
+ * We have a new set of name servers, and it
+ * has not experienced any restarts yet.
+ */
+ fctx->restarts = 0;
+ result = ISC_R_SUCCESS;
+ } else if (result != ISC_R_SUCCESS) {
+ /*
+ * Something has gone wrong.
+ */
+ if (result == DNS_R_FORMERR)
+ keep_trying = ISC_TRUE;
+ goto done;
+ }
+ } else {
+ /*
+ * The server is insane.
+ */
+ /* XXXRTH Log */
+ broken_server = DNS_R_UNEXPECTEDRCODE;
+ keep_trying = ISC_TRUE;
+ goto done;
+ }
+
+ /*
+ * Follow additional section data chains.
+ */
+ chase_additional(fctx);
+
+ /*
+ * Cache the cacheable parts of the message. This may also cause
+ * work to be queued to the DNSSEC validator.
+ */
+ if (WANTCACHE(fctx)) {
+ result = cache_message(fctx, query->addrinfo, now);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ }
+
+ /*
+ * Ncache the negatively cacheable parts of the message. This may
+ * also cause work to be queued to the DNSSEC validator.
+ */
+ if (WANTNCACHE(fctx)) {
+ dns_rdatatype_t covers;
+ if (message->rcode == dns_rcode_nxdomain)
+ covers = dns_rdatatype_any;
+ else
+ covers = fctx->type;
+
+ /*
+ * Cache any negative cache entries in the message.
+ */
+ result = ncache_message(fctx, query->addrinfo, covers, now);
+ }
+
+ done:
+ /*
+ * Remember the query's addrinfo, in case we need to mark the
+ * server as broken.
+ */
+ addrinfo = query->addrinfo;
+
+ /*
+ * Cancel the query.
+ *
+ * XXXRTH Don't cancel the query if waiting for validation?
+ */
+ fctx_cancelquery(&query, &devent, finish, ISC_FALSE);
+
+ if (keep_trying) {
+ if (result == DNS_R_FORMERR)
+ broken_server = DNS_R_FORMERR;
+ if (broken_server != ISC_R_SUCCESS) {
+ /*
+ * Add this server to the list of bad servers for
+ * this fctx.
+ */
+ add_bad(fctx, addrinfo, broken_server);
+ }
+
+ if (get_nameservers) {
+ dns_name_t *name;
+ dns_fixedname_init(&foundname);
+ fname = dns_fixedname_name(&foundname);
+ if (result != ISC_R_SUCCESS) {
+ fctx_done(fctx, DNS_R_SERVFAIL);
+ return;
+ }
+ findoptions = 0;
+ if (dns_rdatatype_atparent(fctx->type))
+ findoptions |= DNS_DBFIND_NOEXACT;
+ if ((options & DNS_FETCHOPT_UNSHARED) == 0)
+ name = &fctx->name;
+ else
+ name = &fctx->domain;
+ result = dns_view_findzonecut(fctx->res->view,
+ name, fname,
+ now, findoptions,
+ ISC_TRUE,
+ &fctx->nameservers,
+ NULL);
+ if (result != ISC_R_SUCCESS) {
+ FCTXTRACE("couldn't find a zonecut");
+ fctx_done(fctx, DNS_R_SERVFAIL);
+ return;
+ }
+ if (!dns_name_issubdomain(fname, &fctx->domain)) {
+ /*
+ * The best nameservers are now above our
+ * QDOMAIN.
+ */
+ FCTXTRACE("nameservers now above QDOMAIN");
+ fctx_done(fctx, DNS_R_SERVFAIL);
+ return;
+ }
+ dns_name_free(&fctx->domain,
+ fctx->res->buckets[fctx->bucketnum].mctx);
+ dns_name_init(&fctx->domain, NULL);
+ result = dns_name_dup(fname,
+ fctx->res->buckets[fctx->bucketnum].mctx,
+ &fctx->domain);
+ if (result != ISC_R_SUCCESS) {
+ fctx_done(fctx, DNS_R_SERVFAIL);
+ return;
+ }
+ fctx_cancelqueries(fctx, ISC_TRUE);
+ fctx_cleanupfinds(fctx);
+ fctx_cleanupaltfinds(fctx);
+ fctx_cleanupforwaddrs(fctx);
+ fctx_cleanupaltaddrs(fctx);
+ }
+ /*
+ * Try again.
+ */
+ fctx_try(fctx);
+ } else if (resend) {
+ /*
+ * Resend (probably with changed options).
+ */
+ FCTXTRACE("resend");
+ result = fctx_query(fctx, addrinfo, options);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) {
+ /*
+ * All has gone well so far, but we are waiting for the
+ * DNSSEC validator to validate the answer.
+ */
+ FCTXTRACE("wait for validator");
+ fctx_cancelqueries(fctx, ISC_TRUE);
+ /*
+ * We must not retransmit while the validator is working;
+ * it has references to the current rmessage.
+ */
+ result = fctx_stopidletimer(fctx);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ } else if (result == DNS_R_CHASEDSSERVERS) {
+ unsigned int n;
+ add_bad(fctx, addrinfo, result);
+ fctx_cancelqueries(fctx, ISC_TRUE);
+ fctx_cleanupfinds(fctx);
+ fctx_cleanupforwaddrs(fctx);
+
+ n = dns_name_countlabels(&fctx->name);
+ dns_name_getlabelsequence(&fctx->name, 1, n - 1, &fctx->nsname);
+
+ FCTXTRACE("suspending DS lookup to find parent's NS records");
+
+ result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
+ dns_rdatatype_ns,
+ NULL, NULL, NULL, 0, task,
+ resume_dslookup, fctx,
+ &fctx->nsrrset, NULL,
+ &fctx->nsfetch);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ fctx->references++;
+ UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ result = fctx_stopidletimer(fctx);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ } else {
+ /*
+ * We're done.
+ */
+ fctx_done(fctx, result);
+ }
+}
+
+
+/***
+ *** Resolver Methods
+ ***/
+
+static void
+destroy(dns_resolver_t *res) {
+ unsigned int i;
+ alternate_t *a;
+
+ REQUIRE(res->references == 0);
+ REQUIRE(!res->priming);
+ REQUIRE(res->primefetch == NULL);
+
+ RTRACE("destroy");
+
+ INSIST(res->nfctx == 0);
+
+ DESTROYLOCK(&res->primelock);
+ DESTROYLOCK(&res->nlock);
+ DESTROYLOCK(&res->lock);
+ for (i = 0; i < res->nbuckets; i++) {
+ INSIST(ISC_LIST_EMPTY(res->buckets[i].fctxs));
+ isc_task_shutdown(res->buckets[i].task);
+ isc_task_detach(&res->buckets[i].task);
+ DESTROYLOCK(&res->buckets[i].lock);
+ isc_mem_detach(&res->buckets[i].mctx);
+ }
+ isc_mem_put(res->mctx, res->buckets,
+ res->nbuckets * sizeof(fctxbucket_t));
+ if (res->dispatchv4 != NULL)
+ dns_dispatch_detach(&res->dispatchv4);
+ if (res->dispatchv6 != NULL)
+ dns_dispatch_detach(&res->dispatchv6);
+ while ((a = ISC_LIST_HEAD(res->alternates)) != NULL) {
+ ISC_LIST_UNLINK(res->alternates, a, link);
+ if (!a->isaddress)
+ dns_name_free(&a->_u._n.name, res->mctx);
+ isc_mem_put(res->mctx, a, sizeof(*a));
+ }
+ dns_resolver_reset_algorithms(res);
+ dns_resolver_resetmustbesecure(res);
+#if USE_ALGLOCK
+ isc_rwlock_destroy(&res->alglock);
+#endif
+#if USE_MBSLOCK
+ isc_rwlock_destroy(&res->mbslock);
+#endif
+ isc_timer_detach(&res->spillattimer);
+ res->magic = 0;
+ isc_mem_put(res->mctx, res, sizeof(*res));
+}
+
+static void
+send_shutdown_events(dns_resolver_t *res) {
+ isc_event_t *event, *next_event;
+ isc_task_t *etask;
+
+ /*
+ * Caller must be holding the resolver lock.
+ */
+
+ for (event = ISC_LIST_HEAD(res->whenshutdown);
+ event != NULL;
+ event = next_event) {
+ next_event = ISC_LIST_NEXT(event, ev_link);
+ ISC_LIST_UNLINK(res->whenshutdown, event, ev_link);
+ etask = event->ev_sender;
+ event->ev_sender = res;
+ isc_task_sendanddetach(&etask, &event);
+ }
+}
+
+static void
+empty_bucket(dns_resolver_t *res) {
+ RTRACE("empty_bucket");
+
+ LOCK(&res->lock);
+
+ INSIST(res->activebuckets > 0);
+ res->activebuckets--;
+ if (res->activebuckets == 0)
+ send_shutdown_events(res);
+
+ UNLOCK(&res->lock);
+}
+
+static void
+spillattimer_countdown(isc_task_t *task, isc_event_t *event) {
+ dns_resolver_t *res = event->ev_arg;
+ isc_result_t result;
+ unsigned int count;
+ isc_boolean_t logit = ISC_FALSE;
+
+ REQUIRE(VALID_RESOLVER(res));
+
+ UNUSED(task);
+
+ LOCK(&res->lock);
+ INSIST(!res->exiting);
+ if (res->spillat > res->spillatmin) {
+ res->spillat--;
+ logit = ISC_TRUE;
+ }
+ if (res->spillat <= res->spillatmin) {
+ result = isc_timer_reset(res->spillattimer,
+ isc_timertype_inactive, NULL,
+ NULL, ISC_TRUE);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ }
+ count = res->spillat;
+ UNLOCK(&res->lock);
+ if (logit)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+ "clients-per-query decreased to %u", count);
+
+ isc_event_free(&event);
+}
+
+isc_result_t
+dns_resolver_create(dns_view_t *view,
+ isc_taskmgr_t *taskmgr, unsigned int ntasks,
+ isc_socketmgr_t *socketmgr,
+ isc_timermgr_t *timermgr,
+ unsigned int options,
+ dns_dispatchmgr_t *dispatchmgr,
+ dns_dispatch_t *dispatchv4,
+ dns_dispatch_t *dispatchv6,
+ dns_resolver_t **resp)
+{
+ dns_resolver_t *res;
+ isc_result_t result = ISC_R_SUCCESS;
+ unsigned int i, buckets_created = 0;
+ isc_task_t *task = NULL;
+ char name[16];
+
+ /*
+ * Create a resolver.
+ */
+
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(ntasks > 0);
+ REQUIRE(resp != NULL && *resp == NULL);
+ REQUIRE(dispatchmgr != NULL);
+ REQUIRE(dispatchv4 != NULL || dispatchv6 != NULL);
+
+ res = isc_mem_get(view->mctx, sizeof(*res));
+ if (res == NULL)
+ return (ISC_R_NOMEMORY);
+ RTRACE("create");
+ res->mctx = view->mctx;
+ res->rdclass = view->rdclass;
+ res->socketmgr = socketmgr;
+ res->timermgr = timermgr;
+ res->taskmgr = taskmgr;
+ res->dispatchmgr = dispatchmgr;
+ res->view = view;
+ res->options = options;
+ res->lame_ttl = 0;
+ ISC_LIST_INIT(res->alternates);
+ res->udpsize = RECV_BUFFER_SIZE;
+ res->algorithms = NULL;
+ res->mustbesecure = NULL;
+ res->spillatmin = res->spillat = 10;
+ res->spillatmax = 100;
+ res->spillattimer = NULL;
+ res->zero_no_soa_ttl = ISC_FALSE;
+
+ res->nbuckets = ntasks;
+ res->activebuckets = ntasks;
+ res->buckets = isc_mem_get(view->mctx,
+ ntasks * sizeof(fctxbucket_t));
+ if (res->buckets == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_res;
+ }
+ for (i = 0; i < ntasks; i++) {
+ result = isc_mutex_init(&res->buckets[i].lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_buckets;
+ res->buckets[i].task = NULL;
+ result = isc_task_create(taskmgr, 0, &res->buckets[i].task);
+ if (result != ISC_R_SUCCESS) {
+ DESTROYLOCK(&res->buckets[i].lock);
+ goto cleanup_buckets;
+ }
+ res->buckets[i].mctx = NULL;
+ result = isc_mem_create(0, 0, &res->buckets[i].mctx);
+ if (result != ISC_R_SUCCESS) {
+ isc_task_detach(&res->buckets[i].task);
+ DESTROYLOCK(&res->buckets[i].lock);
+ goto cleanup_buckets;
+ }
+ snprintf(name, sizeof(name), "res%u", i);
+ isc_task_setname(res->buckets[i].task, name, res);
+ ISC_LIST_INIT(res->buckets[i].fctxs);
+ res->buckets[i].exiting = ISC_FALSE;
+ buckets_created++;
+ }
+
+ res->dispatchv4 = NULL;
+ if (dispatchv4 != NULL)
+ dns_dispatch_attach(dispatchv4, &res->dispatchv4);
+ res->dispatchv6 = NULL;
+ if (dispatchv6 != NULL)
+ dns_dispatch_attach(dispatchv6, &res->dispatchv6);
+
+ res->references = 1;
+ res->exiting = ISC_FALSE;
+ res->frozen = ISC_FALSE;
+ ISC_LIST_INIT(res->whenshutdown);
+ res->priming = ISC_FALSE;
+ res->primefetch = NULL;
+ res->nfctx = 0;
+
+ result = isc_mutex_init(&res->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_dispatches;
+
+ result = isc_mutex_init(&res->nlock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+
+ result = isc_mutex_init(&res->primelock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_nlock;
+
+ task = NULL;
+ result = isc_task_create(taskmgr, 0, &task);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_primelock;
+
+ result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
+ task, spillattimer_countdown, res,
+ &res->spillattimer);
+ isc_task_detach(&task);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_primelock;
+
+#if USE_ALGLOCK
+ result = isc_rwlock_init(&res->alglock, 0, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_spillattimer;
+#endif
+#if USE_MBSLOCK
+ result = isc_rwlock_init(&res->mbslock, 0, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_alglock;
+#endif
+
+ res->magic = RES_MAGIC;
+
+ *resp = res;
+
+ return (ISC_R_SUCCESS);
+
+#if USE_MBSLOCK
+ cleanup_alglock:
+#if USE_ALGLOCK
+ isc_rwlock_destroy(&res->alglock);
+#endif
+#endif
+#if USE_ALGLOCK || USE_MBSLOCK
+ cleanup_spillattimer:
+ isc_timer_detach(&res->spillattimer);
+#endif
+
+ cleanup_primelock:
+ DESTROYLOCK(&res->primelock);
+
+ cleanup_nlock:
+ DESTROYLOCK(&res->nlock);
+
+ cleanup_lock:
+ DESTROYLOCK(&res->lock);
+
+ cleanup_dispatches:
+ if (res->dispatchv6 != NULL)
+ dns_dispatch_detach(&res->dispatchv6);
+ if (res->dispatchv4 != NULL)
+ dns_dispatch_detach(&res->dispatchv4);
+
+ cleanup_buckets:
+ for (i = 0; i < buckets_created; i++) {
+ isc_mem_detach(&res->buckets[i].mctx);
+ DESTROYLOCK(&res->buckets[i].lock);
+ isc_task_shutdown(res->buckets[i].task);
+ isc_task_detach(&res->buckets[i].task);
+ }
+ isc_mem_put(view->mctx, res->buckets,
+ res->nbuckets * sizeof(fctxbucket_t));
+
+ cleanup_res:
+ isc_mem_put(view->mctx, res, sizeof(*res));
+
+ return (result);
+}
+
+static void
+prime_done(isc_task_t *task, isc_event_t *event) {
+ dns_resolver_t *res;
+ dns_fetchevent_t *fevent;
+ dns_fetch_t *fetch;
+ dns_db_t *db = NULL;
+
+ REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
+ fevent = (dns_fetchevent_t *)event;
+ res = event->ev_arg;
+ REQUIRE(VALID_RESOLVER(res));
+
+ UNUSED(task);
+
+ LOCK(&res->lock);
+
+ INSIST(res->priming);
+ res->priming = ISC_FALSE;
+ LOCK(&res->primelock);
+ fetch = res->primefetch;
+ res->primefetch = NULL;
+ UNLOCK(&res->primelock);
+
+ UNLOCK(&res->lock);
+
+ if (fevent->result == ISC_R_SUCCESS &&
+ res->view->cache != NULL && res->view->hints != NULL) {
+ dns_cache_attachdb(res->view->cache, &db);
+ dns_root_checkhints(res->view, res->view->hints, db);
+ dns_db_detach(&db);
+ }
+
+ if (fevent->node != NULL)
+ dns_db_detachnode(fevent->db, &fevent->node);
+ if (fevent->db != NULL)
+ dns_db_detach(&fevent->db);
+ if (dns_rdataset_isassociated(fevent->rdataset))
+ dns_rdataset_disassociate(fevent->rdataset);
+ INSIST(fevent->sigrdataset == NULL);
+
+ isc_mem_put(res->mctx, fevent->rdataset, sizeof(*fevent->rdataset));
+
+ isc_event_free(&event);
+ dns_resolver_destroyfetch(&fetch);
+}
+
+void
+dns_resolver_prime(dns_resolver_t *res) {
+ isc_boolean_t want_priming = ISC_FALSE;
+ dns_rdataset_t *rdataset;
+ isc_result_t result;
+
+ REQUIRE(VALID_RESOLVER(res));
+ REQUIRE(res->frozen);
+
+ RTRACE("dns_resolver_prime");
+
+ LOCK(&res->lock);
+
+ if (!res->exiting && !res->priming) {
+ INSIST(res->primefetch == NULL);
+ res->priming = ISC_TRUE;
+ want_priming = ISC_TRUE;
+ }
+
+ UNLOCK(&res->lock);
+
+ if (want_priming) {
+ /*
+ * To avoid any possible recursive locking problems, we
+ * start the priming fetch like any other fetch, and holding
+ * no resolver locks. No one else will try to start it
+ * because we're the ones who set res->priming to true.
+ * Any other callers of dns_resolver_prime() while we're
+ * running will see that res->priming is already true and
+ * do nothing.
+ */
+ RTRACE("priming");
+ rdataset = isc_mem_get(res->mctx, sizeof(*rdataset));
+ if (rdataset == NULL) {
+ LOCK(&res->lock);
+ INSIST(res->priming);
+ INSIST(res->primefetch == NULL);
+ res->priming = ISC_FALSE;
+ UNLOCK(&res->lock);
+ return;
+ }
+ dns_rdataset_init(rdataset);
+ LOCK(&res->primelock);
+ result = dns_resolver_createfetch(res, dns_rootname,
+ dns_rdatatype_ns,
+ NULL, NULL, NULL, 0,
+ res->buckets[0].task,
+ prime_done,
+ res, rdataset, NULL,
+ &res->primefetch);
+ UNLOCK(&res->primelock);
+ if (result != ISC_R_SUCCESS) {
+ LOCK(&res->lock);
+ INSIST(res->priming);
+ res->priming = ISC_FALSE;
+ UNLOCK(&res->lock);
+ }
+ }
+}
+
+void
+dns_resolver_freeze(dns_resolver_t *res) {
+
+ /*
+ * Freeze resolver.
+ */
+
+ REQUIRE(VALID_RESOLVER(res));
+ REQUIRE(!res->frozen);
+
+ res->frozen = ISC_TRUE;
+}
+
+void
+dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) {
+ REQUIRE(VALID_RESOLVER(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ RRTRACE(source, "attach");
+ LOCK(&source->lock);
+ REQUIRE(!source->exiting);
+
+ INSIST(source->references > 0);
+ source->references++;
+ INSIST(source->references != 0);
+ UNLOCK(&source->lock);
+
+ *targetp = source;
+}
+
+void
+dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task,
+ isc_event_t **eventp)
+{
+ isc_task_t *clone;
+ isc_event_t *event;
+
+ REQUIRE(VALID_RESOLVER(res));
+ REQUIRE(eventp != NULL);
+
+ event = *eventp;
+ *eventp = NULL;
+
+ LOCK(&res->lock);
+
+ if (res->exiting && res->activebuckets == 0) {
+ /*
+ * We're already shutdown. Send the event.
+ */
+ event->ev_sender = res;
+ isc_task_send(task, &event);
+ } else {
+ clone = NULL;
+ isc_task_attach(task, &clone);
+ event->ev_sender = clone;
+ ISC_LIST_APPEND(res->whenshutdown, event, ev_link);
+ }
+
+ UNLOCK(&res->lock);
+}
+
+void
+dns_resolver_shutdown(dns_resolver_t *res) {
+ unsigned int i;
+ fetchctx_t *fctx;
+ isc_socket_t *sock;
+ isc_result_t result;
+
+ REQUIRE(VALID_RESOLVER(res));
+
+ RTRACE("shutdown");
+
+ LOCK(&res->lock);
+
+ if (!res->exiting) {
+ RTRACE("exiting");
+ res->exiting = ISC_TRUE;
+
+ for (i = 0; i < res->nbuckets; i++) {
+ LOCK(&res->buckets[i].lock);
+ for (fctx = ISC_LIST_HEAD(res->buckets[i].fctxs);
+ fctx != NULL;
+ fctx = ISC_LIST_NEXT(fctx, link))
+ fctx_shutdown(fctx);
+ if (res->dispatchv4 != NULL) {
+ sock = dns_dispatch_getsocket(res->dispatchv4);
+ isc_socket_cancel(sock, res->buckets[i].task,
+ ISC_SOCKCANCEL_ALL);
+ }
+ if (res->dispatchv6 != NULL) {
+ sock = dns_dispatch_getsocket(res->dispatchv6);
+ isc_socket_cancel(sock, res->buckets[i].task,
+ ISC_SOCKCANCEL_ALL);
+ }
+ res->buckets[i].exiting = ISC_TRUE;
+ if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) {
+ INSIST(res->activebuckets > 0);
+ res->activebuckets--;
+ }
+ UNLOCK(&res->buckets[i].lock);
+ }
+ if (res->activebuckets == 0)
+ send_shutdown_events(res);
+ result = isc_timer_reset(res->spillattimer,
+ isc_timertype_inactive, NULL,
+ NULL, ISC_TRUE);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ }
+
+ UNLOCK(&res->lock);
+}
+
+void
+dns_resolver_detach(dns_resolver_t **resp) {
+ dns_resolver_t *res;
+ isc_boolean_t need_destroy = ISC_FALSE;
+
+ REQUIRE(resp != NULL);
+ res = *resp;
+ REQUIRE(VALID_RESOLVER(res));
+
+ RTRACE("detach");
+
+ LOCK(&res->lock);
+
+ INSIST(res->references > 0);
+ res->references--;
+ if (res->references == 0) {
+ INSIST(res->exiting && res->activebuckets == 0);
+ need_destroy = ISC_TRUE;
+ }
+
+ UNLOCK(&res->lock);
+
+ if (need_destroy)
+ destroy(res);
+
+ *resp = NULL;
+}
+
+static inline isc_boolean_t
+fctx_match(fetchctx_t *fctx, dns_name_t *name, dns_rdatatype_t type,
+ unsigned int options)
+{
+ if (fctx->type != type || fctx->options != options)
+ return (ISC_FALSE);
+ return (dns_name_equal(&fctx->name, name));
+}
+
+static inline void
+log_fetch(dns_name_t *name, dns_rdatatype_t type) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char typebuf[DNS_RDATATYPE_FORMATSIZE];
+ int level = ISC_LOG_DEBUG(1);
+
+ if (! isc_log_wouldlog(dns_lctx, level))
+ return;
+
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ dns_rdatatype_format(type, typebuf, sizeof(typebuf));
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, level,
+ "createfetch: %s %s", namebuf, typebuf);
+}
+
+isc_result_t
+dns_resolver_createfetch(dns_resolver_t *res, dns_name_t *name,
+ dns_rdatatype_t type,
+ dns_name_t *domain, dns_rdataset_t *nameservers,
+ dns_forwarders_t *forwarders,
+ unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset,
+ dns_fetch_t **fetchp)
+{
+ return (dns_resolver_createfetch2(res, name, type, domain,
+ nameservers, forwarders, NULL, 0,
+ options, task, action, arg,
+ rdataset, sigrdataset, fetchp));
+}
+
+isc_result_t
+dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
+ dns_rdatatype_t type,
+ dns_name_t *domain, dns_rdataset_t *nameservers,
+ dns_forwarders_t *forwarders,
+ isc_sockaddr_t *client, dns_messageid_t id,
+ unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset,
+ dns_fetch_t **fetchp)
+{
+ dns_fetch_t *fetch;
+ fetchctx_t *fctx = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+ unsigned int bucketnum;
+ isc_boolean_t new_fctx = ISC_FALSE;
+ isc_event_t *event;
+ unsigned int count = 0;
+ unsigned int spillat;
+
+ UNUSED(forwarders);
+
+ REQUIRE(VALID_RESOLVER(res));
+ REQUIRE(res->frozen);
+ /* XXXRTH Check for meta type */
+ if (domain != NULL) {
+ REQUIRE(DNS_RDATASET_VALID(nameservers));
+ REQUIRE(nameservers->type == dns_rdatatype_ns);
+ } else
+ REQUIRE(nameservers == NULL);
+ REQUIRE(forwarders == NULL);
+ REQUIRE(!dns_rdataset_isassociated(rdataset));
+ REQUIRE(sigrdataset == NULL ||
+ !dns_rdataset_isassociated(sigrdataset));
+ REQUIRE(fetchp != NULL && *fetchp == NULL);
+
+ log_fetch(name, type);
+
+ /*
+ * XXXRTH use a mempool?
+ */
+ fetch = isc_mem_get(res->mctx, sizeof(*fetch));
+ if (fetch == NULL)
+ return (ISC_R_NOMEMORY);
+
+ bucketnum = dns_name_fullhash(name, ISC_FALSE) % res->nbuckets;
+
+ LOCK(&res->lock);
+ spillat = res->spillat;
+ UNLOCK(&res->lock);
+ LOCK(&res->buckets[bucketnum].lock);
+
+ if (res->buckets[bucketnum].exiting) {
+ result = ISC_R_SHUTTINGDOWN;
+ goto unlock;
+ }
+
+ if ((options & DNS_FETCHOPT_UNSHARED) == 0) {
+ for (fctx = ISC_LIST_HEAD(res->buckets[bucketnum].fctxs);
+ fctx != NULL;
+ fctx = ISC_LIST_NEXT(fctx, link)) {
+ if (fctx_match(fctx, name, type, options))
+ break;
+ }
+ }
+
+ /*
+ * Is this a duplicate?
+ */
+ if (fctx != NULL && client != NULL) {
+ dns_fetchevent_t *fevent;
+ for (fevent = ISC_LIST_HEAD(fctx->events);
+ fevent != NULL;
+ fevent = ISC_LIST_NEXT(fevent, ev_link)) {
+ if (fevent->client != NULL && fevent->id == id &&
+ isc_sockaddr_equal(fevent->client, client)) {
+ result = DNS_R_DUPLICATE;
+ goto unlock;
+ }
+ count++;
+ }
+ }
+ if (count >= res->spillatmin && res->spillatmin != 0) {
+ if (count >= spillat)
+ fctx->spilled = ISC_TRUE;
+ if (fctx->spilled) {
+ result = DNS_R_DROP;
+ goto unlock;
+ }
+ }
+
+ /*
+ * If we didn't have a fetch, would attach to a done fetch, this
+ * fetch has already cloned its results, or if the fetch has gone
+ * "idle" (no one was interested in it), we need to start a new
+ * fetch instead of joining with the existing one.
+ */
+ if (fctx == NULL ||
+ fctx->state == fetchstate_done ||
+ fctx->cloned ||
+ ISC_LIST_EMPTY(fctx->events)) {
+ fctx = NULL;
+ result = fctx_create(res, name, type, domain, nameservers,
+ options, bucketnum, &fctx);
+ if (result != ISC_R_SUCCESS)
+ goto unlock;
+ new_fctx = ISC_TRUE;
+ }
+
+ result = fctx_join(fctx, task, client, id, action, arg,
+ rdataset, sigrdataset, fetch);
+ if (new_fctx) {
+ if (result == ISC_R_SUCCESS) {
+ /*
+ * Launch this fctx.
+ */
+ event = &fctx->control_event;
+ ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
+ DNS_EVENT_FETCHCONTROL,
+ fctx_start, fctx, NULL,
+ NULL, NULL);
+ isc_task_send(res->buckets[bucketnum].task, &event);
+ } else {
+ /*
+ * We don't care about the result of fctx_destroy()
+ * since we know we're not exiting.
+ */
+ (void)fctx_destroy(fctx);
+ }
+ }
+
+ unlock:
+ UNLOCK(&res->buckets[bucketnum].lock);
+
+ if (result == ISC_R_SUCCESS) {
+ FTRACE("created");
+ *fetchp = fetch;
+ } else
+ isc_mem_put(res->mctx, fetch, sizeof(*fetch));
+
+ return (result);
+}
+
+void
+dns_resolver_cancelfetch(dns_fetch_t *fetch) {
+ fetchctx_t *fctx;
+ dns_resolver_t *res;
+ dns_fetchevent_t *event, *next_event;
+ isc_task_t *etask;
+
+ REQUIRE(DNS_FETCH_VALID(fetch));
+ fctx = fetch->private;
+ REQUIRE(VALID_FCTX(fctx));
+ res = fctx->res;
+
+ FTRACE("cancelfetch");
+
+ LOCK(&res->buckets[fctx->bucketnum].lock);
+
+ /*
+ * Find the completion event for this fetch (as opposed
+ * to those for other fetches that have joined the same
+ * fctx) and send it with result = ISC_R_CANCELED.
+ */
+ event = NULL;
+ if (fctx->state != fetchstate_done) {
+ for (event = ISC_LIST_HEAD(fctx->events);
+ event != NULL;
+ event = next_event) {
+ next_event = ISC_LIST_NEXT(event, ev_link);
+ if (event->fetch == fetch) {
+ ISC_LIST_UNLINK(fctx->events, event, ev_link);
+ break;
+ }
+ }
+ }
+ if (event != NULL) {
+ etask = event->ev_sender;
+ event->ev_sender = fctx;
+ event->result = ISC_R_CANCELED;
+ isc_task_sendanddetach(&etask, ISC_EVENT_PTR(&event));
+ }
+ /*
+ * The fctx continues running even if no fetches remain;
+ * the answer is still cached.
+ */
+
+ UNLOCK(&res->buckets[fctx->bucketnum].lock);
+}
+
+void
+dns_resolver_destroyfetch(dns_fetch_t **fetchp) {
+ dns_fetch_t *fetch;
+ dns_resolver_t *res;
+ dns_fetchevent_t *event, *next_event;
+ fetchctx_t *fctx;
+ unsigned int bucketnum;
+ isc_boolean_t bucket_empty = ISC_FALSE;
+
+ REQUIRE(fetchp != NULL);
+ fetch = *fetchp;
+ REQUIRE(DNS_FETCH_VALID(fetch));
+ fctx = fetch->private;
+ REQUIRE(VALID_FCTX(fctx));
+ res = fctx->res;
+
+ FTRACE("destroyfetch");
+
+ bucketnum = fctx->bucketnum;
+ LOCK(&res->buckets[bucketnum].lock);
+
+ /*
+ * Sanity check: the caller should have gotten its event before
+ * trying to destroy the fetch.
+ */
+ event = NULL;
+ if (fctx->state != fetchstate_done) {
+ for (event = ISC_LIST_HEAD(fctx->events);
+ event != NULL;
+ event = next_event) {
+ next_event = ISC_LIST_NEXT(event, ev_link);
+ RUNTIME_CHECK(event->fetch != fetch);
+ }
+ }
+
+ INSIST(fctx->references > 0);
+ fctx->references--;
+ if (fctx->references == 0) {
+ /*
+ * No one cares about the result of this fetch anymore.
+ */
+ if (fctx->pending == 0 && fctx->nqueries == 0 &&
+ ISC_LIST_EMPTY(fctx->validators) &&
+ SHUTTINGDOWN(fctx)) {
+ /*
+ * This fctx is already shutdown; we were just
+ * waiting for the last reference to go away.
+ */
+ bucket_empty = fctx_destroy(fctx);
+ } else {
+ /*
+ * Initiate shutdown.
+ */
+ fctx_shutdown(fctx);
+ }
+ }
+
+ UNLOCK(&res->buckets[bucketnum].lock);
+
+ isc_mem_put(res->mctx, fetch, sizeof(*fetch));
+ *fetchp = NULL;
+
+ if (bucket_empty)
+ empty_bucket(res);
+}
+
+dns_dispatchmgr_t *
+dns_resolver_dispatchmgr(dns_resolver_t *resolver) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ return (resolver->dispatchmgr);
+}
+
+dns_dispatch_t *
+dns_resolver_dispatchv4(dns_resolver_t *resolver) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ return (resolver->dispatchv4);
+}
+
+dns_dispatch_t *
+dns_resolver_dispatchv6(dns_resolver_t *resolver) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ return (resolver->dispatchv6);
+}
+
+isc_socketmgr_t *
+dns_resolver_socketmgr(dns_resolver_t *resolver) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ return (resolver->socketmgr);
+}
+
+isc_taskmgr_t *
+dns_resolver_taskmgr(dns_resolver_t *resolver) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ return (resolver->taskmgr);
+}
+
+isc_uint32_t
+dns_resolver_getlamettl(dns_resolver_t *resolver) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ return (resolver->lame_ttl);
+}
+
+void
+dns_resolver_setlamettl(dns_resolver_t *resolver, isc_uint32_t lame_ttl) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ resolver->lame_ttl = lame_ttl;
+}
+
+unsigned int
+dns_resolver_nrunning(dns_resolver_t *resolver) {
+ unsigned int n;
+ LOCK(&resolver->nlock);
+ n = resolver->nfctx;
+ UNLOCK(&resolver->nlock);
+ return (n);
+}
+
+isc_result_t
+dns_resolver_addalternate(dns_resolver_t *resolver, isc_sockaddr_t *alt,
+ dns_name_t *name, in_port_t port) {
+ alternate_t *a;
+ isc_result_t result;
+
+ REQUIRE(VALID_RESOLVER(resolver));
+ REQUIRE(!resolver->frozen);
+ REQUIRE((alt == NULL) ^ (name == NULL));
+
+ a = isc_mem_get(resolver->mctx, sizeof(*a));
+ if (a == NULL)
+ return (ISC_R_NOMEMORY);
+ if (alt != NULL) {
+ a->isaddress = ISC_TRUE;
+ a->_u.addr = *alt;
+ } else {
+ a->isaddress = ISC_FALSE;
+ a->_u._n.port = port;
+ dns_name_init(&a->_u._n.name, NULL);
+ result = dns_name_dup(name, resolver->mctx, &a->_u._n.name);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(resolver->mctx, a, sizeof(*a));
+ return (result);
+ }
+ }
+ ISC_LINK_INIT(a, link);
+ ISC_LIST_APPEND(resolver->alternates, a, link);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_resolver_setudpsize(dns_resolver_t *resolver, isc_uint16_t udpsize) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ resolver->udpsize = udpsize;
+}
+
+isc_uint16_t
+dns_resolver_getudpsize(dns_resolver_t *resolver) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ return (resolver->udpsize);
+}
+
+static void
+free_algorithm(void *node, void *arg) {
+ unsigned char *algorithms = node;
+ isc_mem_t *mctx = arg;
+
+ isc_mem_put(mctx, algorithms, *algorithms);
+}
+
+void
+dns_resolver_reset_algorithms(dns_resolver_t *resolver) {
+
+ REQUIRE(VALID_RESOLVER(resolver));
+
+#if USE_ALGLOCK
+ RWLOCK(&resolver->alglock, isc_rwlocktype_write);
+#endif
+ if (resolver->algorithms != NULL)
+ dns_rbt_destroy(&resolver->algorithms);
+#if USE_ALGLOCK
+ RWUNLOCK(&resolver->alglock, isc_rwlocktype_write);
+#endif
+}
+
+isc_result_t
+dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name,
+ unsigned int alg)
+{
+ unsigned int len, mask;
+ unsigned char *new;
+ unsigned char *algorithms;
+ isc_result_t result;
+ dns_rbtnode_t *node = NULL;
+
+ REQUIRE(VALID_RESOLVER(resolver));
+ if (alg > 255)
+ return (ISC_R_RANGE);
+
+#if USE_ALGLOCK
+ RWLOCK(&resolver->alglock, isc_rwlocktype_write);
+#endif
+ if (resolver->algorithms == NULL) {
+ result = dns_rbt_create(resolver->mctx, free_algorithm,
+ resolver->mctx, &resolver->algorithms);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ }
+
+ len = alg/8 + 2;
+ mask = 1 << (alg%8);
+
+ result = dns_rbt_addnode(resolver->algorithms, name, &node);
+
+ if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) {
+ algorithms = node->data;
+ if (algorithms == NULL || len > *algorithms) {
+ new = isc_mem_get(resolver->mctx, len);
+ if (new == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ memset(new, 0, len);
+ if (algorithms != NULL)
+ memcpy(new, algorithms, *algorithms);
+ new[len-1] |= mask;
+ *new = len;
+ node->data = new;
+ if (algorithms != NULL)
+ isc_mem_put(resolver->mctx, algorithms,
+ *algorithms);
+ } else
+ algorithms[len-1] |= mask;
+ }
+ result = ISC_R_SUCCESS;
+ cleanup:
+#if USE_ALGLOCK
+ RWUNLOCK(&resolver->alglock, isc_rwlocktype_write);
+#endif
+ return (result);
+}
+
+isc_boolean_t
+dns_resolver_algorithm_supported(dns_resolver_t *resolver, dns_name_t *name,
+ unsigned int alg)
+{
+ unsigned int len, mask;
+ unsigned char *algorithms;
+ void *data = NULL;
+ isc_result_t result;
+ isc_boolean_t found = ISC_FALSE;
+
+ REQUIRE(VALID_RESOLVER(resolver));
+
+#if USE_ALGLOCK
+ RWLOCK(&resolver->alglock, isc_rwlocktype_read);
+#endif
+ if (resolver->algorithms == NULL)
+ goto unlock;
+ result = dns_rbt_findname(resolver->algorithms, name, 0, NULL, &data);
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+ len = alg/8 + 2;
+ mask = 1 << (alg%8);
+ algorithms = data;
+ if (len <= *algorithms && (algorithms[len-1] & mask) != 0)
+ found = ISC_TRUE;
+ }
+ unlock:
+#if USE_ALGLOCK
+ RWUNLOCK(&resolver->alglock, isc_rwlocktype_read);
+#endif
+ if (found)
+ return (ISC_FALSE);
+ return (dst_algorithm_supported(alg));
+}
+
+isc_boolean_t
+dns_resolver_digest_supported(dns_resolver_t *resolver, unsigned int digest) {
+
+ UNUSED(resolver);
+ return (dns_ds_digest_supported(digest));
+}
+
+void
+dns_resolver_resetmustbesecure(dns_resolver_t *resolver) {
+
+ REQUIRE(VALID_RESOLVER(resolver));
+
+#if USE_MBSLOCK
+ RWLOCK(&resolver->mbslock, isc_rwlocktype_write);
+#endif
+ if (resolver->mustbesecure != NULL)
+ dns_rbt_destroy(&resolver->mustbesecure);
+#if USE_MBSLOCK
+ RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write);
+#endif
+}
+
+static isc_boolean_t yes = ISC_TRUE, no = ISC_FALSE;
+
+isc_result_t
+dns_resolver_setmustbesecure(dns_resolver_t *resolver, dns_name_t *name,
+ isc_boolean_t value)
+{
+ isc_result_t result;
+
+ REQUIRE(VALID_RESOLVER(resolver));
+
+#if USE_MBSLOCK
+ RWLOCK(&resolver->mbslock, isc_rwlocktype_write);
+#endif
+ if (resolver->mustbesecure == NULL) {
+ result = dns_rbt_create(resolver->mctx, NULL, NULL,
+ &resolver->mustbesecure);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ }
+ result = dns_rbt_addname(resolver->mustbesecure, name,
+ value ? &yes : &no);
+ cleanup:
+#if USE_MBSLOCK
+ RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write);
+#endif
+ return (result);
+}
+
+isc_boolean_t
+dns_resolver_getmustbesecure(dns_resolver_t *resolver, dns_name_t *name) {
+ void *data = NULL;
+ isc_boolean_t value = ISC_FALSE;
+ isc_result_t result;
+
+ REQUIRE(VALID_RESOLVER(resolver));
+
+#if USE_MBSLOCK
+ RWLOCK(&resolver->mbslock, isc_rwlocktype_read);
+#endif
+ if (resolver->mustbesecure == NULL)
+ goto unlock;
+ result = dns_rbt_findname(resolver->mustbesecure, name, 0, NULL, &data);
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
+ value = *(isc_boolean_t*)data;
+ unlock:
+#if USE_MBSLOCK
+ RWUNLOCK(&resolver->mbslock, isc_rwlocktype_read);
+#endif
+ return (value);
+}
+
+void
+dns_resolver_getclientsperquery(dns_resolver_t *resolver, isc_uint32_t *cur,
+ isc_uint32_t *min, isc_uint32_t *max)
+{
+ REQUIRE(VALID_RESOLVER(resolver));
+
+ LOCK(&resolver->lock);
+ if (cur != NULL)
+ *cur = resolver->spillat;
+ if (min != NULL)
+ *min = resolver->spillatmin;
+ if (max != NULL)
+ *max = resolver->spillatmax;
+ UNLOCK(&resolver->lock);
+}
+
+void
+dns_resolver_setclientsperquery(dns_resolver_t *resolver, isc_uint32_t min,
+ isc_uint32_t max)
+{
+ REQUIRE(VALID_RESOLVER(resolver));
+
+ LOCK(&resolver->lock);
+ resolver->spillatmin = resolver->spillat = min;
+ resolver->spillatmax = max;
+ UNLOCK(&resolver->lock);
+}
+
+isc_boolean_t
+dns_resolver_getzeronosoattl(dns_resolver_t *resolver) {
+ REQUIRE(VALID_RESOLVER(resolver));
+
+ return (resolver->zero_no_soa_ttl);
+}
+
+void
+dns_resolver_setzeronosoattl(dns_resolver_t *resolver, isc_boolean_t state) {
+ REQUIRE(VALID_RESOLVER(resolver));
+
+ resolver->zero_no_soa_ttl = state;
+}
diff --git a/lib/dns/result.c b/lib/dns/result.c
new file mode 100644
index 0000000..fdb58e0
--- /dev/null
+++ b/lib/dns/result.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: result.c,v 1.115.10.7 2005/06/17 02:04:31 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/once.h>
+#include <isc/util.h>
+
+#include <dns/result.h>
+#include <dns/lib.h>
+
+static const char *text[DNS_R_NRESULTS] = {
+ "label too long", /*%< 0 DNS_R_LABELTOOLONG */
+ "bad escape", /*%< 1 DNS_R_BADESCAPE */
+ /*!
+ * Note that DNS_R_BADBITSTRING and DNS_R_BITSTRINGTOOLONG are
+ * deprecated.
+ */
+ "bad bitstring", /*%< 2 DNS_R_BADBITSTRING */
+ "bitstring too long", /*%< 3 DNS_R_BITSTRINGTOOLONG */
+ "empty label", /*%< 4 DNS_R_EMPTYLABEL */
+
+ "bad dotted quad", /*%< 5 DNS_R_BADDOTTEDQUAD */
+ "invalid NS owner name (wildcard)", /*%< 6 DNS_R_INVALIDNS */
+ "unknown class/type", /*%< 7 DNS_R_UNKNOWN */
+ "bad label type", /*%< 8 DNS_R_BADLABELTYPE */
+ "bad compression pointer", /*%< 9 DNS_R_BADPOINTER */
+
+ "too many hops", /*%< 10 DNS_R_TOOMANYHOPS */
+ "disallowed (by application policy)", /*%< 11 DNS_R_DISALLOWED */
+ "extra input text", /*%< 12 DNS_R_EXTRATOKEN */
+ "extra input data", /*%< 13 DNS_R_EXTRADATA */
+ "text too long", /*%< 14 DNS_R_TEXTTOOLONG */
+
+ "not at top of zone", /*%< 15 DNS_R_NOTZONETOP */
+ "syntax error", /*%< 16 DNS_R_SYNTAX */
+ "bad checksum", /*%< 17 DNS_R_BADCKSUM */
+ "bad IPv6 address", /*%< 18 DNS_R_BADAAAA */
+ "no owner", /*%< 19 DNS_R_NOOWNER */
+
+ "no ttl", /*%< 20 DNS_R_NOTTL */
+ "bad class", /*%< 21 DNS_R_BADCLASS */
+ "name too long", /*%< 22 DNS_R_NAMETOOLONG */
+ "partial match", /*%< 23 DNS_R_PARTIALMATCH */
+ "new origin", /*%< 24 DNS_R_NEWORIGIN */
+
+ "unchanged", /*%< 25 DNS_R_UNCHANGED */
+ "bad ttl", /*%< 26 DNS_R_BADTTL */
+ "more data needed/to be rendered", /*%< 27 DNS_R_NOREDATA */
+ "continue", /*%< 28 DNS_R_CONTINUE */
+ "delegation", /*%< 29 DNS_R_DELEGATION */
+
+ "glue", /*%< 30 DNS_R_GLUE */
+ "dname", /*%< 31 DNS_R_DNAME */
+ "cname", /*%< 32 DNS_R_CNAME */
+ "bad database", /*%< 33 DNS_R_BADDB */
+ "zonecut", /*%< 34 DNS_R_ZONECUT */
+
+ "bad zone", /*%< 35 DNS_R_BADZONE */
+ "more data", /*%< 36 DNS_R_MOREDATA */
+ "up to date", /*%< 37 DNS_R_UPTODATE */
+ "tsig verify failure", /*%< 38 DNS_R_TSIGVERIFYFAILURE */
+ "tsig indicates error", /*%< 39 DNS_R_TSIGERRORSET */
+
+ "RRSIG failed to verify", /*%< 40 DNS_R_SIGINVALID */
+ "RRSIG has expired", /*%< 41 DNS_R_SIGEXPIRED */
+ "RRSIG validity period has not begun", /*%< 42 DNS_R_SIGFUTURE */
+ "key is unauthorized to sign data", /*%< 43 DNS_R_KEYUNAUTHORIZED */
+ "invalid time", /*%< 44 DNS_R_INVALIDTIME */
+
+ "expected a TSIG or SIG(0)", /*%< 45 DNS_R_EXPECTEDTSIG */
+ "did not expect a TSIG or SIG(0)", /*%< 46 DNS_R_UNEXPECTEDTSIG */
+ "TKEY is unacceptable", /*%< 47 DNS_R_INVALIDTKEY */
+ "hint", /*%< 48 DNS_R_HINT */
+ "drop", /*%< 49 DNS_R_DROP */
+
+ "zone not loaded", /*%< 50 DNS_R_NOTLOADED */
+ "ncache nxdomain", /*%< 51 DNS_R_NCACHENXDOMAIN */
+ "ncache nxrrset", /*%< 52 DNS_R_NCACHENXRRSET */
+ "wait", /*%< 53 DNS_R_WAIT */
+ "not verified yet", /*%< 54 DNS_R_NOTVERIFIEDYET */
+
+ "no identity", /*%< 55 DNS_R_NOIDENTITY */
+ "no journal", /*%< 56 DNS_R_NOJOURNAL */
+ "alias", /*%< 57 DNS_R_ALIAS */
+ "use TCP", /*%< 58 DNS_R_USETCP */
+ "no valid RRSIG", /*%< 59 DNS_R_NOVALIDSIG */
+
+ "no valid NSEC", /*%< 60 DNS_R_NOVALIDNSEC */
+ "not insecure", /*%< 61 DNS_R_NOTINSECURE */
+ "unknown service", /*%< 62 DNS_R_UNKNOWNSERVICE */
+ "recoverable error occurred", /*%< 63 DNS_R_RECOVERABLE */
+ "unknown opt attribute record", /*%< 64 DNS_R_UNKNOWNOPT */
+
+ "unexpected message id", /*%< 65 DNS_R_UNEXPECTEDID */
+ "seen include file", /*%< 66 DNS_R_SEENINCLUDE */
+ "not exact", /*%< 67 DNS_R_NOTEXACT */
+ "address blackholed", /*%< 68 DNS_R_BLACKHOLED */
+ "bad algorithm", /*%< 69 DNS_R_BADALG */
+
+ "invalid use of a meta type", /*%< 70 DNS_R_METATYPE */
+ "CNAME and other data", /*%< 71 DNS_R_CNAMEANDOTHER */
+ "multiple RRs of singleton type", /*%< 72 DNS_R_SINGLETON */
+ "hint nxrrset", /*%< 73 DNS_R_HINTNXRRSET */
+ "no master file configured", /*%< 74 DNS_R_NOMASTERFILE */
+
+ "unknown protocol", /*%< 75 DNS_R_UNKNOWNPROTO */
+ "clocks are unsynchronized", /*%< 76 DNS_R_CLOCKSKEW */
+ "IXFR failed", /*%< 77 DNS_R_BADIXFR */
+ "not authoritative", /*%< 78 DNS_R_NOTAUTHORITATIVE */
+ "no valid KEY", /*%< 79 DNS_R_NOVALIDKEY */
+
+ "obsolete", /*%< 80 DNS_R_OBSOLETE */
+ "already frozen", /*%< 81 DNS_R_FROZEN */
+ "unknown flag", /*%< 82 DNS_R_UNKNOWNFLAG */
+ "expected a response", /*%< 83 DNS_R_EXPECTEDRESPONSE */
+ "no valid DS", /*%< 84 DNS_R_NOVALIDDS */
+
+ "NS is an address", /*%< 85 DNS_R_NSISADDRESS */
+ "received FORMERR", /*%< 86 DNS_R_REMOTEFORMERR */
+ "truncated TCP response", /*%< 87 DNS_R_TRUNCATEDTCP */
+ "lame server detected", /*%< 88 DNS_R_LAME */
+ "unexpected RCODE", /*%< 89 DNS_R_UNEXPECTEDRCODE */
+
+ "unexpected OPCODE", /*%< 90 DNS_R_UNEXPECTEDOPCODE */
+ "chase DS servers", /*%< 91 DNS_R_CHASEDSSERVERS */
+ "empty name", /*%< 92 DNS_R_EMPTYNAME */
+ "empty wild", /*%< 93 DNS_R_EMPTYWILD */
+ "bad bitmap", /*%< 94 DNS_R_BADBITMAP */
+
+ "from wildcard", /*%< 95 DNS_R_FROMWILDCARD */
+ "bad owner name (check-names)", /*%< 96 DNS_R_BADOWNERNAME */
+ "bad name (check-names)", /*%< 97 DNS_R_BADNAME */
+ "dynamic zone", /*%< 98 DNS_R_DYNAMIC */
+ "unknown command", /*%< 99 DNS_R_UNKNOWNCOMMAND */
+
+ "must-be-secure", /*%< 100 DNS_R_MUSTBESECURE */
+ "covering NSEC record returned", /*%< 101 DNS_R_COVERINGNSEC */
+ "MX is an address", /*%< 102 DNS_R_MXISADDRESS */
+ "duplicate query" /*%< 103 DNS_R_DUPLICATE */
+};
+
+static const char *rcode_text[DNS_R_NRCODERESULTS] = {
+ "NOERROR", /*%< 0 DNS_R_NOEROR */
+ "FORMERR", /*%< 1 DNS_R_FORMERR */
+ "SERVFAIL", /*%< 2 DNS_R_SERVFAIL */
+ "NXDOMAIN", /*%< 3 DNS_R_NXDOMAIN */
+ "NOTIMP", /*%< 4 DNS_R_NOTIMP */
+
+ "REFUSED", /*%< 5 DNS_R_REFUSED */
+ "YXDOMAIN", /*%< 6 DNS_R_YXDOMAIN */
+ "YXRRSET", /*%< 7 DNS_R_YXRRSET */
+ "NXRRSET", /*%< 8 DNS_R_NXRRSET */
+ "NOTAUTH", /*%< 9 DNS_R_NOTAUTH */
+
+ "NOTZONE", /*%< 10 DNS_R_NOTZONE */
+ "<rcode 11>", /*%< 11 has no macro */
+ "<rcode 12>", /*%< 12 has no macro */
+ "<rcode 13>", /*%< 13 has no macro */
+ "<rcode 14>", /*%< 14 has no macro */
+
+ "<rcode 15>", /*%< 15 has no macro */
+ "BADVERS", /*%< 16 DNS_R_BADVERS */
+};
+
+#define DNS_RESULT_RESULTSET 2
+#define DNS_RESULT_RCODERESULTSET 3
+
+static isc_once_t once = ISC_ONCE_INIT;
+
+static void
+initialize_action(void) {
+ isc_result_t result;
+
+ result = isc_result_register(ISC_RESULTCLASS_DNS, DNS_R_NRESULTS,
+ text, dns_msgcat, DNS_RESULT_RESULTSET);
+ if (result == ISC_R_SUCCESS)
+ result = isc_result_register(ISC_RESULTCLASS_DNSRCODE,
+ DNS_R_NRCODERESULTS,
+ rcode_text, dns_msgcat,
+ DNS_RESULT_RCODERESULTSET);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_result_register() failed: %u", result);
+}
+
+static void
+initialize(void) {
+ dns_lib_initmsgcat();
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+const char *
+dns_result_totext(isc_result_t result) {
+ initialize();
+
+ return (isc_result_totext(result));
+}
+
+void
+dns_result_register(void) {
+ initialize();
+}
+
+dns_rcode_t
+dns_result_torcode(isc_result_t result) {
+ dns_rcode_t rcode = dns_rcode_servfail;
+
+ if (DNS_RESULT_ISRCODE(result)) {
+ /*
+ * Rcodes can't be bigger than 12 bits, which is why we
+ * AND with 0xFFF instead of 0xFFFF.
+ */
+ return ((dns_rcode_t)((result) & 0xFFF));
+ }
+ /*
+ * Try to supply an appropriate rcode.
+ */
+ switch (result) {
+ case ISC_R_SUCCESS:
+ rcode = dns_rcode_noerror;
+ break;
+ case ISC_R_BADBASE64:
+ case ISC_R_NOSPACE:
+ case ISC_R_RANGE:
+ case ISC_R_UNEXPECTEDEND:
+ case DNS_R_BADAAAA:
+ /* case DNS_R_BADBITSTRING: deprecated */
+ case DNS_R_BADCKSUM:
+ case DNS_R_BADCLASS:
+ case DNS_R_BADLABELTYPE:
+ case DNS_R_BADPOINTER:
+ case DNS_R_BADTTL:
+ case DNS_R_BADZONE:
+ /* case DNS_R_BITSTRINGTOOLONG: deprecated */
+ case DNS_R_EXTRADATA:
+ case DNS_R_LABELTOOLONG:
+ case DNS_R_NOREDATA:
+ case DNS_R_SYNTAX:
+ case DNS_R_TEXTTOOLONG:
+ case DNS_R_TOOMANYHOPS:
+ case DNS_R_TSIGERRORSET:
+ case DNS_R_UNKNOWN:
+ rcode = dns_rcode_formerr;
+ break;
+ case DNS_R_DISALLOWED:
+ rcode = dns_rcode_refused;
+ break;
+ case DNS_R_TSIGVERIFYFAILURE:
+ case DNS_R_CLOCKSKEW:
+ rcode = dns_rcode_notauth;
+ break;
+ default:
+ rcode = dns_rcode_servfail;
+ }
+
+ return (rcode);
+}
diff --git a/lib/dns/rootns.c b/lib/dns/rootns.c
new file mode 100644
index 0000000..f20a49d
--- /dev/null
+++ b/lib/dns/rootns.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2002 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: rootns.c,v 1.26.18.5 2007/10/31 03:02:45 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/buffer.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/util.h>
+
+#include <dns/callbacks.h>
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/fixedname.h>
+#include <dns/log.h>
+#include <dns/master.h>
+#include <dns/rdata.h>
+#include <dns/rdata.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/rdatastruct.h>
+#include <dns/rdatatype.h>
+#include <dns/result.h>
+#include <dns/rootns.h>
+#include <dns/view.h>
+
+static char root_ns[] =
+";\n"
+"; Internet Root Nameservers\n"
+";\n"
+"; Thu Sep 23 17:57:37 PDT 1999\n"
+";\n"
+"$TTL 518400\n"
+". 518400 IN NS A.ROOT-SERVERS.NET.\n"
+". 518400 IN NS B.ROOT-SERVERS.NET.\n"
+". 518400 IN NS C.ROOT-SERVERS.NET.\n"
+". 518400 IN NS D.ROOT-SERVERS.NET.\n"
+". 518400 IN NS E.ROOT-SERVERS.NET.\n"
+". 518400 IN NS F.ROOT-SERVERS.NET.\n"
+". 518400 IN NS G.ROOT-SERVERS.NET.\n"
+". 518400 IN NS H.ROOT-SERVERS.NET.\n"
+". 518400 IN NS I.ROOT-SERVERS.NET.\n"
+". 518400 IN NS J.ROOT-SERVERS.NET.\n"
+". 518400 IN NS K.ROOT-SERVERS.NET.\n"
+". 518400 IN NS L.ROOT-SERVERS.NET.\n"
+". 518400 IN NS M.ROOT-SERVERS.NET.\n"
+"A.ROOT-SERVERS.NET. 3600000 IN A 198.41.0.4\n"
+"B.ROOT-SERVERS.NET. 3600000 IN A 192.228.79.201\n"
+"C.ROOT-SERVERS.NET. 3600000 IN A 192.33.4.12\n"
+"D.ROOT-SERVERS.NET. 3600000 IN A 128.8.10.90\n"
+"E.ROOT-SERVERS.NET. 3600000 IN A 192.203.230.10\n"
+"F.ROOT-SERVERS.NET. 3600000 IN A 192.5.5.241\n"
+"G.ROOT-SERVERS.NET. 3600000 IN A 192.112.36.4\n"
+"H.ROOT-SERVERS.NET. 3600000 IN A 128.63.2.53\n"
+"I.ROOT-SERVERS.NET. 3600000 IN A 192.36.148.17\n"
+"J.ROOT-SERVERS.NET. 3600000 IN A 192.58.128.30\n"
+"K.ROOT-SERVERS.NET. 3600000 IN A 193.0.14.129\n"
+"L.ROOT-SERVERS.NET. 3600000 IN A 199.7.83.42\n"
+"M.ROOT-SERVERS.NET. 3600000 IN A 202.12.27.33\n";
+
+static isc_result_t
+in_rootns(dns_rdataset_t *rootns, dns_name_t *name) {
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_ns_t ns;
+
+ if (!dns_rdataset_isassociated(rootns))
+ return (ISC_R_NOTFOUND);
+
+ result = dns_rdataset_first(rootns);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(rootns, &rdata);
+ result = dns_rdata_tostruct(&rdata, &ns, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (dns_name_compare(name, &ns.name) == 0)
+ return (ISC_R_SUCCESS);
+ result = dns_rdataset_next(rootns);
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_NOTFOUND;
+ return (result);
+}
+
+static isc_result_t
+check_node(dns_rdataset_t *rootns, dns_name_t *name,
+ dns_rdatasetiter_t *rdsiter) {
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_rdatasetiter_first(rdsiter);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+ switch (rdataset.type) {
+ case dns_rdatatype_a:
+ case dns_rdatatype_aaaa:
+ result = in_rootns(rootns, name);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ break;
+ case dns_rdatatype_ns:
+ if (dns_name_compare(name, dns_rootname) == 0)
+ break;
+ /*FALLTHROUGH*/
+ default:
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+ dns_rdataset_disassociate(&rdataset);
+ result = dns_rdatasetiter_next(rdsiter);
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ cleanup:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ return (result);
+}
+
+static isc_result_t
+check_hints(dns_db_t *db) {
+ isc_result_t result;
+ dns_rdataset_t rootns;
+ dns_dbiterator_t *dbiter = NULL;
+ dns_dbnode_t *node = NULL;
+ isc_stdtime_t now;
+ dns_fixedname_t fixname;
+ dns_name_t *name;
+ dns_rdatasetiter_t *rdsiter = NULL;
+
+ isc_stdtime_get(&now);
+
+ dns_fixedname_init(&fixname);
+ name = dns_fixedname_name(&fixname);
+
+ dns_rdataset_init(&rootns);
+ (void)dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0,
+ now, NULL, name, &rootns, NULL);
+ result = dns_db_createiterator(db, ISC_FALSE, &dbiter);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_dbiterator_first(dbiter);
+ while (result == ISC_R_SUCCESS) {
+ result = dns_dbiterator_current(dbiter, &node, name);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_db_allrdatasets(db, node, NULL, now, &rdsiter);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = check_node(&rootns, name, rdsiter);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ dns_rdatasetiter_destroy(&rdsiter);
+ dns_db_detachnode(db, &node);
+ result = dns_dbiterator_next(dbiter);
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ cleanup:
+ if (dns_rdataset_isassociated(&rootns))
+ dns_rdataset_disassociate(&rootns);
+ if (rdsiter != NULL)
+ dns_rdatasetiter_destroy(&rdsiter);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ if (dbiter != NULL)
+ dns_dbiterator_destroy(&dbiter);
+ return (result);
+}
+
+isc_result_t
+dns_rootns_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
+ const char *filename, dns_db_t **target)
+{
+ isc_result_t result, eresult;
+ isc_buffer_t source;
+ size_t len;
+ dns_rdatacallbacks_t callbacks;
+ dns_db_t *db = NULL;
+
+ REQUIRE(target != NULL && *target == NULL);
+
+ result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
+ rdclass, 0, NULL, &db);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ dns_rdatacallbacks_init(&callbacks);
+
+ len = strlen(root_ns);
+ isc_buffer_init(&source, root_ns, len);
+ isc_buffer_add(&source, len);
+
+ result = dns_db_beginload(db, &callbacks.add,
+ &callbacks.add_private);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (filename != NULL) {
+ /*
+ * Load the hints from the specified filename.
+ */
+ result = dns_master_loadfile(filename, &db->origin,
+ &db->origin, db->rdclass,
+ DNS_MASTER_HINT,
+ &callbacks, db->mctx);
+ } else if (rdclass == dns_rdataclass_in) {
+ /*
+ * Default to using the Internet root servers.
+ */
+ result = dns_master_loadbuffer(&source, &db->origin,
+ &db->origin, db->rdclass,
+ DNS_MASTER_HINT,
+ &callbacks, db->mctx);
+ } else
+ result = ISC_R_NOTFOUND;
+ eresult = dns_db_endload(db, &callbacks.add_private);
+ if (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE)
+ result = eresult;
+ if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
+ goto db_detach;
+ if (check_hints(db) != ISC_R_SUCCESS)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
+ "extra data in root hints '%s'",
+ (filename != NULL) ? filename : "<BUILT-IN>");
+ *target = db;
+ return (ISC_R_SUCCESS);
+
+ db_detach:
+ dns_db_detach(&db);
+
+ return (result);
+}
+
+static void
+report(dns_view_t *view, dns_name_t *name, isc_boolean_t missing,
+ dns_rdata_t *rdata)
+{
+ const char *viewname = "", *sep = "";
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char typebuf[DNS_RDATATYPE_FORMATSIZE];
+ char databuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
+ isc_buffer_t buffer;
+ isc_result_t result;
+
+ if (strcmp(view->name, "_bind") != 0 &&
+ strcmp(view->name, "_default") != 0) {
+ viewname = view->name;
+ sep = ": view ";
+ }
+
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf));
+ isc_buffer_init(&buffer, databuf, sizeof(databuf) - 1);
+ result = dns_rdata_totext(rdata, NULL, &buffer);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ databuf[isc_buffer_usedlength(&buffer)] = '\0';
+
+ if (missing)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
+ "checkhints%s%s: %s/%s (%s) missing from hints",
+ sep, viewname, namebuf, typebuf, databuf);
+ else
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
+ "checkhints%s%s: %s/%s (%s) extra record "
+ "in hints", sep, viewname, namebuf, typebuf,
+ databuf);
+}
+
+static isc_boolean_t
+inrrset(dns_rdataset_t *rrset, dns_rdata_t *rdata) {
+ isc_result_t result;
+ dns_rdata_t current = DNS_RDATA_INIT;
+
+ result = dns_rdataset_first(rrset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(rrset, &current);
+ if (dns_rdata_compare(rdata, &current) == 0)
+ return (ISC_TRUE);
+ dns_rdata_reset(&current);
+ result = dns_rdataset_next(rrset);
+ }
+ return (ISC_FALSE);
+}
+
+/*
+ * Check that the address RRsets match.
+ *
+ * Note we don't complain about missing glue records.
+ */
+
+static void
+check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db,
+ dns_name_t *name, isc_stdtime_t now)
+{
+ isc_result_t hresult, rresult, result;
+ dns_rdataset_t hintrrset, rootrrset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_name_t *foundname;
+ dns_fixedname_t fixed;
+
+ dns_rdataset_init(&hintrrset);
+ dns_rdataset_init(&rootrrset);
+ dns_fixedname_init(&fixed);
+ foundname = dns_fixedname_name(&fixed);
+
+ hresult = dns_db_find(hints, name, NULL, dns_rdatatype_a, 0,
+ now, NULL, foundname, &hintrrset, NULL);
+ rresult = dns_db_find(db, name, NULL, dns_rdatatype_a,
+ DNS_DBFIND_GLUEOK, now, NULL, foundname,
+ &rootrrset, NULL);
+ if (hresult == ISC_R_SUCCESS &&
+ (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
+ result = dns_rdataset_first(&rootrrset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&rootrrset, &rdata);
+ if (!inrrset(&hintrrset, &rdata))
+ report(view, name, ISC_TRUE, &rdata);
+ result = dns_rdataset_next(&rootrrset);
+ }
+ result = dns_rdataset_first(&hintrrset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&hintrrset, &rdata);
+ if (!inrrset(&rootrrset, &rdata))
+ report(view, name, ISC_FALSE, &rdata);
+ result = dns_rdataset_next(&hintrrset);
+ }
+ }
+ if (hresult == ISC_R_NOTFOUND &&
+ (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
+ result = dns_rdataset_first(&rootrrset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&rootrrset, &rdata);
+ report(view, name, ISC_TRUE, &rdata);
+ result = dns_rdataset_next(&rootrrset);
+ }
+ }
+ if (dns_rdataset_isassociated(&rootrrset))
+ dns_rdataset_disassociate(&rootrrset);
+ if (dns_rdataset_isassociated(&hintrrset))
+ dns_rdataset_disassociate(&hintrrset);
+
+ /*
+ * Check AAAA records.
+ */
+ hresult = dns_db_find(hints, name, NULL, dns_rdatatype_aaaa, 0,
+ now, NULL, foundname, &hintrrset, NULL);
+ rresult = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,
+ DNS_DBFIND_GLUEOK, now, NULL, foundname,
+ &rootrrset, NULL);
+ if (hresult == ISC_R_SUCCESS &&
+ (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
+ result = dns_rdataset_first(&rootrrset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&rootrrset, &rdata);
+ if (!inrrset(&hintrrset, &rdata))
+ report(view, name, ISC_TRUE, &rdata);
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(&rootrrset);
+ }
+ result = dns_rdataset_first(&hintrrset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&hintrrset, &rdata);
+ if (!inrrset(&rootrrset, &rdata))
+ report(view, name, ISC_FALSE, &rdata);
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(&hintrrset);
+ }
+ }
+ if (hresult == ISC_R_NOTFOUND &&
+ (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
+ result = dns_rdataset_first(&rootrrset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&rootrrset, &rdata);
+ report(view, name, ISC_TRUE, &rdata);
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(&rootrrset);
+ }
+ }
+ if (dns_rdataset_isassociated(&rootrrset))
+ dns_rdataset_disassociate(&rootrrset);
+ if (dns_rdataset_isassociated(&hintrrset))
+ dns_rdataset_disassociate(&hintrrset);
+}
+
+void
+dns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db) {
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_ns_t ns;
+ dns_rdataset_t hintns, rootns;
+ const char *viewname = "", *sep = "";
+ isc_stdtime_t now;
+ dns_name_t *name;
+ dns_fixedname_t fixed;
+
+ REQUIRE(hints != NULL);
+ REQUIRE(db != NULL);
+ REQUIRE(view != NULL);
+
+ isc_stdtime_get(&now);
+
+ if (strcmp(view->name, "_bind") != 0 &&
+ strcmp(view->name, "_default") != 0) {
+ viewname = view->name;
+ sep = ": view ";
+ }
+
+ dns_rdataset_init(&hintns);
+ dns_rdataset_init(&rootns);
+ dns_fixedname_init(&fixed);
+ name = dns_fixedname_name(&fixed);
+
+ result = dns_db_find(hints, dns_rootname, NULL, dns_rdatatype_ns, 0,
+ now, NULL, name, &hintns, NULL);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
+ "checkhints%s%s: unable to get root NS rrset "
+ "from hints: %s", sep, viewname,
+ dns_result_totext(result));
+ goto cleanup;
+ }
+
+ result = dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0,
+ now, NULL, name, &rootns, NULL);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
+ "checkhints%s%s: unable to get root NS rrset "
+ "from cache: %s", sep, viewname,
+ dns_result_totext(result));
+ goto cleanup;
+ }
+
+ /*
+ * Look for missing root NS names.
+ */
+ result = dns_rdataset_first(&rootns);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&rootns, &rdata);
+ result = dns_rdata_tostruct(&rdata, &ns, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ result = in_rootns(&hintns, &ns.name);
+ if (result != ISC_R_SUCCESS) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ /* missing from hints */
+ dns_name_format(&ns.name, namebuf, sizeof(namebuf));
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
+ "checkhints%s%s: unable to find root "
+ "NS '%s' in hints", sep, viewname,
+ namebuf);
+ } else
+ check_address_records(view, hints, db, &ns.name, now);
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(&rootns);
+ }
+ if (result != ISC_R_NOMORE) {
+ goto cleanup;
+ }
+
+ /*
+ * Look for extra root NS names.
+ */
+ result = dns_rdataset_first(&hintns);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&hintns, &rdata);
+ result = dns_rdata_tostruct(&rdata, &ns, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ result = in_rootns(&rootns, &ns.name);
+ if (result != ISC_R_SUCCESS) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ /* extra entry in hints */
+ dns_name_format(&ns.name, namebuf, sizeof(namebuf));
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
+ "checkhints%s%s: extra NS '%s' in hints",
+ sep, viewname, namebuf);
+ }
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(&hintns);
+ }
+ if (result != ISC_R_NOMORE) {
+ goto cleanup;
+ }
+
+ cleanup:
+ if (dns_rdataset_isassociated(&rootns))
+ dns_rdataset_disassociate(&rootns);
+ if (dns_rdataset_isassociated(&hintns))
+ dns_rdataset_disassociate(&hintns);
+}
diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c
new file mode 100644
index 0000000..fe53778
--- /dev/null
+++ b/lib/dns/sdb.c
@@ -0,0 +1,1538 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: sdb.c,v 1.45.18.13 2007/08/28 07:20:05 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/log.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/util.h>
+
+#include <dns/callbacks.h>
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/fixedname.h>
+#include <dns/log.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/rdatatype.h>
+#include <dns/result.h>
+#include <dns/sdb.h>
+#include <dns/types.h>
+
+#include "rdatalist_p.h"
+
+struct dns_sdbimplementation {
+ const dns_sdbmethods_t *methods;
+ void *driverdata;
+ unsigned int flags;
+ isc_mem_t *mctx;
+ isc_mutex_t driverlock;
+ dns_dbimplementation_t *dbimp;
+};
+
+struct dns_sdb {
+ /* Unlocked */
+ dns_db_t common;
+ char *zone;
+ dns_sdbimplementation_t *implementation;
+ void *dbdata;
+ isc_mutex_t lock;
+ /* Locked */
+ unsigned int references;
+};
+
+struct dns_sdblookup {
+ /* Unlocked */
+ unsigned int magic;
+ dns_sdb_t *sdb;
+ ISC_LIST(dns_rdatalist_t) lists;
+ ISC_LIST(isc_buffer_t) buffers;
+ dns_name_t *name;
+ ISC_LINK(dns_sdblookup_t) link;
+ isc_mutex_t lock;
+ dns_rdatacallbacks_t callbacks;
+ /* Locked */
+ unsigned int references;
+};
+
+typedef struct dns_sdblookup dns_sdbnode_t;
+
+struct dns_sdballnodes {
+ dns_dbiterator_t common;
+ ISC_LIST(dns_sdbnode_t) nodelist;
+ dns_sdbnode_t *current;
+ dns_sdbnode_t *origin;
+};
+
+typedef dns_sdballnodes_t sdb_dbiterator_t;
+
+typedef struct sdb_rdatasetiter {
+ dns_rdatasetiter_t common;
+ dns_rdatalist_t *current;
+} sdb_rdatasetiter_t;
+
+#define SDB_MAGIC ISC_MAGIC('S', 'D', 'B', '-')
+
+/*%
+ * Note that "impmagic" is not the first four bytes of the struct, so
+ * ISC_MAGIC_VALID cannot be used.
+ */
+#define VALID_SDB(sdb) ((sdb) != NULL && \
+ (sdb)->common.impmagic == SDB_MAGIC)
+
+#define SDBLOOKUP_MAGIC ISC_MAGIC('S','D','B','L')
+#define VALID_SDBLOOKUP(sdbl) ISC_MAGIC_VALID(sdbl, SDBLOOKUP_MAGIC)
+#define VALID_SDBNODE(sdbn) VALID_SDBLOOKUP(sdbn)
+
+/* These values are taken from RFC1537 */
+#define SDB_DEFAULT_REFRESH (60 * 60 * 8)
+#define SDB_DEFAULT_RETRY (60 * 60 * 2)
+#define SDB_DEFAULT_EXPIRE (60 * 60 * 24 * 7)
+#define SDB_DEFAULT_MINIMUM (60 * 60 * 24)
+
+/* This is a reasonable value */
+#define SDB_DEFAULT_TTL (60 * 60 * 24)
+
+#ifdef __COVERITY__
+#define MAYBE_LOCK(sdb) LOCK(&sdb->implementation->driverlock)
+#define MAYBE_UNLOCK(sdb) UNLOCK(&sdb->implementation->driverlock)
+#else
+#define MAYBE_LOCK(sdb) \
+ do { \
+ unsigned int flags = sdb->implementation->flags; \
+ if ((flags & DNS_SDBFLAG_THREADSAFE) == 0) \
+ LOCK(&sdb->implementation->driverlock); \
+ } while (0)
+
+#define MAYBE_UNLOCK(sdb) \
+ do { \
+ unsigned int flags = sdb->implementation->flags; \
+ if ((flags & DNS_SDBFLAG_THREADSAFE) == 0) \
+ UNLOCK(&sdb->implementation->driverlock); \
+ } while (0)
+#endif
+
+static int dummy;
+
+static isc_result_t dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin,
+ dns_dbtype_t type, dns_rdataclass_t rdclass,
+ unsigned int argc, char *argv[],
+ void *driverarg, dns_db_t **dbp);
+
+static isc_result_t findrdataset(dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers,
+ isc_stdtime_t now, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset);
+
+static isc_result_t createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep);
+
+static void destroynode(dns_sdbnode_t *node);
+
+static void detachnode(dns_db_t *db, dns_dbnode_t **targetp);
+
+
+static void list_tordataset(dns_rdatalist_t *rdatalist,
+ dns_db_t *db, dns_dbnode_t *node,
+ dns_rdataset_t *rdataset);
+
+static void dbiterator_destroy(dns_dbiterator_t **iteratorp);
+static isc_result_t dbiterator_first(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_last(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_seek(dns_dbiterator_t *iterator,
+ dns_name_t *name);
+static isc_result_t dbiterator_prev(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_next(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_current(dns_dbiterator_t *iterator,
+ dns_dbnode_t **nodep,
+ dns_name_t *name);
+static isc_result_t dbiterator_pause(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_origin(dns_dbiterator_t *iterator,
+ dns_name_t *name);
+
+static dns_dbiteratormethods_t dbiterator_methods = {
+ dbiterator_destroy,
+ dbiterator_first,
+ dbiterator_last,
+ dbiterator_seek,
+ dbiterator_prev,
+ dbiterator_next,
+ dbiterator_current,
+ dbiterator_pause,
+ dbiterator_origin
+};
+
+static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
+static isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator);
+static isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator);
+static void rdatasetiter_current(dns_rdatasetiter_t *iterator,
+ dns_rdataset_t *rdataset);
+
+static dns_rdatasetitermethods_t rdatasetiter_methods = {
+ rdatasetiter_destroy,
+ rdatasetiter_first,
+ rdatasetiter_next,
+ rdatasetiter_current
+};
+
+/*
+ * Functions used by implementors of simple databases
+ */
+isc_result_t
+dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
+ void *driverdata, unsigned int flags, isc_mem_t *mctx,
+ dns_sdbimplementation_t **sdbimp)
+{
+ dns_sdbimplementation_t *imp;
+ isc_result_t result;
+
+ REQUIRE(drivername != NULL);
+ REQUIRE(methods != NULL);
+ REQUIRE(methods->lookup != NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(sdbimp != NULL && *sdbimp == NULL);
+ REQUIRE((flags & ~(DNS_SDBFLAG_RELATIVEOWNER |
+ DNS_SDBFLAG_RELATIVERDATA |
+ DNS_SDBFLAG_THREADSAFE)) == 0);
+
+ imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t));
+ if (imp == NULL)
+ return (ISC_R_NOMEMORY);
+ imp->methods = methods;
+ imp->driverdata = driverdata;
+ imp->flags = flags;
+ imp->mctx = NULL;
+ isc_mem_attach(mctx, &imp->mctx);
+ result = isc_mutex_init(&imp->driverlock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_mctx;
+
+ imp->dbimp = NULL;
+ result = dns_db_register(drivername, dns_sdb_create, imp, mctx,
+ &imp->dbimp);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_mutex;
+ *sdbimp = imp;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_mutex:
+ DESTROYLOCK(&imp->driverlock);
+ cleanup_mctx:
+ isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
+ return (result);
+}
+
+void
+dns_sdb_unregister(dns_sdbimplementation_t **sdbimp) {
+ dns_sdbimplementation_t *imp;
+ isc_mem_t *mctx;
+
+ REQUIRE(sdbimp != NULL && *sdbimp != NULL);
+
+ imp = *sdbimp;
+ dns_db_unregister(&imp->dbimp);
+ DESTROYLOCK(&imp->driverlock);
+
+ mctx = imp->mctx;
+ isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
+ isc_mem_detach(&mctx);
+
+ *sdbimp = NULL;
+}
+
+static inline unsigned int
+initial_size(unsigned int len) {
+ unsigned int size;
+
+ for (size = 1024; size < (64 * 1024); size *= 2)
+ if (len < size)
+ return (size);
+ return (65535);
+}
+
+isc_result_t
+dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval, dns_ttl_t ttl,
+ const unsigned char *rdatap, unsigned int rdlen)
+{
+ dns_rdatalist_t *rdatalist;
+ dns_rdata_t *rdata;
+ isc_buffer_t *rdatabuf = NULL;
+ isc_result_t result;
+ isc_mem_t *mctx;
+ isc_region_t region;
+
+ mctx = lookup->sdb->common.mctx;
+
+ rdatalist = ISC_LIST_HEAD(lookup->lists);
+ while (rdatalist != NULL) {
+ if (rdatalist->type == typeval)
+ break;
+ rdatalist = ISC_LIST_NEXT(rdatalist, link);
+ }
+
+ if (rdatalist == NULL) {
+ rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
+ if (rdatalist == NULL)
+ return (ISC_R_NOMEMORY);
+ rdatalist->rdclass = lookup->sdb->common.rdclass;
+ rdatalist->type = typeval;
+ rdatalist->covers = 0;
+ rdatalist->ttl = ttl;
+ ISC_LIST_INIT(rdatalist->rdata);
+ ISC_LINK_INIT(rdatalist, link);
+ ISC_LIST_APPEND(lookup->lists, rdatalist, link);
+ } else
+ if (rdatalist->ttl != ttl)
+ return (DNS_R_BADTTL);
+
+ rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
+ if (rdata == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = isc_buffer_allocate(mctx, &rdatabuf, rdlen);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ DE_CONST(rdatap, region.base);
+ region.length = rdlen;
+ isc_buffer_copyregion(rdatabuf, &region);
+ isc_buffer_usedregion(rdatabuf, &region);
+ dns_rdata_init(rdata);
+ dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
+ &region);
+ ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
+ ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
+ rdata = NULL;
+
+ failure:
+ if (rdata != NULL)
+ isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
+ return (result);
+}
+
+
+isc_result_t
+dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
+ const char *data)
+{
+ unsigned int datalen;
+ dns_rdatatype_t typeval;
+ isc_textregion_t r;
+ isc_lex_t *lex = NULL;
+ isc_result_t result;
+ unsigned char *p = NULL;
+ unsigned int size = 0; /* Init to suppress compiler warning */
+ isc_mem_t *mctx;
+ dns_sdbimplementation_t *imp;
+ dns_name_t *origin;
+ isc_buffer_t b;
+ isc_buffer_t rb;
+
+ REQUIRE(VALID_SDBLOOKUP(lookup));
+ REQUIRE(type != NULL);
+ REQUIRE(data != NULL);
+
+ mctx = lookup->sdb->common.mctx;
+
+ DE_CONST(type, r.base);
+ r.length = strlen(type);
+ result = dns_rdatatype_fromtext(&typeval, &r);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ imp = lookup->sdb->implementation;
+ if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
+ origin = &lookup->sdb->common.origin;
+ else
+ origin = dns_rootname;
+
+ result = isc_lex_create(mctx, 64, &lex);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ datalen = strlen(data);
+ size = initial_size(datalen);
+ for (;;) {
+ isc_buffer_init(&b, data, datalen);
+ isc_buffer_add(&b, datalen);
+ result = isc_lex_openbuffer(lex, &b);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ if (size >= 65535)
+ size = 65535;
+ p = isc_mem_get(mctx, size);
+ if (p == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto failure;
+ }
+ isc_buffer_init(&rb, p, size);
+ result = dns_rdata_fromtext(NULL,
+ lookup->sdb->common.rdclass,
+ typeval, lex,
+ origin, 0,
+ mctx, &rb,
+ &lookup->callbacks);
+ if (result != ISC_R_NOSPACE)
+ break;
+
+ /*
+ * Is the RR too big?
+ */
+ if (size >= 65535)
+ break;
+ isc_mem_put(mctx, p, size);
+ p = NULL;
+ size *= 2;
+ } while (result == ISC_R_NOSPACE);
+
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_sdb_putrdata(lookup, typeval, ttl,
+ isc_buffer_base(&rb),
+ isc_buffer_usedlength(&rb));
+ failure:
+ if (p != NULL)
+ isc_mem_put(mctx, p, size);
+ if (lex != NULL)
+ isc_lex_destroy(&lex);
+
+ return (result);
+}
+
+static isc_result_t
+getnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) {
+ dns_name_t *newname, *origin;
+ dns_fixedname_t fnewname;
+ dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db;
+ dns_sdbimplementation_t *imp = sdb->implementation;
+ dns_sdbnode_t *sdbnode;
+ isc_mem_t *mctx = sdb->common.mctx;
+ isc_buffer_t b;
+ isc_result_t result;
+
+ dns_fixedname_init(&fnewname);
+ newname = dns_fixedname_name(&fnewname);
+
+ if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
+ origin = &sdb->common.origin;
+ else
+ origin = dns_rootname;
+ isc_buffer_init(&b, name, strlen(name));
+ isc_buffer_add(&b, strlen(name));
+
+ result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (allnodes->common.relative_names) {
+ /* All names are relative to the root */
+ unsigned int nlabels = dns_name_countlabels(newname);
+ dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
+ }
+
+ sdbnode = ISC_LIST_HEAD(allnodes->nodelist);
+ if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) {
+ sdbnode = NULL;
+ result = createnode(sdb, &sdbnode);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t));
+ if (sdbnode->name == NULL) {
+ destroynode(sdbnode);
+ return (ISC_R_NOMEMORY);
+ }
+ dns_name_init(sdbnode->name, NULL);
+ result = dns_name_dup(newname, mctx, sdbnode->name);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, sdbnode->name, sizeof(dns_name_t));
+ destroynode(sdbnode);
+ return (result);
+ }
+ ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link);
+ if (allnodes->origin == NULL &&
+ dns_name_equal(newname, &sdb->common.origin))
+ allnodes->origin = sdbnode;
+ }
+ *nodep = sdbnode;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
+ const char *type, dns_ttl_t ttl, const char *data)
+{
+ isc_result_t result;
+ dns_sdbnode_t *sdbnode = NULL;
+ result = getnode(allnodes, name, &sdbnode);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ return (dns_sdb_putrr(sdbnode, type, ttl, data));
+}
+
+isc_result_t
+dns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
+ dns_rdatatype_t type, dns_ttl_t ttl,
+ const void *rdata, unsigned int rdlen)
+{
+ isc_result_t result;
+ dns_sdbnode_t *sdbnode = NULL;
+ result = getnode(allnodes, name, &sdbnode);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));
+}
+
+isc_result_t
+dns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
+ isc_uint32_t serial)
+{
+ char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
+ int n;
+
+ REQUIRE(mname != NULL);
+ REQUIRE(rname != NULL);
+
+ n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u",
+ mname, rname, serial,
+ SDB_DEFAULT_REFRESH, SDB_DEFAULT_RETRY,
+ SDB_DEFAULT_EXPIRE, SDB_DEFAULT_MINIMUM);
+ if (n >= (int)sizeof(str) || n < 0)
+ return (ISC_R_NOSPACE);
+ return (dns_sdb_putrr(lookup, "SOA", SDB_DEFAULT_TTL, str));
+}
+
+/*
+ * DB routines
+ */
+
+static void
+attach(dns_db_t *source, dns_db_t **targetp) {
+ dns_sdb_t *sdb = (dns_sdb_t *) source;
+
+ REQUIRE(VALID_SDB(sdb));
+
+ LOCK(&sdb->lock);
+ REQUIRE(sdb->references > 0);
+ sdb->references++;
+ UNLOCK(&sdb->lock);
+
+ *targetp = source;
+}
+
+static void
+destroy(dns_sdb_t *sdb) {
+ isc_mem_t *mctx;
+ dns_sdbimplementation_t *imp = sdb->implementation;
+
+ mctx = sdb->common.mctx;
+
+ if (imp->methods->destroy != NULL) {
+ MAYBE_LOCK(sdb);
+ imp->methods->destroy(sdb->zone, imp->driverdata,
+ &sdb->dbdata);
+ MAYBE_UNLOCK(sdb);
+ }
+
+ isc_mem_free(mctx, sdb->zone);
+ DESTROYLOCK(&sdb->lock);
+
+ sdb->common.magic = 0;
+ sdb->common.impmagic = 0;
+
+ dns_name_free(&sdb->common.origin, mctx);
+
+ isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
+ isc_mem_detach(&mctx);
+}
+
+static void
+detach(dns_db_t **dbp) {
+ dns_sdb_t *sdb = (dns_sdb_t *)(*dbp);
+ isc_boolean_t need_destroy = ISC_FALSE;
+
+ REQUIRE(VALID_SDB(sdb));
+ LOCK(&sdb->lock);
+ REQUIRE(sdb->references > 0);
+ sdb->references--;
+ if (sdb->references == 0)
+ need_destroy = ISC_TRUE;
+ UNLOCK(&sdb->lock);
+
+ if (need_destroy)
+ destroy(sdb);
+
+ *dbp = NULL;
+}
+
+static isc_result_t
+beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
+ UNUSED(db);
+ UNUSED(addp);
+ UNUSED(dbloadp);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+endload(dns_db_t *db, dns_dbload_t **dbloadp) {
+ UNUSED(db);
+ UNUSED(dbloadp);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
+ dns_masterformat_t masterformat) {
+ UNUSED(db);
+ UNUSED(version);
+ UNUSED(filename);
+ UNUSED(masterformat);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static void
+currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
+ REQUIRE(versionp != NULL && *versionp == NULL);
+
+ UNUSED(db);
+
+ *versionp = (void *) &dummy;
+ return;
+}
+
+static isc_result_t
+newversion(dns_db_t *db, dns_dbversion_t **versionp) {
+ UNUSED(db);
+ UNUSED(versionp);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static void
+attachversion(dns_db_t *db, dns_dbversion_t *source,
+ dns_dbversion_t **targetp)
+{
+ REQUIRE(source != NULL && source == (void *) &dummy);
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ UNUSED(db);
+ *targetp = source;
+ return;
+}
+
+static void
+closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
+ REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
+ REQUIRE(commit == ISC_FALSE);
+
+ UNUSED(db);
+ UNUSED(commit);
+
+ *versionp = NULL;
+}
+
+static isc_result_t
+createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) {
+ dns_sdbnode_t *node;
+ isc_result_t result;
+
+ node = isc_mem_get(sdb->common.mctx, sizeof(dns_sdbnode_t));
+ if (node == NULL)
+ return (ISC_R_NOMEMORY);
+
+ node->sdb = NULL;
+ attach((dns_db_t *)sdb, (dns_db_t **)&node->sdb);
+ ISC_LIST_INIT(node->lists);
+ ISC_LIST_INIT(node->buffers);
+ ISC_LINK_INIT(node, link);
+ node->name = NULL;
+ result = isc_mutex_init(&node->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(sdb->common.mctx, node, sizeof(dns_sdbnode_t));
+ return (result);
+ }
+ dns_rdatacallbacks_init(&node->callbacks);
+ node->references = 1;
+ node->magic = SDBLOOKUP_MAGIC;
+
+ *nodep = node;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+destroynode(dns_sdbnode_t *node) {
+ dns_rdatalist_t *list;
+ dns_rdata_t *rdata;
+ isc_buffer_t *b;
+ dns_sdb_t *sdb;
+ isc_mem_t *mctx;
+
+ sdb = node->sdb;
+ mctx = sdb->common.mctx;
+
+ while (!ISC_LIST_EMPTY(node->lists)) {
+ list = ISC_LIST_HEAD(node->lists);
+ while (!ISC_LIST_EMPTY(list->rdata)) {
+ rdata = ISC_LIST_HEAD(list->rdata);
+ ISC_LIST_UNLINK(list->rdata, rdata, link);
+ isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
+ }
+ ISC_LIST_UNLINK(node->lists, list, link);
+ isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
+ }
+
+ while (!ISC_LIST_EMPTY(node->buffers)) {
+ b = ISC_LIST_HEAD(node->buffers);
+ ISC_LIST_UNLINK(node->buffers, b, link);
+ isc_buffer_free(&b);
+ }
+
+ if (node->name != NULL) {
+ dns_name_free(node->name, mctx);
+ isc_mem_put(mctx, node->name, sizeof(dns_name_t));
+ }
+ DESTROYLOCK(&node->lock);
+ node->magic = 0;
+ isc_mem_put(mctx, node, sizeof(dns_sdbnode_t));
+ detach((dns_db_t **) (void *)&sdb);
+}
+
+static isc_result_t
+findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
+ dns_dbnode_t **nodep)
+{
+ dns_sdb_t *sdb = (dns_sdb_t *)db;
+ dns_sdbnode_t *node = NULL;
+ isc_result_t result;
+ isc_buffer_t b;
+ char namestr[DNS_NAME_MAXTEXT + 1];
+ isc_boolean_t isorigin;
+ dns_sdbimplementation_t *imp;
+
+ REQUIRE(VALID_SDB(sdb));
+ REQUIRE(create == ISC_FALSE);
+ REQUIRE(nodep != NULL && *nodep == NULL);
+
+ UNUSED(name);
+ UNUSED(create);
+
+ imp = sdb->implementation;
+
+ isc_buffer_init(&b, namestr, sizeof(namestr));
+ if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
+ dns_name_t relname;
+ unsigned int labels;
+
+ labels = dns_name_countlabels(name) -
+ dns_name_countlabels(&db->origin);
+ dns_name_init(&relname, NULL);
+ dns_name_getlabelsequence(name, 0, labels, &relname);
+ result = dns_name_totext(&relname, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else {
+ result = dns_name_totext(name, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ isc_buffer_putuint8(&b, 0);
+
+ result = createnode(sdb, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ isorigin = dns_name_equal(name, &sdb->common.origin);
+
+ MAYBE_LOCK(sdb);
+ result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata, node);
+ MAYBE_UNLOCK(sdb);
+ if (result != ISC_R_SUCCESS &&
+ !(result == ISC_R_NOTFOUND &&
+ isorigin && imp->methods->authority != NULL))
+ {
+ destroynode(node);
+ return (result);
+ }
+
+ if (isorigin && imp->methods->authority != NULL) {
+ MAYBE_LOCK(sdb);
+ result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
+ MAYBE_UNLOCK(sdb);
+ if (result != ISC_R_SUCCESS) {
+ destroynode(node);
+ return (result);
+ }
+ }
+
+ *nodep = node;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
+ dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
+ dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ dns_sdb_t *sdb = (dns_sdb_t *)db;
+ dns_dbnode_t *node = NULL;
+ dns_fixedname_t fname;
+ dns_rdataset_t xrdataset;
+ dns_name_t *xname;
+ unsigned int nlabels, olabels;
+ isc_result_t result;
+ unsigned int i;
+
+ REQUIRE(VALID_SDB(sdb));
+ REQUIRE(nodep == NULL || *nodep == NULL);
+ REQUIRE(version == NULL || version == (void *) &dummy);
+
+ UNUSED(options);
+ UNUSED(sdb);
+
+ if (!dns_name_issubdomain(name, &db->origin))
+ return (DNS_R_NXDOMAIN);
+
+ olabels = dns_name_countlabels(&db->origin);
+ nlabels = dns_name_countlabels(name);
+
+ dns_fixedname_init(&fname);
+ xname = dns_fixedname_name(&fname);
+
+ if (rdataset == NULL) {
+ dns_rdataset_init(&xrdataset);
+ rdataset = &xrdataset;
+ }
+
+ result = DNS_R_NXDOMAIN;
+
+ for (i = olabels; i <= nlabels; i++) {
+ /*
+ * Unless this is an explicit lookup at the origin, don't
+ * look at the origin.
+ */
+ if (i == olabels && i != nlabels)
+ continue;
+
+ /*
+ * Look up the next label.
+ */
+ dns_name_getlabelsequence(name, nlabels - i, i, xname);
+ result = findnode(db, xname, ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS) {
+ result = DNS_R_NXDOMAIN;
+ continue;
+ }
+
+ /*
+ * Look for a DNAME at the current label, unless this is
+ * the qname.
+ */
+ if (i < nlabels) {
+ result = findrdataset(db, node, version,
+ dns_rdatatype_dname,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS) {
+ result = DNS_R_DNAME;
+ break;
+ }
+ }
+
+ /*
+ * Look for an NS at the current label, unless this is the
+ * origin or glue is ok.
+ */
+ if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
+ result = findrdataset(db, node, version,
+ dns_rdatatype_ns,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS) {
+ if (i == nlabels && type == dns_rdatatype_any)
+ {
+ result = DNS_R_ZONECUT;
+ dns_rdataset_disassociate(rdataset);
+ if (sigrdataset != NULL)
+ dns_rdataset_disassociate
+ (sigrdataset);
+ } else
+ result = DNS_R_DELEGATION;
+ break;
+ }
+ }
+
+ /*
+ * If the current name is not the qname, add another label
+ * and try again.
+ */
+ if (i < nlabels) {
+ destroynode(node);
+ node = NULL;
+ continue;
+ }
+
+ /*
+ * If we're looking for ANY, we're done.
+ */
+ if (type == dns_rdatatype_any) {
+ result = ISC_R_SUCCESS;
+ break;
+ }
+
+ /*
+ * Look for the qtype.
+ */
+ result = findrdataset(db, node, version, type,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS)
+ break;
+
+ /*
+ * Look for a CNAME
+ */
+ if (type != dns_rdatatype_cname) {
+ result = findrdataset(db, node, version,
+ dns_rdatatype_cname,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS) {
+ result = DNS_R_CNAME;
+ break;
+ }
+ }
+
+ result = DNS_R_NXRRSET;
+ break;
+ }
+
+ if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+
+ if (foundname != NULL) {
+ isc_result_t xresult;
+
+ xresult = dns_name_copy(xname, foundname, NULL);
+ if (xresult != ISC_R_SUCCESS) {
+ if (node != NULL)
+ destroynode(node);
+ if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+ return (DNS_R_BADDB);
+ }
+ }
+
+ if (nodep != NULL)
+ *nodep = node;
+ else if (node != NULL)
+ detachnode(db, &node);
+
+ return (result);
+}
+
+static isc_result_t
+findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
+ isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ UNUSED(db);
+ UNUSED(name);
+ UNUSED(options);
+ UNUSED(now);
+ UNUSED(nodep);
+ UNUSED(foundname);
+ UNUSED(rdataset);
+ UNUSED(sigrdataset);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static void
+attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
+ dns_sdb_t *sdb = (dns_sdb_t *)db;
+ dns_sdbnode_t *node = (dns_sdbnode_t *)source;
+
+ REQUIRE(VALID_SDB(sdb));
+
+ UNUSED(sdb);
+
+ LOCK(&node->lock);
+ INSIST(node->references > 0);
+ node->references++;
+ INSIST(node->references != 0); /* Catch overflow. */
+ UNLOCK(&node->lock);
+
+ *targetp = source;
+}
+
+static void
+detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
+ dns_sdb_t *sdb = (dns_sdb_t *)db;
+ dns_sdbnode_t *node;
+ isc_boolean_t need_destroy = ISC_FALSE;
+
+ REQUIRE(VALID_SDB(sdb));
+ REQUIRE(targetp != NULL && *targetp != NULL);
+
+ UNUSED(sdb);
+
+ node = (dns_sdbnode_t *)(*targetp);
+
+ LOCK(&node->lock);
+ INSIST(node->references > 0);
+ node->references--;
+ if (node->references == 0)
+ need_destroy = ISC_TRUE;
+ UNLOCK(&node->lock);
+
+ if (need_destroy)
+ destroynode(node);
+
+ *targetp = NULL;
+}
+
+static isc_result_t
+expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(now);
+ INSIST(0);
+ return (ISC_R_UNEXPECTED);
+}
+
+static void
+printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(out);
+ return;
+}
+
+static isc_result_t
+createiterator(dns_db_t *db, isc_boolean_t relative_names,
+ dns_dbiterator_t **iteratorp)
+{
+ dns_sdb_t *sdb = (dns_sdb_t *)db;
+ sdb_dbiterator_t *sdbiter;
+ dns_sdbimplementation_t *imp = sdb->implementation;
+ isc_result_t result;
+
+ REQUIRE(VALID_SDB(sdb));
+
+ if (imp->methods->allnodes == NULL)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
+ if (sdbiter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ sdbiter->common.methods = &dbiterator_methods;
+ sdbiter->common.db = NULL;
+ dns_db_attach(db, &sdbiter->common.db);
+ sdbiter->common.relative_names = relative_names;
+ sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
+ ISC_LIST_INIT(sdbiter->nodelist);
+ sdbiter->current = NULL;
+ sdbiter->origin = NULL;
+
+ MAYBE_LOCK(sdb);
+ result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
+ MAYBE_UNLOCK(sdb);
+ if (result != ISC_R_SUCCESS) {
+ dbiterator_destroy((dns_dbiterator_t **) (void *)&sdbiter);
+ return (result);
+ }
+
+ if (sdbiter->origin != NULL) {
+ ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
+ ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
+ }
+
+ *iteratorp = (dns_dbiterator_t *)sdbiter;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers,
+ isc_stdtime_t now, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset)
+{
+ dns_rdatalist_t *list;
+ dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
+
+ REQUIRE(VALID_SDBNODE(node));
+
+ UNUSED(db);
+ UNUSED(version);
+ UNUSED(covers);
+ UNUSED(now);
+ UNUSED(sigrdataset);
+
+ if (type == dns_rdatatype_rrsig)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ list = ISC_LIST_HEAD(sdbnode->lists);
+ while (list != NULL) {
+ if (list->type == type)
+ break;
+ list = ISC_LIST_NEXT(list, link);
+ }
+ if (list == NULL)
+ return (ISC_R_NOTFOUND);
+
+ list_tordataset(list, db, node, rdataset);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
+{
+ sdb_rdatasetiter_t *iterator;
+
+ REQUIRE(version == NULL || version == &dummy);
+
+ UNUSED(version);
+ UNUSED(now);
+
+ iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
+ if (iterator == NULL)
+ return (ISC_R_NOMEMORY);
+
+ iterator->common.magic = DNS_RDATASETITER_MAGIC;
+ iterator->common.methods = &rdatasetiter_methods;
+ iterator->common.db = db;
+ iterator->common.node = NULL;
+ attachnode(db, node, &iterator->common.node);
+ iterator->common.version = version;
+ iterator->common.now = now;
+
+ *iteratorp = (dns_rdatasetiter_t *)iterator;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
+ dns_rdataset_t *addedrdataset)
+{
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(version);
+ UNUSED(now);
+ UNUSED(rdataset);
+ UNUSED(options);
+ UNUSED(addedrdataset);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdataset_t *rdataset, unsigned int options,
+ dns_rdataset_t *newrdataset)
+{
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(version);
+ UNUSED(rdataset);
+ UNUSED(options);
+ UNUSED(newrdataset);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers)
+{
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(version);
+ UNUSED(type);
+ UNUSED(covers);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_boolean_t
+issecure(dns_db_t *db) {
+ UNUSED(db);
+
+ return (ISC_FALSE);
+}
+
+static unsigned int
+nodecount(dns_db_t *db) {
+ UNUSED(db);
+
+ return (0);
+}
+
+static isc_boolean_t
+ispersistent(dns_db_t *db) {
+ UNUSED(db);
+ return (ISC_TRUE);
+}
+
+static void
+overmem(dns_db_t *db, isc_boolean_t overmem) {
+ UNUSED(db);
+ UNUSED(overmem);
+}
+
+static void
+settask(dns_db_t *db, isc_task_t *task) {
+ UNUSED(db);
+ UNUSED(task);
+}
+
+
+static dns_dbmethods_t sdb_methods = {
+ attach,
+ detach,
+ beginload,
+ endload,
+ dump,
+ currentversion,
+ newversion,
+ attachversion,
+ closeversion,
+ findnode,
+ find,
+ findzonecut,
+ attachnode,
+ detachnode,
+ expirenode,
+ printnode,
+ createiterator,
+ findrdataset,
+ allrdatasets,
+ addrdataset,
+ subtractrdataset,
+ deleterdataset,
+ issecure,
+ nodecount,
+ ispersistent,
+ overmem,
+ settask,
+ NULL
+};
+
+static isc_result_t
+dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
+ dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
+ void *driverarg, dns_db_t **dbp)
+{
+ dns_sdb_t *sdb;
+ isc_result_t result;
+ char zonestr[DNS_NAME_MAXTEXT + 1];
+ isc_buffer_t b;
+ dns_sdbimplementation_t *imp;
+
+ REQUIRE(driverarg != NULL);
+
+ imp = driverarg;
+
+ if (type != dns_dbtype_zone)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
+ if (sdb == NULL)
+ return (ISC_R_NOMEMORY);
+ memset(sdb, 0, sizeof(dns_sdb_t));
+
+ dns_name_init(&sdb->common.origin, NULL);
+ sdb->common.attributes = 0;
+ sdb->common.methods = &sdb_methods;
+ sdb->common.rdclass = rdclass;
+ sdb->common.mctx = NULL;
+ sdb->implementation = imp;
+
+ isc_mem_attach(mctx, &sdb->common.mctx);
+
+ result = isc_mutex_init(&sdb->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_mctx;
+
+ result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+
+ isc_buffer_init(&b, zonestr, sizeof(zonestr));
+ result = dns_name_totext(origin, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_origin;
+ isc_buffer_putuint8(&b, 0);
+
+ sdb->zone = isc_mem_strdup(mctx, zonestr);
+ if (sdb->zone == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_origin;
+ }
+
+ sdb->dbdata = NULL;
+ if (imp->methods->create != NULL) {
+ MAYBE_LOCK(sdb);
+ result = imp->methods->create(sdb->zone, argc, argv,
+ imp->driverdata, &sdb->dbdata);
+ MAYBE_UNLOCK(sdb);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_zonestr;
+ }
+
+ sdb->references = 1;
+
+ sdb->common.magic = DNS_DB_MAGIC;
+ sdb->common.impmagic = SDB_MAGIC;
+
+ *dbp = (dns_db_t *)sdb;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_zonestr:
+ isc_mem_free(mctx, sdb->zone);
+ cleanup_origin:
+ dns_name_free(&sdb->common.origin, mctx);
+ cleanup_lock:
+ isc_mutex_destroy(&sdb->lock);
+ cleanup_mctx:
+ isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
+ isc_mem_detach(&mctx);
+
+ return (result);
+}
+
+
+/*
+ * Rdataset Methods
+ */
+
+static void
+disassociate(dns_rdataset_t *rdataset) {
+ dns_dbnode_t *node = rdataset->private5;
+ dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
+ dns_db_t *db = (dns_db_t *) sdbnode->sdb;
+
+ detachnode(db, &node);
+ isc__rdatalist_disassociate(rdataset);
+}
+
+static void
+rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
+ dns_dbnode_t *node = source->private5;
+ dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
+ dns_db_t *db = (dns_db_t *) sdbnode->sdb;
+ dns_dbnode_t *tempdb = NULL;
+
+ isc__rdatalist_clone(source, target);
+ attachnode(db, node, &tempdb);
+ source->private5 = tempdb;
+}
+
+static dns_rdatasetmethods_t methods = {
+ disassociate,
+ isc__rdatalist_first,
+ isc__rdatalist_next,
+ isc__rdatalist_current,
+ rdataset_clone,
+ isc__rdatalist_count,
+ isc__rdatalist_addnoqname,
+ isc__rdatalist_getnoqname,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void
+list_tordataset(dns_rdatalist_t *rdatalist,
+ dns_db_t *db, dns_dbnode_t *node,
+ dns_rdataset_t *rdataset)
+{
+ /*
+ * The sdb rdataset is an rdatalist with some additions.
+ * - private1 & private2 are used by the rdatalist.
+ * - private3 & private 4 are unused.
+ * - private5 is the node.
+ */
+
+ /* This should never fail. */
+ RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
+ ISC_R_SUCCESS);
+
+ rdataset->methods = &methods;
+ dns_db_attachnode(db, node, &rdataset->private5);
+}
+
+/*
+ * Database Iterator Methods
+ */
+static void
+dbiterator_destroy(dns_dbiterator_t **iteratorp) {
+ sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
+ dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
+
+ while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
+ dns_sdbnode_t *node;
+ node = ISC_LIST_HEAD(sdbiter->nodelist);
+ ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
+ destroynode(node);
+ }
+
+ dns_db_detach(&sdbiter->common.db);
+ isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
+
+ *iteratorp = NULL;
+}
+
+static isc_result_t
+dbiterator_first(dns_dbiterator_t *iterator) {
+ sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
+
+ sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
+ if (sdbiter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_last(dns_dbiterator_t *iterator) {
+ sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
+
+ sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
+ if (sdbiter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
+ sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
+
+ sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
+ while (sdbiter->current != NULL)
+ if (dns_name_equal(sdbiter->current->name, name))
+ return (ISC_R_SUCCESS);
+ return (ISC_R_NOTFOUND);
+}
+
+static isc_result_t
+dbiterator_prev(dns_dbiterator_t *iterator) {
+ sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
+
+ sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
+ if (sdbiter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_next(dns_dbiterator_t *iterator) {
+ sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
+
+ sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
+ if (sdbiter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
+ dns_name_t *name)
+{
+ sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
+
+ attachnode(iterator->db, sdbiter->current, nodep);
+ if (name != NULL)
+ return (dns_name_copy(sdbiter->current->name, name, NULL));
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_pause(dns_dbiterator_t *iterator) {
+ UNUSED(iterator);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
+ UNUSED(iterator);
+ return (dns_name_copy(dns_rootname, name, NULL));
+}
+
+/*
+ * Rdataset Iterator Methods
+ */
+
+static void
+rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
+ sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
+ detachnode(sdbiterator->common.db, &sdbiterator->common.node);
+ isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
+ sizeof(sdb_rdatasetiter_t));
+ *iteratorp = NULL;
+}
+
+static isc_result_t
+rdatasetiter_first(dns_rdatasetiter_t *iterator) {
+ sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
+ dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
+
+ if (ISC_LIST_EMPTY(sdbnode->lists))
+ return (ISC_R_NOMORE);
+ sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+rdatasetiter_next(dns_rdatasetiter_t *iterator) {
+ sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
+
+ sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
+ if (sdbiterator->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static void
+rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
+ sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
+
+ list_tordataset(sdbiterator->current, iterator->db, iterator->node,
+ rdataset);
+}
diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c
new file mode 100644
index 0000000..b91f825
--- /dev/null
+++ b/lib/dns/sdlz.c
@@ -0,0 +1,1786 @@
+/*
+ * Portions Copyright (C) 2005-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1999-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER 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) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER 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 development of Dynamically Loadable Zones (DLZ) for Bind 9 was
+ * conceived and contributed by Rob Butler.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: sdlz.c,v 1.2.2.11 2007/08/28 07:20:05 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+#include <string.h>
+
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/log.h>
+#include <isc/rwlock.h>
+#include <isc/string.h>
+#include <isc/util.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/region.h>
+
+#include <dns/callbacks.h>
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/dlz.h>
+#include <dns/fixedname.h>
+#include <dns/log.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/rdatatype.h>
+#include <dns/result.h>
+#include <dns/master.h>
+#include <dns/sdlz.h>
+#include <dns/types.h>
+
+#include "rdatalist_p.h"
+
+/*
+ * Private Types
+ */
+
+struct dns_sdlzimplementation {
+ const dns_sdlzmethods_t *methods;
+ isc_mem_t *mctx;
+ void *driverarg;
+ unsigned int flags;
+ isc_mutex_t driverlock;
+ dns_dlzimplementation_t *dlz_imp;
+};
+
+struct dns_sdlz_db {
+ /* Unlocked */
+ dns_db_t common;
+ void *dbdata;
+ dns_sdlzimplementation_t *dlzimp;
+ isc_mutex_t refcnt_lock;
+ /* Locked */
+ unsigned int references;
+};
+
+struct dns_sdlzlookup {
+ /* Unlocked */
+ unsigned int magic;
+ dns_sdlz_db_t *sdlz;
+ ISC_LIST(dns_rdatalist_t) lists;
+ ISC_LIST(isc_buffer_t) buffers;
+ dns_name_t *name;
+ ISC_LINK(dns_sdlzlookup_t) link;
+ isc_mutex_t lock;
+ dns_rdatacallbacks_t callbacks;
+ /* Locked */
+ unsigned int references;
+};
+
+typedef struct dns_sdlzlookup dns_sdlznode_t;
+
+struct dns_sdlzallnodes {
+ dns_dbiterator_t common;
+ ISC_LIST(dns_sdlznode_t) nodelist;
+ dns_sdlznode_t *current;
+ dns_sdlznode_t *origin;
+};
+
+typedef dns_sdlzallnodes_t sdlz_dbiterator_t;
+
+typedef struct sdlz_rdatasetiter {
+ dns_rdatasetiter_t common;
+ dns_rdatalist_t *current;
+} sdlz_rdatasetiter_t;
+
+
+#define SDLZDB_MAGIC ISC_MAGIC('D', 'L', 'Z', 'S')
+
+/*
+ * Note that "impmagic" is not the first four bytes of the struct, so
+ * ISC_MAGIC_VALID cannot be used.
+ */
+
+#define VALID_SDLZDB(sdlzdb) ((sdlzdb) != NULL && \
+ (sdlzdb)->common.impmagic == SDLZDB_MAGIC)
+
+#define SDLZLOOKUP_MAGIC ISC_MAGIC('D','L','Z','L')
+#define VALID_SDLZLOOKUP(sdlzl) ISC_MAGIC_VALID(sdlzl, SDLZLOOKUP_MAGIC)
+#define VALID_SDLZNODE(sdlzn) VALID_SDLZLOOKUP(sdlzn)
+
+/* These values are taken from RFC 1537 */
+#define SDLZ_DEFAULT_REFRESH (60 * 60 * 8)
+#define SDLZ_DEFAULT_RETRY (60 * 60 * 2)
+#define SDLZ_DEFAULT_EXPIRE (60 * 60 * 24 * 7)
+#define SDLZ_DEFAULT_MINIMUM (60 * 60 * 24)
+
+/* This is a reasonable value */
+#define SDLZ_DEFAULT_TTL (60 * 60 * 24)
+
+static int dummy;
+
+#ifdef __COVERITY__
+#define MAYBE_LOCK(imp) LOCK(&imp->driverlock)
+#define MAYBE_UNLOCK(imp) UNLOCK(&imp->driverlock)
+#else
+#define MAYBE_LOCK(imp) \
+ do { \
+ unsigned int flags = imp->flags; \
+ if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
+ LOCK(&imp->driverlock); \
+ } while (0)
+
+#define MAYBE_UNLOCK(imp) \
+ do { \
+ unsigned int flags = imp->flags; \
+ if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
+ UNLOCK(&imp->driverlock); \
+ } while (0)
+#endif
+
+/*
+ * Forward references. Try to keep these to a minimum.
+ */
+
+static void list_tordataset(dns_rdatalist_t *rdatalist,
+ dns_db_t *db, dns_dbnode_t *node,
+ dns_rdataset_t *rdataset);
+
+static void detachnode(dns_db_t *db, dns_dbnode_t **targetp);
+
+static void dbiterator_destroy(dns_dbiterator_t **iteratorp);
+static isc_result_t dbiterator_first(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_last(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_seek(dns_dbiterator_t *iterator,
+ dns_name_t *name);
+static isc_result_t dbiterator_prev(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_next(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_current(dns_dbiterator_t *iterator,
+ dns_dbnode_t **nodep,
+ dns_name_t *name);
+static isc_result_t dbiterator_pause(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_origin(dns_dbiterator_t *iterator,
+ dns_name_t *name);
+
+static dns_dbiteratormethods_t dbiterator_methods = {
+ dbiterator_destroy,
+ dbiterator_first,
+ dbiterator_last,
+ dbiterator_seek,
+ dbiterator_prev,
+ dbiterator_next,
+ dbiterator_current,
+ dbiterator_pause,
+ dbiterator_origin
+};
+
+/*
+ * Utility functions
+ */
+
+/*% Converts the input string to lowercase, in place. */
+
+static void
+dns_sdlz_tolower(char *str) {
+
+ unsigned int len = strlen(str);
+ unsigned int i;
+
+ for (i = 0; i < len; i++) {
+ if (str[i] >= 'A' && str[i] <= 'Z')
+ str[i] += 32;
+ }
+
+}
+
+static inline unsigned int
+initial_size(const char *data) {
+ unsigned int len = (strlen(data) / 64) + 1;
+ return (len * 64 + 64);
+}
+
+/*
+ * Rdataset Iterator Methods. These methods were "borrowed" from the SDB
+ * driver interface. See the SDB driver interface documentation for more info.
+ */
+
+static void
+rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
+ sdlz_rdatasetiter_t *sdlziterator =
+ (sdlz_rdatasetiter_t *)(*iteratorp);
+
+ detachnode(sdlziterator->common.db, &sdlziterator->common.node);
+ isc_mem_put(sdlziterator->common.db->mctx, sdlziterator,
+ sizeof(sdlz_rdatasetiter_t));
+ *iteratorp = NULL;
+}
+
+static isc_result_t
+rdatasetiter_first(dns_rdatasetiter_t *iterator) {
+ sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
+ dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)iterator->node;
+
+ if (ISC_LIST_EMPTY(sdlznode->lists))
+ return (ISC_R_NOMORE);
+ sdlziterator->current = ISC_LIST_HEAD(sdlznode->lists);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+rdatasetiter_next(dns_rdatasetiter_t *iterator) {
+ sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
+
+ sdlziterator->current = ISC_LIST_NEXT(sdlziterator->current, link);
+ if (sdlziterator->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static void
+rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
+ sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
+
+ list_tordataset(sdlziterator->current, iterator->db, iterator->node,
+ rdataset);
+}
+
+static dns_rdatasetitermethods_t rdatasetiter_methods = {
+ rdatasetiter_destroy,
+ rdatasetiter_first,
+ rdatasetiter_next,
+ rdatasetiter_current
+};
+
+/*
+ * DB routines. These methods were "borrowed" from the SDB driver interface.
+ * See the SDB driver interface documentation for more info.
+ */
+
+static void
+attach(dns_db_t *source, dns_db_t **targetp) {
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *) source;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+
+ LOCK(&sdlz->refcnt_lock);
+ REQUIRE(sdlz->references > 0);
+ sdlz->references++;
+ UNLOCK(&sdlz->refcnt_lock);
+
+ *targetp = source;
+}
+
+static void
+destroy(dns_sdlz_db_t *sdlz) {
+ isc_mem_t *mctx;
+ mctx = sdlz->common.mctx;
+
+ sdlz->common.magic = 0;
+ sdlz->common.impmagic = 0;
+
+ isc_mutex_destroy(&sdlz->refcnt_lock);
+
+ dns_name_free(&sdlz->common.origin, mctx);
+
+ isc_mem_put(mctx, sdlz, sizeof(dns_sdlz_db_t));
+ isc_mem_detach(&mctx);
+}
+
+static void
+detach(dns_db_t **dbp) {
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)(*dbp);
+ isc_boolean_t need_destroy = ISC_FALSE;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+ LOCK(&sdlz->refcnt_lock);
+ REQUIRE(sdlz->references > 0);
+ sdlz->references--;
+ if (sdlz->references == 0)
+ need_destroy = ISC_TRUE;
+ UNLOCK(&sdlz->refcnt_lock);
+
+ if (need_destroy)
+ destroy(sdlz);
+
+ *dbp = NULL;
+}
+
+static isc_result_t
+beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
+ UNUSED(db);
+ UNUSED(addp);
+ UNUSED(dbloadp);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+endload(dns_db_t *db, dns_dbload_t **dbloadp) {
+ UNUSED(db);
+ UNUSED(dbloadp);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
+ dns_masterformat_t masterformat)
+{
+ UNUSED(db);
+ UNUSED(version);
+ UNUSED(filename);
+ UNUSED(masterformat);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static void
+currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
+ REQUIRE(versionp != NULL && *versionp == NULL);
+
+ UNUSED(db);
+
+ *versionp = (void *) &dummy;
+ return;
+}
+
+static isc_result_t
+newversion(dns_db_t *db, dns_dbversion_t **versionp) {
+ UNUSED(db);
+ UNUSED(versionp);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static void
+attachversion(dns_db_t *db, dns_dbversion_t *source,
+ dns_dbversion_t **targetp)
+{
+ REQUIRE(source != NULL && source == (void *) &dummy);
+
+ UNUSED(db);
+ UNUSED(source);
+ UNUSED(targetp);
+ *targetp = source;
+}
+
+static void
+closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
+ REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
+ REQUIRE(commit == ISC_FALSE);
+
+ UNUSED(db);
+ UNUSED(commit);
+
+ *versionp = NULL;
+}
+
+static isc_result_t
+createnode(dns_sdlz_db_t *sdlz, dns_sdlznode_t **nodep) {
+ dns_sdlznode_t *node;
+ isc_result_t result;
+
+ node = isc_mem_get(sdlz->common.mctx, sizeof(dns_sdlznode_t));
+ if (node == NULL)
+ return (ISC_R_NOMEMORY);
+
+ node->sdlz = NULL;
+ attach((dns_db_t *)sdlz, (dns_db_t **)&node->sdlz);
+ ISC_LIST_INIT(node->lists);
+ ISC_LIST_INIT(node->buffers);
+ ISC_LINK_INIT(node, link);
+ node->name = NULL;
+ result = isc_mutex_init(&node->lock);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_mutex_init() failed: %s",
+ isc_result_totext(result));
+ isc_mem_put(sdlz->common.mctx, node, sizeof(dns_sdlznode_t));
+ return (ISC_R_UNEXPECTED);
+ }
+ dns_rdatacallbacks_init(&node->callbacks);
+ node->references = 1;
+ node->magic = SDLZLOOKUP_MAGIC;
+
+ *nodep = node;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+destroynode(dns_sdlznode_t *node) {
+ dns_rdatalist_t *list;
+ dns_rdata_t *rdata;
+ isc_buffer_t *b;
+ dns_sdlz_db_t *sdlz;
+ dns_db_t *db;
+ isc_mem_t *mctx;
+
+ sdlz = node->sdlz;
+ mctx = sdlz->common.mctx;
+
+ while (!ISC_LIST_EMPTY(node->lists)) {
+ list = ISC_LIST_HEAD(node->lists);
+ while (!ISC_LIST_EMPTY(list->rdata)) {
+ rdata = ISC_LIST_HEAD(list->rdata);
+ ISC_LIST_UNLINK(list->rdata, rdata, link);
+ isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
+ }
+ ISC_LIST_UNLINK(node->lists, list, link);
+ isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
+ }
+
+ while (!ISC_LIST_EMPTY(node->buffers)) {
+ b = ISC_LIST_HEAD(node->buffers);
+ ISC_LIST_UNLINK(node->buffers, b, link);
+ isc_buffer_free(&b);
+ }
+
+ if (node->name != NULL) {
+ dns_name_free(node->name, mctx);
+ isc_mem_put(mctx, node->name, sizeof(dns_name_t));
+ }
+ DESTROYLOCK(&node->lock);
+ node->magic = 0;
+ isc_mem_put(mctx, node, sizeof(dns_sdlznode_t));
+ db = &sdlz->common;
+ detach(&db);
+}
+
+static isc_result_t
+findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
+ dns_dbnode_t **nodep)
+{
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
+ dns_sdlznode_t *node = NULL;
+ isc_result_t result;
+ isc_buffer_t b;
+ char namestr[DNS_NAME_MAXTEXT + 1];
+ isc_buffer_t b2;
+ char zonestr[DNS_NAME_MAXTEXT + 1];
+ isc_boolean_t isorigin;
+ dns_sdlzauthorityfunc_t authority;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+ REQUIRE(create == ISC_FALSE);
+ REQUIRE(nodep != NULL && *nodep == NULL);
+
+ UNUSED(name);
+ UNUSED(create);
+
+ isc_buffer_init(&b, namestr, sizeof(namestr));
+ if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVEOWNER) != 0) {
+ dns_name_t relname;
+ unsigned int labels;
+
+ labels = dns_name_countlabels(name) -
+ dns_name_countlabels(&db->origin);
+ dns_name_init(&relname, NULL);
+ dns_name_getlabelsequence(name, 0, labels, &relname);
+ result = dns_name_totext(&relname, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else {
+ result = dns_name_totext(name, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ isc_buffer_putuint8(&b, 0);
+
+ isc_buffer_init(&b2, zonestr, sizeof(zonestr));
+ result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b2);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_putuint8(&b2, 0);
+
+ result = createnode(sdlz, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ isorigin = dns_name_equal(name, &sdlz->common.origin);
+
+ /* make sure strings are always lowercase */
+ dns_sdlz_tolower(zonestr);
+ dns_sdlz_tolower(namestr);
+
+ MAYBE_LOCK(sdlz->dlzimp);
+
+ /* try to lookup the host (namestr) */
+ result = sdlz->dlzimp->methods->lookup(zonestr, namestr,
+ sdlz->dlzimp->driverarg,
+ sdlz->dbdata, node);
+
+ /*
+ * if the host (namestr) was not found, try to lookup a
+ * "wildcard" host.
+ */
+ if (result != ISC_R_SUCCESS) {
+ result = sdlz->dlzimp->methods->lookup(zonestr, "*",
+ sdlz->dlzimp->driverarg,
+ sdlz->dbdata, node);
+ }
+
+ MAYBE_UNLOCK(sdlz->dlzimp);
+
+ if (result != ISC_R_SUCCESS && !isorigin) {
+ destroynode(node);
+ return (result);
+ }
+
+ if (isorigin && sdlz->dlzimp->methods->authority != NULL) {
+ MAYBE_LOCK(sdlz->dlzimp);
+ authority = sdlz->dlzimp->methods->authority;
+ result = (*authority)(zonestr, sdlz->dlzimp->driverarg,
+ sdlz->dbdata, node);
+ MAYBE_UNLOCK(sdlz->dlzimp);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_NOTIMPLEMENTED) {
+ destroynode(node);
+ return (result);
+ }
+ }
+
+ *nodep = node;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
+ isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ UNUSED(db);
+ UNUSED(name);
+ UNUSED(options);
+ UNUSED(now);
+ UNUSED(nodep);
+ UNUSED(foundname);
+ UNUSED(rdataset);
+ UNUSED(sigrdataset);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static void
+attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
+ dns_sdlznode_t *node = (dns_sdlznode_t *)source;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+
+ UNUSED(sdlz);
+
+ LOCK(&node->lock);
+ INSIST(node->references > 0);
+ node->references++;
+ INSIST(node->references != 0); /* Catch overflow. */
+ UNLOCK(&node->lock);
+
+ *targetp = source;
+}
+
+static void
+detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
+ dns_sdlznode_t *node;
+ isc_boolean_t need_destroy = ISC_FALSE;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+ REQUIRE(targetp != NULL && *targetp != NULL);
+
+ UNUSED(sdlz);
+
+ node = (dns_sdlznode_t *)(*targetp);
+
+ LOCK(&node->lock);
+ INSIST(node->references > 0);
+ node->references--;
+ if (node->references == 0)
+ need_destroy = ISC_TRUE;
+ UNLOCK(&node->lock);
+
+ if (need_destroy)
+ destroynode(node);
+
+ *targetp = NULL;
+}
+
+static isc_result_t
+expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(now);
+ INSIST(0);
+ return (ISC_R_UNEXPECTED);
+}
+
+static void
+printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(out);
+ return;
+}
+
+static isc_result_t
+createiterator(dns_db_t *db, isc_boolean_t relative_names,
+ dns_dbiterator_t **iteratorp)
+{
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
+ sdlz_dbiterator_t *sdlziter;
+ isc_result_t result;
+ isc_buffer_t b;
+ char zonestr[DNS_NAME_MAXTEXT + 1];
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+
+ if (sdlz->dlzimp->methods->allnodes == NULL)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ isc_buffer_init(&b, zonestr, sizeof(zonestr));
+ result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_putuint8(&b, 0);
+
+ sdlziter = isc_mem_get(sdlz->common.mctx, sizeof(sdlz_dbiterator_t));
+ if (sdlziter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ sdlziter->common.methods = &dbiterator_methods;
+ sdlziter->common.db = NULL;
+ dns_db_attach(db, &sdlziter->common.db);
+ sdlziter->common.relative_names = relative_names;
+ sdlziter->common.magic = DNS_DBITERATOR_MAGIC;
+ ISC_LIST_INIT(sdlziter->nodelist);
+ sdlziter->current = NULL;
+ sdlziter->origin = NULL;
+
+ /* make sure strings are always lowercase */
+ dns_sdlz_tolower(zonestr);
+
+ MAYBE_LOCK(sdlz->dlzimp);
+ result = sdlz->dlzimp->methods->allnodes(zonestr,
+ sdlz->dlzimp->driverarg,
+ sdlz->dbdata, sdlziter);
+ MAYBE_UNLOCK(sdlz->dlzimp);
+ if (result != ISC_R_SUCCESS) {
+ dns_dbiterator_t *iter = &sdlziter->common;
+ dbiterator_destroy(&iter);
+ return (result);
+ }
+
+ if (sdlziter->origin != NULL) {
+ ISC_LIST_UNLINK(sdlziter->nodelist, sdlziter->origin, link);
+ ISC_LIST_PREPEND(sdlziter->nodelist, sdlziter->origin, link);
+ }
+
+ *iteratorp = (dns_dbiterator_t *)sdlziter;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers,
+ isc_stdtime_t now, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset)
+{
+ dns_rdatalist_t *list;
+ dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
+
+ REQUIRE(VALID_SDLZNODE(node));
+
+ UNUSED(db);
+ UNUSED(version);
+ UNUSED(covers);
+ UNUSED(now);
+ UNUSED(sigrdataset);
+
+ if (type == dns_rdatatype_sig || type == dns_rdatatype_rrsig)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ list = ISC_LIST_HEAD(sdlznode->lists);
+ while (list != NULL) {
+ if (list->type == type)
+ break;
+ list = ISC_LIST_NEXT(list, link);
+ }
+ if (list == NULL)
+ return (ISC_R_NOTFOUND);
+
+ list_tordataset(list, db, node, rdataset);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
+ dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
+ dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
+ dns_dbnode_t *node = NULL;
+ dns_fixedname_t fname;
+ dns_rdataset_t xrdataset;
+ dns_name_t *xname;
+ unsigned int nlabels, olabels;
+ isc_result_t result;
+ unsigned int i;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+ REQUIRE(nodep == NULL || *nodep == NULL);
+ REQUIRE(version == NULL || version == (void *) &dummy);
+
+ UNUSED(options);
+ UNUSED(sdlz);
+
+ if (!dns_name_issubdomain(name, &db->origin))
+ return (DNS_R_NXDOMAIN);
+
+ olabels = dns_name_countlabels(&db->origin);
+ nlabels = dns_name_countlabels(name);
+
+ dns_fixedname_init(&fname);
+ xname = dns_fixedname_name(&fname);
+
+ if (rdataset == NULL) {
+ dns_rdataset_init(&xrdataset);
+ rdataset = &xrdataset;
+ }
+
+ result = DNS_R_NXDOMAIN;
+
+ for (i = olabels; i <= nlabels; i++) {
+ /*
+ * Unless this is an explicit lookup at the origin, don't
+ * look at the origin.
+ */
+ if (i == olabels && i != nlabels)
+ continue;
+
+ /*
+ * Look up the next label.
+ */
+ dns_name_getlabelsequence(name, nlabels - i, i, xname);
+ result = findnode(db, xname, ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS) {
+ result = DNS_R_NXDOMAIN;
+ continue;
+ }
+
+ /*
+ * Look for a DNAME at the current label, unless this is
+ * the qname.
+ */
+ if (i < nlabels) {
+ result = findrdataset(db, node, version,
+ dns_rdatatype_dname,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS) {
+ result = DNS_R_DNAME;
+ break;
+ }
+ }
+
+ /*
+ * Look for an NS at the current label, unless this is the
+ * origin or glue is ok.
+ */
+ if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
+ result = findrdataset(db, node, version,
+ dns_rdatatype_ns,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS) {
+ if (i == nlabels && type == dns_rdatatype_any)
+ {
+ result = DNS_R_ZONECUT;
+ dns_rdataset_disassociate(rdataset);
+ if (sigrdataset != NULL)
+ dns_rdataset_disassociate
+ (sigrdataset);
+ } else
+ result = DNS_R_DELEGATION;
+ break;
+ }
+ }
+
+ /*
+ * If the current name is not the qname, add another label
+ * and try again.
+ */
+ if (i < nlabels) {
+ destroynode(node);
+ node = NULL;
+ continue;
+ }
+
+ /*
+ * If we're looking for ANY, we're done.
+ */
+ if (type == dns_rdatatype_any) {
+ result = ISC_R_SUCCESS;
+ break;
+ }
+
+ /*
+ * Look for the qtype.
+ */
+ result = findrdataset(db, node, version, type,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS)
+ break;
+
+ /*
+ * Look for a CNAME
+ */
+ if (type != dns_rdatatype_cname) {
+ result = findrdataset(db, node, version,
+ dns_rdatatype_cname,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS) {
+ result = DNS_R_CNAME;
+ break;
+ }
+ }
+
+ result = DNS_R_NXRRSET;
+ break;
+ }
+
+ if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+
+ if (foundname != NULL) {
+ isc_result_t xresult;
+
+ xresult = dns_name_copy(xname, foundname, NULL);
+ if (xresult != ISC_R_SUCCESS) {
+ if (node != NULL)
+ destroynode(node);
+ if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+ return (DNS_R_BADDB);
+ }
+ }
+
+ if (nodep != NULL)
+ *nodep = node;
+ else if (node != NULL)
+ detachnode(db, &node);
+
+ return (result);
+}
+
+static isc_result_t
+allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
+{
+ sdlz_rdatasetiter_t *iterator;
+
+ REQUIRE(version == NULL || version == &dummy);
+
+ UNUSED(version);
+ UNUSED(now);
+
+ iterator = isc_mem_get(db->mctx, sizeof(sdlz_rdatasetiter_t));
+ if (iterator == NULL)
+ return (ISC_R_NOMEMORY);
+
+ iterator->common.magic = DNS_RDATASETITER_MAGIC;
+ iterator->common.methods = &rdatasetiter_methods;
+ iterator->common.db = db;
+ iterator->common.node = NULL;
+ attachnode(db, node, &iterator->common.node);
+ iterator->common.version = version;
+ iterator->common.now = now;
+
+ *iteratorp = (dns_rdatasetiter_t *)iterator;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
+ dns_rdataset_t *addedrdataset)
+{
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(version);
+ UNUSED(now);
+ UNUSED(rdataset);
+ UNUSED(options);
+ UNUSED(addedrdataset);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdataset_t *rdataset, unsigned int options,
+ dns_rdataset_t *newrdataset)
+{
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(version);
+ UNUSED(rdataset);
+ UNUSED(options);
+ UNUSED(newrdataset);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers)
+{
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(version);
+ UNUSED(type);
+ UNUSED(covers);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_boolean_t
+issecure(dns_db_t *db) {
+ UNUSED(db);
+
+ return (ISC_FALSE);
+}
+
+static unsigned int
+nodecount(dns_db_t *db) {
+ UNUSED(db);
+
+ return (0);
+}
+
+static isc_boolean_t
+ispersistent(dns_db_t *db) {
+ UNUSED(db);
+ return (ISC_TRUE);
+}
+
+static void
+overmem(dns_db_t *db, isc_boolean_t overmem) {
+ UNUSED(db);
+ UNUSED(overmem);
+}
+
+static void
+settask(dns_db_t *db, isc_task_t *task) {
+ UNUSED(db);
+ UNUSED(task);
+}
+
+
+static dns_dbmethods_t sdlzdb_methods = {
+ attach,
+ detach,
+ beginload,
+ endload,
+ dump,
+ currentversion,
+ newversion,
+ attachversion,
+ closeversion,
+ findnode,
+ find,
+ findzonecut,
+ attachnode,
+ detachnode,
+ expirenode,
+ printnode,
+ createiterator,
+ findrdataset,
+ allrdatasets,
+ addrdataset,
+ subtractrdataset,
+ deleterdataset,
+ issecure,
+ nodecount,
+ ispersistent,
+ overmem,
+ settask,
+ NULL,
+};
+
+/*
+ * Database Iterator Methods. These methods were "borrowed" from the SDB
+ * driver interface. See the SDB driver interface documentation for more info.
+ */
+
+static void
+dbiterator_destroy(dns_dbiterator_t **iteratorp) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)(*iteratorp);
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)sdlziter->common.db;
+
+ while (!ISC_LIST_EMPTY(sdlziter->nodelist)) {
+ dns_sdlznode_t *node;
+ node = ISC_LIST_HEAD(sdlziter->nodelist);
+ ISC_LIST_UNLINK(sdlziter->nodelist, node, link);
+ destroynode(node);
+ }
+
+ dns_db_detach(&sdlziter->common.db);
+ isc_mem_put(sdlz->common.mctx, sdlziter, sizeof(sdlz_dbiterator_t));
+
+ *iteratorp = NULL;
+}
+
+static isc_result_t
+dbiterator_first(dns_dbiterator_t *iterator) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
+ if (sdlziter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_last(dns_dbiterator_t *iterator) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ sdlziter->current = ISC_LIST_TAIL(sdlziter->nodelist);
+ if (sdlziter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
+ while (sdlziter->current != NULL)
+ if (dns_name_equal(sdlziter->current->name, name))
+ return (ISC_R_SUCCESS);
+ return (ISC_R_NOTFOUND);
+}
+
+static isc_result_t
+dbiterator_prev(dns_dbiterator_t *iterator) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ sdlziter->current = ISC_LIST_PREV(sdlziter->current, link);
+ if (sdlziter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_next(dns_dbiterator_t *iterator) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
+ if (sdlziter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
+ dns_name_t *name)
+{
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ attachnode(iterator->db, sdlziter->current, nodep);
+ if (name != NULL)
+ return (dns_name_copy(sdlziter->current->name, name, NULL));
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_pause(dns_dbiterator_t *iterator) {
+ UNUSED(iterator);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
+ UNUSED(iterator);
+ return (dns_name_copy(dns_rootname, name, NULL));
+}
+
+/*
+ * Rdataset Methods. These methods were "borrowed" from the SDB driver
+ * interface. See the SDB driver interface documentation for more info.
+ */
+
+static void
+disassociate(dns_rdataset_t *rdataset) {
+ dns_dbnode_t *node = rdataset->private5;
+ dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
+ dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
+
+ detachnode(db, &node);
+ isc__rdatalist_disassociate(rdataset);
+}
+
+static void
+rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
+ dns_dbnode_t *node = source->private5;
+ dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
+ dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
+ dns_dbnode_t *tempdb = NULL;
+
+ isc__rdatalist_clone(source, target);
+ attachnode(db, node, &tempdb);
+ source->private5 = tempdb;
+}
+
+static dns_rdatasetmethods_t rdataset_methods = {
+ disassociate,
+ isc__rdatalist_first,
+ isc__rdatalist_next,
+ isc__rdatalist_current,
+ rdataset_clone,
+ isc__rdatalist_count,
+ isc__rdatalist_addnoqname,
+ isc__rdatalist_getnoqname,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void
+list_tordataset(dns_rdatalist_t *rdatalist,
+ dns_db_t *db, dns_dbnode_t *node,
+ dns_rdataset_t *rdataset)
+{
+ /*
+ * The sdlz rdataset is an rdatalist with some additions.
+ * - private1 & private2 are used by the rdatalist.
+ * - private3 & private 4 are unused.
+ * - private5 is the node.
+ */
+
+ /* This should never fail. */
+ RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
+ ISC_R_SUCCESS);
+
+ rdataset->methods = &rdataset_methods;
+ dns_db_attachnode(db, node, &rdataset->private5);
+}
+
+/*
+ * SDLZ core methods. This is the core of the new DLZ functionality.
+ */
+
+/*%
+ * Build a 'bind' database driver structure to be returned by
+ * either the find zone or the allow zone transfer method.
+ * This method is only available in this source file, it is
+ * not made available anywhere else.
+ */
+
+static isc_result_t
+dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
+ dns_name_t *name, dns_rdataclass_t rdclass, dns_db_t **dbp)
+{
+ isc_result_t result;
+ dns_sdlz_db_t *sdlzdb;
+ dns_sdlzimplementation_t *imp;
+
+ /* check that things are as we expect */
+ REQUIRE(dbp != NULL && *dbp == NULL);
+ REQUIRE(name != NULL);
+
+ imp = (dns_sdlzimplementation_t *) driverarg;
+
+ /* allocate and zero memory for driver structure */
+ sdlzdb = isc_mem_get(mctx, sizeof(dns_sdlz_db_t));
+ if (sdlzdb == NULL)
+ return (ISC_R_NOMEMORY);
+ memset(sdlzdb, 0, sizeof(dns_sdlz_db_t));
+
+ /* initialize and set origin */
+ dns_name_init(&sdlzdb->common.origin, NULL);
+ result = dns_name_dupwithoffsets(name, mctx, &sdlzdb->common.origin);
+ if (result != ISC_R_SUCCESS)
+ goto mem_cleanup;
+
+ /* initialize the reference count mutex */
+ result = isc_mutex_init(&sdlzdb->refcnt_lock);
+ if (result != ISC_R_SUCCESS)
+ goto name_cleanup;
+
+ /* set the rest of the database structure attributes */
+ sdlzdb->dlzimp = imp;
+ sdlzdb->common.methods = &sdlzdb_methods;
+ sdlzdb->common.attributes = 0;
+ sdlzdb->common.rdclass = rdclass;
+ sdlzdb->common.mctx = NULL;
+ sdlzdb->dbdata = dbdata;
+ sdlzdb->references = 1;
+
+ /* attach to the memory context */
+ isc_mem_attach(mctx, &sdlzdb->common.mctx);
+
+ /* mark structure as valid */
+ sdlzdb->common.magic = DNS_DB_MAGIC;
+ sdlzdb->common.impmagic = SDLZDB_MAGIC;
+ *dbp = (dns_db_t *) sdlzdb;
+
+ return (result);
+
+ /*
+ * reference count mutex could not be initialized, clean up
+ * name memory
+ */
+ name_cleanup:
+ dns_name_free(&sdlzdb->common.origin, mctx);
+ mem_cleanup:
+ isc_mem_put(mctx, sdlzdb, sizeof(dns_sdlz_db_t));
+ return (result);
+}
+
+static isc_result_t
+dns_sdlzallowzonexfr(void *driverarg, void *dbdata, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_name_t *name,
+ isc_sockaddr_t *clientaddr, dns_db_t **dbp)
+{
+ isc_buffer_t b;
+ isc_buffer_t b2;
+ char namestr[DNS_NAME_MAXTEXT + 1];
+ char clientstr[(sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")
+ + 1];
+ isc_netaddr_t netaddr;
+ isc_result_t result;
+ dns_sdlzimplementation_t *imp;
+
+ /*
+ * Perform checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(driverarg != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(clientaddr != NULL);
+ REQUIRE(dbp != NULL && *dbp == NULL);
+
+ imp = (dns_sdlzimplementation_t *) driverarg;
+
+ /* Convert DNS name to ascii text */
+ isc_buffer_init(&b, namestr, sizeof(namestr));
+ result = dns_name_totext(name, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_putuint8(&b, 0);
+
+ /* convert client address to ascii text */
+ isc_buffer_init(&b2, clientstr, sizeof(clientstr));
+ isc_netaddr_fromsockaddr(&netaddr, clientaddr);
+ result = isc_netaddr_totext(&netaddr, &b2);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_putuint8(&b2, 0);
+
+ /* make sure strings are always lowercase */
+ dns_sdlz_tolower(namestr);
+ dns_sdlz_tolower(clientstr);
+
+ /* Call SDLZ driver's find zone method */
+ if (imp->methods->allowzonexfr != NULL) {
+ MAYBE_LOCK(imp);
+ result = imp->methods->allowzonexfr(imp->driverarg, dbdata,
+ namestr, clientstr);
+ MAYBE_UNLOCK(imp);
+ /*
+ * if zone is supported and transfers allowed build a 'bind'
+ * database driver
+ */
+ if (result == ISC_R_SUCCESS)
+ result = dns_sdlzcreateDBP(mctx, driverarg, dbdata,
+ name, rdclass, dbp);
+ return (result);
+ }
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
+ char *argv[], void *driverarg, void **dbdata)
+{
+ dns_sdlzimplementation_t *imp;
+ isc_result_t result = ISC_R_NOTFOUND;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Loading SDLZ driver.");
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(driverarg != NULL);
+ REQUIRE(dlzname != NULL);
+ REQUIRE(dbdata != NULL);
+ UNUSED(mctx);
+
+ imp = driverarg;
+
+ /* If the create method exists, call it. */
+ if (imp->methods->create != NULL) {
+ MAYBE_LOCK(imp);
+ result = imp->methods->create(dlzname, argc, argv,
+ imp->driverarg, dbdata);
+ MAYBE_UNLOCK(imp);
+ }
+
+ /* Write debugging message to log */
+ if (result == ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "SDLZ driver loaded successfully.");
+ } else {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "SDLZ driver failed to load.");
+ }
+
+ return (result);
+}
+
+static void
+dns_sdlzdestroy(void *driverdata, void **dbdata)
+{
+
+ dns_sdlzimplementation_t *imp;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unloading SDLZ driver.");
+
+ imp = driverdata;
+
+ /* If the destroy method exists, call it. */
+ if (imp->methods->destroy != NULL) {
+ MAYBE_LOCK(imp);
+ imp->methods->destroy(imp->driverarg, dbdata);
+ MAYBE_UNLOCK(imp);
+ }
+}
+
+static isc_result_t
+dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_name_t *name, dns_db_t **dbp)
+{
+ isc_buffer_t b;
+ char namestr[DNS_NAME_MAXTEXT + 1];
+ isc_result_t result;
+ dns_sdlzimplementation_t *imp;
+
+ /*
+ * Perform checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(driverarg != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(dbp != NULL && *dbp == NULL);
+
+ imp = (dns_sdlzimplementation_t *) driverarg;
+
+ /* Convert DNS name to ascii text */
+ isc_buffer_init(&b, namestr, sizeof(namestr));
+ result = dns_name_totext(name, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_putuint8(&b, 0);
+
+ /* make sure strings are always lowercase */
+ dns_sdlz_tolower(namestr);
+
+ /* Call SDLZ driver's find zone method */
+ MAYBE_LOCK(imp);
+ result = imp->methods->findzone(imp->driverarg, dbdata, namestr);
+ MAYBE_UNLOCK(imp);
+
+ /*
+ * if zone is supported build a 'bind' database driver
+ * structure to return
+ */
+ if (result == ISC_R_SUCCESS)
+ result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,
+ rdclass, dbp);
+
+ return (result);
+}
+
+static dns_dlzmethods_t sdlzmethods = {
+ dns_sdlzcreate,
+ dns_sdlzdestroy,
+ dns_sdlzfindzone,
+ dns_sdlzallowzonexfr
+};
+
+/*
+ * Public functions.
+ */
+
+isc_result_t
+dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
+ const char *data)
+{
+ dns_rdatalist_t *rdatalist;
+ dns_rdata_t *rdata;
+ dns_rdatatype_t typeval;
+ isc_consttextregion_t r;
+ isc_buffer_t b;
+ isc_buffer_t *rdatabuf = NULL;
+ isc_lex_t *lex;
+ isc_result_t result;
+ unsigned int size;
+ isc_mem_t *mctx;
+ dns_name_t *origin;
+
+ REQUIRE(VALID_SDLZLOOKUP(lookup));
+ REQUIRE(type != NULL);
+ REQUIRE(data != NULL);
+
+ mctx = lookup->sdlz->common.mctx;
+
+ r.base = type;
+ r.length = strlen(type);
+ result = dns_rdatatype_fromtext(&typeval, (void *) &r);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ rdatalist = ISC_LIST_HEAD(lookup->lists);
+ while (rdatalist != NULL) {
+ if (rdatalist->type == typeval)
+ break;
+ rdatalist = ISC_LIST_NEXT(rdatalist, link);
+ }
+
+ if (rdatalist == NULL) {
+ rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
+ if (rdatalist == NULL)
+ return (ISC_R_NOMEMORY);
+ rdatalist->rdclass = lookup->sdlz->common.rdclass;
+ rdatalist->type = typeval;
+ rdatalist->covers = 0;
+ rdatalist->ttl = ttl;
+ ISC_LIST_INIT(rdatalist->rdata);
+ ISC_LINK_INIT(rdatalist, link);
+ ISC_LIST_APPEND(lookup->lists, rdatalist, link);
+ } else
+ if (rdatalist->ttl != ttl)
+ return (DNS_R_BADTTL);
+
+ rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
+ if (rdata == NULL)
+ return (ISC_R_NOMEMORY);
+ dns_rdata_init(rdata);
+
+ if ((lookup->sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
+ origin = &lookup->sdlz->common.origin;
+ else
+ origin = dns_rootname;
+
+ lex = NULL;
+ result = isc_lex_create(mctx, 64, &lex);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ size = initial_size(data);
+ do {
+ isc_buffer_init(&b, data, strlen(data));
+ isc_buffer_add(&b, strlen(data));
+
+ result = isc_lex_openbuffer(lex, &b);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ rdatabuf = NULL;
+ result = isc_buffer_allocate(mctx, &rdatabuf, size);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_rdata_fromtext(rdata, rdatalist->rdclass,
+ rdatalist->type, lex,
+ origin, ISC_FALSE,
+ mctx, rdatabuf,
+ &lookup->callbacks);
+ if (result != ISC_R_SUCCESS)
+ isc_buffer_free(&rdatabuf);
+ size *= 2;
+ } while (result == ISC_R_NOSPACE);
+
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
+ ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
+
+ if (lex != NULL)
+ isc_lex_destroy(&lex);
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (rdatabuf != NULL)
+ isc_buffer_free(&rdatabuf);
+ if (lex != NULL)
+ isc_lex_destroy(&lex);
+ isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
+
+ return (result);
+}
+
+isc_result_t
+dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
+ const char *type, dns_ttl_t ttl, const char *data)
+{
+ dns_name_t *newname, *origin;
+ dns_fixedname_t fnewname;
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)allnodes->common.db;
+ dns_sdlznode_t *sdlznode;
+ isc_mem_t *mctx = sdlz->common.mctx;
+ isc_buffer_t b;
+ isc_result_t result;
+
+ dns_fixedname_init(&fnewname);
+ newname = dns_fixedname_name(&fnewname);
+
+ if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
+ origin = &sdlz->common.origin;
+ else
+ origin = dns_rootname;
+ isc_buffer_init(&b, name, strlen(name));
+ isc_buffer_add(&b, strlen(name));
+
+ result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (allnodes->common.relative_names) {
+ /* All names are relative to the root */
+ unsigned int nlabels = dns_name_countlabels(newname);
+ dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
+ }
+
+ sdlznode = ISC_LIST_HEAD(allnodes->nodelist);
+ if (sdlznode == NULL || !dns_name_equal(sdlznode->name, newname)) {
+ sdlznode = NULL;
+ result = createnode(sdlz, &sdlznode);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ sdlznode->name = isc_mem_get(mctx, sizeof(dns_name_t));
+ if (sdlznode->name == NULL) {
+ destroynode(sdlznode);
+ return (ISC_R_NOMEMORY);
+ }
+ dns_name_init(sdlznode->name, NULL);
+ result = dns_name_dup(newname, mctx, sdlznode->name);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, sdlznode->name, sizeof(dns_name_t));
+ destroynode(sdlznode);
+ return (result);
+ }
+ ISC_LIST_PREPEND(allnodes->nodelist, sdlznode, link);
+ if (allnodes->origin == NULL &&
+ dns_name_equal(newname, &sdlz->common.origin))
+ allnodes->origin = sdlznode;
+ }
+ return (dns_sdlz_putrr(sdlznode, type, ttl, data));
+
+}
+
+isc_result_t
+dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
+ isc_uint32_t serial)
+{
+ char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
+ int n;
+
+ REQUIRE(mname != NULL);
+ REQUIRE(rname != NULL);
+
+ n = snprintf(str, sizeof str, "%s %s %u %u %u %u %u",
+ mname, rname, serial,
+ SDLZ_DEFAULT_REFRESH, SDLZ_DEFAULT_RETRY,
+ SDLZ_DEFAULT_EXPIRE, SDLZ_DEFAULT_MINIMUM);
+ if (n >= (int)sizeof(str) || n < 0)
+ return (ISC_R_NOSPACE);
+ return (dns_sdlz_putrr(lookup, "SOA", SDLZ_DEFAULT_TTL, str));
+}
+
+isc_result_t
+dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
+ void *driverarg, unsigned int flags, isc_mem_t *mctx,
+ dns_sdlzimplementation_t **sdlzimp)
+{
+
+ dns_sdlzimplementation_t *imp;
+ isc_result_t result;
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(drivername != NULL);
+ REQUIRE(methods != NULL);
+ REQUIRE(methods->findzone != NULL);
+ REQUIRE(methods->lookup != NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(sdlzimp != NULL && *sdlzimp == NULL);
+ REQUIRE((flags & ~(DNS_SDLZFLAG_RELATIVEOWNER |
+ DNS_SDLZFLAG_RELATIVERDATA |
+ DNS_SDLZFLAG_THREADSAFE)) == 0);
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering SDLZ driver '%s'", drivername);
+
+ /*
+ * Allocate memory for a sdlz_implementation object. Error if
+ * we cannot.
+ */
+ imp = isc_mem_get(mctx, sizeof(dns_sdlzimplementation_t));
+ if (imp == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /* Make sure memory region is set to all 0's */
+ memset(imp, 0, sizeof(dns_sdlzimplementation_t));
+
+ /* Store the data passed into this method */
+ imp->methods = methods;
+ imp->driverarg = driverarg;
+ imp->flags = flags;
+ imp->mctx = NULL;
+
+ /* attach the new sdlz_implementation object to a memory context */
+ isc_mem_attach(mctx, &imp->mctx);
+
+ /*
+ * initialize the driver lock, error if we cannot
+ * (used if a driver does not support multiple threads)
+ */
+ result = isc_mutex_init(&imp->driverlock);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_mutex_init() failed: %s",
+ isc_result_totext(result));
+ goto cleanup_mctx;
+ }
+
+ imp->dlz_imp = NULL;
+
+ /*
+ * register the DLZ driver. Pass in our "extra" sdlz information as
+ * a driverarg. (that's why we stored the passed in driver arg in our
+ * sdlz_implementation structure) Also, store the dlz_implementation
+ * structure in our sdlz_implementation.
+ */
+ result = dns_dlzregister(drivername, &sdlzmethods, imp, mctx,
+ &imp->dlz_imp);
+
+ /* if registration fails, cleanup and get outta here. */
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_mutex;
+
+ *sdlzimp = imp;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_mutex:
+ /* destroy the driver lock, we don't need it anymore */
+ DESTROYLOCK(&imp->driverlock);
+
+ cleanup_mctx:
+ /*
+ * return the memory back to the available memory pool and
+ * remove it from the memory context.
+ */
+ isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
+ isc_mem_detach(&mctx);
+ return (result);
+}
+
+void
+dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) {
+ dns_sdlzimplementation_t *imp;
+ isc_mem_t *mctx;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering SDLZ driver.");
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(sdlzimp != NULL && *sdlzimp != NULL);
+
+ imp = *sdlzimp;
+
+ /* Unregister the DLZ driver implementation */
+ dns_dlzunregister(&imp->dlz_imp);
+
+ /* destroy the driver lock, we don't need it anymore */
+ DESTROYLOCK(&imp->driverlock);
+
+ mctx = imp->mctx;
+
+ /*
+ * return the memory back to the available memory pool and
+ * remove it from the memory context.
+ */
+ isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
+ isc_mem_detach(&mctx);
+
+ *sdlzimp = NULL;
+}
diff --git a/lib/dns/soa.c b/lib/dns/soa.c
new file mode 100644
index 0000000..20198c0
--- /dev/null
+++ b/lib/dns/soa.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2004, 2005 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: soa.c,v 1.4.18.2 2005/04/29 00:16:05 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/util.h>
+
+#include <dns/rdata.h>
+#include <dns/soa.h>
+
+static inline isc_uint32_t
+decode_uint32(unsigned char *p) {
+ return ((p[0] << 24) +
+ (p[1] << 16) +
+ (p[2] << 8) +
+ (p[3] << 0));
+}
+
+static inline void
+encode_uint32(isc_uint32_t val, unsigned char *p) {
+ p[0] = (isc_uint8_t)(val >> 24);
+ p[1] = (isc_uint8_t)(val >> 16);
+ p[2] = (isc_uint8_t)(val >> 8);
+ p[3] = (isc_uint8_t)(val >> 0);
+}
+
+static isc_uint32_t
+soa_get(dns_rdata_t *rdata, int offset) {
+ INSIST(rdata->type == dns_rdatatype_soa);
+ /*
+ * Locate the field within the SOA RDATA based
+ * on its position relative to the end of the data.
+ *
+ * This is a bit of a kludge, but the alternative approach of
+ * using dns_rdata_tostruct() and dns_rdata_fromstruct() would
+ * involve a lot of unnecessary work (like building domain
+ * names and allocating temporary memory) when all we really
+ * want to do is to get 32 bits of fixed-sized data.
+ */
+ INSIST(rdata->length >= 20);
+ INSIST(offset >= 0 && offset <= 16);
+ return (decode_uint32(rdata->data + rdata->length - 20 + offset));
+}
+
+isc_uint32_t
+dns_soa_getserial(dns_rdata_t *rdata) {
+ return soa_get(rdata, 0);
+}
+isc_uint32_t
+dns_soa_getrefresh(dns_rdata_t *rdata) {
+ return soa_get(rdata, 4);
+}
+isc_uint32_t
+dns_soa_getretry(dns_rdata_t *rdata) {
+ return soa_get(rdata, 8);
+}
+isc_uint32_t
+dns_soa_getexpire(dns_rdata_t *rdata) {
+ return soa_get(rdata, 12);
+}
+isc_uint32_t
+dns_soa_getminimum(dns_rdata_t *rdata) {
+ return soa_get(rdata, 16);
+}
+
+static void
+soa_set(dns_rdata_t *rdata, isc_uint32_t val, int offset) {
+ INSIST(rdata->type == dns_rdatatype_soa);
+ INSIST(rdata->length >= 20);
+ INSIST(offset >= 0 && offset <= 16);
+ encode_uint32(val, rdata->data + rdata->length - 20 + offset);
+}
+
+void
+dns_soa_setserial(isc_uint32_t val, dns_rdata_t *rdata) {
+ soa_set(rdata, val, 0);
+}
+void
+dns_soa_setrefresh(isc_uint32_t val, dns_rdata_t *rdata) {
+ soa_set(rdata, val, 4);
+}
+void
+dns_soa_setretry(isc_uint32_t val, dns_rdata_t *rdata) {
+ soa_set(rdata, val, 8);
+}
+void
+dns_soa_setexpire(isc_uint32_t val, dns_rdata_t *rdata) {
+ soa_set(rdata, val, 12);
+}
+void
+dns_soa_setminimum(isc_uint32_t val, dns_rdata_t *rdata) {
+ soa_set(rdata, val, 16);
+}
diff --git a/lib/dns/ssu.c b/lib/dns/ssu.c
new file mode 100644
index 0000000..fa3011c
--- /dev/null
+++ b/lib/dns/ssu.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2004-2006 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.
+ */
+
+/*! \file */
+/*
+ * $Id: ssu.c,v 1.24.18.4 2006/02/16 23:51:32 marka Exp $
+ * Principal Author: Brian Wellington
+ */
+
+#include <config.h>
+
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/util.h>
+
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/ssu.h>
+
+#define SSUTABLEMAGIC ISC_MAGIC('S', 'S', 'U', 'T')
+#define VALID_SSUTABLE(table) ISC_MAGIC_VALID(table, SSUTABLEMAGIC)
+
+#define SSURULEMAGIC ISC_MAGIC('S', 'S', 'U', 'R')
+#define VALID_SSURULE(table) ISC_MAGIC_VALID(table, SSURULEMAGIC)
+
+struct dns_ssurule {
+ unsigned int magic;
+ isc_boolean_t grant; /*%< is this a grant or a deny? */
+ unsigned int matchtype; /*%< which type of pattern match? */
+ dns_name_t *identity; /*%< the identity to match */
+ dns_name_t *name; /*%< the name being updated */
+ unsigned int ntypes; /*%< number of data types covered */
+ dns_rdatatype_t *types; /*%< the data types. Can include ANY, */
+ /*%< defaults to all but SIG,SOA,NS if NULL */
+ ISC_LINK(dns_ssurule_t) link;
+};
+
+struct dns_ssutable {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ unsigned int references;
+ isc_mutex_t lock;
+ ISC_LIST(dns_ssurule_t) rules;
+};
+
+isc_result_t
+dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **tablep) {
+ isc_result_t result;
+ dns_ssutable_t *table;
+
+ REQUIRE(tablep != NULL && *tablep == NULL);
+ REQUIRE(mctx != NULL);
+
+ table = isc_mem_get(mctx, sizeof(dns_ssutable_t));
+ if (table == NULL)
+ return (ISC_R_NOMEMORY);
+ result = isc_mutex_init(&table->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, table, sizeof(dns_ssutable_t));
+ return (result);
+ }
+ table->references = 1;
+ table->mctx = mctx;
+ ISC_LIST_INIT(table->rules);
+ table->magic = SSUTABLEMAGIC;
+ *tablep = table;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+destroy(dns_ssutable_t *table) {
+ isc_mem_t *mctx;
+
+ REQUIRE(VALID_SSUTABLE(table));
+
+ mctx = table->mctx;
+ while (!ISC_LIST_EMPTY(table->rules)) {
+ dns_ssurule_t *rule = ISC_LIST_HEAD(table->rules);
+ if (rule->identity != NULL) {
+ dns_name_free(rule->identity, mctx);
+ isc_mem_put(mctx, rule->identity, sizeof(dns_name_t));
+ }
+ if (rule->name != NULL) {
+ dns_name_free(rule->name, mctx);
+ isc_mem_put(mctx, rule->name, sizeof(dns_name_t));
+ }
+ if (rule->types != NULL)
+ isc_mem_put(mctx, rule->types,
+ rule->ntypes * sizeof(dns_rdatatype_t));
+ ISC_LIST_UNLINK(table->rules, rule, link);
+ rule->magic = 0;
+ isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
+ }
+ DESTROYLOCK(&table->lock);
+ table->magic = 0;
+ isc_mem_put(mctx, table, sizeof(dns_ssutable_t));
+}
+
+void
+dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp) {
+ REQUIRE(VALID_SSUTABLE(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ LOCK(&source->lock);
+
+ INSIST(source->references > 0);
+ source->references++;
+ INSIST(source->references != 0);
+
+ UNLOCK(&source->lock);
+
+ *targetp = source;
+}
+
+void
+dns_ssutable_detach(dns_ssutable_t **tablep) {
+ dns_ssutable_t *table;
+ isc_boolean_t done = ISC_FALSE;
+
+ REQUIRE(tablep != NULL);
+ table = *tablep;
+ REQUIRE(VALID_SSUTABLE(table));
+
+ LOCK(&table->lock);
+
+ INSIST(table->references > 0);
+ if (--table->references == 0)
+ done = ISC_TRUE;
+ UNLOCK(&table->lock);
+
+ *tablep = NULL;
+
+ if (done)
+ destroy(table);
+}
+
+isc_result_t
+dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant,
+ dns_name_t *identity, unsigned int matchtype,
+ dns_name_t *name, unsigned int ntypes,
+ dns_rdatatype_t *types)
+{
+ dns_ssurule_t *rule;
+ isc_mem_t *mctx;
+ isc_result_t result;
+
+ REQUIRE(VALID_SSUTABLE(table));
+ REQUIRE(dns_name_isabsolute(identity));
+ REQUIRE(dns_name_isabsolute(name));
+ REQUIRE(matchtype <= DNS_SSUMATCHTYPE_MAX);
+ if (matchtype == DNS_SSUMATCHTYPE_WILDCARD)
+ REQUIRE(dns_name_iswildcard(name));
+ if (ntypes > 0)
+ REQUIRE(types != NULL);
+
+ mctx = table->mctx;
+ rule = isc_mem_get(mctx, sizeof(dns_ssurule_t));
+ if (rule == NULL)
+ return (ISC_R_NOMEMORY);
+
+ rule->identity = NULL;
+ rule->name = NULL;
+ rule->types = NULL;
+
+ rule->grant = grant;
+
+ rule->identity = isc_mem_get(mctx, sizeof(dns_name_t));
+ if (rule->identity == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto failure;
+ }
+ dns_name_init(rule->identity, NULL);
+ result = dns_name_dup(identity, mctx, rule->identity);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ rule->name = isc_mem_get(mctx, sizeof(dns_name_t));
+ if (rule->name == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto failure;
+ }
+ dns_name_init(rule->name, NULL);
+ result = dns_name_dup(name, mctx, rule->name);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ rule->matchtype = matchtype;
+
+ rule->ntypes = ntypes;
+ if (ntypes > 0) {
+ rule->types = isc_mem_get(mctx,
+ ntypes * sizeof(dns_rdatatype_t));
+ if (rule->types == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto failure;
+ }
+ memcpy(rule->types, types, ntypes * sizeof(dns_rdatatype_t));
+ } else
+ rule->types = NULL;
+
+ rule->magic = SSURULEMAGIC;
+ ISC_LIST_INITANDAPPEND(table->rules, rule, link);
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (rule->identity != NULL) {
+ if (dns_name_dynamic(rule->identity))
+ dns_name_free(rule->identity, mctx);
+ isc_mem_put(mctx, rule->identity, sizeof(dns_name_t));
+ }
+ if (rule->name != NULL) {
+ if (dns_name_dynamic(rule->name))
+ dns_name_free(rule->name, mctx);
+ isc_mem_put(mctx, rule->name, sizeof(dns_name_t));
+ }
+ if (rule->types != NULL)
+ isc_mem_put(mctx, rule->types,
+ ntypes * sizeof(dns_rdatatype_t));
+ isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
+
+ return (result);
+}
+
+static inline isc_boolean_t
+isusertype(dns_rdatatype_t type) {
+ return (ISC_TF(type != dns_rdatatype_ns &&
+ type != dns_rdatatype_soa &&
+ type != dns_rdatatype_rrsig));
+}
+
+isc_boolean_t
+dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
+ dns_name_t *name, dns_rdatatype_t type)
+{
+ dns_ssurule_t *rule;
+ unsigned int i;
+ dns_fixedname_t fixed;
+ dns_name_t *wildcard;
+ isc_result_t result;
+
+ REQUIRE(VALID_SSUTABLE(table));
+ REQUIRE(signer == NULL || dns_name_isabsolute(signer));
+ REQUIRE(dns_name_isabsolute(name));
+
+ if (signer == NULL)
+ return (ISC_FALSE);
+ rule = ISC_LIST_HEAD(table->rules);
+ rule = ISC_LIST_NEXT(rule, link);
+ for (rule = ISC_LIST_HEAD(table->rules);
+ rule != NULL;
+ rule = ISC_LIST_NEXT(rule, link))
+ {
+ if (dns_name_iswildcard(rule->identity)) {
+ if (!dns_name_matcheswildcard(signer, rule->identity))
+ continue;
+ } else if (!dns_name_equal(signer, rule->identity))
+ continue;
+
+ if (rule->matchtype == DNS_SSUMATCHTYPE_NAME) {
+ if (!dns_name_equal(name, rule->name))
+ continue;
+ } else if (rule->matchtype == DNS_SSUMATCHTYPE_SUBDOMAIN) {
+ if (!dns_name_issubdomain(name, rule->name))
+ continue;
+ } else if (rule->matchtype == DNS_SSUMATCHTYPE_WILDCARD) {
+ if (!dns_name_matcheswildcard(name, rule->name))
+ continue;
+ } else if (rule->matchtype == DNS_SSUMATCHTYPE_SELF) {
+ if (!dns_name_equal(signer, name))
+ continue;
+ } else if (rule->matchtype == DNS_SSUMATCHTYPE_SELFSUB) {
+ if (!dns_name_issubdomain(name, signer))
+ continue;
+ } else if (rule->matchtype == DNS_SSUMATCHTYPE_SELFWILD) {
+ dns_fixedname_init(&fixed);
+ wildcard = dns_fixedname_name(&fixed);
+ result = dns_name_concatenate(dns_wildcardname, signer,
+ wildcard, NULL);
+ if (result != ISC_R_SUCCESS)
+ continue;
+ if (!dns_name_matcheswildcard(name, wildcard))
+ continue;
+ }
+
+ if (rule->ntypes == 0) {
+ if (!isusertype(type))
+ continue;
+ } else {
+ for (i = 0; i < rule->ntypes; i++) {
+ if (rule->types[i] == dns_rdatatype_any ||
+ rule->types[i] == type)
+ break;
+ }
+ if (i == rule->ntypes)
+ continue;
+ }
+ return (rule->grant);
+ }
+
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+dns_ssurule_isgrant(const dns_ssurule_t *rule) {
+ REQUIRE(VALID_SSURULE(rule));
+ return (rule->grant);
+}
+
+dns_name_t *
+dns_ssurule_identity(const dns_ssurule_t *rule) {
+ REQUIRE(VALID_SSURULE(rule));
+ return (rule->identity);
+}
+
+unsigned int
+dns_ssurule_matchtype(const dns_ssurule_t *rule) {
+ REQUIRE(VALID_SSURULE(rule));
+ return (rule->matchtype);
+}
+
+dns_name_t *
+dns_ssurule_name(const dns_ssurule_t *rule) {
+ REQUIRE(VALID_SSURULE(rule));
+ return (rule->name);
+}
+
+unsigned int
+dns_ssurule_types(const dns_ssurule_t *rule, dns_rdatatype_t **types) {
+ REQUIRE(VALID_SSURULE(rule));
+ REQUIRE(types != NULL && *types != NULL);
+ *types = rule->types;
+ return (rule->ntypes);
+}
+
+isc_result_t
+dns_ssutable_firstrule(const dns_ssutable_t *table, dns_ssurule_t **rule) {
+ REQUIRE(VALID_SSUTABLE(table));
+ REQUIRE(rule != NULL && *rule == NULL);
+ *rule = ISC_LIST_HEAD(table->rules);
+ return (*rule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
+}
+
+isc_result_t
+dns_ssutable_nextrule(dns_ssurule_t *rule, dns_ssurule_t **nextrule) {
+ REQUIRE(VALID_SSURULE(rule));
+ REQUIRE(nextrule != NULL && *nextrule == NULL);
+ *nextrule = ISC_LIST_NEXT(rule, link);
+ return (*nextrule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE);
+}
diff --git a/lib/dns/stats.c b/lib/dns/stats.c
new file mode 100644
index 0000000..660046f
--- /dev/null
+++ b/lib/dns/stats.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2004, 2005 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: stats.c,v 1.6.18.4 2005/06/27 00:20:02 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+
+#include <dns/stats.h>
+
+LIBDNS_EXTERNAL_DATA const char *dns_statscounter_names[DNS_STATS_NCOUNTERS] =
+ {
+ "success",
+ "referral",
+ "nxrrset",
+ "nxdomain",
+ "recursion",
+ "failure",
+ "duplicate",
+ "dropped"
+ };
+
+isc_result_t
+dns_stats_alloccounters(isc_mem_t *mctx, isc_uint64_t **ctrp) {
+ int i;
+ isc_uint64_t *p =
+ isc_mem_get(mctx, DNS_STATS_NCOUNTERS * sizeof(isc_uint64_t));
+ if (p == NULL)
+ return (ISC_R_NOMEMORY);
+ for (i = 0; i < DNS_STATS_NCOUNTERS; i++)
+ p[i] = 0;
+ *ctrp = p;
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_stats_freecounters(isc_mem_t *mctx, isc_uint64_t **ctrp) {
+ isc_mem_put(mctx, *ctrp, DNS_STATS_NCOUNTERS * sizeof(isc_uint64_t));
+ *ctrp = NULL;
+}
diff --git a/lib/dns/tcpmsg.c b/lib/dns/tcpmsg.c
new file mode 100644
index 0000000..018c4ce
--- /dev/null
+++ b/lib/dns/tcpmsg.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2004-2006 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: tcpmsg.c,v 1.25.18.4 2006/08/10 23:59:29 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/task.h>
+#include <isc/util.h>
+
+#include <dns/events.h>
+#include <dns/result.h>
+#include <dns/tcpmsg.h>
+
+#ifdef TCPMSG_DEBUG
+#include <stdio.h> /* Required for printf. */
+#define XDEBUG(x) printf x
+#else
+#define XDEBUG(x)
+#endif
+
+#define TCPMSG_MAGIC ISC_MAGIC('T', 'C', 'P', 'm')
+#define VALID_TCPMSG(foo) ISC_MAGIC_VALID(foo, TCPMSG_MAGIC)
+
+static void recv_length(isc_task_t *, isc_event_t *);
+static void recv_message(isc_task_t *, isc_event_t *);
+
+
+static void
+recv_length(isc_task_t *task, isc_event_t *ev_in) {
+ isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
+ isc_event_t *dev;
+ dns_tcpmsg_t *tcpmsg = ev_in->ev_arg;
+ isc_region_t region;
+ isc_result_t result;
+
+ INSIST(VALID_TCPMSG(tcpmsg));
+
+ dev = &tcpmsg->event;
+ tcpmsg->address = ev->address;
+
+ if (ev->result != ISC_R_SUCCESS) {
+ tcpmsg->result = ev->result;
+ goto send_and_free;
+ }
+
+ /*
+ * Success.
+ */
+ tcpmsg->size = ntohs(tcpmsg->size);
+ if (tcpmsg->size == 0) {
+ tcpmsg->result = ISC_R_UNEXPECTEDEND;
+ goto send_and_free;
+ }
+ if (tcpmsg->size > tcpmsg->maxsize) {
+ tcpmsg->result = ISC_R_RANGE;
+ goto send_and_free;
+ }
+
+ region.base = isc_mem_get(tcpmsg->mctx, tcpmsg->size);
+ region.length = tcpmsg->size;
+ if (region.base == NULL) {
+ tcpmsg->result = ISC_R_NOMEMORY;
+ goto send_and_free;
+ }
+ XDEBUG(("Allocated %d bytes\n", tcpmsg->size));
+
+ isc_buffer_init(&tcpmsg->buffer, region.base, region.length);
+ result = isc_socket_recv(tcpmsg->sock, &region, 0,
+ task, recv_message, tcpmsg);
+ if (result != ISC_R_SUCCESS) {
+ tcpmsg->result = result;
+ goto send_and_free;
+ }
+
+ isc_event_free(&ev_in);
+ return;
+
+ send_and_free:
+ isc_task_send(tcpmsg->task, &dev);
+ tcpmsg->task = NULL;
+ isc_event_free(&ev_in);
+ return;
+}
+
+static void
+recv_message(isc_task_t *task, isc_event_t *ev_in) {
+ isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
+ isc_event_t *dev;
+ dns_tcpmsg_t *tcpmsg = ev_in->ev_arg;
+
+ (void)task;
+
+ INSIST(VALID_TCPMSG(tcpmsg));
+
+ dev = &tcpmsg->event;
+ tcpmsg->address = ev->address;
+
+ if (ev->result != ISC_R_SUCCESS) {
+ tcpmsg->result = ev->result;
+ goto send_and_free;
+ }
+
+ tcpmsg->result = ISC_R_SUCCESS;
+ isc_buffer_add(&tcpmsg->buffer, ev->n);
+
+ XDEBUG(("Received %d bytes (of %d)\n", ev->n, tcpmsg->size));
+
+ send_and_free:
+ isc_task_send(tcpmsg->task, &dev);
+ tcpmsg->task = NULL;
+ isc_event_free(&ev_in);
+}
+
+void
+dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg) {
+ REQUIRE(mctx != NULL);
+ REQUIRE(sock != NULL);
+ REQUIRE(tcpmsg != NULL);
+
+ tcpmsg->magic = TCPMSG_MAGIC;
+ tcpmsg->size = 0;
+ tcpmsg->buffer.base = NULL;
+ tcpmsg->buffer.length = 0;
+ tcpmsg->maxsize = 65535; /* Largest message possible. */
+ tcpmsg->mctx = mctx;
+ tcpmsg->sock = sock;
+ tcpmsg->task = NULL; /* None yet. */
+ tcpmsg->result = ISC_R_UNEXPECTED; /* None yet. */
+ /*
+ * Should probably initialize the event here, but it can wait.
+ */
+}
+
+
+void
+dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize) {
+ REQUIRE(VALID_TCPMSG(tcpmsg));
+ REQUIRE(maxsize < 65536);
+
+ tcpmsg->maxsize = maxsize;
+}
+
+
+isc_result_t
+dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ isc_result_t result;
+ isc_region_t region;
+
+ REQUIRE(VALID_TCPMSG(tcpmsg));
+ REQUIRE(task != NULL);
+ REQUIRE(tcpmsg->task == NULL); /* not currently in use */
+
+ if (tcpmsg->buffer.base != NULL) {
+ isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base,
+ tcpmsg->buffer.length);
+ tcpmsg->buffer.base = NULL;
+ tcpmsg->buffer.length = 0;
+ }
+
+ tcpmsg->task = task;
+ tcpmsg->action = action;
+ tcpmsg->arg = arg;
+ tcpmsg->result = ISC_R_UNEXPECTED; /* unknown right now */
+
+ ISC_EVENT_INIT(&tcpmsg->event, sizeof(isc_event_t), 0, 0,
+ DNS_EVENT_TCPMSG, action, arg, tcpmsg,
+ NULL, NULL);
+
+ region.base = (unsigned char *)&tcpmsg->size;
+ region.length = 2; /* isc_uint16_t */
+ result = isc_socket_recv(tcpmsg->sock, &region, 0,
+ tcpmsg->task, recv_length, tcpmsg);
+
+ if (result != ISC_R_SUCCESS)
+ tcpmsg->task = NULL;
+
+ return (result);
+}
+
+void
+dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg) {
+ REQUIRE(VALID_TCPMSG(tcpmsg));
+
+ isc_socket_cancel(tcpmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
+}
+
+void
+dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer) {
+ REQUIRE(VALID_TCPMSG(tcpmsg));
+ REQUIRE(buffer != NULL);
+
+ *buffer = tcpmsg->buffer;
+ tcpmsg->buffer.base = NULL;
+ tcpmsg->buffer.length = 0;
+}
+
+#if 0
+void
+dns_tcpmsg_freebuffer(dns_tcpmsg_t *tcpmsg) {
+ REQUIRE(VALID_TCPMSG(tcpmsg));
+
+ if (tcpmsg->buffer.base == NULL)
+ return;
+
+ isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, tcpmsg->buffer.length);
+ tcpmsg->buffer.base = NULL;
+ tcpmsg->buffer.length = 0;
+}
+#endif
+
+void
+dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg) {
+ REQUIRE(VALID_TCPMSG(tcpmsg));
+
+ tcpmsg->magic = 0;
+
+ if (tcpmsg->buffer.base != NULL) {
+ isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base,
+ tcpmsg->buffer.length);
+ tcpmsg->buffer.base = NULL;
+ tcpmsg->buffer.length = 0;
+ }
+}
diff --git a/lib/dns/time.c b/lib/dns/time.c
new file mode 100644
index 0000000..b4e7bee
--- /dev/null
+++ b/lib/dns/time.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: time.c,v 1.26.18.3 2005/04/29 00:16:06 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <time.h>
+
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/stdtime.h>
+#include <isc/util.h>
+
+#include <dns/result.h>
+#include <dns/time.h>
+
+static int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+isc_result_t
+dns_time64_totext(isc_int64_t t, isc_buffer_t *target) {
+ struct tm tm;
+ char buf[sizeof("YYYYMMDDHHMMSS")];
+ int secs;
+ unsigned int l;
+ isc_region_t region;
+
+ REQUIRE(t >= 0);
+
+#define is_leap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+#define year_secs(y) ((is_leap(y) ? 366 : 365 ) * 86400)
+#define month_secs(m,y) ((days[m] + ((m == 1 && is_leap(y)) ? 1 : 0 )) * 86400)
+
+ tm.tm_year = 70;
+ while ((secs = year_secs(tm.tm_year + 1900)) <= t) {
+ t -= secs;
+ tm.tm_year++;
+ if (tm.tm_year + 1900 > 9999)
+ return (ISC_R_RANGE);
+ }
+ tm.tm_mon = 0;
+ while ((secs = month_secs(tm.tm_mon, tm.tm_year + 1900)) <= t) {
+ t -= secs;
+ tm.tm_mon++;
+ }
+ tm.tm_mday = 1;
+ while (86400 <= t) {
+ t -= 86400;
+ tm.tm_mday++;
+ }
+ tm.tm_hour = 0;
+ while (3600 <= t) {
+ t -= 3600;
+ tm.tm_hour++;
+ }
+ tm.tm_min = 0;
+ while (60 <= t) {
+ t -= 60;
+ tm.tm_min++;
+ }
+ tm.tm_sec = (int)t;
+ /* yyyy mm dd HH MM SS */
+ snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ isc_buffer_availableregion(target, &region);
+ l = strlen(buf);
+
+ if (l > region.length)
+ return (ISC_R_NOSPACE);
+
+ memcpy(region.base, buf, l);
+ isc_buffer_add(target, l);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_time32_totext(isc_uint32_t value, isc_buffer_t *target) {
+ isc_stdtime_t now;
+ isc_int64_t start;
+ isc_int64_t base;
+ isc_int64_t t;
+
+ /*
+ * Adjust the time to the closest epoch. This should be changed
+ * to use a 64-bit counterpart to isc_stdtime_get() if one ever
+ * is defined, but even the current code is good until the year
+ * 2106.
+ */
+ isc_stdtime_get(&now);
+ start = (isc_int64_t) now;
+ start -= 0x7fffffff;
+ base = 0;
+ while ((t = (base + value)) < start) {
+ base += 0x80000000;
+ base += 0x80000000;
+ }
+ return (dns_time64_totext(t, target));
+}
+
+isc_result_t
+dns_time64_fromtext(const char *source, isc_int64_t *target) {
+ int year, month, day, hour, minute, second;
+ isc_int64_t value;
+ int secs;
+ int i;
+
+#define RANGE(min, max, value) \
+ do { \
+ if (value < (min) || value > (max)) \
+ return (ISC_R_RANGE); \
+ } while (0)
+
+ if (strlen(source) != 14U)
+ return (DNS_R_SYNTAX);
+ if (sscanf(source, "%4d%2d%2d%2d%2d%2d",
+ &year, &month, &day, &hour, &minute, &second) != 6)
+ return (DNS_R_SYNTAX);
+
+ RANGE(1970, 9999, year);
+ RANGE(1, 12, month);
+ RANGE(1, days[month - 1] +
+ ((month == 2 && is_leap(year)) ? 1 : 0), day);
+ RANGE(0, 23, hour);
+ RANGE(0, 59, minute);
+ RANGE(0, 60, second); /* 60 == leap second. */
+
+ /*
+ * Calulate seconds since epoch.
+ */
+ value = second + (60 * minute) + (3600 * hour) + ((day - 1) * 86400);
+ for (i = 0; i < (month - 1); i++)
+ value += days[i] * 86400;
+ if (is_leap(year) && month > 2)
+ value += 86400;
+ for (i = 1970; i < year; i++) {
+ secs = (is_leap(i) ? 366 : 365) * 86400;
+ value += secs;
+ }
+
+ *target = value;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_time32_fromtext(const char *source, isc_uint32_t *target) {
+ isc_int64_t value64;
+ isc_result_t result;
+ result = dns_time64_fromtext(source, &value64);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ *target = (isc_uint32_t)value64;
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/dns/timer.c b/lib/dns/timer.c
new file mode 100644
index 0000000..b225722
--- /dev/null
+++ b/lib/dns/timer.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2004, 2005 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: timer.c,v 1.3.18.2 2005/04/29 00:16:06 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/result.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+
+#include <dns/types.h>
+#include <dns/timer.h>
+
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto failure; \
+ } while (0)
+
+isc_result_t
+dns_timer_setidle(isc_timer_t *timer, unsigned int maxtime,
+ unsigned int idletime, isc_boolean_t purge)
+{
+ isc_result_t result;
+ isc_interval_t maxinterval, idleinterval;
+ isc_time_t expires;
+
+ /* Compute the time of expiry. */
+ isc_interval_set(&maxinterval, maxtime, 0);
+ CHECK(isc_time_nowplusinterval(&expires, &maxinterval));
+
+ /*
+ * Compute the idle interval, and add a spare nanosecond to
+ * work around the silly limitation of the ISC timer interface
+ * that you cannot specify an idle interval of zero.
+ */
+ isc_interval_set(&idleinterval, idletime, 1);
+
+ CHECK(isc_timer_reset(timer, isc_timertype_once,
+ &expires, &idleinterval,
+ purge));
+ failure:
+ return (result);
+}
diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c
new file mode 100644
index 0000000..e4dbdc7
--- /dev/null
+++ b/lib/dns/tkey.c
@@ -0,0 +1,1242 @@
+/*
+ * Copyright (C) 2004, 2005 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: tkey.c,v 1.76.18.5 2005/11/30 03:44:39 marka Exp $
+ */
+/*! \file */
+#include <config.h>
+
+#include <isc/buffer.h>
+#include <isc/entropy.h>
+#include <isc/md5.h>
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/dnssec.h>
+#include <dns/fixedname.h>
+#include <dns/keyvalues.h>
+#include <dns/log.h>
+#include <dns/message.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/result.h>
+#include <dns/tkey.h>
+#include <dns/tsig.h>
+
+#include <dst/dst.h>
+#include <dst/gssapi.h>
+
+#define TKEY_RANDOM_AMOUNT 16
+
+#define RETERR(x) do { \
+ result = (x); \
+ if (result != ISC_R_SUCCESS) \
+ goto failure; \
+ } while (0)
+
+static void
+tkey_log(const char *fmt, ...) ISC_FORMAT_PRINTF(1, 2);
+
+static void
+tkey_log(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_REQUEST, ISC_LOG_DEBUG(4), fmt, ap);
+ va_end(ap);
+}
+
+isc_result_t
+dns_tkeyctx_create(isc_mem_t *mctx, isc_entropy_t *ectx, dns_tkeyctx_t **tctxp)
+{
+ dns_tkeyctx_t *tctx;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(ectx != NULL);
+ REQUIRE(tctxp != NULL && *tctxp == NULL);
+
+ tctx = isc_mem_get(mctx, sizeof(dns_tkeyctx_t));
+ if (tctx == NULL)
+ return (ISC_R_NOMEMORY);
+ tctx->mctx = NULL;
+ isc_mem_attach(mctx, &tctx->mctx);
+ tctx->ectx = NULL;
+ isc_entropy_attach(ectx, &tctx->ectx);
+ tctx->dhkey = NULL;
+ tctx->domain = NULL;
+ tctx->gsscred = NULL;
+
+ *tctxp = tctx;
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_tkeyctx_destroy(dns_tkeyctx_t **tctxp) {
+ isc_mem_t *mctx;
+ dns_tkeyctx_t *tctx;
+
+ REQUIRE(tctxp != NULL && *tctxp != NULL);
+
+ tctx = *tctxp;
+ mctx = tctx->mctx;
+
+ if (tctx->dhkey != NULL)
+ dst_key_free(&tctx->dhkey);
+ if (tctx->domain != NULL) {
+ if (dns_name_dynamic(tctx->domain))
+ dns_name_free(tctx->domain, mctx);
+ isc_mem_put(mctx, tctx->domain, sizeof(dns_name_t));
+ }
+ isc_entropy_detach(&tctx->ectx);
+ isc_mem_put(mctx, tctx, sizeof(dns_tkeyctx_t));
+ isc_mem_detach(&mctx);
+ *tctxp = NULL;
+}
+
+static isc_result_t
+add_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata,
+ isc_uint32_t ttl, dns_namelist_t *namelist)
+{
+ isc_result_t result;
+ isc_region_t r, newr;
+ dns_rdata_t *newrdata = NULL;
+ dns_name_t *newname = NULL;
+ dns_rdatalist_t *newlist = NULL;
+ dns_rdataset_t *newset = NULL;
+ isc_buffer_t *tmprdatabuf = NULL;
+
+ RETERR(dns_message_gettemprdata(msg, &newrdata));
+
+ dns_rdata_toregion(rdata, &r);
+ RETERR(isc_buffer_allocate(msg->mctx, &tmprdatabuf, r.length));
+ isc_buffer_availableregion(tmprdatabuf, &newr);
+ memcpy(newr.base, r.base, r.length);
+ dns_rdata_fromregion(newrdata, rdata->rdclass, rdata->type, &newr);
+ dns_message_takebuffer(msg, &tmprdatabuf);
+
+ RETERR(dns_message_gettempname(msg, &newname));
+ dns_name_init(newname, NULL);
+ RETERR(dns_name_dup(name, msg->mctx, newname));
+
+ RETERR(dns_message_gettemprdatalist(msg, &newlist));
+ newlist->rdclass = newrdata->rdclass;
+ newlist->type = newrdata->type;
+ newlist->covers = 0;
+ newlist->ttl = ttl;
+ ISC_LIST_INIT(newlist->rdata);
+ ISC_LIST_APPEND(newlist->rdata, newrdata, link);
+
+ RETERR(dns_message_gettemprdataset(msg, &newset));
+ dns_rdataset_init(newset);
+ RETERR(dns_rdatalist_tordataset(newlist, newset));
+
+ ISC_LIST_INIT(newname->list);
+ ISC_LIST_APPEND(newname->list, newset, link);
+
+ ISC_LIST_APPEND(*namelist, newname, link);
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (newrdata != NULL) {
+ if (ISC_LINK_LINKED(newrdata, link))
+ ISC_LIST_UNLINK(newlist->rdata, newrdata, link);
+ dns_message_puttemprdata(msg, &newrdata);
+ }
+ if (newname != NULL)
+ dns_message_puttempname(msg, &newname);
+ if (newset != NULL) {
+ dns_rdataset_disassociate(newset);
+ dns_message_puttemprdataset(msg, &newset);
+ }
+ if (newlist != NULL)
+ dns_message_puttemprdatalist(msg, &newlist);
+ return (result);
+}
+
+static void
+free_namelist(dns_message_t *msg, dns_namelist_t *namelist) {
+ dns_name_t *name;
+ dns_rdataset_t *set;
+
+ while (!ISC_LIST_EMPTY(*namelist)) {
+ name = ISC_LIST_HEAD(*namelist);
+ ISC_LIST_UNLINK(*namelist, name, link);
+ while (!ISC_LIST_EMPTY(name->list)) {
+ set = ISC_LIST_HEAD(name->list);
+ ISC_LIST_UNLINK(name->list, set, link);
+ dns_message_puttemprdataset(msg, &set);
+ }
+ dns_message_puttempname(msg, &name);
+ }
+}
+
+static isc_result_t
+compute_secret(isc_buffer_t *shared, isc_region_t *queryrandomness,
+ isc_region_t *serverrandomness, isc_buffer_t *secret)
+{
+ isc_md5_t md5ctx;
+ isc_region_t r, r2;
+ unsigned char digests[32];
+ unsigned int i;
+
+ isc_buffer_usedregion(shared, &r);
+
+ /*
+ * MD5 ( query data | DH value ).
+ */
+ isc_md5_init(&md5ctx);
+ isc_md5_update(&md5ctx, queryrandomness->base,
+ queryrandomness->length);
+ isc_md5_update(&md5ctx, r.base, r.length);
+ isc_md5_final(&md5ctx, digests);
+
+ /*
+ * MD5 ( server data | DH value ).
+ */
+ isc_md5_init(&md5ctx);
+ isc_md5_update(&md5ctx, serverrandomness->base,
+ serverrandomness->length);
+ isc_md5_update(&md5ctx, r.base, r.length);
+ isc_md5_final(&md5ctx, &digests[ISC_MD5_DIGESTLENGTH]);
+
+ /*
+ * XOR ( DH value, MD5-1 | MD5-2).
+ */
+ isc_buffer_availableregion(secret, &r);
+ isc_buffer_usedregion(shared, &r2);
+ if (r.length < sizeof(digests) || r.length < r2.length)
+ return (ISC_R_NOSPACE);
+ if (r2.length > sizeof(digests)) {
+ memcpy(r.base, r2.base, r2.length);
+ for (i = 0; i < sizeof(digests); i++)
+ r.base[i] ^= digests[i];
+ isc_buffer_add(secret, r2.length);
+ } else {
+ memcpy(r.base, digests, sizeof(digests));
+ for (i = 0; i < r2.length; i++)
+ r.base[i] ^= r2.base[i];
+ isc_buffer_add(secret, sizeof(digests));
+ }
+ return (ISC_R_SUCCESS);
+
+}
+
+static isc_result_t
+process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
+ dns_rdata_tkey_t *tkeyin, dns_tkeyctx_t *tctx,
+ dns_rdata_tkey_t *tkeyout,
+ dns_tsig_keyring_t *ring, dns_namelist_t *namelist)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_name_t *keyname, ourname;
+ dns_rdataset_t *keyset = NULL;
+ dns_rdata_t keyrdata = DNS_RDATA_INIT, ourkeyrdata = DNS_RDATA_INIT;
+ isc_boolean_t found_key = ISC_FALSE, found_incompatible = ISC_FALSE;
+ dst_key_t *pubkey = NULL;
+ isc_buffer_t ourkeybuf, *shared = NULL;
+ isc_region_t r, r2, ourkeyr;
+ unsigned char keydata[DST_KEY_MAXSIZE];
+ unsigned int sharedsize;
+ isc_buffer_t secret;
+ unsigned char *randomdata = NULL, secretdata[256];
+ dns_ttl_t ttl = 0;
+
+ if (tctx->dhkey == NULL) {
+ tkey_log("process_dhtkey: tkey-dhkey not defined");
+ tkeyout->error = dns_tsigerror_badalg;
+ return (DNS_R_REFUSED);
+ }
+
+ if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_HMACMD5_NAME)) {
+ tkey_log("process_dhtkey: algorithms other than "
+ "hmac-md5 are not supported");
+ tkeyout->error = dns_tsigerror_badalg;
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * Look for a DH KEY record that will work with ours.
+ */
+ for (result = dns_message_firstname(msg, DNS_SECTION_ADDITIONAL);
+ result == ISC_R_SUCCESS && !found_key;
+ result = dns_message_nextname(msg, DNS_SECTION_ADDITIONAL))
+ {
+ keyname = NULL;
+ dns_message_currentname(msg, DNS_SECTION_ADDITIONAL, &keyname);
+ keyset = NULL;
+ result = dns_message_findtype(keyname, dns_rdatatype_key, 0,
+ &keyset);
+ if (result != ISC_R_SUCCESS)
+ continue;
+
+ for (result = dns_rdataset_first(keyset);
+ result == ISC_R_SUCCESS && !found_key;
+ result = dns_rdataset_next(keyset))
+ {
+ dns_rdataset_current(keyset, &keyrdata);
+ pubkey = NULL;
+ result = dns_dnssec_keyfromrdata(keyname, &keyrdata,
+ msg->mctx, &pubkey);
+ if (result != ISC_R_SUCCESS) {
+ dns_rdata_reset(&keyrdata);
+ continue;
+ }
+ if (dst_key_alg(pubkey) == DNS_KEYALG_DH) {
+ if (dst_key_paramcompare(pubkey, tctx->dhkey))
+ {
+ found_key = ISC_TRUE;
+ ttl = keyset->ttl;
+ break;
+ } else
+ found_incompatible = ISC_TRUE;
+ }
+ dst_key_free(&pubkey);
+ dns_rdata_reset(&keyrdata);
+ }
+ }
+
+ if (!found_key) {
+ if (found_incompatible) {
+ tkey_log("process_dhtkey: found an incompatible key");
+ tkeyout->error = dns_tsigerror_badkey;
+ return (ISC_R_SUCCESS);
+ } else {
+ tkey_log("process_dhtkey: failed to find a key");
+ return (DNS_R_FORMERR);
+ }
+ }
+
+ RETERR(add_rdata_to_list(msg, keyname, &keyrdata, ttl, namelist));
+
+ isc_buffer_init(&ourkeybuf, keydata, sizeof(keydata));
+ RETERR(dst_key_todns(tctx->dhkey, &ourkeybuf));
+ isc_buffer_usedregion(&ourkeybuf, &ourkeyr);
+ dns_rdata_fromregion(&ourkeyrdata, dns_rdataclass_any,
+ dns_rdatatype_key, &ourkeyr);
+
+ dns_name_init(&ourname, NULL);
+ dns_name_clone(dst_key_name(tctx->dhkey), &ourname);
+
+ /*
+ * XXXBEW The TTL should be obtained from the database, if it exists.
+ */
+ RETERR(add_rdata_to_list(msg, &ourname, &ourkeyrdata, 0, namelist));
+
+ RETERR(dst_key_secretsize(tctx->dhkey, &sharedsize));
+ RETERR(isc_buffer_allocate(msg->mctx, &shared, sharedsize));
+
+ result = dst_key_computesecret(pubkey, tctx->dhkey, shared);
+ if (result != ISC_R_SUCCESS) {
+ tkey_log("process_dhtkey: failed to compute shared secret: %s",
+ isc_result_totext(result));
+ goto failure;
+ }
+ dst_key_free(&pubkey);
+
+ isc_buffer_init(&secret, secretdata, sizeof(secretdata));
+
+ randomdata = isc_mem_get(tkeyout->mctx, TKEY_RANDOM_AMOUNT);
+ if (randomdata == NULL)
+ goto failure;
+
+ result = isc_entropy_getdata(tctx->ectx, randomdata,
+ TKEY_RANDOM_AMOUNT, NULL, 0);
+ if (result != ISC_R_SUCCESS) {
+ tkey_log("process_dhtkey: failed to obtain entropy: %s",
+ isc_result_totext(result));
+ goto failure;
+ }
+
+ r.base = randomdata;
+ r.length = TKEY_RANDOM_AMOUNT;
+ r2.base = tkeyin->key;
+ r2.length = tkeyin->keylen;
+ RETERR(compute_secret(shared, &r2, &r, &secret));
+ isc_buffer_free(&shared);
+
+ RETERR(dns_tsigkey_create(name, &tkeyin->algorithm,
+ isc_buffer_base(&secret),
+ isc_buffer_usedlength(&secret),
+ ISC_TRUE, signer, tkeyin->inception,
+ tkeyin->expire, msg->mctx, ring, NULL));
+
+ /* This key is good for a long time */
+ tkeyout->inception = tkeyin->inception;
+ tkeyout->expire = tkeyin->expire;
+
+ tkeyout->key = randomdata;
+ tkeyout->keylen = TKEY_RANDOM_AMOUNT;
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (!ISC_LIST_EMPTY(*namelist))
+ free_namelist(msg, namelist);
+ if (shared != NULL)
+ isc_buffer_free(&shared);
+ if (pubkey != NULL)
+ dst_key_free(&pubkey);
+ if (randomdata != NULL)
+ isc_mem_put(tkeyout->mctx, randomdata, TKEY_RANDOM_AMOUNT);
+ return (result);
+}
+
+static isc_result_t
+process_gsstkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
+ dns_rdata_tkey_t *tkeyin, dns_tkeyctx_t *tctx,
+ dns_rdata_tkey_t *tkeyout,
+ dns_tsig_keyring_t *ring, dns_namelist_t *namelist)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ dst_key_t *dstkey = NULL;
+ void *gssctx = NULL;
+ isc_stdtime_t now;
+ isc_region_t intoken;
+ unsigned char array[1024];
+ isc_buffer_t outtoken;
+
+ UNUSED(namelist);
+
+ if (tctx->gsscred == NULL)
+ return (ISC_R_NOPERM);
+
+ if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPI_NAME) &&
+ !dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
+ tkeyout->error = dns_tsigerror_badalg;
+ return (ISC_R_SUCCESS);
+ }
+
+ intoken.base = tkeyin->key;
+ intoken.length = tkeyin->keylen;
+
+ isc_buffer_init(&outtoken, array, sizeof(array));
+ RETERR(dst_gssapi_acceptctx(name, tctx->gsscred, &intoken,
+ &outtoken, &gssctx));
+
+ dstkey = NULL;
+ RETERR(dst_key_fromgssapi(name, gssctx, msg->mctx, &dstkey));
+
+ result = dns_tsigkey_createfromkey(name, &tkeyin->algorithm,
+ dstkey, ISC_TRUE, signer,
+ tkeyin->inception, tkeyin->expire,
+ msg->mctx, ring, NULL);
+#if 1
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+#else
+ if (result == ISC_R_NOTFOUND) {
+ tkeyout->error = dns_tsigerror_badalg;
+ return (ISC_R_SUCCESS);
+ }
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+#endif
+
+ /* This key is good for a long time */
+ isc_stdtime_get(&now);
+ tkeyout->inception = tkeyin->inception;
+ tkeyout->expire = tkeyin->expire;
+
+ tkeyout->key = isc_mem_get(msg->mctx,
+ isc_buffer_usedlength(&outtoken));
+ if (tkeyout->key == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto failure;
+ }
+ tkeyout->keylen = isc_buffer_usedlength(&outtoken);
+ memcpy(tkeyout->key, isc_buffer_base(&outtoken), tkeyout->keylen);
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (dstkey != NULL)
+ dst_key_free(&dstkey);
+
+ return (result);
+}
+
+static isc_result_t
+process_deletetkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
+ dns_rdata_tkey_t *tkeyin,
+ dns_rdata_tkey_t *tkeyout,
+ dns_tsig_keyring_t *ring,
+ dns_namelist_t *namelist)
+{
+ isc_result_t result;
+ dns_tsigkey_t *tsigkey = NULL;
+ dns_name_t *identity;
+
+ UNUSED(msg);
+ UNUSED(namelist);
+
+ result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring);
+ if (result != ISC_R_SUCCESS) {
+ tkeyout->error = dns_tsigerror_badname;
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * Only allow a delete if the identity that created the key is the
+ * same as the identity that signed the message.
+ */
+ identity = dns_tsigkey_identity(tsigkey);
+ if (identity == NULL || !dns_name_equal(identity, signer)) {
+ dns_tsigkey_detach(&tsigkey);
+ return (DNS_R_REFUSED);
+ }
+
+ /*
+ * Set the key to be deleted when no references are left. If the key
+ * was not generated with TKEY and is in the config file, it may be
+ * reloaded later.
+ */
+ dns_tsigkey_setdeleted(tsigkey);
+
+ /* Release the reference */
+ dns_tsigkey_detach(&tsigkey);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx,
+ dns_tsig_keyring_t *ring)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_rdata_tkey_t tkeyin, tkeyout;
+ isc_boolean_t freetkeyin = ISC_FALSE;
+ dns_name_t *qname, *name, *keyname, *signer, tsigner;
+ dns_fixedname_t fkeyname;
+ dns_rdataset_t *tkeyset;
+ dns_rdata_t rdata;
+ dns_namelist_t namelist;
+ char tkeyoutdata[512];
+ isc_buffer_t tkeyoutbuf;
+
+ REQUIRE(msg != NULL);
+ REQUIRE(tctx != NULL);
+ REQUIRE(ring != NULL);
+
+ ISC_LIST_INIT(namelist);
+
+ /*
+ * Interpret the question section.
+ */
+ result = dns_message_firstname(msg, DNS_SECTION_QUESTION);
+ if (result != ISC_R_SUCCESS)
+ return (DNS_R_FORMERR);
+
+ qname = NULL;
+ dns_message_currentname(msg, DNS_SECTION_QUESTION, &qname);
+
+ /*
+ * Look for a TKEY record that matches the question.
+ */
+ tkeyset = NULL;
+ name = NULL;
+ result = dns_message_findname(msg, DNS_SECTION_ADDITIONAL, qname,
+ dns_rdatatype_tkey, 0, &name, &tkeyset);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * Try the answer section, since that's where Win2000
+ * puts it.
+ */
+ if (dns_message_findname(msg, DNS_SECTION_ANSWER, qname,
+ dns_rdatatype_tkey, 0, &name,
+ &tkeyset) != ISC_R_SUCCESS)
+ {
+ result = DNS_R_FORMERR;
+ tkey_log("dns_tkey_processquery: couldn't find a TKEY "
+ "matching the question");
+ goto failure;
+ }
+ }
+ result = dns_rdataset_first(tkeyset);
+ if (result != ISC_R_SUCCESS) {
+ result = DNS_R_FORMERR;
+ goto failure;
+ }
+ dns_rdata_init(&rdata);
+ dns_rdataset_current(tkeyset, &rdata);
+
+ RETERR(dns_rdata_tostruct(&rdata, &tkeyin, NULL));
+ freetkeyin = ISC_TRUE;
+
+ if (tkeyin.error != dns_rcode_noerror) {
+ result = DNS_R_FORMERR;
+ goto failure;
+ }
+
+ /*
+ * Before we go any farther, verify that the message was signed.
+ * GSSAPI TKEY doesn't require a signature, the rest do.
+ */
+ dns_name_init(&tsigner, NULL);
+ result = dns_message_signer(msg, &tsigner);
+ if (result != ISC_R_SUCCESS) {
+ if (tkeyin.mode == DNS_TKEYMODE_GSSAPI &&
+ result == ISC_R_NOTFOUND)
+ signer = NULL;
+ else {
+ tkey_log("dns_tkey_processquery: query was not "
+ "properly signed - rejecting");
+ result = DNS_R_FORMERR;
+ goto failure;
+ }
+ } else
+ signer = &tsigner;
+
+ tkeyout.common.rdclass = tkeyin.common.rdclass;
+ tkeyout.common.rdtype = tkeyin.common.rdtype;
+ ISC_LINK_INIT(&tkeyout.common, link);
+ tkeyout.mctx = msg->mctx;
+
+ dns_name_init(&tkeyout.algorithm, NULL);
+ dns_name_clone(&tkeyin.algorithm, &tkeyout.algorithm);
+
+ tkeyout.inception = tkeyout.expire = 0;
+ tkeyout.mode = tkeyin.mode;
+ tkeyout.error = 0;
+ tkeyout.keylen = tkeyout.otherlen = 0;
+ tkeyout.key = tkeyout.other = NULL;
+
+ /*
+ * A delete operation must have a fully specified key name. If this
+ * is not a delete, we do the following:
+ * if (qname != ".")
+ * keyname = qname + defaultdomain
+ * else
+ * keyname = <random hex> + defaultdomain
+ */
+ if (tkeyin.mode != DNS_TKEYMODE_DELETE) {
+ dns_tsigkey_t *tsigkey = NULL;
+
+ if (tctx->domain == NULL) {
+ tkey_log("dns_tkey_processquery: tkey-domain not set");
+ result = DNS_R_REFUSED;
+ goto failure;
+ }
+
+ dns_fixedname_init(&fkeyname);
+ keyname = dns_fixedname_name(&fkeyname);
+
+ if (!dns_name_equal(qname, dns_rootname)) {
+ unsigned int n = dns_name_countlabels(qname);
+ RUNTIME_CHECK(dns_name_copy(qname, keyname, NULL)
+ == ISC_R_SUCCESS);
+ dns_name_getlabelsequence(keyname, 0, n - 1, keyname);
+ } else {
+ static char hexdigits[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ unsigned char randomdata[16];
+ char randomtext[32];
+ isc_buffer_t b;
+ unsigned int i, j;
+
+ result = isc_entropy_getdata(tctx->ectx,
+ randomdata,
+ sizeof(randomdata),
+ NULL, 0);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ for (i = 0, j = 0; i < sizeof(randomdata); i++) {
+ unsigned char val = randomdata[i];
+ randomtext[j++] = hexdigits[val >> 4];
+ randomtext[j++] = hexdigits[val & 0xF];
+ }
+ isc_buffer_init(&b, randomtext, sizeof(randomtext));
+ isc_buffer_add(&b, sizeof(randomtext));
+ result = dns_name_fromtext(keyname, &b, NULL,
+ ISC_FALSE, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ }
+ result = dns_name_concatenate(keyname, tctx->domain,
+ keyname, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring);
+ if (result == ISC_R_SUCCESS) {
+ tkeyout.error = dns_tsigerror_badname;
+ dns_tsigkey_detach(&tsigkey);
+ goto failure_with_tkey;
+ } else if (result != ISC_R_NOTFOUND)
+ goto failure;
+ } else
+ keyname = qname;
+
+ switch (tkeyin.mode) {
+ case DNS_TKEYMODE_DIFFIEHELLMAN:
+ tkeyout.error = dns_rcode_noerror;
+ RETERR(process_dhtkey(msg, signer, keyname, &tkeyin,
+ tctx, &tkeyout, ring,
+ &namelist));
+ break;
+ case DNS_TKEYMODE_GSSAPI:
+ tkeyout.error = dns_rcode_noerror;
+ RETERR(process_gsstkey(msg, signer, keyname, &tkeyin,
+ tctx, &tkeyout, ring,
+ &namelist));
+ break;
+ case DNS_TKEYMODE_DELETE:
+ tkeyout.error = dns_rcode_noerror;
+ RETERR(process_deletetkey(msg, signer, keyname,
+ &tkeyin, &tkeyout,
+ ring, &namelist));
+ break;
+ case DNS_TKEYMODE_SERVERASSIGNED:
+ case DNS_TKEYMODE_RESOLVERASSIGNED:
+ result = DNS_R_NOTIMP;
+ goto failure;
+ default:
+ tkeyout.error = dns_tsigerror_badmode;
+ }
+
+ failure_with_tkey:
+ dns_rdata_init(&rdata);
+ isc_buffer_init(&tkeyoutbuf, tkeyoutdata, sizeof(tkeyoutdata));
+ result = dns_rdata_fromstruct(&rdata, tkeyout.common.rdclass,
+ tkeyout.common.rdtype, &tkeyout,
+ &tkeyoutbuf);
+
+ if (freetkeyin) {
+ dns_rdata_freestruct(&tkeyin);
+ freetkeyin = ISC_FALSE;
+ }
+
+ if (tkeyout.key != NULL)
+ isc_mem_put(msg->mctx, tkeyout.key, tkeyout.keylen);
+ if (tkeyout.other != NULL)
+ isc_mem_put(msg->mctx, tkeyout.other, tkeyout.otherlen);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ RETERR(add_rdata_to_list(msg, keyname, &rdata, 0, &namelist));
+
+ RETERR(dns_message_reply(msg, ISC_TRUE));
+
+ name = ISC_LIST_HEAD(namelist);
+ while (name != NULL) {
+ dns_name_t *next = ISC_LIST_NEXT(name, link);
+ ISC_LIST_UNLINK(namelist, name, link);
+ dns_message_addname(msg, name, DNS_SECTION_ANSWER);
+ name = next;
+ }
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (freetkeyin)
+ dns_rdata_freestruct(&tkeyin);
+ if (!ISC_LIST_EMPTY(namelist))
+ free_namelist(msg, &namelist);
+ return (result);
+}
+
+static isc_result_t
+buildquery(dns_message_t *msg, dns_name_t *name,
+ dns_rdata_tkey_t *tkey)
+{
+ dns_name_t *qname = NULL, *aname = NULL;
+ dns_rdataset_t *question = NULL, *tkeyset = NULL;
+ dns_rdatalist_t *tkeylist = NULL;
+ dns_rdata_t *rdata = NULL;
+ isc_buffer_t *dynbuf = NULL;
+ isc_result_t result;
+
+ REQUIRE(msg != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(tkey != NULL);
+
+ RETERR(dns_message_gettempname(msg, &qname));
+ RETERR(dns_message_gettempname(msg, &aname));
+
+ RETERR(dns_message_gettemprdataset(msg, &question));
+ dns_rdataset_init(question);
+ dns_rdataset_makequestion(question, dns_rdataclass_any,
+ dns_rdatatype_tkey);
+
+ RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 512));
+ RETERR(dns_message_gettemprdata(msg, &rdata));
+ RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
+ dns_rdatatype_tkey, tkey, dynbuf));
+ dns_message_takebuffer(msg, &dynbuf);
+
+ RETERR(dns_message_gettemprdatalist(msg, &tkeylist));
+ tkeylist->rdclass = dns_rdataclass_any;
+ tkeylist->type = dns_rdatatype_tkey;
+ tkeylist->covers = 0;
+ tkeylist->ttl = 0;
+ ISC_LIST_INIT(tkeylist->rdata);
+ ISC_LIST_APPEND(tkeylist->rdata, rdata, link);
+
+ RETERR(dns_message_gettemprdataset(msg, &tkeyset));
+ dns_rdataset_init(tkeyset);
+ RETERR(dns_rdatalist_tordataset(tkeylist, tkeyset));
+
+ dns_name_init(qname, NULL);
+ dns_name_clone(name, qname);
+
+ dns_name_init(aname, NULL);
+ dns_name_clone(name, aname);
+
+ ISC_LIST_APPEND(qname->list, question, link);
+ ISC_LIST_APPEND(aname->list, tkeyset, link);
+
+ dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
+ dns_message_addname(msg, aname, DNS_SECTION_ADDITIONAL);
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (qname != NULL)
+ dns_message_puttempname(msg, &qname);
+ if (aname != NULL)
+ dns_message_puttempname(msg, &aname);
+ if (question != NULL) {
+ dns_rdataset_disassociate(question);
+ dns_message_puttemprdataset(msg, &question);
+ }
+ if (dynbuf != NULL)
+ isc_buffer_free(&dynbuf);
+ return (result);
+}
+
+isc_result_t
+dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name,
+ dns_name_t *algorithm, isc_buffer_t *nonce,
+ isc_uint32_t lifetime)
+{
+ dns_rdata_tkey_t tkey;
+ dns_rdata_t *rdata = NULL;
+ isc_buffer_t *dynbuf = NULL;
+ isc_region_t r;
+ dns_name_t keyname;
+ dns_namelist_t namelist;
+ isc_result_t result;
+ isc_stdtime_t now;
+
+ REQUIRE(msg != NULL);
+ REQUIRE(key != NULL);
+ REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH);
+ REQUIRE(dst_key_isprivate(key));
+ REQUIRE(name != NULL);
+ REQUIRE(algorithm != NULL);
+
+ tkey.common.rdclass = dns_rdataclass_any;
+ tkey.common.rdtype = dns_rdatatype_tkey;
+ ISC_LINK_INIT(&tkey.common, link);
+ tkey.mctx = msg->mctx;
+ dns_name_init(&tkey.algorithm, NULL);
+ dns_name_clone(algorithm, &tkey.algorithm);
+ isc_stdtime_get(&now);
+ tkey.inception = now;
+ tkey.expire = now + lifetime;
+ tkey.mode = DNS_TKEYMODE_DIFFIEHELLMAN;
+ if (nonce != NULL)
+ isc_buffer_usedregion(nonce, &r);
+ else {
+ r.base = isc_mem_get(msg->mctx, 0);
+ r.length = 0;
+ }
+ tkey.error = 0;
+ tkey.key = r.base;
+ tkey.keylen = r.length;
+ tkey.other = NULL;
+ tkey.otherlen = 0;
+
+ RETERR(buildquery(msg, name, &tkey));
+
+ if (nonce == NULL)
+ isc_mem_put(msg->mctx, r.base, 0);
+
+ RETERR(dns_message_gettemprdata(msg, &rdata));
+ RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
+ RETERR(dst_key_todns(key, dynbuf));
+ isc_buffer_usedregion(dynbuf, &r);
+ dns_rdata_fromregion(rdata, dns_rdataclass_any,
+ dns_rdatatype_key, &r);
+ dns_message_takebuffer(msg, &dynbuf);
+
+ dns_name_init(&keyname, NULL);
+ dns_name_clone(dst_key_name(key), &keyname);
+
+ ISC_LIST_INIT(namelist);
+ RETERR(add_rdata_to_list(msg, &keyname, rdata, 0, &namelist));
+ dns_message_addname(msg, ISC_LIST_HEAD(namelist),
+ DNS_SECTION_ADDITIONAL);
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+
+ if (dynbuf != NULL)
+ isc_buffer_free(&dynbuf);
+ return (result);
+}
+
+isc_result_t
+dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name,
+ dns_name_t *gname, void *cred,
+ isc_uint32_t lifetime, void **context)
+{
+ dns_rdata_tkey_t tkey;
+ isc_result_t result;
+ isc_stdtime_t now;
+ isc_buffer_t token;
+ unsigned char array[1024];
+
+ REQUIRE(msg != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(gname != NULL);
+ REQUIRE(context != NULL && *context == NULL);
+
+ isc_buffer_init(&token, array, sizeof(array));
+ result = dst_gssapi_initctx(gname, cred, NULL, &token, context);
+ if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
+ return (result);
+
+ tkey.common.rdclass = dns_rdataclass_any;
+ tkey.common.rdtype = dns_rdatatype_tkey;
+ ISC_LINK_INIT(&tkey.common, link);
+ tkey.mctx = NULL;
+ dns_name_init(&tkey.algorithm, NULL);
+ dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm);
+ isc_stdtime_get(&now);
+ tkey.inception = now;
+ tkey.expire = now + lifetime;
+ tkey.mode = DNS_TKEYMODE_GSSAPI;
+ tkey.error = 0;
+ tkey.key = isc_buffer_base(&token);
+ tkey.keylen = isc_buffer_usedlength(&token);
+ tkey.other = NULL;
+ tkey.otherlen = 0;
+
+ RETERR(buildquery(msg, name, &tkey));
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+ return (result);
+}
+
+isc_result_t
+dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key) {
+ dns_rdata_tkey_t tkey;
+
+ REQUIRE(msg != NULL);
+ REQUIRE(key != NULL);
+
+ tkey.common.rdclass = dns_rdataclass_any;
+ tkey.common.rdtype = dns_rdatatype_tkey;
+ ISC_LINK_INIT(&tkey.common, link);
+ tkey.mctx = msg->mctx;
+ dns_name_init(&tkey.algorithm, NULL);
+ dns_name_clone(key->algorithm, &tkey.algorithm);
+ tkey.inception = tkey.expire = 0;
+ tkey.mode = DNS_TKEYMODE_DELETE;
+ tkey.error = 0;
+ tkey.keylen = tkey.otherlen = 0;
+ tkey.key = tkey.other = NULL;
+
+ return (buildquery(msg, &key->name, &tkey));
+}
+
+static isc_result_t
+find_tkey(dns_message_t *msg, dns_name_t **name, dns_rdata_t *rdata,
+ int section)
+{
+ dns_rdataset_t *tkeyset;
+ isc_result_t result;
+
+ result = dns_message_firstname(msg, section);
+ while (result == ISC_R_SUCCESS) {
+ *name = NULL;
+ dns_message_currentname(msg, section, name);
+ tkeyset = NULL;
+ result = dns_message_findtype(*name, dns_rdatatype_tkey, 0,
+ &tkeyset);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_rdataset_first(tkeyset);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_rdataset_current(tkeyset, rdata);
+ return (ISC_R_SUCCESS);
+ }
+ result = dns_message_nextname(msg, section);
+ }
+ if (result == ISC_R_NOMORE)
+ return (ISC_R_NOTFOUND);
+ return (result);
+}
+
+isc_result_t
+dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+ dst_key_t *key, isc_buffer_t *nonce,
+ dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring)
+{
+ dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT;
+ dns_name_t keyname, *tkeyname, *theirkeyname, *ourkeyname, *tempname;
+ dns_rdataset_t *theirkeyset = NULL, *ourkeyset = NULL;
+ dns_rdata_t theirkeyrdata = DNS_RDATA_INIT;
+ dst_key_t *theirkey = NULL;
+ dns_rdata_tkey_t qtkey, rtkey;
+ unsigned char secretdata[256];
+ unsigned int sharedsize;
+ isc_buffer_t *shared = NULL, secret;
+ isc_region_t r, r2;
+ isc_result_t result;
+ isc_boolean_t freertkey = ISC_FALSE;
+
+ REQUIRE(qmsg != NULL);
+ REQUIRE(rmsg != NULL);
+ REQUIRE(key != NULL);
+ REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH);
+ REQUIRE(dst_key_isprivate(key));
+ if (outkey != NULL)
+ REQUIRE(*outkey == NULL);
+
+ if (rmsg->rcode != dns_rcode_noerror)
+ return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
+ RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
+ RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
+ freertkey = ISC_TRUE;
+
+ RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata,
+ DNS_SECTION_ADDITIONAL));
+ RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
+
+ if (rtkey.error != dns_rcode_noerror ||
+ rtkey.mode != DNS_TKEYMODE_DIFFIEHELLMAN ||
+ rtkey.mode != qtkey.mode ||
+ !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) ||
+ rmsg->rcode != dns_rcode_noerror)
+ {
+ tkey_log("dns_tkey_processdhresponse: tkey mode invalid "
+ "or error set");
+ result = DNS_R_INVALIDTKEY;
+ dns_rdata_freestruct(&qtkey);
+ goto failure;
+ }
+
+ dns_rdata_freestruct(&qtkey);
+
+ dns_name_init(&keyname, NULL);
+ dns_name_clone(dst_key_name(key), &keyname);
+
+ ourkeyname = NULL;
+ ourkeyset = NULL;
+ RETERR(dns_message_findname(rmsg, DNS_SECTION_ANSWER, &keyname,
+ dns_rdatatype_key, 0, &ourkeyname,
+ &ourkeyset));
+
+ result = dns_message_firstname(rmsg, DNS_SECTION_ANSWER);
+ while (result == ISC_R_SUCCESS) {
+ theirkeyname = NULL;
+ dns_message_currentname(rmsg, DNS_SECTION_ANSWER,
+ &theirkeyname);
+ if (dns_name_equal(theirkeyname, ourkeyname))
+ goto next;
+ theirkeyset = NULL;
+ result = dns_message_findtype(theirkeyname, dns_rdatatype_key,
+ 0, &theirkeyset);
+ if (result == ISC_R_SUCCESS) {
+ RETERR(dns_rdataset_first(theirkeyset));
+ break;
+ }
+ next:
+ result = dns_message_nextname(rmsg, DNS_SECTION_ANSWER);
+ }
+
+ if (theirkeyset == NULL) {
+ tkey_log("dns_tkey_processdhresponse: failed to find server "
+ "key");
+ result = ISC_R_NOTFOUND;
+ goto failure;
+ }
+
+ dns_rdataset_current(theirkeyset, &theirkeyrdata);
+ RETERR(dns_dnssec_keyfromrdata(theirkeyname, &theirkeyrdata,
+ rmsg->mctx, &theirkey));
+
+ RETERR(dst_key_secretsize(key, &sharedsize));
+ RETERR(isc_buffer_allocate(rmsg->mctx, &shared, sharedsize));
+
+ RETERR(dst_key_computesecret(theirkey, key, shared));
+
+ isc_buffer_init(&secret, secretdata, sizeof(secretdata));
+
+ r.base = rtkey.key;
+ r.length = rtkey.keylen;
+ if (nonce != NULL)
+ isc_buffer_usedregion(nonce, &r2);
+ else {
+ r2.base = isc_mem_get(rmsg->mctx, 0);
+ r2.length = 0;
+ }
+ RETERR(compute_secret(shared, &r2, &r, &secret));
+ if (nonce == NULL)
+ isc_mem_put(rmsg->mctx, r2.base, 0);
+
+ isc_buffer_usedregion(&secret, &r);
+ result = dns_tsigkey_create(tkeyname, &rtkey.algorithm,
+ r.base, r.length, ISC_TRUE,
+ NULL, rtkey.inception, rtkey.expire,
+ rmsg->mctx, ring, outkey);
+ isc_buffer_free(&shared);
+ dns_rdata_freestruct(&rtkey);
+ dst_key_free(&theirkey);
+ return (result);
+
+ failure:
+ if (shared != NULL)
+ isc_buffer_free(&shared);
+
+ if (theirkey != NULL)
+ dst_key_free(&theirkey);
+
+ if (freertkey)
+ dns_rdata_freestruct(&rtkey);
+
+ return (result);
+}
+
+isc_result_t
+dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+ dns_name_t *gname, void *cred, void **context,
+ dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring)
+{
+ dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT;
+ dns_name_t *tkeyname;
+ dns_rdata_tkey_t rtkey, qtkey;
+ isc_buffer_t outtoken;
+ dst_key_t *dstkey = NULL;
+ isc_region_t r;
+ isc_result_t result;
+ unsigned char array[1024];
+
+ REQUIRE(qmsg != NULL);
+ REQUIRE(rmsg != NULL);
+ REQUIRE(gname != NULL);
+ if (outkey != NULL)
+ REQUIRE(*outkey == NULL);
+
+ if (rmsg->rcode != dns_rcode_noerror)
+ return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
+ RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
+ RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
+
+ RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata,
+ DNS_SECTION_ADDITIONAL));
+ RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
+
+ if (rtkey.error != dns_rcode_noerror ||
+ rtkey.mode != DNS_TKEYMODE_GSSAPI ||
+ !dns_name_equal(&rtkey.algorithm, &rtkey.algorithm))
+ {
+ tkey_log("dns_tkey_processdhresponse: tkey mode invalid "
+ "or error set");
+ result = DNS_R_INVALIDTKEY;
+ goto failure;
+ }
+
+ isc_buffer_init(&outtoken, array, sizeof(array));
+ r.base = rtkey.key;
+ r.length = rtkey.keylen;
+ RETERR(dst_gssapi_initctx(gname, cred, &r, &outtoken, context));
+
+ dstkey = NULL;
+ RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx,
+ &dstkey));
+
+ RETERR(dns_tsigkey_createfromkey(tkeyname, DNS_TSIG_GSSAPI_NAME,
+ dstkey, ISC_TRUE, NULL,
+ rtkey.inception, rtkey.expire,
+ rmsg->mctx, ring, outkey));
+
+ dns_rdata_freestruct(&rtkey);
+ return (result);
+
+ failure:
+ return (result);
+}
+
+isc_result_t
+dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+ dns_tsig_keyring_t *ring)
+{
+ dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT;
+ dns_name_t *tkeyname, *tempname;
+ dns_rdata_tkey_t qtkey, rtkey;
+ dns_tsigkey_t *tsigkey = NULL;
+ isc_result_t result;
+
+ REQUIRE(qmsg != NULL);
+ REQUIRE(rmsg != NULL);
+
+ if (rmsg->rcode != dns_rcode_noerror)
+ return(ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
+
+ RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
+ RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
+
+ RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata,
+ DNS_SECTION_ADDITIONAL));
+ RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
+
+ if (rtkey.error != dns_rcode_noerror ||
+ rtkey.mode != DNS_TKEYMODE_DELETE ||
+ rtkey.mode != qtkey.mode ||
+ !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) ||
+ rmsg->rcode != dns_rcode_noerror)
+ {
+ tkey_log("dns_tkey_processdeleteresponse: tkey mode invalid "
+ "or error set");
+ result = DNS_R_INVALIDTKEY;
+ dns_rdata_freestruct(&qtkey);
+ dns_rdata_freestruct(&rtkey);
+ goto failure;
+ }
+
+ dns_rdata_freestruct(&qtkey);
+
+ RETERR(dns_tsigkey_find(&tsigkey, tkeyname, &rtkey.algorithm, ring));
+
+ dns_rdata_freestruct(&rtkey);
+
+ /*
+ * Mark the key as deleted.
+ */
+ dns_tsigkey_setdeleted(tsigkey);
+ /*
+ * Release the reference.
+ */
+ dns_tsigkey_detach(&tsigkey);
+
+ failure:
+ return (result);
+}
diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c
new file mode 100644
index 0000000..cca1f99
--- /dev/null
+++ b/lib/dns/tsig.c
@@ -0,0 +1,1464 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2002 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: tsig.c,v 1.117.18.11 2007/09/26 23:46:34 tbox Exp $
+ */
+/*! \file */
+#include <config.h>
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/refcount.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/util.h>
+
+#include <dns/keyvalues.h>
+#include <dns/log.h>
+#include <dns/message.h>
+#include <dns/rbt.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/result.h>
+#include <dns/tsig.h>
+
+#include <dst/result.h>
+
+#define TSIG_MAGIC ISC_MAGIC('T', 'S', 'I', 'G')
+#define VALID_TSIG_KEY(x) ISC_MAGIC_VALID(x, TSIG_MAGIC)
+
+#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
+#define algname_is_allocated(algname) \
+ ((algname) != dns_tsig_hmacmd5_name && \
+ (algname) != dns_tsig_hmacsha1_name && \
+ (algname) != dns_tsig_hmacsha224_name && \
+ (algname) != dns_tsig_hmacsha256_name && \
+ (algname) != dns_tsig_hmacsha384_name && \
+ (algname) != dns_tsig_hmacsha512_name && \
+ (algname) != dns_tsig_gssapi_name && \
+ (algname) != dns_tsig_gssapims_name)
+
+#define BADTIMELEN 6
+
+static unsigned char hmacmd5_ndata[] = "\010hmac-md5\007sig-alg\003reg\003int";
+static unsigned char hmacmd5_offsets[] = { 0, 9, 17, 21, 25 };
+
+static dns_name_t hmacmd5 = {
+ DNS_NAME_MAGIC,
+ hmacmd5_ndata, 26, 5,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ hmacmd5_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+dns_name_t *dns_tsig_hmacmd5_name = &hmacmd5;
+
+static unsigned char gsstsig_ndata[] = "\010gss-tsig";
+static unsigned char gsstsig_offsets[] = { 0, 9 };
+
+static dns_name_t gsstsig = {
+ DNS_NAME_MAGIC,
+ gsstsig_ndata, 10, 2,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ gsstsig_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapi_name = &gsstsig;
+
+/* It's nice of Microsoft to conform to their own standard. */
+static unsigned char gsstsigms_ndata[] = "\003gss\011microsoft\003com";
+static unsigned char gsstsigms_offsets[] = { 0, 4, 14, 18 };
+
+static dns_name_t gsstsigms = {
+ DNS_NAME_MAGIC,
+ gsstsigms_ndata, 19, 4,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ gsstsigms_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapims_name = &gsstsigms;
+
+static unsigned char hmacsha1_ndata[] = "\011hmac-sha1";
+static unsigned char hmacsha1_offsets[] = { 0, 10 };
+
+static dns_name_t hmacsha1 = {
+ DNS_NAME_MAGIC,
+ hmacsha1_ndata, 11, 2,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ hmacsha1_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha1_name = &hmacsha1;
+
+static unsigned char hmacsha224_ndata[] = "\013hmac-sha224";
+static unsigned char hmacsha224_offsets[] = { 0, 12 };
+
+static dns_name_t hmacsha224 = {
+ DNS_NAME_MAGIC,
+ hmacsha224_ndata, 13, 2,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ hmacsha224_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha224_name = &hmacsha224;
+
+static unsigned char hmacsha256_ndata[] = "\013hmac-sha256";
+static unsigned char hmacsha256_offsets[] = { 0, 12 };
+
+static dns_name_t hmacsha256 = {
+ DNS_NAME_MAGIC,
+ hmacsha256_ndata, 13, 2,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ hmacsha256_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha256_name = &hmacsha256;
+
+static unsigned char hmacsha384_ndata[] = "\013hmac-sha384";
+static unsigned char hmacsha384_offsets[] = { 0, 12 };
+
+static dns_name_t hmacsha384 = {
+ DNS_NAME_MAGIC,
+ hmacsha384_ndata, 13, 2,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ hmacsha384_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha384_name = &hmacsha384;
+
+static unsigned char hmacsha512_ndata[] = "\013hmac-sha512";
+static unsigned char hmacsha512_offsets[] = { 0, 12 };
+
+static dns_name_t hmacsha512 = {
+ DNS_NAME_MAGIC,
+ hmacsha512_ndata, 13, 2,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ hmacsha512_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
+};
+
+LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha512_name = &hmacsha512;
+
+static isc_result_t
+tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg);
+
+static void
+tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+
+static void
+tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
+ va_list ap;
+ char message[4096];
+ char namestr[DNS_NAME_FORMATSIZE];
+
+ if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
+ return;
+ if (key != NULL)
+ dns_name_format(&key->name, namestr, sizeof(namestr));
+ else
+ strcpy(namestr, "<null>");
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
+ level, "tsig key '%s': %s", namestr, message);
+}
+
+isc_result_t
+dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
+ dst_key_t *dstkey, isc_boolean_t generated,
+ dns_name_t *creator, isc_stdtime_t inception,
+ isc_stdtime_t expire, isc_mem_t *mctx,
+ dns_tsig_keyring_t *ring, dns_tsigkey_t **key)
+{
+ dns_tsigkey_t *tkey;
+ isc_result_t ret;
+ unsigned int refs = 0;
+
+ REQUIRE(key == NULL || *key == NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(algorithm != NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(key != NULL || ring != NULL);
+
+ tkey = (dns_tsigkey_t *) isc_mem_get(mctx, sizeof(dns_tsigkey_t));
+ if (tkey == NULL)
+ return (ISC_R_NOMEMORY);
+
+ dns_name_init(&tkey->name, NULL);
+ ret = dns_name_dup(name, mctx, &tkey->name);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_key;
+ (void)dns_name_downcase(&tkey->name, &tkey->name, NULL);
+
+ if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
+ tkey->algorithm = DNS_TSIG_HMACMD5_NAME;
+ if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) {
+ ret = DNS_R_BADALG;
+ goto cleanup_name;
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) {
+ tkey->algorithm = DNS_TSIG_HMACSHA1_NAME;
+ if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA1) {
+ ret = DNS_R_BADALG;
+ goto cleanup_name;
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) {
+ tkey->algorithm = DNS_TSIG_HMACSHA224_NAME;
+ if (dstkey != NULL &&
+ dst_key_alg(dstkey) != DST_ALG_HMACSHA224) {
+ ret = DNS_R_BADALG;
+ goto cleanup_name;
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) {
+ tkey->algorithm = DNS_TSIG_HMACSHA256_NAME;
+ if (dstkey != NULL &&
+ dst_key_alg(dstkey) != DST_ALG_HMACSHA256) {
+ ret = DNS_R_BADALG;
+ goto cleanup_name;
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) {
+ tkey->algorithm = DNS_TSIG_HMACSHA384_NAME;
+ if (dstkey != NULL &&
+ dst_key_alg(dstkey) != DST_ALG_HMACSHA384) {
+ ret = DNS_R_BADALG;
+ goto cleanup_name;
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) {
+ tkey->algorithm = DNS_TSIG_HMACSHA512_NAME;
+ if (dstkey != NULL &&
+ dst_key_alg(dstkey) != DST_ALG_HMACSHA512) {
+ ret = DNS_R_BADALG;
+ goto cleanup_name;
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) {
+ tkey->algorithm = DNS_TSIG_GSSAPI_NAME;
+ if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) {
+ ret = DNS_R_BADALG;
+ goto cleanup_name;
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
+ tkey->algorithm = DNS_TSIG_GSSAPIMS_NAME;
+ if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) {
+ ret = DNS_R_BADALG;
+ goto cleanup_name;
+ }
+ } else {
+ if (dstkey != NULL) {
+ ret = DNS_R_BADALG;
+ goto cleanup_name;
+ }
+ tkey->algorithm = isc_mem_get(mctx, sizeof(dns_name_t));
+ if (tkey->algorithm == NULL) {
+ ret = ISC_R_NOMEMORY;
+ goto cleanup_name;
+ }
+ dns_name_init(tkey->algorithm, NULL);
+ ret = dns_name_dup(algorithm, mctx, tkey->algorithm);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_algorithm;
+ (void)dns_name_downcase(tkey->algorithm, tkey->algorithm,
+ NULL);
+ }
+
+ if (creator != NULL) {
+ tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t));
+ if (tkey->creator == NULL) {
+ ret = ISC_R_NOMEMORY;
+ goto cleanup_algorithm;
+ }
+ dns_name_init(tkey->creator, NULL);
+ ret = dns_name_dup(creator, mctx, tkey->creator);
+ if (ret != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t));
+ goto cleanup_algorithm;
+ }
+ } else
+ tkey->creator = NULL;
+
+ tkey->key = dstkey;
+ tkey->ring = ring;
+
+ if (key != NULL)
+ refs++;
+ if (ring != NULL)
+ refs++;
+ ret = isc_refcount_init(&tkey->refs, refs);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_creator;
+
+ tkey->generated = generated;
+ tkey->inception = inception;
+ tkey->expire = expire;
+ tkey->mctx = mctx;
+
+ tkey->magic = TSIG_MAGIC;
+
+ if (ring != NULL) {
+ RWLOCK(&ring->lock, isc_rwlocktype_write);
+ ret = dns_rbt_addname(ring->keys, name, tkey);
+ if (ret != ISC_R_SUCCESS) {
+ RWUNLOCK(&ring->lock, isc_rwlocktype_write);
+ goto cleanup_refs;
+ }
+ RWUNLOCK(&ring->lock, isc_rwlocktype_write);
+ }
+
+ if (dstkey != NULL && dst_key_size(dstkey) < 64) {
+ char namestr[DNS_NAME_FORMATSIZE];
+ dns_name_format(name, namestr, sizeof(namestr));
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
+ DNS_LOGMODULE_TSIG, ISC_LOG_INFO,
+ "the key '%s' is too short to be secure",
+ namestr);
+ }
+ if (key != NULL)
+ *key = tkey;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_refs:
+ tkey->magic = 0;
+ while (refs-- > 0)
+ isc_refcount_decrement(&tkey->refs, NULL);
+ isc_refcount_destroy(&tkey->refs);
+ cleanup_creator:
+ if (tkey->creator != NULL) {
+ dns_name_free(tkey->creator, mctx);
+ isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t));
+ }
+ cleanup_algorithm:
+ if (algname_is_allocated(tkey->algorithm)) {
+ if (dns_name_dynamic(tkey->algorithm))
+ dns_name_free(tkey->algorithm, mctx);
+ isc_mem_put(mctx, tkey->algorithm, sizeof(dns_name_t));
+ }
+ cleanup_name:
+ dns_name_free(&tkey->name, mctx);
+ cleanup_key:
+ isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t));
+
+ return (ret);
+}
+
+isc_result_t
+dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
+ unsigned char *secret, int length, isc_boolean_t generated,
+ dns_name_t *creator, isc_stdtime_t inception,
+ isc_stdtime_t expire, isc_mem_t *mctx,
+ dns_tsig_keyring_t *ring, dns_tsigkey_t **key)
+{
+ dst_key_t *dstkey = NULL;
+ isc_result_t result;
+
+ REQUIRE(length >= 0);
+ if (length > 0)
+ REQUIRE(secret != NULL);
+
+ if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
+ if (secret != NULL) {
+ isc_buffer_t b;
+
+ isc_buffer_init(&b, secret, length);
+ isc_buffer_add(&b, length);
+ result = dst_key_frombuffer(name, DST_ALG_HMACMD5,
+ DNS_KEYOWNER_ENTITY,
+ DNS_KEYPROTO_DNSSEC,
+ dns_rdataclass_in,
+ &b, mctx, &dstkey);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) {
+ if (secret != NULL) {
+ isc_buffer_t b;
+
+ isc_buffer_init(&b, secret, length);
+ isc_buffer_add(&b, length);
+ result = dst_key_frombuffer(name, DST_ALG_HMACSHA1,
+ DNS_KEYOWNER_ENTITY,
+ DNS_KEYPROTO_DNSSEC,
+ dns_rdataclass_in,
+ &b, mctx, &dstkey);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) {
+ if (secret != NULL) {
+ isc_buffer_t b;
+
+ isc_buffer_init(&b, secret, length);
+ isc_buffer_add(&b, length);
+ result = dst_key_frombuffer(name, DST_ALG_HMACSHA224,
+ DNS_KEYOWNER_ENTITY,
+ DNS_KEYPROTO_DNSSEC,
+ dns_rdataclass_in,
+ &b, mctx, &dstkey);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) {
+ if (secret != NULL) {
+ isc_buffer_t b;
+
+ isc_buffer_init(&b, secret, length);
+ isc_buffer_add(&b, length);
+ result = dst_key_frombuffer(name, DST_ALG_HMACSHA256,
+ DNS_KEYOWNER_ENTITY,
+ DNS_KEYPROTO_DNSSEC,
+ dns_rdataclass_in,
+ &b, mctx, &dstkey);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) {
+ if (secret != NULL) {
+ isc_buffer_t b;
+
+ isc_buffer_init(&b, secret, length);
+ isc_buffer_add(&b, length);
+ result = dst_key_frombuffer(name, DST_ALG_HMACSHA384,
+ DNS_KEYOWNER_ENTITY,
+ DNS_KEYPROTO_DNSSEC,
+ dns_rdataclass_in,
+ &b, mctx, &dstkey);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) {
+ if (secret != NULL) {
+ isc_buffer_t b;
+
+ isc_buffer_init(&b, secret, length);
+ isc_buffer_add(&b, length);
+ result = dst_key_frombuffer(name, DST_ALG_HMACSHA512,
+ DNS_KEYOWNER_ENTITY,
+ DNS_KEYPROTO_DNSSEC,
+ dns_rdataclass_in,
+ &b, mctx, &dstkey);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ } else if (length > 0)
+ return (DNS_R_BADALG);
+
+ result = dns_tsigkey_createfromkey(name, algorithm, dstkey,
+ generated, creator,
+ inception, expire, mctx, ring, key);
+ if (result != ISC_R_SUCCESS && dstkey != NULL)
+ dst_key_free(&dstkey);
+ return (result);
+}
+
+void
+dns_tsigkey_attach(dns_tsigkey_t *source, dns_tsigkey_t **targetp) {
+ REQUIRE(VALID_TSIG_KEY(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ isc_refcount_increment(&source->refs, NULL);
+ *targetp = source;
+}
+
+static void
+tsigkey_free(dns_tsigkey_t *key) {
+ REQUIRE(VALID_TSIG_KEY(key));
+
+ key->magic = 0;
+ dns_name_free(&key->name, key->mctx);
+ if (algname_is_allocated(key->algorithm)) {
+ dns_name_free(key->algorithm, key->mctx);
+ isc_mem_put(key->mctx, key->algorithm, sizeof(dns_name_t));
+ }
+ if (key->key != NULL)
+ dst_key_free(&key->key);
+ if (key->creator != NULL) {
+ dns_name_free(key->creator, key->mctx);
+ isc_mem_put(key->mctx, key->creator, sizeof(dns_name_t));
+ }
+ isc_refcount_destroy(&key->refs);
+ isc_mem_put(key->mctx, key, sizeof(dns_tsigkey_t));
+}
+
+void
+dns_tsigkey_detach(dns_tsigkey_t **keyp) {
+ dns_tsigkey_t *key;
+ unsigned int refs;
+
+ REQUIRE(keyp != NULL);
+ REQUIRE(VALID_TSIG_KEY(*keyp));
+
+ key = *keyp;
+ isc_refcount_decrement(&key->refs, &refs);
+
+ if (refs == 0)
+ tsigkey_free(key);
+
+ *keyp = NULL;
+}
+
+void
+dns_tsigkey_setdeleted(dns_tsigkey_t *key) {
+ REQUIRE(VALID_TSIG_KEY(key));
+ REQUIRE(key->ring != NULL);
+
+ RWLOCK(&key->ring->lock, isc_rwlocktype_write);
+ (void)dns_rbt_deletename(key->ring->keys, &key->name, ISC_FALSE);
+ RWUNLOCK(&key->ring->lock, isc_rwlocktype_write);
+}
+
+static void
+buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
+ isc_uint16_t valhi;
+ isc_uint32_t vallo;
+
+ valhi = (isc_uint16_t)(val >> 32);
+ vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
+ isc_buffer_putuint16(b, valhi);
+ isc_buffer_putuint32(b, vallo);
+}
+
+isc_result_t
+dns_tsig_sign(dns_message_t *msg) {
+ dns_tsigkey_t *key;
+ dns_rdata_any_tsig_t tsig, querytsig;
+ unsigned char data[128];
+ isc_buffer_t databuf, sigbuf;
+ isc_buffer_t *dynbuf;
+ dns_name_t *owner;
+ dns_rdata_t *rdata = NULL;
+ dns_rdatalist_t *datalist;
+ dns_rdataset_t *dataset;
+ isc_region_t r;
+ isc_stdtime_t now;
+ isc_mem_t *mctx;
+ dst_context_t *ctx = NULL;
+ isc_result_t ret;
+ unsigned char badtimedata[BADTIMELEN];
+ unsigned int sigsize = 0;
+
+ REQUIRE(msg != NULL);
+ REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg)));
+
+ /*
+ * If this is a response, there should be a query tsig.
+ */
+ if (is_response(msg) && msg->querytsig == NULL)
+ return (DNS_R_EXPECTEDTSIG);
+
+ dynbuf = NULL;
+
+ mctx = msg->mctx;
+ key = dns_message_gettsigkey(msg);
+
+ tsig.mctx = mctx;
+ tsig.common.rdclass = dns_rdataclass_any;
+ tsig.common.rdtype = dns_rdatatype_tsig;
+ ISC_LINK_INIT(&tsig.common, link);
+ dns_name_init(&tsig.algorithm, NULL);
+ dns_name_clone(key->algorithm, &tsig.algorithm);
+
+ isc_stdtime_get(&now);
+ tsig.timesigned = now + msg->timeadjust;
+ tsig.fudge = DNS_TSIG_FUDGE;
+
+ tsig.originalid = msg->id;
+
+ isc_buffer_init(&databuf, data, sizeof(data));
+
+ if (is_response(msg))
+ tsig.error = msg->querytsigstatus;
+ else
+ tsig.error = dns_rcode_noerror;
+
+ if (tsig.error != dns_tsigerror_badtime) {
+ tsig.otherlen = 0;
+ tsig.other = NULL;
+ } else {
+ isc_buffer_t otherbuf;
+
+ tsig.otherlen = BADTIMELEN;
+ tsig.other = badtimedata;
+ isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
+ buffer_putuint48(&otherbuf, tsig.timesigned);
+ }
+
+ if (key->key != NULL && tsig.error != dns_tsigerror_badsig) {
+ unsigned char header[DNS_MESSAGE_HEADERLEN];
+ isc_buffer_t headerbuf;
+ isc_uint16_t digestbits;
+
+ ret = dst_context_create(key->key, mctx, &ctx);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ /*
+ * If this is a response, digest the query signature.
+ */
+ if (is_response(msg)) {
+ dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
+
+ ret = dns_rdataset_first(msg->querytsig);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+ dns_rdataset_current(msg->querytsig, &querytsigrdata);
+ ret = dns_rdata_tostruct(&querytsigrdata, &querytsig,
+ NULL);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+ isc_buffer_putuint16(&databuf, querytsig.siglen);
+ if (isc_buffer_availablelength(&databuf) <
+ querytsig.siglen)
+ {
+ ret = ISC_R_NOSPACE;
+ goto cleanup_context;
+ }
+ isc_buffer_putmem(&databuf, querytsig.signature,
+ querytsig.siglen);
+ isc_buffer_usedregion(&databuf, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+ }
+
+ /*
+ * Digest the header.
+ */
+ isc_buffer_init(&headerbuf, header, sizeof(header));
+ dns_message_renderheader(msg, &headerbuf);
+ isc_buffer_usedregion(&headerbuf, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ /*
+ * Digest the remainder of the message.
+ */
+ isc_buffer_usedregion(msg->buffer, &r);
+ isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ if (msg->tcp_continuation == 0) {
+ /*
+ * Digest the name, class, ttl, alg.
+ */
+ dns_name_toregion(&key->name, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ isc_buffer_clear(&databuf);
+ isc_buffer_putuint16(&databuf, dns_rdataclass_any);
+ isc_buffer_putuint32(&databuf, 0); /* ttl */
+ isc_buffer_usedregion(&databuf, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ dns_name_toregion(&tsig.algorithm, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ }
+ /* Digest the timesigned and fudge */
+ isc_buffer_clear(&databuf);
+ if (tsig.error == dns_tsigerror_badtime)
+ tsig.timesigned = querytsig.timesigned;
+ buffer_putuint48(&databuf, tsig.timesigned);
+ isc_buffer_putuint16(&databuf, tsig.fudge);
+ isc_buffer_usedregion(&databuf, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ if (msg->tcp_continuation == 0) {
+ /*
+ * Digest the error and other data length.
+ */
+ isc_buffer_clear(&databuf);
+ isc_buffer_putuint16(&databuf, tsig.error);
+ isc_buffer_putuint16(&databuf, tsig.otherlen);
+
+ isc_buffer_usedregion(&databuf, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ /*
+ * Digest the error and other data.
+ */
+ if (tsig.otherlen > 0) {
+ r.length = tsig.otherlen;
+ r.base = tsig.other;
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+ }
+ }
+
+ ret = dst_key_sigsize(key->key, &sigsize);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+ tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize);
+ if (tsig.signature == NULL) {
+ ret = ISC_R_NOMEMORY;
+ goto cleanup_context;
+ }
+
+ isc_buffer_init(&sigbuf, tsig.signature, sigsize);
+ ret = dst_context_sign(ctx, &sigbuf);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_signature;
+ dst_context_destroy(&ctx);
+ digestbits = dst_key_getbits(key->key);
+ if (digestbits != 0) {
+ unsigned int bytes = (digestbits + 1) / 8;
+ if (is_response(msg) && bytes < querytsig.siglen)
+ bytes = querytsig.siglen;
+ if (bytes > isc_buffer_usedlength(&sigbuf))
+ bytes = isc_buffer_usedlength(&sigbuf);
+ tsig.siglen = bytes;
+ } else
+ tsig.siglen = isc_buffer_usedlength(&sigbuf);
+ } else {
+ tsig.siglen = 0;
+ tsig.signature = NULL;
+ }
+
+ ret = dns_message_gettemprdata(msg, &rdata);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_signature;
+ ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_rdata;
+ ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any,
+ dns_rdatatype_tsig, &tsig, dynbuf);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_dynbuf;
+
+ dns_message_takebuffer(msg, &dynbuf);
+
+ if (tsig.signature != NULL) {
+ isc_mem_put(mctx, tsig.signature, sigsize);
+ tsig.signature = NULL;
+ }
+
+ owner = NULL;
+ ret = dns_message_gettempname(msg, &owner);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_rdata;
+ dns_name_init(owner, NULL);
+ ret = dns_name_dup(&key->name, msg->mctx, owner);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_owner;
+
+ datalist = NULL;
+ ret = dns_message_gettemprdatalist(msg, &datalist);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_owner;
+ dataset = NULL;
+ ret = dns_message_gettemprdataset(msg, &dataset);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_rdatalist;
+ datalist->rdclass = dns_rdataclass_any;
+ datalist->type = dns_rdatatype_tsig;
+ datalist->covers = 0;
+ datalist->ttl = 0;
+ ISC_LIST_INIT(datalist->rdata);
+ ISC_LIST_APPEND(datalist->rdata, rdata, link);
+ dns_rdataset_init(dataset);
+ RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset)
+ == ISC_R_SUCCESS);
+ msg->tsig = dataset;
+ msg->tsigname = owner;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_rdatalist:
+ dns_message_puttemprdatalist(msg, &datalist);
+ cleanup_owner:
+ dns_message_puttempname(msg, &owner);
+ goto cleanup_rdata;
+ cleanup_dynbuf:
+ isc_buffer_free(&dynbuf);
+ cleanup_rdata:
+ dns_message_puttemprdata(msg, &rdata);
+ cleanup_signature:
+ if (tsig.signature != NULL)
+ isc_mem_put(mctx, tsig.signature, sigsize);
+ cleanup_context:
+ if (ctx != NULL)
+ dst_context_destroy(&ctx);
+ return (ret);
+}
+
+isc_result_t
+dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
+ dns_tsig_keyring_t *ring1, dns_tsig_keyring_t *ring2)
+{
+ dns_rdata_any_tsig_t tsig, querytsig;
+ isc_region_t r, source_r, header_r, sig_r;
+ isc_buffer_t databuf;
+ unsigned char data[32];
+ dns_name_t *keyname;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_stdtime_t now;
+ isc_result_t ret;
+ dns_tsigkey_t *tsigkey;
+ dst_key_t *key = NULL;
+ unsigned char header[DNS_MESSAGE_HEADERLEN];
+ dst_context_t *ctx = NULL;
+ isc_mem_t *mctx;
+ isc_uint16_t addcount, id;
+ unsigned int siglen;
+ unsigned int alg;
+
+ REQUIRE(source != NULL);
+ REQUIRE(DNS_MESSAGE_VALID(msg));
+ tsigkey = dns_message_gettsigkey(msg);
+ REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
+
+ msg->verify_attempted = 1;
+
+ if (msg->tcp_continuation) {
+ if (tsigkey == NULL || msg->querytsig == NULL)
+ return (DNS_R_UNEXPECTEDTSIG);
+ return (tsig_verify_tcp(source, msg));
+ }
+
+ /*
+ * There should be a TSIG record...
+ */
+ if (msg->tsig == NULL)
+ return (DNS_R_EXPECTEDTSIG);
+
+ /*
+ * If this is a response and there's no key or query TSIG, there
+ * shouldn't be one on the response.
+ */
+ if (is_response(msg) &&
+ (tsigkey == NULL || msg->querytsig == NULL))
+ return (DNS_R_UNEXPECTEDTSIG);
+
+ mctx = msg->mctx;
+
+ /*
+ * If we're here, we know the message is well formed and contains a
+ * TSIG record.
+ */
+
+ keyname = msg->tsigname;
+ ret = dns_rdataset_first(msg->tsig);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ dns_rdataset_current(msg->tsig, &rdata);
+ ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ dns_rdata_reset(&rdata);
+ if (is_response(msg)) {
+ ret = dns_rdataset_first(msg->querytsig);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ dns_rdataset_current(msg->querytsig, &rdata);
+ ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ }
+
+ /*
+ * Do the key name and algorithm match that of the query?
+ */
+ if (is_response(msg) &&
+ (!dns_name_equal(keyname, &tsigkey->name) ||
+ !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)))
+ {
+ msg->tsigstatus = dns_tsigerror_badkey;
+ tsig_log(msg->tsigkey, 2,
+ "key name and algorithm do not match");
+ return (DNS_R_TSIGVERIFYFAILURE);
+ }
+
+ /*
+ * Get the current time.
+ */
+ isc_stdtime_get(&now);
+
+ /*
+ * Find dns_tsigkey_t based on keyname.
+ */
+ if (tsigkey == NULL) {
+ ret = ISC_R_NOTFOUND;
+ if (ring1 != NULL)
+ ret = dns_tsigkey_find(&tsigkey, keyname,
+ &tsig.algorithm, ring1);
+ if (ret == ISC_R_NOTFOUND && ring2 != NULL)
+ ret = dns_tsigkey_find(&tsigkey, keyname,
+ &tsig.algorithm, ring2);
+ if (ret != ISC_R_SUCCESS) {
+ msg->tsigstatus = dns_tsigerror_badkey;
+ ret = dns_tsigkey_create(keyname, &tsig.algorithm,
+ NULL, 0, ISC_FALSE, NULL,
+ now, now,
+ mctx, NULL, &msg->tsigkey);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ tsig_log(msg->tsigkey, 2, "unknown key");
+ return (DNS_R_TSIGVERIFYFAILURE);
+ }
+ msg->tsigkey = tsigkey;
+ }
+
+ key = tsigkey->key;
+
+ /*
+ * Is the time ok?
+ */
+ if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
+ msg->tsigstatus = dns_tsigerror_badtime;
+ tsig_log(msg->tsigkey, 2, "signature has expired");
+ return (DNS_R_CLOCKSKEW);
+ } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) {
+ msg->tsigstatus = dns_tsigerror_badtime;
+ tsig_log(msg->tsigkey, 2, "signature is in the future");
+ return (DNS_R_CLOCKSKEW);
+ }
+
+ /*
+ * Check digest length.
+ */
+ alg = dst_key_alg(key);
+ ret = dst_key_sigsize(key, &siglen);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ if (alg == DST_ALG_HMACMD5 || alg == DST_ALG_HMACSHA1 ||
+ alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
+ alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) {
+ isc_uint16_t digestbits = dst_key_getbits(key);
+ if (tsig.siglen > siglen) {
+ tsig_log(msg->tsigkey, 2, "signature length to big");
+ return (DNS_R_FORMERR);
+ }
+ if (tsig.siglen > 0 &&
+ (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) {
+ tsig_log(msg->tsigkey, 2,
+ "signature length below minimum");
+ return (DNS_R_FORMERR);
+ }
+ if (tsig.siglen > 0 && digestbits != 0 &&
+ tsig.siglen < ((digestbits + 1) / 8)) {
+ msg->tsigstatus = dns_tsigerror_badtrunc;
+ tsig_log(msg->tsigkey, 2,
+ "truncated signature length too small");
+ return (DNS_R_TSIGVERIFYFAILURE);
+ }
+ if (tsig.siglen > 0 && digestbits == 0 &&
+ tsig.siglen < siglen) {
+ msg->tsigstatus = dns_tsigerror_badtrunc;
+ tsig_log(msg->tsigkey, 2, "signature length too small");
+ return (DNS_R_TSIGVERIFYFAILURE);
+ }
+ }
+
+ if (tsig.siglen > 0) {
+ sig_r.base = tsig.signature;
+ sig_r.length = tsig.siglen;
+
+ ret = dst_context_create(key, mctx, &ctx);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+
+ if (is_response(msg)) {
+ isc_buffer_init(&databuf, data, sizeof(data));
+ isc_buffer_putuint16(&databuf, querytsig.siglen);
+ isc_buffer_usedregion(&databuf, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+ if (querytsig.siglen > 0) {
+ r.length = querytsig.siglen;
+ r.base = querytsig.signature;
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+ }
+ }
+
+ /*
+ * Extract the header.
+ */
+ isc_buffer_usedregion(source, &r);
+ memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
+ isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
+
+ /*
+ * Decrement the additional field counter.
+ */
+ memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
+ addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
+ memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
+
+ /*
+ * Put in the original id.
+ */
+ id = htons(tsig.originalid);
+ memcpy(&header[0], &id, 2);
+
+ /*
+ * Digest the modified header.
+ */
+ header_r.base = (unsigned char *) header;
+ header_r.length = DNS_MESSAGE_HEADERLEN;
+ ret = dst_context_adddata(ctx, &header_r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ /*
+ * Digest all non-TSIG records.
+ */
+ isc_buffer_usedregion(source, &source_r);
+ r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
+ r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ /*
+ * Digest the key name.
+ */
+ dns_name_toregion(&tsigkey->name, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ isc_buffer_init(&databuf, data, sizeof(data));
+ isc_buffer_putuint16(&databuf, tsig.common.rdclass);
+ isc_buffer_putuint32(&databuf, msg->tsig->ttl);
+ isc_buffer_usedregion(&databuf, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ /*
+ * Digest the key algorithm.
+ */
+ dns_name_toregion(tsigkey->algorithm, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ isc_buffer_clear(&databuf);
+ buffer_putuint48(&databuf, tsig.timesigned);
+ isc_buffer_putuint16(&databuf, tsig.fudge);
+ isc_buffer_putuint16(&databuf, tsig.error);
+ isc_buffer_putuint16(&databuf, tsig.otherlen);
+ isc_buffer_usedregion(&databuf, &r);
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ if (tsig.otherlen > 0) {
+ r.base = tsig.other;
+ r.length = tsig.otherlen;
+ ret = dst_context_adddata(ctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+ }
+
+ ret = dst_context_verify(ctx, &sig_r);
+ if (ret == DST_R_VERIFYFAILURE) {
+ msg->tsigstatus = dns_tsigerror_badsig;
+ ret = DNS_R_TSIGVERIFYFAILURE;
+ tsig_log(msg->tsigkey, 2,
+ "signature failed to verify");
+ goto cleanup_context;
+ } else if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ dst_context_destroy(&ctx);
+ } else if (tsig.error != dns_tsigerror_badsig &&
+ tsig.error != dns_tsigerror_badkey)
+ {
+ msg->tsigstatus = dns_tsigerror_badsig;
+ tsig_log(msg->tsigkey, 2, "signature was empty");
+ return (DNS_R_TSIGVERIFYFAILURE);
+ }
+
+ msg->tsigstatus = dns_rcode_noerror;
+
+ if (tsig.error != dns_rcode_noerror) {
+ if (tsig.error == dns_tsigerror_badtime)
+ return (DNS_R_CLOCKSKEW);
+ else
+ return (DNS_R_TSIGERRORSET);
+ }
+
+ msg->verified_sig = 1;
+
+ return (ISC_R_SUCCESS);
+
+cleanup_context:
+ if (ctx != NULL)
+ dst_context_destroy(&ctx);
+
+ return (ret);
+}
+
+static isc_result_t
+tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
+ dns_rdata_any_tsig_t tsig, querytsig;
+ isc_region_t r, source_r, header_r, sig_r;
+ isc_buffer_t databuf;
+ unsigned char data[32];
+ dns_name_t *keyname;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_stdtime_t now;
+ isc_result_t ret;
+ dns_tsigkey_t *tsigkey;
+ dst_key_t *key = NULL;
+ unsigned char header[DNS_MESSAGE_HEADERLEN];
+ isc_uint16_t addcount, id;
+ isc_boolean_t has_tsig = ISC_FALSE;
+ isc_mem_t *mctx;
+
+ REQUIRE(source != NULL);
+ REQUIRE(msg != NULL);
+ REQUIRE(dns_message_gettsigkey(msg) != NULL);
+ REQUIRE(msg->tcp_continuation == 1);
+ REQUIRE(msg->querytsig != NULL);
+
+ if (!is_response(msg))
+ return (DNS_R_EXPECTEDRESPONSE);
+
+ mctx = msg->mctx;
+
+ tsigkey = dns_message_gettsigkey(msg);
+
+ /*
+ * Extract and parse the previous TSIG
+ */
+ ret = dns_rdataset_first(msg->querytsig);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ dns_rdataset_current(msg->querytsig, &rdata);
+ ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
+ if (ret != ISC_R_SUCCESS)
+ return (ret);
+ dns_rdata_reset(&rdata);
+
+ /*
+ * If there is a TSIG in this message, do some checks.
+ */
+ if (msg->tsig != NULL) {
+ has_tsig = ISC_TRUE;
+
+ keyname = msg->tsigname;
+ ret = dns_rdataset_first(msg->tsig);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_querystruct;
+ dns_rdataset_current(msg->tsig, &rdata);
+ ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_querystruct;
+
+ /*
+ * Do the key name and algorithm match that of the query?
+ */
+ if (!dns_name_equal(keyname, &tsigkey->name) ||
+ !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))
+ {
+ msg->tsigstatus = dns_tsigerror_badkey;
+ ret = DNS_R_TSIGVERIFYFAILURE;
+ tsig_log(msg->tsigkey, 2,
+ "key name and algorithm do not match");
+ goto cleanup_querystruct;
+ }
+
+ /*
+ * Is the time ok?
+ */
+ isc_stdtime_get(&now);
+
+ if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
+ msg->tsigstatus = dns_tsigerror_badtime;
+ tsig_log(msg->tsigkey, 2, "signature has expired");
+ ret = DNS_R_CLOCKSKEW;
+ goto cleanup_querystruct;
+ } else if (now + msg->timeadjust <
+ tsig.timesigned - tsig.fudge)
+ {
+ msg->tsigstatus = dns_tsigerror_badtime;
+ tsig_log(msg->tsigkey, 2,
+ "signature is in the future");
+ ret = DNS_R_CLOCKSKEW;
+ goto cleanup_querystruct;
+ }
+ }
+
+ key = tsigkey->key;
+
+ if (msg->tsigctx == NULL) {
+ ret = dst_context_create(key, mctx, &msg->tsigctx);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_querystruct;
+
+ /*
+ * Digest the length of the query signature
+ */
+ isc_buffer_init(&databuf, data, sizeof(data));
+ isc_buffer_putuint16(&databuf, querytsig.siglen);
+ isc_buffer_usedregion(&databuf, &r);
+ ret = dst_context_adddata(msg->tsigctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ /*
+ * Digest the data of the query signature
+ */
+ if (querytsig.siglen > 0) {
+ r.length = querytsig.siglen;
+ r.base = querytsig.signature;
+ ret = dst_context_adddata(msg->tsigctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+ }
+ }
+
+ /*
+ * Extract the header.
+ */
+ isc_buffer_usedregion(source, &r);
+ memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
+ isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
+
+ /*
+ * Decrement the additional field counter if necessary.
+ */
+ if (has_tsig) {
+ memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
+ addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
+ memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
+ }
+
+ /*
+ * Put in the original id.
+ */
+ /* XXX Can TCP transfers be forwarded? How would that work? */
+ if (has_tsig) {
+ id = htons(tsig.originalid);
+ memcpy(&header[0], &id, 2);
+ }
+
+ /*
+ * Digest the modified header.
+ */
+ header_r.base = (unsigned char *) header;
+ header_r.length = DNS_MESSAGE_HEADERLEN;
+ ret = dst_context_adddata(msg->tsigctx, &header_r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ /*
+ * Digest all non-TSIG records.
+ */
+ isc_buffer_usedregion(source, &source_r);
+ r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
+ if (has_tsig)
+ r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
+ else
+ r.length = source_r.length - DNS_MESSAGE_HEADERLEN;
+ ret = dst_context_adddata(msg->tsigctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ /*
+ * Digest the time signed and fudge.
+ */
+ if (has_tsig) {
+ isc_buffer_init(&databuf, data, sizeof(data));
+ buffer_putuint48(&databuf, tsig.timesigned);
+ isc_buffer_putuint16(&databuf, tsig.fudge);
+ isc_buffer_usedregion(&databuf, &r);
+ ret = dst_context_adddata(msg->tsigctx, &r);
+ if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ sig_r.base = tsig.signature;
+ sig_r.length = tsig.siglen;
+ if (tsig.siglen == 0) {
+ if (tsig.error != dns_rcode_noerror) {
+ if (tsig.error == dns_tsigerror_badtime)
+ ret = DNS_R_CLOCKSKEW;
+ else
+ ret = DNS_R_TSIGERRORSET;
+ } else {
+ tsig_log(msg->tsigkey, 2,
+ "signature is empty");
+ ret = DNS_R_TSIGVERIFYFAILURE;
+ }
+ goto cleanup_context;
+ }
+
+ ret = dst_context_verify(msg->tsigctx, &sig_r);
+ if (ret == DST_R_VERIFYFAILURE) {
+ msg->tsigstatus = dns_tsigerror_badsig;
+ tsig_log(msg->tsigkey, 2,
+ "signature failed to verify");
+ ret = DNS_R_TSIGVERIFYFAILURE;
+ goto cleanup_context;
+ }
+ else if (ret != ISC_R_SUCCESS)
+ goto cleanup_context;
+
+ dst_context_destroy(&msg->tsigctx);
+ }
+
+ msg->tsigstatus = dns_rcode_noerror;
+ return (ISC_R_SUCCESS);
+
+ cleanup_context:
+ dst_context_destroy(&msg->tsigctx);
+
+ cleanup_querystruct:
+ dns_rdata_freestruct(&querytsig);
+
+ return (ret);
+
+}
+
+isc_result_t
+dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
+ dns_name_t *algorithm, dns_tsig_keyring_t *ring)
+{
+ dns_tsigkey_t *key;
+ isc_stdtime_t now;
+ isc_result_t result;
+
+ REQUIRE(tsigkey != NULL);
+ REQUIRE(*tsigkey == NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(ring != NULL);
+
+ isc_stdtime_get(&now);
+ RWLOCK(&ring->lock, isc_rwlocktype_read);
+ key = NULL;
+ result = dns_rbt_findname(ring->keys, name, 0, NULL, (void *)&key);
+ if (result == DNS_R_PARTIALMATCH || result == ISC_R_NOTFOUND) {
+ RWUNLOCK(&ring->lock, isc_rwlocktype_read);
+ return (ISC_R_NOTFOUND);
+ }
+ if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) {
+ RWUNLOCK(&ring->lock, isc_rwlocktype_read);
+ return (ISC_R_NOTFOUND);
+ }
+ if (key->inception != key->expire && key->expire < now) {
+ /*
+ * The key has expired.
+ */
+ RWUNLOCK(&ring->lock, isc_rwlocktype_read);
+ RWLOCK(&ring->lock, isc_rwlocktype_write);
+ (void) dns_rbt_deletename(ring->keys, name, ISC_FALSE);
+ RWUNLOCK(&ring->lock, isc_rwlocktype_write);
+ return (ISC_R_NOTFOUND);
+ }
+
+ isc_refcount_increment(&key->refs, NULL);
+ RWUNLOCK(&ring->lock, isc_rwlocktype_read);
+ *tsigkey = key;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+free_tsignode(void *node, void *_unused) {
+ dns_tsigkey_t *key;
+
+ UNUSED(_unused);
+
+ REQUIRE(node != NULL);
+
+ key = node;
+ dns_tsigkey_detach(&key);
+}
+
+isc_result_t
+dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
+ isc_result_t result;
+ dns_tsig_keyring_t *ring;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(ringp != NULL);
+ REQUIRE(*ringp == NULL);
+
+ ring = isc_mem_get(mctx, sizeof(dns_tsig_keyring_t));
+ if (ring == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = isc_rwlock_init(&ring->lock, 0, 0);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
+ return (result);
+ }
+
+ ring->keys = NULL;
+ result = dns_rbt_create(mctx, free_tsignode, NULL, &ring->keys);
+ if (result != ISC_R_SUCCESS) {
+ isc_rwlock_destroy(&ring->lock);
+ isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
+ return (result);
+ }
+
+ ring->mctx = mctx;
+
+ *ringp = ring;
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp) {
+ dns_tsig_keyring_t *ring;
+
+ REQUIRE(ringp != NULL);
+ REQUIRE(*ringp != NULL);
+
+ ring = *ringp;
+ *ringp = NULL;
+
+ dns_rbt_destroy(&ring->keys);
+ isc_rwlock_destroy(&ring->lock);
+ isc_mem_put(ring->mctx, ring, sizeof(dns_tsig_keyring_t));
+}
diff --git a/lib/dns/ttl.c b/lib/dns/ttl.c
new file mode 100644
index 0000000..39d2ac3
--- /dev/null
+++ b/lib/dns/ttl.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2004, 2005 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: ttl.c,v 1.25.18.2 2005/04/29 00:16:07 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/parseint.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/result.h>
+#include <dns/ttl.h>
+
+#define RETERR(x) do { \
+ isc_result_t _r = (x); \
+ if (_r != ISC_R_SUCCESS) \
+ return (_r); \
+ } while (0)
+
+
+static isc_result_t bind_ttl(isc_textregion_t *source, isc_uint32_t *ttl);
+
+/*
+ * Helper for dns_ttl_totext().
+ */
+static isc_result_t
+ttlfmt(unsigned int t, const char *s, isc_boolean_t verbose,
+ isc_boolean_t space, isc_buffer_t *target)
+{
+ char tmp[60];
+ size_t len;
+ isc_region_t region;
+
+ if (verbose)
+ len = snprintf(tmp, sizeof(tmp), "%s%u %s%s",
+ space ? " " : "",
+ t, s,
+ t == 1 ? "" : "s");
+ else
+ len = snprintf(tmp, sizeof(tmp), "%u%c", t, s[0]);
+
+ INSIST(len + 1 <= sizeof(tmp));
+ isc_buffer_availableregion(target, &region);
+ if (len > region.length)
+ return (ISC_R_NOSPACE);
+ memcpy(region.base, tmp, len);
+ isc_buffer_add(target, len);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Derived from bind8 ns_format_ttl().
+ */
+isc_result_t
+dns_ttl_totext(isc_uint32_t src, isc_boolean_t verbose, isc_buffer_t *target) {
+ unsigned secs, mins, hours, days, weeks, x;
+
+ 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 != 0) {
+ RETERR(ttlfmt(weeks, "week", verbose, ISC_TF(x > 0), target));
+ x++;
+ }
+ if (days != 0) {
+ RETERR(ttlfmt(days, "day", verbose, ISC_TF(x > 0), target));
+ x++;
+ }
+ if (hours != 0) {
+ RETERR(ttlfmt(hours, "hour", verbose, ISC_TF(x > 0), target));
+ x++;
+ }
+ if (mins != 0) {
+ RETERR(ttlfmt(mins, "minute", verbose, ISC_TF(x > 0), target));
+ x++;
+ }
+ if (secs != 0 ||
+ (weeks == 0 && days == 0 && hours == 0 && mins == 0)) {
+ RETERR(ttlfmt(secs, "second", verbose, ISC_TF(x > 0), target));
+ x++;
+ }
+ INSIST (x > 0);
+ /*
+ * If only a single unit letter is printed, print it
+ * in upper case. (Why? Because BIND 8 does that.
+ * Presumably it has a reason.)
+ */
+ if (x == 1 && !verbose) {
+ isc_region_t region;
+ /*
+ * The unit letter is the last character in the
+ * used region of the buffer.
+ *
+ * toupper() does not need its argument to be masked of cast
+ * here because region.base is type unsigned char *.
+ */
+ isc_buffer_usedregion(target, &region);
+ region.base[region.length - 1] =
+ toupper(region.base[region.length - 1]);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_counter_fromtext(isc_textregion_t *source, isc_uint32_t *ttl) {
+ return (bind_ttl(source, ttl));
+}
+
+isc_result_t
+dns_ttl_fromtext(isc_textregion_t *source, isc_uint32_t *ttl) {
+ isc_result_t result;
+
+ result = bind_ttl(source, ttl);
+ if (result != ISC_R_SUCCESS)
+ result = DNS_R_BADTTL;
+ return (result);
+}
+
+static isc_result_t
+bind_ttl(isc_textregion_t *source, isc_uint32_t *ttl) {
+ isc_uint32_t tmp = 0;
+ isc_uint32_t n;
+ char *s;
+ char buf[64];
+ char nbuf[64]; /* Number buffer */
+
+ /*
+ * Copy the buffer as it may not be NULL terminated.
+ * No legal counter / ttl is longer that 63 characters.
+ */
+ if (source->length > sizeof(buf) - 1)
+ return (DNS_R_SYNTAX);
+ strncpy(buf, source->base, source->length);
+ buf[source->length] = '\0';
+ s = buf;
+
+ do {
+ isc_result_t result;
+
+ char *np = nbuf;
+ while (*s != '\0' && isdigit((unsigned char)*s))
+ *np++ = *s++;
+ *np++ = '\0';
+ INSIST(np - nbuf <= (int)sizeof(nbuf));
+ result = isc_parse_uint32(&n, nbuf, 10);
+ if (result != ISC_R_SUCCESS)
+ return (DNS_R_SYNTAX);
+ switch (*s) {
+ case 'w':
+ case 'W':
+ tmp += n * 7 * 24 * 3600;
+ s++;
+ break;
+ case 'd':
+ case 'D':
+ tmp += n * 24 * 3600;
+ s++;
+ break;
+ case 'h':
+ case 'H':
+ tmp += n * 3600;
+ s++;
+ break;
+ case 'm':
+ case 'M':
+ tmp += n * 60;
+ s++;
+ break;
+ case 's':
+ case 'S':
+ tmp += n;
+ s++;
+ break;
+ case '\0':
+ /* Plain number? */
+ if (tmp != 0)
+ return (DNS_R_SYNTAX);
+ tmp = n;
+ break;
+ default:
+ return (DNS_R_SYNTAX);
+ }
+ } while (*s != '\0');
+ *ttl = tmp;
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/dns/validator.c b/lib/dns/validator.c
new file mode 100644
index 0000000..9538b302
--- /dev/null
+++ b/lib/dns/validator.c
@@ -0,0 +1,3078 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: validator.c,v 1.119.18.35 2007/09/26 04:39:45 each Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/util.h>
+#include <isc/sha2.h>
+
+#include <dns/db.h>
+#include <dns/ds.h>
+#include <dns/dnssec.h>
+#include <dns/events.h>
+#include <dns/keytable.h>
+#include <dns/log.h>
+#include <dns/message.h>
+#include <dns/ncache.h>
+#include <dns/nsec.h>
+#include <dns/rdata.h>
+#include <dns/rdatastruct.h>
+#include <dns/rdataset.h>
+#include <dns/rdatatype.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+#include <dns/validator.h>
+#include <dns/view.h>
+
+/*! \file
+ * \brief
+ * Basic processing sequences.
+ *
+ * \li When called with rdataset and sigrdataset:
+ * validator_start -> validate -> proveunsecure -> startfinddlvsep ->
+ * dlv_validator_start -> validator_start -> validate -> proveunsecure
+ *
+ * validator_start -> validate -> nsecvalidate (secure wildcard answer)
+ *
+ * \li When called with rdataset, sigrdataset and with DNS_VALIDATOR_DLV:
+ * validator_start -> startfinddlvsep -> dlv_validator_start ->
+ * validator_start -> validate -> proveunsecure
+ *
+ * \li When called with rdataset:
+ * validator_start -> proveunsecure -> startfinddlvsep ->
+ * dlv_validator_start -> validator_start -> proveunsecure
+ *
+ * \li When called with rdataset and with DNS_VALIDATOR_DLV:
+ * validator_start -> startfinddlvsep -> dlv_validator_start ->
+ * validator_start -> proveunsecure
+ *
+ * \li When called without a rdataset:
+ * validator_start -> nsecvalidate -> proveunsecure -> startfinddlvsep ->
+ * dlv_validator_start -> validator_start -> nsecvalidate -> proveunsecure
+ *
+ * Note: there isn't a case for DNS_VALIDATOR_DLV here as we want nsecvalidate()
+ * to always validate the authority section even when it does not contain
+ * signatures.
+ *
+ * validator_start: determines what type of validation to do.
+ * validate: attempts to perform a positive validation.
+ * proveunsecure: attempts to prove the answer comes from a unsecure zone.
+ * nsecvalidate: attempts to prove a negative response.
+ * startfinddlvsep: starts the DLV record lookup.
+ * dlv_validator_start: resets state and restarts the lookup using the
+ * DLV RRset found by startfinddlvsep.
+ */
+
+#define VALIDATOR_MAGIC ISC_MAGIC('V', 'a', 'l', '?')
+#define VALID_VALIDATOR(v) ISC_MAGIC_VALID(v, VALIDATOR_MAGIC)
+
+#define VALATTR_SHUTDOWN 0x0001 /*%< Shutting down. */
+#define VALATTR_CANCELED 0x0002 /*%< Cancelled. */
+#define VALATTR_TRIEDVERIFY 0x0004 /*%< We have found a key and
+ * have attempted a verify. */
+#define VALATTR_INSECURITY 0x0010 /*%< Attempting proveunsecure. */
+#define VALATTR_DLVTRIED 0x0020 /*%< Looked for a DLV record. */
+
+/*!
+ * NSEC proofs to be looked for.
+ */
+#define VALATTR_NEEDNOQNAME 0x0100
+#define VALATTR_NEEDNOWILDCARD 0x0200
+#define VALATTR_NEEDNODATA 0x0400
+
+/*!
+ * NSEC proofs that have been found.
+ */
+#define VALATTR_FOUNDNOQNAME 0x1000
+#define VALATTR_FOUNDNOWILDCARD 0x2000
+#define VALATTR_FOUNDNODATA 0x4000
+
+#define NEEDNODATA(val) ((val->attributes & VALATTR_NEEDNODATA) != 0)
+#define NEEDNOQNAME(val) ((val->attributes & VALATTR_NEEDNOQNAME) != 0)
+#define NEEDNOWILDCARD(val) ((val->attributes & VALATTR_NEEDNOWILDCARD) != 0)
+#define DLVTRIED(val) ((val->attributes & VALATTR_DLVTRIED) != 0)
+
+#define SHUTDOWN(v) (((v)->attributes & VALATTR_SHUTDOWN) != 0)
+#define CANCELED(v) (((v)->attributes & VALATTR_CANCELED) != 0)
+
+static void
+destroy(dns_validator_t *val);
+
+static isc_result_t
+get_dst_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo,
+ dns_rdataset_t *rdataset);
+
+static isc_result_t
+validate(dns_validator_t *val, isc_boolean_t resume);
+
+static isc_result_t
+validatezonekey(dns_validator_t *val);
+
+static isc_result_t
+nsecvalidate(dns_validator_t *val, isc_boolean_t resume);
+
+static isc_result_t
+proveunsecure(dns_validator_t *val, isc_boolean_t resume);
+
+static void
+validator_logv(dns_validator_t *val, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *fmt, va_list ap)
+ ISC_FORMAT_PRINTF(5, 0);
+
+static void
+validator_log(dns_validator_t *val, int level, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+
+static void
+validator_logcreate(dns_validator_t *val,
+ dns_name_t *name, dns_rdatatype_t type,
+ const char *caller, const char *operation);
+
+static isc_result_t
+dlv_validatezonekey(dns_validator_t *val);
+
+static void
+dlv_validator_start(dns_validator_t *val);
+
+static isc_result_t
+finddlvsep(dns_validator_t *val, isc_boolean_t resume);
+
+static isc_result_t
+startfinddlvsep(dns_validator_t *val, dns_name_t *unsecure);
+
+/*%
+ * Mark the RRsets as a answer.
+ */
+static inline void
+markanswer(dns_validator_t *val) {
+ validator_log(val, ISC_LOG_DEBUG(3), "marking as answer");
+ if (val->event->rdataset != NULL)
+ val->event->rdataset->trust = dns_trust_answer;
+ if (val->event->sigrdataset != NULL)
+ val->event->sigrdataset->trust = dns_trust_answer;
+}
+
+static void
+validator_done(dns_validator_t *val, isc_result_t result) {
+ isc_task_t *task;
+
+ if (val->event == NULL)
+ return;
+
+ /*
+ * Caller must be holding the lock.
+ */
+
+ val->event->result = result;
+ task = val->event->ev_sender;
+ val->event->ev_sender = val;
+ val->event->ev_type = DNS_EVENT_VALIDATORDONE;
+ val->event->ev_action = val->action;
+ val->event->ev_arg = val->arg;
+ isc_task_sendanddetach(&task, (isc_event_t **)&val->event);
+}
+
+static inline isc_boolean_t
+exit_check(dns_validator_t *val) {
+ /*
+ * Caller must be holding the lock.
+ */
+ if (!SHUTDOWN(val))
+ return (ISC_FALSE);
+
+ INSIST(val->event == NULL);
+
+ if (val->fetch != NULL || val->subvalidator != NULL)
+ return (ISC_FALSE);
+
+ return (ISC_TRUE);
+}
+
+/*%
+ * Look in the NSEC record returned from a DS query to see if there is
+ * a NS RRset at this name. If it is found we are at a delegation point.
+ */
+static isc_boolean_t
+isdelegation(dns_name_t *name, dns_rdataset_t *rdataset,
+ isc_result_t dbresult)
+{
+ dns_rdataset_t set;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_boolean_t found;
+ isc_result_t result;
+
+ REQUIRE(dbresult == DNS_R_NXRRSET || dbresult == DNS_R_NCACHENXRRSET);
+
+ dns_rdataset_init(&set);
+ if (dbresult == DNS_R_NXRRSET)
+ dns_rdataset_clone(rdataset, &set);
+ else {
+ result = dns_ncache_getrdataset(rdataset, name,
+ dns_rdatatype_nsec, &set);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_FALSE);
+ }
+
+ INSIST(set.type == dns_rdatatype_nsec);
+
+ found = ISC_FALSE;
+ result = dns_rdataset_first(&set);
+ if (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&set, &rdata);
+ found = dns_nsec_typepresent(&rdata, dns_rdatatype_ns);
+ }
+ dns_rdataset_disassociate(&set);
+ return (found);
+}
+
+/*%
+ * We have been asked to to look for a key.
+ * If found resume the validation process.
+ * If not found fail the validation process.
+ */
+static void
+fetch_callback_validator(isc_task_t *task, isc_event_t *event) {
+ dns_fetchevent_t *devent;
+ dns_validator_t *val;
+ dns_rdataset_t *rdataset;
+ isc_boolean_t want_destroy;
+ isc_result_t result;
+ isc_result_t eresult;
+
+ UNUSED(task);
+ INSIST(event->ev_type == DNS_EVENT_FETCHDONE);
+ devent = (dns_fetchevent_t *)event;
+ val = devent->ev_arg;
+ rdataset = &val->frdataset;
+ eresult = devent->result;
+
+ /* Free resources which are not of interest. */
+ if (devent->node != NULL)
+ dns_db_detachnode(devent->db, &devent->node);
+ if (devent->db != NULL)
+ dns_db_detach(&devent->db);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+ isc_event_free(&event);
+ dns_resolver_destroyfetch(&val->fetch);
+
+ INSIST(val->event != NULL);
+
+ validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_validator");
+ LOCK(&val->lock);
+ if (CANCELED(val)) {
+ validator_done(val, ISC_R_CANCELED);
+ } else if (eresult == ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "keyset with trust %d", rdataset->trust);
+ /*
+ * Only extract the dst key if the keyset is secure.
+ */
+ if (rdataset->trust >= dns_trust_secure) {
+ result = get_dst_key(val, val->siginfo, rdataset);
+ if (result == ISC_R_SUCCESS)
+ val->keyset = &val->frdataset;
+ }
+ result = validate(val, ISC_TRUE);
+ if (result != DNS_R_WAIT)
+ validator_done(val, result);
+ } else {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "fetch_callback_validator: got %s",
+ isc_result_totext(eresult));
+ if (eresult == ISC_R_CANCELED)
+ validator_done(val, eresult);
+ else
+ validator_done(val, DNS_R_NOVALIDKEY);
+ }
+ want_destroy = exit_check(val);
+ UNLOCK(&val->lock);
+ if (want_destroy)
+ destroy(val);
+}
+
+/*%
+ * We were asked to look for a DS record as part of following a key chain
+ * upwards. If found resume the validation process. If not found fail the
+ * validation process.
+ */
+static void
+dsfetched(isc_task_t *task, isc_event_t *event) {
+ dns_fetchevent_t *devent;
+ dns_validator_t *val;
+ dns_rdataset_t *rdataset;
+ isc_boolean_t want_destroy;
+ isc_result_t result;
+ isc_result_t eresult;
+
+ UNUSED(task);
+ INSIST(event->ev_type == DNS_EVENT_FETCHDONE);
+ devent = (dns_fetchevent_t *)event;
+ val = devent->ev_arg;
+ rdataset = &val->frdataset;
+ eresult = devent->result;
+
+ /* Free resources which are not of interest. */
+ if (devent->node != NULL)
+ dns_db_detachnode(devent->db, &devent->node);
+ if (devent->db != NULL)
+ dns_db_detach(&devent->db);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+ isc_event_free(&event);
+ dns_resolver_destroyfetch(&val->fetch);
+
+ INSIST(val->event != NULL);
+
+ validator_log(val, ISC_LOG_DEBUG(3), "in dsfetched");
+ LOCK(&val->lock);
+ if (CANCELED(val)) {
+ validator_done(val, ISC_R_CANCELED);
+ } else if (eresult == ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "dsset with trust %d", rdataset->trust);
+ val->dsset = &val->frdataset;
+ result = validatezonekey(val);
+ if (result != DNS_R_WAIT)
+ validator_done(val, result);
+ } else if (eresult == DNS_R_NXRRSET ||
+ eresult == DNS_R_NCACHENXRRSET ||
+ eresult == DNS_R_SERVFAIL) /* RFC 1034 parent? */
+ {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "falling back to insecurity proof (%s)",
+ dns_result_totext(eresult));
+ val->attributes |= VALATTR_INSECURITY;
+ result = proveunsecure(val, ISC_FALSE);
+ if (result != DNS_R_WAIT)
+ validator_done(val, result);
+ } else {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "dsfetched: got %s",
+ isc_result_totext(eresult));
+ if (eresult == ISC_R_CANCELED)
+ validator_done(val, eresult);
+ else
+ validator_done(val, DNS_R_NOVALIDDS);
+ }
+ want_destroy = exit_check(val);
+ UNLOCK(&val->lock);
+ if (want_destroy)
+ destroy(val);
+}
+
+/*%
+ * We were asked to look for the DS record as part of proving that a
+ * name is unsecure.
+ *
+ * If the DS record doesn't exist and the query name corresponds to
+ * a delegation point we are transitioning from a secure zone to a
+ * unsecure zone.
+ *
+ * If the DS record exists it will be secure. We can continue looking
+ * for the break point in the chain of trust.
+ */
+static void
+dsfetched2(isc_task_t *task, isc_event_t *event) {
+ dns_fetchevent_t *devent;
+ dns_validator_t *val;
+ dns_name_t *tname;
+ isc_boolean_t want_destroy;
+ isc_result_t result;
+ isc_result_t eresult;
+
+ UNUSED(task);
+ INSIST(event->ev_type == DNS_EVENT_FETCHDONE);
+ devent = (dns_fetchevent_t *)event;
+ val = devent->ev_arg;
+ eresult = devent->result;
+
+ /* Free resources which are not of interest. */
+ if (devent->node != NULL)
+ dns_db_detachnode(devent->db, &devent->node);
+ if (devent->db != NULL)
+ dns_db_detach(&devent->db);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+ dns_resolver_destroyfetch(&val->fetch);
+
+ INSIST(val->event != NULL);
+
+ validator_log(val, ISC_LOG_DEBUG(3), "in dsfetched2: %s",
+ dns_result_totext(eresult));
+ LOCK(&val->lock);
+ if (CANCELED(val)) {
+ validator_done(val, ISC_R_CANCELED);
+ } else if (eresult == DNS_R_NXRRSET || eresult == DNS_R_NCACHENXRRSET) {
+ /*
+ * There is no DS. If this is a delegation, we're done.
+ */
+ tname = dns_fixedname_name(&devent->foundname);
+ if (isdelegation(tname, &val->frdataset, eresult)) {
+ if (val->mustbesecure) {
+ validator_log(val, ISC_LOG_WARNING,
+ "must be secure failure");
+ validator_done(val, DNS_R_MUSTBESECURE);
+ } else if (val->view->dlv == NULL || DLVTRIED(val)) {
+ markanswer(val);
+ validator_done(val, ISC_R_SUCCESS);
+ } else {
+ result = startfinddlvsep(val, tname);
+ if (result != DNS_R_WAIT)
+ validator_done(val, result);
+ }
+ } else {
+ result = proveunsecure(val, ISC_TRUE);
+ if (result != DNS_R_WAIT)
+ validator_done(val, result);
+ }
+ } else if (eresult == ISC_R_SUCCESS ||
+ eresult == DNS_R_NXDOMAIN ||
+ eresult == DNS_R_NCACHENXDOMAIN)
+ {
+ /*
+ * There is a DS which may or may not be a zone cut.
+ * In either case we are still in a secure zone resume
+ * validation.
+ */
+ result = proveunsecure(val, ISC_TRUE);
+ if (result != DNS_R_WAIT)
+ validator_done(val, result);
+ } else {
+ if (eresult == ISC_R_CANCELED)
+ validator_done(val, eresult);
+ else
+ validator_done(val, DNS_R_NOVALIDDS);
+ }
+ isc_event_free(&event);
+ want_destroy = exit_check(val);
+ UNLOCK(&val->lock);
+ if (want_destroy)
+ destroy(val);
+}
+
+/*%
+ * Callback from when a DNSKEY RRset has been validated.
+ *
+ * Resumes the stalled validation process.
+ */
+static void
+keyvalidated(isc_task_t *task, isc_event_t *event) {
+ dns_validatorevent_t *devent;
+ dns_validator_t *val;
+ isc_boolean_t want_destroy;
+ isc_result_t result;
+ isc_result_t eresult;
+
+ UNUSED(task);
+ INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE);
+
+ devent = (dns_validatorevent_t *)event;
+ val = devent->ev_arg;
+ eresult = devent->result;
+
+ isc_event_free(&event);
+ dns_validator_destroy(&val->subvalidator);
+
+ INSIST(val->event != NULL);
+
+ validator_log(val, ISC_LOG_DEBUG(3), "in keyvalidated");
+ LOCK(&val->lock);
+ if (CANCELED(val)) {
+ validator_done(val, ISC_R_CANCELED);
+ } else if (eresult == ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "keyset with trust %d", val->frdataset.trust);
+ /*
+ * Only extract the dst key if the keyset is secure.
+ */
+ if (val->frdataset.trust >= dns_trust_secure)
+ (void) get_dst_key(val, val->siginfo, &val->frdataset);
+ result = validate(val, ISC_TRUE);
+ if (result != DNS_R_WAIT)
+ validator_done(val, result);
+ } else {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "keyvalidated: got %s",
+ isc_result_totext(eresult));
+ validator_done(val, eresult);
+ }
+ want_destroy = exit_check(val);
+ UNLOCK(&val->lock);
+ if (want_destroy)
+ destroy(val);
+}
+
+/*%
+ * Callback when the DS record has been validated.
+ *
+ * Resumes validation of the zone key or the unsecure zone proof.
+ */
+static void
+dsvalidated(isc_task_t *task, isc_event_t *event) {
+ dns_validatorevent_t *devent;
+ dns_validator_t *val;
+ isc_boolean_t want_destroy;
+ isc_result_t result;
+ isc_result_t eresult;
+
+ UNUSED(task);
+ INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE);
+
+ devent = (dns_validatorevent_t *)event;
+ val = devent->ev_arg;
+ eresult = devent->result;
+
+ isc_event_free(&event);
+ dns_validator_destroy(&val->subvalidator);
+
+ INSIST(val->event != NULL);
+
+ validator_log(val, ISC_LOG_DEBUG(3), "in dsvalidated");
+ LOCK(&val->lock);
+ if (CANCELED(val)) {
+ validator_done(val, ISC_R_CANCELED);
+ } else if (eresult == ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "dsset with trust %d", val->frdataset.trust);
+ if ((val->attributes & VALATTR_INSECURITY) != 0)
+ result = proveunsecure(val, ISC_TRUE);
+ else
+ result = validatezonekey(val);
+ if (result != DNS_R_WAIT)
+ validator_done(val, result);
+ } else {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "dsvalidated: got %s",
+ isc_result_totext(eresult));
+ validator_done(val, eresult);
+ }
+ want_destroy = exit_check(val);
+ UNLOCK(&val->lock);
+ if (want_destroy)
+ destroy(val);
+}
+
+/*%
+ * Return ISC_R_SUCCESS if we can determine that the name doesn't exist
+ * or we can determine whether there is data or not at the name.
+ * If the name does not exist return the wildcard name.
+ *
+ * Return ISC_R_IGNORE when the NSEC is not the appropriate one.
+ */
+static isc_result_t
+nsecnoexistnodata(dns_validator_t *val, dns_name_t* name, dns_name_t *nsecname,
+ dns_rdataset_t *nsecset, isc_boolean_t *exists,
+ isc_boolean_t *data, dns_name_t *wild)
+{
+ int order;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_result_t result;
+ dns_namereln_t relation;
+ unsigned int olabels, nlabels, labels;
+ dns_rdata_nsec_t nsec;
+ isc_boolean_t atparent;
+ isc_boolean_t ns;
+ isc_boolean_t soa;
+
+ REQUIRE(exists != NULL);
+ REQUIRE(data != NULL);
+ REQUIRE(nsecset != NULL &&
+ nsecset->type == dns_rdatatype_nsec);
+
+ result = dns_rdataset_first(nsecset);
+ if (result != ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "failure processing NSEC set");
+ return (result);
+ }
+ dns_rdataset_current(nsecset, &rdata);
+
+ validator_log(val, ISC_LOG_DEBUG(3), "looking for relevant nsec");
+ relation = dns_name_fullcompare(name, nsecname, &order, &olabels);
+
+ if (order < 0) {
+ /*
+ * The name is not within the NSEC range.
+ */
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "NSEC does not cover name, before NSEC");
+ return (ISC_R_IGNORE);
+ }
+
+ if (order == 0) {
+ /*
+ * The names are the same.
+ */
+ atparent = dns_rdatatype_atparent(val->event->type);
+ ns = dns_nsec_typepresent(&rdata, dns_rdatatype_ns);
+ soa = dns_nsec_typepresent(&rdata, dns_rdatatype_soa);
+ if (ns && !soa) {
+ if (!atparent) {
+ /*
+ * This NSEC record is from somewhere higher in
+ * the DNS, and at the parent of a delegation.
+ * It can not be legitimately used here.
+ */
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "ignoring parent nsec");
+ return (ISC_R_IGNORE);
+ }
+ } else if (atparent && ns && soa) {
+ /*
+ * This NSEC record is from the child.
+ * It can not be legitimately used here.
+ */
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "ignoring child nsec");
+ return (ISC_R_IGNORE);
+ }
+ if (val->event->type == dns_rdatatype_cname ||
+ val->event->type == dns_rdatatype_nxt ||
+ val->event->type == dns_rdatatype_nsec ||
+ val->event->type == dns_rdatatype_key ||
+ !dns_nsec_typepresent(&rdata, dns_rdatatype_cname)) {
+ *exists = ISC_TRUE;
+ *data = dns_nsec_typepresent(&rdata, val->event->type);
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "nsec proves name exists (owner) data=%d",
+ *data);
+ return (ISC_R_SUCCESS);
+ }
+ validator_log(val, ISC_LOG_DEBUG(3), "NSEC proves CNAME exists");
+ return (ISC_R_IGNORE);
+ }
+
+ if (relation == dns_namereln_subdomain &&
+ dns_nsec_typepresent(&rdata, dns_rdatatype_ns) &&
+ !dns_nsec_typepresent(&rdata, dns_rdatatype_soa))
+ {
+ /*
+ * This NSEC record is from somewhere higher in
+ * the DNS, and at the parent of a delegation.
+ * It can not be legitimately used here.
+ */
+ validator_log(val, ISC_LOG_DEBUG(3), "ignoring parent nsec");
+ return (ISC_R_IGNORE);
+ }
+
+ result = dns_rdata_tostruct(&rdata, &nsec, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ relation = dns_name_fullcompare(&nsec.next, name, &order, &nlabels);
+ if (order == 0) {
+ dns_rdata_freestruct(&nsec);
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "ignoring nsec matches next name");
+ return (ISC_R_IGNORE);
+ }
+
+ if (order < 0 && !dns_name_issubdomain(nsecname, &nsec.next)) {
+ /*
+ * The name is not within the NSEC range.
+ */
+ dns_rdata_freestruct(&nsec);
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "ignoring nsec because name is past end of range");
+ return (ISC_R_IGNORE);
+ }
+
+ if (order > 0 && relation == dns_namereln_subdomain) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "nsec proves name exist (empty)");
+ dns_rdata_freestruct(&nsec);
+ *exists = ISC_TRUE;
+ *data = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+ }
+ if (wild != NULL) {
+ dns_name_t common;
+ dns_name_init(&common, NULL);
+ if (olabels > nlabels) {
+ labels = dns_name_countlabels(nsecname);
+ dns_name_getlabelsequence(nsecname, labels - olabels,
+ olabels, &common);
+ } else {
+ labels = dns_name_countlabels(&nsec.next);
+ dns_name_getlabelsequence(&nsec.next, labels - nlabels,
+ nlabels, &common);
+ }
+ result = dns_name_concatenate(dns_wildcardname, &common,
+ wild, NULL);
+ if (result != ISC_R_SUCCESS) {
+ dns_rdata_freestruct(&nsec);
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "failure generating wildcard name");
+ return (result);
+ }
+ }
+ dns_rdata_freestruct(&nsec);
+ validator_log(val, ISC_LOG_DEBUG(3), "nsec range ok");
+ *exists = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Callback for when NSEC records have been validated.
+ *
+ * Looks for NOQNAME and NODATA proofs.
+ *
+ * Resumes nsecvalidate.
+ */
+static void
+authvalidated(isc_task_t *task, isc_event_t *event) {
+ dns_validatorevent_t *devent;
+ dns_validator_t *val;
+ dns_rdataset_t *rdataset;
+ isc_boolean_t want_destroy;
+ isc_result_t result;
+ isc_boolean_t exists, data;
+
+ UNUSED(task);
+ INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE);
+
+ devent = (dns_validatorevent_t *)event;
+ rdataset = devent->rdataset;
+ val = devent->ev_arg;
+ result = devent->result;
+ dns_validator_destroy(&val->subvalidator);
+
+ INSIST(val->event != NULL);
+
+ validator_log(val, ISC_LOG_DEBUG(3), "in authvalidated");
+ LOCK(&val->lock);
+ if (CANCELED(val)) {
+ validator_done(val, ISC_R_CANCELED);
+ } else if (result != ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "authvalidated: got %s",
+ isc_result_totext(result));
+ if (result == ISC_R_CANCELED)
+ validator_done(val, result);
+ else {
+ result = nsecvalidate(val, ISC_TRUE);
+ if (result != DNS_R_WAIT)
+ validator_done(val, result);
+ }
+ } else {
+ dns_name_t **proofs = val->event->proofs;
+ dns_name_t *wild = dns_fixedname_name(&val->wild);
+
+ if (rdataset->trust == dns_trust_secure)
+ val->seensig = ISC_TRUE;
+
+ if (rdataset->type == dns_rdatatype_nsec &&
+ rdataset->trust == dns_trust_secure &&
+ ((val->attributes & VALATTR_NEEDNODATA) != 0 ||
+ (val->attributes & VALATTR_NEEDNOQNAME) != 0) &&
+ (val->attributes & VALATTR_FOUNDNODATA) == 0 &&
+ (val->attributes & VALATTR_FOUNDNOQNAME) == 0 &&
+ nsecnoexistnodata(val, val->event->name, devent->name,
+ rdataset, &exists, &data, wild)
+ == ISC_R_SUCCESS)
+ {
+ if (exists && !data) {
+ val->attributes |= VALATTR_FOUNDNODATA;
+ if (NEEDNODATA(val))
+ proofs[DNS_VALIDATOR_NODATAPROOF] =
+ devent->name;
+ }
+ if (!exists) {
+ val->attributes |= VALATTR_FOUNDNOQNAME;
+ if (NEEDNOQNAME(val))
+ proofs[DNS_VALIDATOR_NOQNAMEPROOF] =
+ devent->name;
+ }
+ }
+ result = nsecvalidate(val, ISC_TRUE);
+ if (result != DNS_R_WAIT)
+ validator_done(val, result);
+ }
+ want_destroy = exit_check(val);
+ UNLOCK(&val->lock);
+ if (want_destroy)
+ destroy(val);
+
+ /*
+ * Free stuff from the event.
+ */
+ isc_event_free(&event);
+}
+
+/*%
+ * Looks for the requested name and type in the view (zones and cache).
+ *
+ * When looking for a DLV record also checks to make sure the NSEC record
+ * returns covers the query name as part of aggressive negative caching.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOTFOUND
+ * \li DNS_R_NCACHENXDOMAIN
+ * \li DNS_R_NCACHENXRRSET
+ * \li DNS_R_NXRRSET
+ * \li DNS_R_NXDOMAIN
+ */
+static inline isc_result_t
+view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
+ dns_fixedname_t fixedname;
+ dns_name_t *foundname;
+ dns_rdata_nsec_t nsec;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_result_t result;
+ unsigned int options;
+ char buf1[DNS_NAME_FORMATSIZE];
+ char buf2[DNS_NAME_FORMATSIZE];
+ char buf3[DNS_NAME_FORMATSIZE];
+
+ if (dns_rdataset_isassociated(&val->frdataset))
+ dns_rdataset_disassociate(&val->frdataset);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+
+ if (val->view->zonetable == NULL)
+ return (ISC_R_CANCELED);
+
+ options = DNS_DBFIND_PENDINGOK;
+ if (type == dns_rdatatype_dlv)
+ options |= DNS_DBFIND_COVERINGNSEC;
+ dns_fixedname_init(&fixedname);
+ foundname = dns_fixedname_name(&fixedname);
+ result = dns_view_find(val->view, name, type, 0, options,
+ ISC_FALSE, NULL, NULL, foundname,
+ &val->frdataset, &val->fsigrdataset);
+ if (result == DNS_R_NXDOMAIN) {
+ if (dns_rdataset_isassociated(&val->frdataset))
+ dns_rdataset_disassociate(&val->frdataset);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+ } else if (result == DNS_R_COVERINGNSEC) {
+ validator_log(val, ISC_LOG_DEBUG(3), "DNS_R_COVERINGNSEC");
+ /*
+ * Check if the returned NSEC covers the name.
+ */
+ INSIST(type == dns_rdatatype_dlv);
+ if (val->frdataset.trust != dns_trust_secure) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "covering nsec: trust %u",
+ val->frdataset.trust);
+ goto notfound;
+ }
+ result = dns_rdataset_first(&val->frdataset);
+ if (result != ISC_R_SUCCESS)
+ goto notfound;
+ dns_rdataset_current(&val->frdataset, &rdata);
+ if (dns_nsec_typepresent(&rdata, dns_rdatatype_ns) &&
+ !dns_nsec_typepresent(&rdata, dns_rdatatype_soa)) {
+ /* Parent NSEC record. */
+ if (dns_name_issubdomain(name, foundname)) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "covering nsec: for parent");
+ goto notfound;
+ }
+ }
+ result = dns_rdata_tostruct(&rdata, &nsec, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto notfound;
+ if (dns_name_compare(foundname, &nsec.next) >= 0) {
+ /* End of zone chain. */
+ if (!dns_name_issubdomain(name, &nsec.next)) {
+ /*
+ * XXXMPA We could look for a parent NSEC
+ * at nsec.next and if found retest with
+ * this NSEC.
+ */
+ dns_rdata_freestruct(&nsec);
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "covering nsec: not in zone");
+ goto notfound;
+ }
+ } else if (dns_name_compare(name, &nsec.next) >= 0) {
+ /*
+ * XXXMPA We could check if this NSEC is at a zone
+ * apex and if the qname is not below it and look for
+ * a parent NSEC with the same name. This requires
+ * that we can cache both NSEC records which we
+ * currently don't support.
+ */
+ dns_rdata_freestruct(&nsec);
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "covering nsec: not in range");
+ goto notfound;
+ }
+ if (isc_log_wouldlog(dns_lctx,ISC_LOG_DEBUG(3))) {
+ dns_name_format(name, buf1, sizeof buf1);
+ dns_name_format(foundname, buf2, sizeof buf2);
+ dns_name_format(&nsec.next, buf3, sizeof buf3);
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "covering nsec found: '%s' '%s' '%s'",
+ buf1, buf2, buf3);
+ }
+ if (dns_rdataset_isassociated(&val->frdataset))
+ dns_rdataset_disassociate(&val->frdataset);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+ dns_rdata_freestruct(&nsec);
+ result = DNS_R_NCACHENXDOMAIN;
+ } else if (result != ISC_R_SUCCESS &&
+ result != DNS_R_NCACHENXDOMAIN &&
+ result != DNS_R_NCACHENXRRSET &&
+ result != DNS_R_NXRRSET &&
+ result != ISC_R_NOTFOUND) {
+ goto notfound;
+ }
+ return (result);
+
+ notfound:
+ if (dns_rdataset_isassociated(&val->frdataset))
+ dns_rdataset_disassociate(&val->frdataset);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+ return (ISC_R_NOTFOUND);
+}
+
+/*%
+ * Checks to make sure we are not going to loop. As we use a SHARED fetch
+ * the validation process will stall if looping was to occur.
+ */
+static inline isc_boolean_t
+check_deadlock(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
+ dns_validator_t *parent;
+
+ for (parent = val; parent != NULL; parent = parent->parent) {
+ if (parent->event != NULL &&
+ parent->event->type == type &&
+ dns_name_equal(parent->event->name, name))
+ {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "continuing validation would lead to "
+ "deadlock: aborting validation");
+ return (ISC_TRUE);
+ }
+ }
+ return (ISC_FALSE);
+}
+
+/*%
+ * Start a fetch for the requested name and type.
+ */
+static inline isc_result_t
+create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
+ isc_taskaction_t callback, const char *caller)
+{
+ if (dns_rdataset_isassociated(&val->frdataset))
+ dns_rdataset_disassociate(&val->frdataset);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+
+ if (check_deadlock(val, name, type))
+ return (DNS_R_NOVALIDSIG);
+
+ validator_logcreate(val, name, type, caller, "fetch");
+ return (dns_resolver_createfetch(val->view->resolver, name, type,
+ NULL, NULL, NULL, 0,
+ val->event->ev_sender,
+ callback, val,
+ &val->frdataset,
+ &val->fsigrdataset,
+ &val->fetch));
+}
+
+/*%
+ * Start a subvalidation process.
+ */
+static inline isc_result_t
+create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
+ isc_taskaction_t action, const char *caller)
+{
+ isc_result_t result;
+
+ if (check_deadlock(val, name, type))
+ return (DNS_R_NOVALIDSIG);
+
+ validator_logcreate(val, name, type, caller, "validator");
+ result = dns_validator_create(val->view, name, type,
+ rdataset, sigrdataset, NULL, 0,
+ val->task, action, val,
+ &val->subvalidator);
+ if (result == ISC_R_SUCCESS) {
+ val->subvalidator->parent = val;
+ val->subvalidator->depth = val->depth + 1;
+ }
+ return (result);
+}
+
+/*%
+ * Try to find a key that could have signed 'siginfo' among those
+ * in 'rdataset'. If found, build a dst_key_t for it and point
+ * val->key at it.
+ *
+ * If val->key is non-NULL, this returns the next matching key.
+ */
+static isc_result_t
+get_dst_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo,
+ dns_rdataset_t *rdataset)
+{
+ isc_result_t result;
+ isc_buffer_t b;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dst_key_t *oldkey = val->key;
+ isc_boolean_t foundold;
+
+ if (oldkey == NULL)
+ foundold = ISC_TRUE;
+ else {
+ foundold = ISC_FALSE;
+ val->key = NULL;
+ }
+
+ result = dns_rdataset_first(rdataset);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ do {
+ dns_rdataset_current(rdataset, &rdata);
+
+ isc_buffer_init(&b, rdata.data, rdata.length);
+ isc_buffer_add(&b, rdata.length);
+ INSIST(val->key == NULL);
+ result = dst_key_fromdns(&siginfo->signer, rdata.rdclass, &b,
+ val->view->mctx, &val->key);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ if (siginfo->algorithm ==
+ (dns_secalg_t)dst_key_alg(val->key) &&
+ siginfo->keyid ==
+ (dns_keytag_t)dst_key_id(val->key) &&
+ dst_key_iszonekey(val->key))
+ {
+ if (foundold)
+ /*
+ * This is the key we're looking for.
+ */
+ return (ISC_R_SUCCESS);
+ else if (dst_key_compare(oldkey, val->key) == ISC_TRUE)
+ {
+ foundold = ISC_TRUE;
+ dst_key_free(&oldkey);
+ }
+ }
+ dst_key_free(&val->key);
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(rdataset);
+ } while (result == ISC_R_SUCCESS);
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_NOTFOUND;
+
+ failure:
+ if (oldkey != NULL)
+ dst_key_free(&oldkey);
+
+ return (result);
+}
+
+/*%
+ * Get the key that genertated this signature.
+ */
+static isc_result_t
+get_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo) {
+ isc_result_t result;
+ unsigned int nlabels;
+ int order;
+ dns_namereln_t namereln;
+
+ /*
+ * Is the signer name appropriate for this signature?
+ *
+ * The signer name must be at the same level as the owner name
+ * or closer to the the DNS root.
+ */
+ namereln = dns_name_fullcompare(val->event->name, &siginfo->signer,
+ &order, &nlabels);
+ if (namereln != dns_namereln_subdomain &&
+ namereln != dns_namereln_equal)
+ return (DNS_R_CONTINUE);
+
+ if (namereln == dns_namereln_equal) {
+ /*
+ * If this is a self-signed keyset, it must not be a zone key
+ * (since get_key is not called from validatezonekey).
+ */
+ if (val->event->rdataset->type == dns_rdatatype_dnskey)
+ return (DNS_R_CONTINUE);
+
+ /*
+ * Records appearing in the parent zone at delegation
+ * points cannot be self-signed.
+ */
+ if (dns_rdatatype_atparent(val->event->rdataset->type))
+ return (DNS_R_CONTINUE);
+ }
+
+ /*
+ * Do we know about this key?
+ */
+ result = view_find(val, &siginfo->signer, dns_rdatatype_dnskey);
+ if (result == ISC_R_SUCCESS) {
+ /*
+ * We have an rrset for the given keyname.
+ */
+ val->keyset = &val->frdataset;
+ if (val->frdataset.trust == dns_trust_pending &&
+ dns_rdataset_isassociated(&val->fsigrdataset))
+ {
+ /*
+ * We know the key but haven't validated it yet.
+ */
+ result = create_validator(val, &siginfo->signer,
+ dns_rdatatype_dnskey,
+ &val->frdataset,
+ &val->fsigrdataset,
+ keyvalidated,
+ "get_key");
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ return (DNS_R_WAIT);
+ } else if (val->frdataset.trust == dns_trust_pending) {
+ /*
+ * Having a pending key with no signature means that
+ * something is broken.
+ */
+ result = DNS_R_CONTINUE;
+ } else if (val->frdataset.trust < dns_trust_secure) {
+ /*
+ * The key is legitimately insecure. There's no
+ * point in even attempting verification.
+ */
+ val->key = NULL;
+ result = ISC_R_SUCCESS;
+ } else {
+ /*
+ * See if we've got the key used in the signature.
+ */
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "keyset with trust %d",
+ val->frdataset.trust);
+ result = get_dst_key(val, siginfo, val->keyset);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * Either the key we're looking for is not
+ * in the rrset, or something bad happened.
+ * Give up.
+ */
+ result = DNS_R_CONTINUE;
+ }
+ }
+ } else if (result == ISC_R_NOTFOUND) {
+ /*
+ * We don't know anything about this key.
+ */
+ result = create_fetch(val, &siginfo->signer, dns_rdatatype_dnskey,
+ fetch_callback_validator, "get_key");
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ return (DNS_R_WAIT);
+ } else if (result == DNS_R_NCACHENXDOMAIN ||
+ result == DNS_R_NCACHENXRRSET ||
+ result == DNS_R_NXDOMAIN ||
+ result == DNS_R_NXRRSET)
+ {
+ /*
+ * This key doesn't exist.
+ */
+ result = DNS_R_CONTINUE;
+ }
+
+ if (dns_rdataset_isassociated(&val->frdataset) &&
+ val->keyset != &val->frdataset)
+ dns_rdataset_disassociate(&val->frdataset);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+
+ return (result);
+}
+
+static dns_keytag_t
+compute_keytag(dns_rdata_t *rdata, dns_rdata_dnskey_t *key) {
+ isc_region_t r;
+
+ dns_rdata_toregion(rdata, &r);
+ return (dst_region_computeid(&r, key->algorithm));
+}
+
+/*%
+ * Is this keyset self-signed?
+ */
+static isc_boolean_t
+isselfsigned(dns_validator_t *val) {
+ dns_rdataset_t *rdataset, *sigrdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_t sigrdata = DNS_RDATA_INIT;
+ dns_rdata_dnskey_t key;
+ dns_rdata_rrsig_t sig;
+ dns_keytag_t keytag;
+ isc_result_t result;
+
+ rdataset = val->event->rdataset;
+ sigrdataset = val->event->sigrdataset;
+
+ INSIST(rdataset->type == dns_rdatatype_dnskey);
+
+ for (result = dns_rdataset_first(rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(rdataset))
+ {
+ dns_rdata_reset(&rdata);
+ dns_rdataset_current(rdataset, &rdata);
+ (void)dns_rdata_tostruct(&rdata, &key, NULL);
+ keytag = compute_keytag(&rdata, &key);
+ for (result = dns_rdataset_first(sigrdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(sigrdataset))
+ {
+ dns_rdata_reset(&sigrdata);
+ dns_rdataset_current(sigrdataset, &sigrdata);
+ (void)dns_rdata_tostruct(&sigrdata, &sig, NULL);
+
+ if (sig.algorithm == key.algorithm &&
+ sig.keyid == keytag)
+ return (ISC_TRUE);
+ }
+ }
+ return (ISC_FALSE);
+}
+
+/*%
+ * Attempt to verify the rdataset using the given key and rdata (RRSIG).
+ * The signature was good and from a wildcard record and the QNAME does
+ * not match the wildcard we need to look for a NOQNAME proof.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS if the verification succeeds.
+ * \li Others if the verification fails.
+ */
+static isc_result_t
+verify(dns_validator_t *val, dst_key_t *key, dns_rdata_t *rdata,
+ isc_uint16_t keyid)
+{
+ isc_result_t result;
+ dns_fixedname_t fixed;
+ isc_boolean_t ignore = ISC_FALSE;
+
+ val->attributes |= VALATTR_TRIEDVERIFY;
+ dns_fixedname_init(&fixed);
+ again:
+ result = dns_dnssec_verify2(val->event->name, val->event->rdataset,
+ key, ignore, val->view->mctx, rdata,
+ dns_fixedname_name(&fixed));
+ if (result == DNS_R_SIGEXPIRED && val->view->acceptexpired) {
+ ignore = ISC_TRUE;
+ goto again;
+ }
+ if (ignore && (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD))
+ validator_log(val, ISC_LOG_INFO,
+ "accepted expired %sRRSIG (keyid=%u)",
+ (result == DNS_R_FROMWILDCARD) ?
+ "wildcard " : "", keyid);
+ else
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "verify rdataset (keyid=%u): %s",
+ keyid, isc_result_totext(result));
+ if (result == DNS_R_FROMWILDCARD) {
+ if (!dns_name_equal(val->event->name,
+ dns_fixedname_name(&fixed)))
+ val->attributes |= VALATTR_NEEDNOQNAME;
+ result = ISC_R_SUCCESS;
+ }
+ return (result);
+}
+
+/*%
+ * Attempts positive response validation of a normal RRset.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS Validation completed successfully
+ * \li DNS_R_WAIT Validation has started but is waiting
+ * for an event.
+ * \li Other return codes are possible and all indicate failure.
+ */
+static isc_result_t
+validate(dns_validator_t *val, isc_boolean_t resume) {
+ isc_result_t result;
+ dns_validatorevent_t *event;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ /*
+ * Caller must be holding the validator lock.
+ */
+
+ event = val->event;
+
+ if (resume) {
+ /*
+ * We already have a sigrdataset.
+ */
+ result = ISC_R_SUCCESS;
+ validator_log(val, ISC_LOG_DEBUG(3), "resuming validate");
+ } else {
+ result = dns_rdataset_first(event->sigrdataset);
+ }
+
+ for (;
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(event->sigrdataset))
+ {
+ dns_rdata_reset(&rdata);
+ dns_rdataset_current(event->sigrdataset, &rdata);
+ if (val->siginfo == NULL) {
+ val->siginfo = isc_mem_get(val->view->mctx,
+ sizeof(*val->siginfo));
+ if (val->siginfo == NULL)
+ return (ISC_R_NOMEMORY);
+ }
+ result = dns_rdata_tostruct(&rdata, val->siginfo, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * At this point we could check that the signature algorithm
+ * was known and "sufficiently good".
+ */
+ if (!dns_resolver_algorithm_supported(val->view->resolver,
+ event->name,
+ val->siginfo->algorithm))
+ continue;
+
+ if (!resume) {
+ result = get_key(val, val->siginfo);
+ if (result == DNS_R_CONTINUE)
+ continue; /* Try the next SIG RR. */
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ /*
+ * The key is insecure, so mark the data as insecure also.
+ */
+ if (val->key == NULL) {
+ if (val->mustbesecure) {
+ validator_log(val, ISC_LOG_WARNING,
+ "must be secure failure");
+ return (DNS_R_MUSTBESECURE);
+ }
+ markanswer(val);
+ return (ISC_R_SUCCESS);
+ }
+
+ do {
+ result = verify(val, val->key, &rdata,
+ val->siginfo->keyid);
+ if (result == ISC_R_SUCCESS)
+ break;
+ if (val->keynode != NULL) {
+ dns_keynode_t *nextnode = NULL;
+ result = dns_keytable_findnextkeynode(
+ val->keytable,
+ val->keynode,
+ &nextnode);
+ dns_keytable_detachkeynode(val->keytable,
+ &val->keynode);
+ val->keynode = nextnode;
+ if (result != ISC_R_SUCCESS) {
+ val->key = NULL;
+ break;
+ }
+ val->key = dns_keynode_key(val->keynode);
+ } else {
+ if (get_dst_key(val, val->siginfo, val->keyset)
+ != ISC_R_SUCCESS)
+ break;
+ }
+ } while (1);
+ if (result != ISC_R_SUCCESS)
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "failed to verify rdataset");
+ else {
+ isc_uint32_t ttl;
+ isc_stdtime_t now;
+
+ isc_stdtime_get(&now);
+ ttl = ISC_MIN(event->rdataset->ttl,
+ val->siginfo->timeexpire - now);
+ if (val->keyset != NULL)
+ ttl = ISC_MIN(ttl, val->keyset->ttl);
+ event->rdataset->ttl = ttl;
+ event->sigrdataset->ttl = ttl;
+ }
+
+ if (val->keynode != NULL)
+ dns_keytable_detachkeynode(val->keytable,
+ &val->keynode);
+ else {
+ if (val->key != NULL)
+ dst_key_free(&val->key);
+ if (val->keyset != NULL) {
+ dns_rdataset_disassociate(val->keyset);
+ val->keyset = NULL;
+ }
+ }
+ val->key = NULL;
+ if ((val->attributes & VALATTR_NEEDNOQNAME) != 0) {
+ if (val->event->message == NULL) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "no message available for noqname proof");
+ return (DNS_R_NOVALIDSIG);
+ }
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "looking for noqname proof");
+ return (nsecvalidate(val, ISC_FALSE));
+ } else if (result == ISC_R_SUCCESS) {
+ event->rdataset->trust = dns_trust_secure;
+ event->sigrdataset->trust = dns_trust_secure;
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "marking as secure");
+ return (result);
+ } else {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "verify failure: %s",
+ isc_result_totext(result));
+ resume = ISC_FALSE;
+ }
+ }
+ if (result != ISC_R_NOMORE) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "failed to iterate signatures: %s",
+ isc_result_totext(result));
+ return (result);
+ }
+
+ validator_log(val, ISC_LOG_INFO, "no valid signature found");
+ return (DNS_R_NOVALIDSIG);
+}
+
+/*%
+ * Validate the DNSKEY RRset by looking for a DNSKEY that matches a
+ * DLV record and that also verifies the DNSKEY RRset.
+ */
+static isc_result_t
+dlv_validatezonekey(dns_validator_t *val) {
+ dns_keytag_t keytag;
+ dns_rdata_dlv_t dlv;
+ dns_rdata_dnskey_t key;
+ dns_rdata_rrsig_t sig;
+ dns_rdata_t dlvrdata = DNS_RDATA_INIT;
+ dns_rdata_t keyrdata = DNS_RDATA_INIT;
+ dns_rdata_t newdsrdata = DNS_RDATA_INIT;
+ dns_rdata_t sigrdata = DNS_RDATA_INIT;
+ dns_rdataset_t trdataset;
+ dst_key_t *dstkey;
+ isc_boolean_t supported_algorithm;
+ isc_result_t result;
+ unsigned char dsbuf[DNS_DS_BUFFERSIZE];
+ isc_uint8_t digest_type;
+
+ validator_log(val, ISC_LOG_DEBUG(3), "dlv_validatezonekey");
+
+ /*
+ * Look through the DLV record and find the keys that can sign the
+ * key set and the matching signature. For each such key, attempt
+ * verification.
+ */
+ supported_algorithm = ISC_FALSE;
+
+ /*
+ * If DNS_DSDIGEST_SHA256 is present we are required to prefer
+ * it over DNS_DSDIGEST_SHA1. This in practice means that we
+ * need to ignore DNS_DSDIGEST_SHA1 if a DNS_DSDIGEST_SHA256
+ * is present.
+ */
+ digest_type = DNS_DSDIGEST_SHA1;
+ for (result = dns_rdataset_first(&val->dlv);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&val->dlv)) {
+ dns_rdata_reset(&dlvrdata);
+ dns_rdataset_current(&val->dlv, &dlvrdata);
+ dns_rdata_tostruct(&dlvrdata, &dlv, NULL);
+
+ if (!dns_resolver_algorithm_supported(val->view->resolver,
+ val->event->name,
+ dlv.algorithm))
+ continue;
+
+ if (dlv.digest_type == DNS_DSDIGEST_SHA256 &&
+ dlv.length == ISC_SHA256_DIGESTLENGTH) {
+ digest_type = DNS_DSDIGEST_SHA256;
+ break;
+ }
+ }
+
+ for (result = dns_rdataset_first(&val->dlv);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&val->dlv))
+ {
+ dns_rdata_reset(&dlvrdata);
+ dns_rdataset_current(&val->dlv, &dlvrdata);
+ (void)dns_rdata_tostruct(&dlvrdata, &dlv, NULL);
+
+ if (!dns_resolver_digest_supported(val->view->resolver,
+ dlv.digest_type))
+ continue;
+
+ if (dlv.digest_type != digest_type)
+ continue;
+
+ if (!dns_resolver_algorithm_supported(val->view->resolver,
+ val->event->name,
+ dlv.algorithm))
+ continue;
+
+ supported_algorithm = ISC_TRUE;
+
+ dns_rdataset_init(&trdataset);
+ dns_rdataset_clone(val->event->rdataset, &trdataset);
+
+ for (result = dns_rdataset_first(&trdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&trdataset))
+ {
+ dns_rdata_reset(&keyrdata);
+ dns_rdataset_current(&trdataset, &keyrdata);
+ (void)dns_rdata_tostruct(&keyrdata, &key, NULL);
+ keytag = compute_keytag(&keyrdata, &key);
+ if (dlv.key_tag != keytag ||
+ dlv.algorithm != key.algorithm)
+ continue;
+ dns_rdata_reset(&newdsrdata);
+ result = dns_ds_buildrdata(val->event->name,
+ &keyrdata, dlv.digest_type,
+ dsbuf, &newdsrdata);
+ if (result != ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "dns_ds_buildrdata() -> %s",
+ dns_result_totext(result));
+ continue;
+ }
+ /* Covert to DLV */
+ newdsrdata.type = dns_rdatatype_dlv;
+ if (dns_rdata_compare(&dlvrdata, &newdsrdata) == 0)
+ break;
+ }
+ if (result != ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "no DNSKEY matching DLV");
+ continue;
+ }
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "Found matching DLV record: checking for signature");
+
+ for (result = dns_rdataset_first(val->event->sigrdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(val->event->sigrdataset))
+ {
+ dns_rdata_reset(&sigrdata);
+ dns_rdataset_current(val->event->sigrdataset,
+ &sigrdata);
+ (void)dns_rdata_tostruct(&sigrdata, &sig, NULL);
+ if (dlv.key_tag != sig.keyid &&
+ dlv.algorithm != sig.algorithm)
+ continue;
+ dstkey = NULL;
+ result = dns_dnssec_keyfromrdata(val->event->name,
+ &keyrdata,
+ val->view->mctx,
+ &dstkey);
+ if (result != ISC_R_SUCCESS)
+ /*
+ * This really shouldn't happen, but...
+ */
+ continue;
+
+ result = verify(val, dstkey, &sigrdata, sig.keyid);
+ dst_key_free(&dstkey);
+ if (result == ISC_R_SUCCESS)
+ break;
+ }
+ dns_rdataset_disassociate(&trdataset);
+ if (result == ISC_R_SUCCESS)
+ break;
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "no RRSIG matching DLV key");
+ }
+ if (result == ISC_R_SUCCESS) {
+ val->event->rdataset->trust = dns_trust_secure;
+ val->event->sigrdataset->trust = dns_trust_secure;
+ validator_log(val, ISC_LOG_DEBUG(3), "marking as secure");
+ return (result);
+ } else if (result == ISC_R_NOMORE && !supported_algorithm) {
+ if (val->mustbesecure) {
+ validator_log(val, ISC_LOG_WARNING,
+ "must be secure failure");
+ return (DNS_R_MUSTBESECURE);
+ }
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "no supported algorithm/digest (dlv)");
+ markanswer(val);
+ return (ISC_R_SUCCESS);
+ } else
+ return (DNS_R_NOVALIDSIG);
+}
+
+/*%
+ * Attempts positive response validation of an RRset containing zone keys.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS Validation completed successfully
+ * \li DNS_R_WAIT Validation has started but is waiting
+ * for an event.
+ * \li Other return codes are possible and all indicate failure.
+ */
+static isc_result_t
+validatezonekey(dns_validator_t *val) {
+ isc_result_t result;
+ dns_validatorevent_t *event;
+ dns_rdataset_t trdataset;
+ dns_rdata_t dsrdata = DNS_RDATA_INIT;
+ dns_rdata_t newdsrdata = DNS_RDATA_INIT;
+ dns_rdata_t keyrdata = DNS_RDATA_INIT;
+ dns_rdata_t sigrdata = DNS_RDATA_INIT;
+ unsigned char dsbuf[DNS_DS_BUFFERSIZE];
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_keytag_t keytag;
+ dns_rdata_ds_t ds;
+ dns_rdata_dnskey_t key;
+ dns_rdata_rrsig_t sig;
+ dst_key_t *dstkey;
+ isc_boolean_t supported_algorithm;
+ isc_boolean_t atsep = ISC_FALSE;
+ isc_uint8_t digest_type;
+
+ /*
+ * Caller must be holding the validator lock.
+ */
+
+ event = val->event;
+
+ if (val->havedlvsep && val->dlv.trust >= dns_trust_secure &&
+ dns_name_equal(event->name, dns_fixedname_name(&val->dlvsep)))
+ return (dlv_validatezonekey(val));
+
+ if (val->dsset == NULL) {
+ /*
+ * First, see if this key was signed by a trusted key.
+ */
+ for (result = dns_rdataset_first(val->event->sigrdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(val->event->sigrdataset))
+ {
+ dns_keynode_t *keynode = NULL, *nextnode = NULL;
+
+ dns_rdata_reset(&sigrdata);
+ dns_rdataset_current(val->event->sigrdataset,
+ &sigrdata);
+ (void)dns_rdata_tostruct(&sigrdata, &sig, NULL);
+ result = dns_keytable_findkeynode(val->keytable,
+ val->event->name,
+ sig.algorithm,
+ sig.keyid,
+ &keynode);
+ if (result == DNS_R_PARTIALMATCH ||
+ result == ISC_R_SUCCESS)
+ atsep = ISC_TRUE;
+ while (result == ISC_R_SUCCESS) {
+ dstkey = dns_keynode_key(keynode);
+ result = verify(val, dstkey, &sigrdata,
+ sig.keyid);
+ if (result == ISC_R_SUCCESS) {
+ dns_keytable_detachkeynode(val->keytable,
+ &keynode);
+ break;
+ }
+ result = dns_keytable_findnextkeynode(
+ val->keytable,
+ keynode,
+ &nextnode);
+ dns_keytable_detachkeynode(val->keytable,
+ &keynode);
+ keynode = nextnode;
+ }
+ if (result == ISC_R_SUCCESS) {
+ event->rdataset->trust = dns_trust_secure;
+ event->sigrdataset->trust = dns_trust_secure;
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "signed by trusted key; "
+ "marking as secure");
+ return (result);
+ }
+ }
+
+ /*
+ * If this is the root name and there was no trusted key,
+ * give up, since there's no DS at the root.
+ */
+ if (dns_name_equal(event->name, dns_rootname)) {
+ if ((val->attributes & VALATTR_TRIEDVERIFY) != 0)
+ return (DNS_R_NOVALIDSIG);
+ else
+ return (DNS_R_NOVALIDDS);
+ }
+
+ if (atsep) {
+ /*
+ * We have not found a key to verify this DNSKEY
+ * RRset. As this is a SEP we have to assume that
+ * the RRset is invalid.
+ */
+ dns_name_format(val->event->name, namebuf,
+ sizeof(namebuf));
+ validator_log(val, ISC_LOG_DEBUG(2),
+ "unable to find a DNSKEY which verifies "
+ "the DNSKEY RRset and also matches one "
+ "of specified trusted-keys for '%s'",
+ namebuf);
+ return (DNS_R_NOVALIDKEY);
+ }
+
+ /*
+ * Otherwise, try to find the DS record.
+ */
+ result = view_find(val, val->event->name, dns_rdatatype_ds);
+ if (result == ISC_R_SUCCESS) {
+ /*
+ * We have DS records.
+ */
+ val->dsset = &val->frdataset;
+ if (val->frdataset.trust == dns_trust_pending &&
+ dns_rdataset_isassociated(&val->fsigrdataset))
+ {
+ result = create_validator(val,
+ val->event->name,
+ dns_rdatatype_ds,
+ &val->frdataset,
+ &val->fsigrdataset,
+ dsvalidated,
+ "validatezonekey");
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ return (DNS_R_WAIT);
+ } else if (val->frdataset.trust == dns_trust_pending) {
+ /*
+ * There should never be an unsigned DS.
+ */
+ dns_rdataset_disassociate(&val->frdataset);
+ validator_log(val, ISC_LOG_DEBUG(2),
+ "unsigned DS record");
+ return (DNS_R_NOVALIDSIG);
+ } else
+ result = ISC_R_SUCCESS;
+ } else if (result == ISC_R_NOTFOUND) {
+ /*
+ * We don't have the DS. Find it.
+ */
+ result = create_fetch(val, val->event->name,
+ dns_rdatatype_ds, dsfetched,
+ "validatezonekey");
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ return (DNS_R_WAIT);
+ } else if (result == DNS_R_NCACHENXDOMAIN ||
+ result == DNS_R_NCACHENXRRSET ||
+ result == DNS_R_NXDOMAIN ||
+ result == DNS_R_NXRRSET)
+ {
+ /*
+ * The DS does not exist.
+ */
+ if (dns_rdataset_isassociated(&val->frdataset))
+ dns_rdataset_disassociate(&val->frdataset);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+ validator_log(val, ISC_LOG_DEBUG(2), "no DS record");
+ return (DNS_R_NOVALIDSIG);
+ }
+ }
+
+ /*
+ * We have a DS set.
+ */
+ INSIST(val->dsset != NULL);
+
+ if (val->dsset->trust < dns_trust_secure) {
+ if (val->mustbesecure) {
+ validator_log(val, ISC_LOG_WARNING,
+ "must be secure failure");
+ return (DNS_R_MUSTBESECURE);
+ }
+ markanswer(val);
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * Look through the DS record and find the keys that can sign the
+ * key set and the matching signature. For each such key, attempt
+ * verification.
+ */
+
+ supported_algorithm = ISC_FALSE;
+
+ /*
+ * If DNS_DSDIGEST_SHA256 is present we are required to prefer
+ * it over DNS_DSDIGEST_SHA1. This in practice means that we
+ * need to ignore DNS_DSDIGEST_SHA1 if a DNS_DSDIGEST_SHA256
+ * is present.
+ */
+ digest_type = DNS_DSDIGEST_SHA1;
+ for (result = dns_rdataset_first(val->dsset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(val->dsset)) {
+ dns_rdata_reset(&dsrdata);
+ dns_rdataset_current(val->dsset, &dsrdata);
+ dns_rdata_tostruct(&dsrdata, &ds, NULL);
+
+ if (!dns_resolver_algorithm_supported(val->view->resolver,
+ val->event->name,
+ ds.algorithm))
+ continue;
+
+ if (ds.digest_type == DNS_DSDIGEST_SHA256 &&
+ ds.length == ISC_SHA256_DIGESTLENGTH) {
+ digest_type = DNS_DSDIGEST_SHA256;
+ break;
+ }
+ }
+
+ for (result = dns_rdataset_first(val->dsset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(val->dsset))
+ {
+ dns_rdata_reset(&dsrdata);
+ dns_rdataset_current(val->dsset, &dsrdata);
+ (void)dns_rdata_tostruct(&dsrdata, &ds, NULL);
+
+ if (!dns_resolver_digest_supported(val->view->resolver,
+ ds.digest_type))
+ continue;
+
+ if (ds.digest_type != digest_type)
+ continue;
+
+ if (!dns_resolver_algorithm_supported(val->view->resolver,
+ val->event->name,
+ ds.algorithm))
+ continue;
+
+ supported_algorithm = ISC_TRUE;
+
+ dns_rdataset_init(&trdataset);
+ dns_rdataset_clone(val->event->rdataset, &trdataset);
+
+ /*
+ * Look for the KEY that matches the DS record.
+ */
+ for (result = dns_rdataset_first(&trdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&trdataset))
+ {
+ dns_rdata_reset(&keyrdata);
+ dns_rdataset_current(&trdataset, &keyrdata);
+ (void)dns_rdata_tostruct(&keyrdata, &key, NULL);
+ keytag = compute_keytag(&keyrdata, &key);
+ if (ds.key_tag != keytag ||
+ ds.algorithm != key.algorithm)
+ continue;
+ dns_rdata_reset(&newdsrdata);
+ result = dns_ds_buildrdata(val->event->name,
+ &keyrdata, ds.digest_type,
+ dsbuf, &newdsrdata);
+ if (result != ISC_R_SUCCESS)
+ continue;
+ if (dns_rdata_compare(&dsrdata, &newdsrdata) == 0)
+ break;
+ }
+ if (result != ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "no DNSKEY matching DS");
+ continue;
+ }
+
+ for (result = dns_rdataset_first(val->event->sigrdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(val->event->sigrdataset))
+ {
+ dns_rdata_reset(&sigrdata);
+ dns_rdataset_current(val->event->sigrdataset,
+ &sigrdata);
+ (void)dns_rdata_tostruct(&sigrdata, &sig, NULL);
+ if (ds.key_tag != sig.keyid ||
+ ds.algorithm != sig.algorithm)
+ continue;
+
+ dstkey = NULL;
+ result = dns_dnssec_keyfromrdata(val->event->name,
+ &keyrdata,
+ val->view->mctx,
+ &dstkey);
+ if (result != ISC_R_SUCCESS)
+ /*
+ * This really shouldn't happen, but...
+ */
+ continue;
+ result = verify(val, dstkey, &sigrdata, sig.keyid);
+ dst_key_free(&dstkey);
+ if (result == ISC_R_SUCCESS)
+ break;
+ }
+ dns_rdataset_disassociate(&trdataset);
+ if (result == ISC_R_SUCCESS)
+ break;
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "no RRSIG matching DS key");
+ }
+ if (result == ISC_R_SUCCESS) {
+ event->rdataset->trust = dns_trust_secure;
+ event->sigrdataset->trust = dns_trust_secure;
+ validator_log(val, ISC_LOG_DEBUG(3), "marking as secure");
+ return (result);
+ } else if (result == ISC_R_NOMORE && !supported_algorithm) {
+ if (val->mustbesecure) {
+ validator_log(val, ISC_LOG_WARNING,
+ "must be secure failure");
+ return (DNS_R_MUSTBESECURE);
+ }
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "no supported algorithm/digest (DS)");
+ markanswer(val);
+ return (ISC_R_SUCCESS);
+ } else
+ return (DNS_R_NOVALIDSIG);
+}
+
+/*%
+ * Starts a positive response validation.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS Validation completed successfully
+ * \li DNS_R_WAIT Validation has started but is waiting
+ * for an event.
+ * \li Other return codes are possible and all indicate failure.
+ */
+static isc_result_t
+start_positive_validation(dns_validator_t *val) {
+ /*
+ * If this is not a key, go straight into validate().
+ */
+ if (val->event->type != dns_rdatatype_dnskey || !isselfsigned(val))
+ return (validate(val, ISC_FALSE));
+
+ return (validatezonekey(val));
+}
+
+/*%
+ * Look for NODATA at the wildcard and NOWILDCARD proofs in the
+ * previously validated NSEC records. As these proofs are mutually
+ * exclusive we stop when one is found.
+ *
+ * Returns
+ * \li ISC_R_SUCCESS
+ */
+static isc_result_t
+checkwildcard(dns_validator_t *val) {
+ dns_name_t *name, *wild;
+ dns_message_t *message = val->event->message;
+ isc_result_t result;
+ isc_boolean_t exists, data;
+ char namebuf[DNS_NAME_FORMATSIZE];
+
+ wild = dns_fixedname_name(&val->wild);
+ dns_name_format(wild, namebuf, sizeof(namebuf));
+ validator_log(val, ISC_LOG_DEBUG(3), "in checkwildcard: %s", namebuf);
+
+ for (result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+ result == ISC_R_SUCCESS;
+ result = dns_message_nextname(message, DNS_SECTION_AUTHORITY))
+ {
+ dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
+
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link))
+ {
+ if (rdataset->type != dns_rdatatype_nsec)
+ continue;
+ val->nsecset = rdataset;
+
+ for (sigrdataset = ISC_LIST_HEAD(name->list);
+ sigrdataset != NULL;
+ sigrdataset = ISC_LIST_NEXT(sigrdataset, link))
+ {
+ if (sigrdataset->type == dns_rdatatype_rrsig &&
+ sigrdataset->covers == rdataset->type)
+ break;
+ }
+ if (sigrdataset == NULL)
+ continue;
+
+ if (rdataset->trust != dns_trust_secure)
+ continue;
+
+ if (((val->attributes & VALATTR_NEEDNODATA) != 0 ||
+ (val->attributes & VALATTR_NEEDNOWILDCARD) != 0) &&
+ (val->attributes & VALATTR_FOUNDNODATA) == 0 &&
+ (val->attributes & VALATTR_FOUNDNOWILDCARD) == 0 &&
+ nsecnoexistnodata(val, wild, name, rdataset,
+ &exists, &data, NULL)
+ == ISC_R_SUCCESS)
+ {
+ dns_name_t **proofs = val->event->proofs;
+ if (exists && !data)
+ val->attributes |= VALATTR_FOUNDNODATA;
+ if (exists && !data && NEEDNODATA(val))
+ proofs[DNS_VALIDATOR_NODATAPROOF] =
+ name;
+ if (!exists)
+ val->attributes |=
+ VALATTR_FOUNDNOWILDCARD;
+ if (!exists && NEEDNOQNAME(val))
+ proofs[DNS_VALIDATOR_NOWILDCARDPROOF] =
+ name;
+ return (ISC_R_SUCCESS);
+ }
+ }
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ return (result);
+}
+
+/*%
+ * Prove a negative answer is good or that there is a NOQNAME when the
+ * answer is from a wildcard.
+ *
+ * Loop through the authority section looking for NODATA, NOWILDCARD
+ * and NOQNAME proofs in the NSEC records by calling authvalidated().
+ *
+ * If the required proofs are found we are done.
+ *
+ * If the proofs are not found attempt to prove this is a unsecure
+ * response.
+ */
+static isc_result_t
+nsecvalidate(dns_validator_t *val, isc_boolean_t resume) {
+ dns_name_t *name;
+ dns_message_t *message = val->event->message;
+ isc_result_t result;
+
+ if (!resume)
+ result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+ else {
+ result = ISC_R_SUCCESS;
+ validator_log(val, ISC_LOG_DEBUG(3), "resuming nsecvalidate");
+ }
+
+ for (;
+ result == ISC_R_SUCCESS;
+ result = dns_message_nextname(message, DNS_SECTION_AUTHORITY))
+ {
+ dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
+
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+ if (resume) {
+ rdataset = ISC_LIST_NEXT(val->currentset, link);
+ val->currentset = NULL;
+ resume = ISC_FALSE;
+ } else
+ rdataset = ISC_LIST_HEAD(name->list);
+
+ for (;
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link))
+ {
+ if (rdataset->type == dns_rdatatype_rrsig)
+ continue;
+
+ for (sigrdataset = ISC_LIST_HEAD(name->list);
+ sigrdataset != NULL;
+ sigrdataset = ISC_LIST_NEXT(sigrdataset,
+ link))
+ {
+ if (sigrdataset->type == dns_rdatatype_rrsig &&
+ sigrdataset->covers == rdataset->type)
+ break;
+ }
+ /*
+ * If a signed zone is missing the zone key, bad
+ * things could happen. A query for data in the zone
+ * would lead to a query for the zone key, which
+ * would return a negative answer, which would contain
+ * an SOA and an NSEC signed by the missing key, which
+ * would trigger another query for the DNSKEY (since
+ * the first one is still in progress), and go into an
+ * infinite loop. Avoid that.
+ */
+ if (val->event->type == dns_rdatatype_dnskey &&
+ dns_name_equal(name, val->event->name))
+ {
+ dns_rdata_t nsec = DNS_RDATA_INIT;
+
+ if (rdataset->type != dns_rdatatype_nsec)
+ continue;
+
+ result = dns_rdataset_first(rdataset);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_rdataset_current(rdataset, &nsec);
+ if (dns_nsec_typepresent(&nsec,
+ dns_rdatatype_soa))
+ continue;
+ }
+ val->currentset = rdataset;
+ result = create_validator(val, name, rdataset->type,
+ rdataset, sigrdataset,
+ authvalidated,
+ "nsecvalidate");
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ return (DNS_R_WAIT);
+
+ }
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Do we only need to check for NOQNAME? To get here we must have
+ * had a secure wildcard answer.
+ */
+ if ((val->attributes & VALATTR_NEEDNODATA) == 0 &&
+ (val->attributes & VALATTR_NEEDNOWILDCARD) == 0 &&
+ (val->attributes & VALATTR_NEEDNOQNAME) != 0) {
+ if ((val->attributes & VALATTR_FOUNDNOQNAME) != 0) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "noqname proof found");
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "marking as secure");
+ val->event->rdataset->trust = dns_trust_secure;
+ val->event->sigrdataset->trust = dns_trust_secure;
+ return (ISC_R_SUCCESS);
+ }
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "noqname proof not found");
+ return (DNS_R_NOVALIDNSEC);
+ }
+
+ /*
+ * Do we need to check for the wildcard?
+ */
+ if ((val->attributes & VALATTR_FOUNDNOQNAME) != 0 &&
+ (((val->attributes & VALATTR_NEEDNODATA) != 0 &&
+ (val->attributes & VALATTR_FOUNDNODATA) == 0) ||
+ (val->attributes & VALATTR_NEEDNOWILDCARD) != 0)) {
+ result = checkwildcard(val);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ if (((val->attributes & VALATTR_NEEDNODATA) != 0 &&
+ (val->attributes & VALATTR_FOUNDNODATA) != 0) ||
+ ((val->attributes & VALATTR_NEEDNOQNAME) != 0 &&
+ (val->attributes & VALATTR_FOUNDNOQNAME) != 0 &&
+ (val->attributes & VALATTR_NEEDNOWILDCARD) != 0 &&
+ (val->attributes & VALATTR_FOUNDNOWILDCARD) != 0)) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "nonexistence proof(s) found");
+ return (ISC_R_SUCCESS);
+ }
+
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "nonexistence proof(s) not found");
+ val->attributes |= VALATTR_INSECURITY;
+ return (proveunsecure(val, ISC_FALSE));
+}
+
+static isc_boolean_t
+check_ds(dns_validator_t *val, dns_name_t *name, dns_rdataset_t *rdataset) {
+ dns_rdata_t dsrdata = DNS_RDATA_INIT;
+ dns_rdata_ds_t ds;
+ isc_result_t result;
+
+ for (result = dns_rdataset_first(rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(rdataset)) {
+ dns_rdataset_current(rdataset, &dsrdata);
+ (void)dns_rdata_tostruct(&dsrdata, &ds, NULL);
+
+ if (dns_resolver_digest_supported(val->view->resolver,
+ ds.digest_type) &&
+ dns_resolver_algorithm_supported(val->view->resolver,
+ name, ds.algorithm)) {
+ dns_rdata_reset(&dsrdata);
+ return (ISC_TRUE);
+ }
+ dns_rdata_reset(&dsrdata);
+ }
+ return (ISC_FALSE);
+}
+
+/*%
+ * Callback from fetching a DLV record.
+ *
+ * Resumes the DLV lookup process.
+ */
+static void
+dlvfetched(isc_task_t *task, isc_event_t *event) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_fetchevent_t *devent;
+ dns_validator_t *val;
+ isc_boolean_t want_destroy;
+ isc_result_t eresult;
+ isc_result_t result;
+
+ UNUSED(task);
+ INSIST(event->ev_type == DNS_EVENT_FETCHDONE);
+ devent = (dns_fetchevent_t *)event;
+ val = devent->ev_arg;
+ eresult = devent->result;
+
+ /* Free resources which are not of interest. */
+ if (devent->node != NULL)
+ dns_db_detachnode(devent->db, &devent->node);
+ if (devent->db != NULL)
+ dns_db_detach(&devent->db);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+ isc_event_free(&event);
+ dns_resolver_destroyfetch(&val->fetch);
+
+ INSIST(val->event != NULL);
+ validator_log(val, ISC_LOG_DEBUG(3), "in dlvfetched: %s",
+ dns_result_totext(eresult));
+
+ LOCK(&val->lock);
+ if (eresult == ISC_R_SUCCESS) {
+ dns_name_format(dns_fixedname_name(&val->dlvsep), namebuf,
+ sizeof(namebuf));
+ dns_rdataset_clone(&val->frdataset, &val->dlv);
+ val->havedlvsep = ISC_TRUE;
+ validator_log(val, ISC_LOG_DEBUG(3), "DLV %s found", namebuf);
+ dlv_validator_start(val);
+ } else if (eresult == DNS_R_NXRRSET ||
+ eresult == DNS_R_NXDOMAIN ||
+ eresult == DNS_R_NCACHENXRRSET ||
+ eresult == DNS_R_NCACHENXDOMAIN) {
+ result = finddlvsep(val, ISC_TRUE);
+ if (result == ISC_R_SUCCESS) {
+ dns_name_format(dns_fixedname_name(&val->dlvsep),
+ namebuf, sizeof(namebuf));
+ validator_log(val, ISC_LOG_DEBUG(3), "DLV %s found",
+ namebuf);
+ dlv_validator_start(val);
+ } else if (result == ISC_R_NOTFOUND) {
+ validator_log(val, ISC_LOG_DEBUG(3), "DLV not found");
+ markanswer(val);
+ validator_done(val, ISC_R_SUCCESS);
+ } else {
+ validator_log(val, ISC_LOG_DEBUG(3), "DLV lookup: %s",
+ dns_result_totext(result));
+ if (result != DNS_R_WAIT)
+ validator_done(val, result);
+ }
+ } else {
+ validator_log(val, ISC_LOG_DEBUG(3), "DLV lookup: %s",
+ dns_result_totext(eresult));
+ validator_done(val, eresult);
+ }
+ want_destroy = exit_check(val);
+ UNLOCK(&val->lock);
+ if (want_destroy)
+ destroy(val);
+}
+
+/*%
+ * Start the DLV lookup proccess.
+ *
+ * Returns
+ * \li ISC_R_SUCCESS
+ * \li DNS_R_WAIT
+ * \li Others on validation failures.
+ */
+static isc_result_t
+startfinddlvsep(dns_validator_t *val, dns_name_t *unsecure) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ isc_result_t result;
+
+ INSIST(!DLVTRIED(val));
+
+ val->attributes |= VALATTR_DLVTRIED;
+
+ dns_name_format(unsecure, namebuf, sizeof(namebuf));
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "plain DNSSEC returns unsecure (%s): looking for DLV",
+ namebuf);
+
+ if (dns_name_issubdomain(val->event->name, val->view->dlv)) {
+ validator_log(val, ISC_LOG_WARNING, "must be secure failure");
+ return (DNS_R_MUSTBESECURE);
+ }
+
+ val->dlvlabels = dns_name_countlabels(unsecure) - 1;
+ result = finddlvsep(val, ISC_FALSE);
+ if (result == ISC_R_NOTFOUND) {
+ validator_log(val, ISC_LOG_DEBUG(3), "DLV not found");
+ markanswer(val);
+ return (ISC_R_SUCCESS);
+ }
+ if (result != ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3), "DLV lookup: %s",
+ dns_result_totext(result));
+ return (result);
+ }
+ dns_name_format(dns_fixedname_name(&val->dlvsep), namebuf,
+ sizeof(namebuf));
+ validator_log(val, ISC_LOG_DEBUG(3), "DLV %s found", namebuf);
+ dlv_validator_start(val);
+ return (DNS_R_WAIT);
+}
+
+/*%
+ * Continue the DLV lookup process.
+ *
+ * Returns
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOTFOUND
+ * \li DNS_R_WAIT
+ * \li Others on validation failure.
+ */
+static isc_result_t
+finddlvsep(dns_validator_t *val, isc_boolean_t resume) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_fixedname_t dlvfixed;
+ dns_name_t *dlvname;
+ dns_name_t *dlvsep;
+ dns_name_t noroot;
+ isc_result_t result;
+ unsigned int labels;
+
+ INSIST(val->view->dlv != NULL);
+
+ if (!resume) {
+
+ if (dns_name_issubdomain(val->event->name, val->view->dlv)) {
+ validator_log(val, ISC_LOG_WARNING,
+ "must be secure failure");
+ return (DNS_R_MUSTBESECURE);
+ }
+
+ dns_fixedname_init(&val->dlvsep);
+ dlvsep = dns_fixedname_name(&val->dlvsep);
+ dns_name_copy(val->event->name, dlvsep, NULL);
+ /*
+ * If this is a response to a DS query, we need to look in
+ * the parent zone for the trust anchor.
+ */
+ if (val->event->type == dns_rdatatype_ds) {
+ labels = dns_name_countlabels(dlvsep);
+ if (labels == 0)
+ return (ISC_R_NOTFOUND);
+ dns_name_getlabelsequence(dlvsep, 1, labels - 1,
+ dlvsep);
+ }
+ } else {
+ dlvsep = dns_fixedname_name(&val->dlvsep);
+ labels = dns_name_countlabels(dlvsep);
+ dns_name_getlabelsequence(dlvsep, 1, labels - 1, dlvsep);
+ }
+ dns_name_init(&noroot, NULL);
+ dns_fixedname_init(&dlvfixed);
+ dlvname = dns_fixedname_name(&dlvfixed);
+ labels = dns_name_countlabels(dlvsep);
+ if (labels == 0)
+ return (ISC_R_NOTFOUND);
+ dns_name_getlabelsequence(dlvsep, 0, labels - 1, &noroot);
+ result = dns_name_concatenate(&noroot, val->view->dlv, dlvname, NULL);
+ while (result == ISC_R_NOSPACE) {
+ labels = dns_name_countlabels(dlvsep);
+ dns_name_getlabelsequence(dlvsep, 1, labels - 1, dlvsep);
+ dns_name_getlabelsequence(dlvsep, 0, labels - 2, &noroot);
+ result = dns_name_concatenate(&noroot, val->view->dlv,
+ dlvname, NULL);
+ }
+ if (result != ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(2), "DLV concatenate failed");
+ return (DNS_R_NOVALIDSIG);
+ }
+
+ while (dns_name_countlabels(dlvname) >=
+ dns_name_countlabels(val->view->dlv) + val->dlvlabels) {
+ dns_name_format(dlvname, namebuf, sizeof(namebuf));
+ validator_log(val, ISC_LOG_DEBUG(3), "looking for DLV %s",
+ namebuf);
+ result = view_find(val, dlvname, dns_rdatatype_dlv);
+ if (result == ISC_R_SUCCESS) {
+ if (val->frdataset.trust < dns_trust_secure)
+ return (DNS_R_NOVALIDSIG);
+ val->havedlvsep = ISC_TRUE;
+ dns_rdataset_clone(&val->frdataset, &val->dlv);
+ return (ISC_R_SUCCESS);
+ }
+ if (result == ISC_R_NOTFOUND) {
+ result = create_fetch(val, dlvname, dns_rdatatype_dlv,
+ dlvfetched, "finddlvsep");
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ return (DNS_R_WAIT);
+ }
+ if (result != DNS_R_NXRRSET &&
+ result != DNS_R_NXDOMAIN &&
+ result != DNS_R_NCACHENXRRSET &&
+ result != DNS_R_NCACHENXDOMAIN)
+ return (result);
+ /*
+ * Strip first labels from both dlvsep and dlvname.
+ */
+ labels = dns_name_countlabels(dlvsep);
+ if (labels == 0)
+ break;
+ dns_name_getlabelsequence(dlvsep, 1, labels - 1, dlvsep);
+ labels = dns_name_countlabels(dlvname);
+ dns_name_getlabelsequence(dlvname, 1, labels - 1, dlvname);
+ }
+ return (ISC_R_NOTFOUND);
+}
+
+/*%
+ * proveunsecure walks down from the SEP looking for a break in the
+ * chain of trust. That occurs when we can prove the DS record does
+ * not exist at a delegation point or the DS exists at a delegation
+ * but we don't support the algorithm/digest.
+ *
+ * If DLV is active and we look for a DLV record at or below the
+ * point we go insecure. If found we restart the validation process.
+ * If not found or DLV isn't active we mark the response as a answer.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS val->event->name is in a unsecure zone
+ * \li DNS_R_WAIT validation is in progress.
+ * \li DNS_R_MUSTBESECURE val->event->name is supposed to be secure
+ * (policy) but we proved that it is unsecure.
+ * \li DNS_R_NOVALIDSIG
+ * \li DNS_R_NOVALIDNSEC
+ * \li DNS_R_NOTINSECURE
+ */
+static isc_result_t
+proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
+ isc_result_t result;
+ dns_fixedname_t fixedsecroot;
+ dns_name_t *secroot;
+ dns_name_t *tname;
+ char namebuf[DNS_NAME_FORMATSIZE];
+
+ dns_fixedname_init(&fixedsecroot);
+ secroot = dns_fixedname_name(&fixedsecroot);
+ if (val->havedlvsep)
+ dns_name_copy(dns_fixedname_name(&val->dlvsep), secroot, NULL);
+ else {
+ dns_name_copy(val->event->name, secroot, NULL);
+ /*
+ * If this is a response to a DS query, we need to look in
+ * the parent zone for the trust anchor.
+ */
+ if (val->event->type == dns_rdatatype_ds &&
+ dns_name_countlabels(secroot) > 1U)
+ dns_name_split(secroot, 1, NULL, secroot);
+ result = dns_keytable_finddeepestmatch(val->keytable,
+ secroot, secroot);
+
+ if (result == ISC_R_NOTFOUND) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "not beneath secure root");
+ if (val->mustbesecure) {
+ validator_log(val, ISC_LOG_WARNING,
+ "must be secure failure");
+ result = DNS_R_MUSTBESECURE;
+ goto out;
+ }
+ if (val->view->dlv == NULL || DLVTRIED(val)) {
+ markanswer(val);
+ return (ISC_R_SUCCESS);
+ }
+ return (startfinddlvsep(val, dns_rootname));
+ } else if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ if (!resume) {
+ /*
+ * We are looking for breaks below the SEP so add a label.
+ */
+ val->labels = dns_name_countlabels(secroot) + 1;
+ } else {
+ validator_log(val, ISC_LOG_DEBUG(3), "resuming proveunsecure");
+ if (val->frdataset.trust >= dns_trust_secure &&
+ !check_ds(val, dns_fixedname_name(&val->fname),
+ &val->frdataset)) {
+ dns_name_format(dns_fixedname_name(&val->fname),
+ namebuf, sizeof(namebuf));
+ if (val->mustbesecure) {
+ validator_log(val, ISC_LOG_WARNING,
+ "must be secure failure at '%s'",
+ namebuf);
+ result = DNS_R_MUSTBESECURE;
+ goto out;
+ }
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "no supported algorithm/digest (%s/DS)",
+ namebuf);
+ if (val->view->dlv == NULL || DLVTRIED(val)) {
+ markanswer(val);
+ result = ISC_R_SUCCESS;
+ goto out;
+ }
+ result = startfinddlvsep(val,
+ dns_fixedname_name(&val->fname));
+ goto out;
+ }
+ val->labels++;
+ }
+
+ for (;
+ val->labels <= dns_name_countlabels(val->event->name);
+ val->labels++)
+ {
+
+ dns_fixedname_init(&val->fname);
+ tname = dns_fixedname_name(&val->fname);
+ if (val->labels == dns_name_countlabels(val->event->name))
+ dns_name_copy(val->event->name, tname, NULL);
+ else
+ dns_name_split(val->event->name, val->labels,
+ NULL, tname);
+
+ dns_name_format(tname, namebuf, sizeof(namebuf));
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "checking existence of DS at '%s'",
+ namebuf);
+
+ result = view_find(val, tname, dns_rdatatype_ds);
+
+ if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) {
+ /*
+ * There is no DS. If this is a delegation,
+ * we maybe done.
+ */
+ if (val->frdataset.trust == dns_trust_pending) {
+ result = create_fetch(val, tname,
+ dns_rdatatype_ds,
+ dsfetched2,
+ "proveunsecure");
+ if (result != ISC_R_SUCCESS)
+ goto out;
+ return (DNS_R_WAIT);
+ }
+ if (val->frdataset.trust < dns_trust_secure) {
+ /*
+ * This shouldn't happen, since the negative
+ * response should have been validated. Since
+ * there's no way of validating existing
+ * negative response blobs, give up.
+ */
+ result = DNS_R_NOVALIDSIG;
+ goto out;
+ }
+ if (isdelegation(tname, &val->frdataset, result)) {
+ if (val->mustbesecure) {
+ validator_log(val, ISC_LOG_WARNING,
+ "must be secure failure");
+ return (DNS_R_MUSTBESECURE);
+ }
+ if (val->view->dlv == NULL || DLVTRIED(val)) {
+ markanswer(val);
+ return (ISC_R_SUCCESS);
+ }
+ return (startfinddlvsep(val, tname));
+ }
+ continue;
+ } else if (result == ISC_R_SUCCESS) {
+ /*
+ * There is a DS here. Verify that it's secure and
+ * continue.
+ */
+ if (val->frdataset.trust >= dns_trust_secure) {
+ if (!check_ds(val, tname, &val->frdataset)) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "no supported algorithm/"
+ "digest (%s/DS)", namebuf);
+ if (val->mustbesecure) {
+ validator_log(val,
+ ISC_LOG_WARNING,
+ "must be secure failure");
+ result = DNS_R_MUSTBESECURE;
+ goto out;
+ }
+ if (val->view->dlv == NULL ||
+ DLVTRIED(val)) {
+ markanswer(val);
+ result = ISC_R_SUCCESS;
+ goto out;
+ }
+ result = startfinddlvsep(val, tname);
+ goto out;
+ }
+ continue;
+ }
+ else if (!dns_rdataset_isassociated(&val->fsigrdataset))
+ {
+ result = DNS_R_NOVALIDSIG;
+ goto out;
+ }
+ result = create_validator(val, tname, dns_rdatatype_ds,
+ &val->frdataset,
+ &val->fsigrdataset,
+ dsvalidated,
+ "proveunsecure");
+ if (result != ISC_R_SUCCESS)
+ goto out;
+ return (DNS_R_WAIT);
+ } else if (result == DNS_R_NXDOMAIN ||
+ result == DNS_R_NCACHENXDOMAIN) {
+ /*
+ * This is not a zone cut. Assuming things are
+ * as expected, continue.
+ */
+ if (!dns_rdataset_isassociated(&val->frdataset)) {
+ /*
+ * There should be an NSEC here, since we
+ * are still in a secure zone.
+ */
+ result = DNS_R_NOVALIDNSEC;
+ goto out;
+ } else if (val->frdataset.trust < dns_trust_secure) {
+ /*
+ * This shouldn't happen, since the negative
+ * response should have been validated. Since
+ * there's no way of validating existing
+ * negative response blobs, give up.
+ */
+ result = DNS_R_NOVALIDSIG;
+ goto out;
+ }
+ continue;
+ } else if (result == ISC_R_NOTFOUND) {
+ /*
+ * We don't know anything about the DS. Find it.
+ */
+ result = create_fetch(val, tname, dns_rdatatype_ds,
+ dsfetched2, "proveunsecure");
+ if (result != ISC_R_SUCCESS)
+ goto out;
+ return (DNS_R_WAIT);
+ }
+ }
+ validator_log(val, ISC_LOG_DEBUG(3), "insecurity proof failed");
+ return (DNS_R_NOTINSECURE); /* Couldn't complete insecurity proof */
+
+ out:
+ if (dns_rdataset_isassociated(&val->frdataset))
+ dns_rdataset_disassociate(&val->frdataset);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+ return (result);
+}
+
+/*%
+ * Reset state and revalidate the answer using DLV.
+ */
+static void
+dlv_validator_start(dns_validator_t *val) {
+ isc_event_t *event;
+
+ validator_log(val, ISC_LOG_DEBUG(3), "dlv_validator_start");
+
+ /*
+ * Reset state and try again.
+ */
+ val->attributes &= VALATTR_DLVTRIED;
+ val->options &= ~DNS_VALIDATOR_DLV;
+
+ event = (isc_event_t *)val->event;
+ isc_task_send(val->task, &event);
+}
+
+/*%
+ * Start the validation process.
+ *
+ * Attempt to valididate the answer based on the category it appears to
+ * fall in.
+ * \li 1. secure positive answer.
+ * \li 2. unsecure positive answer.
+ * \li 3. a negative answer (secure or unsecure).
+ *
+ * Note a answer that appears to be a secure positive answer may actually
+ * be a unsecure positive answer.
+ */
+static void
+validator_start(isc_task_t *task, isc_event_t *event) {
+ dns_validator_t *val;
+ dns_validatorevent_t *vevent;
+ isc_boolean_t want_destroy = ISC_FALSE;
+ isc_result_t result = ISC_R_FAILURE;
+
+ UNUSED(task);
+ REQUIRE(event->ev_type == DNS_EVENT_VALIDATORSTART);
+ vevent = (dns_validatorevent_t *)event;
+ val = vevent->validator;
+
+ /* If the validator has been cancelled, val->event == NULL */
+ if (val->event == NULL)
+ return;
+
+ if (DLVTRIED(val))
+ validator_log(val, ISC_LOG_DEBUG(3), "restarting using DLV");
+ else
+ validator_log(val, ISC_LOG_DEBUG(3), "starting");
+
+ LOCK(&val->lock);
+
+ if ((val->options & DNS_VALIDATOR_DLV) != 0 &&
+ val->event->rdataset != NULL) {
+ validator_log(val, ISC_LOG_DEBUG(3), "looking for DLV");
+ result = startfinddlvsep(val, dns_rootname);
+ } else if (val->event->rdataset != NULL &&
+ val->event->sigrdataset != NULL) {
+ isc_result_t saved_result;
+
+ /*
+ * This looks like a simple validation. We say "looks like"
+ * because it might end up requiring an insecurity proof.
+ */
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "attempting positive response validation");
+
+ INSIST(dns_rdataset_isassociated(val->event->rdataset));
+ INSIST(dns_rdataset_isassociated(val->event->sigrdataset));
+ result = start_positive_validation(val);
+ if (result == DNS_R_NOVALIDSIG &&
+ (val->attributes & VALATTR_TRIEDVERIFY) == 0)
+ {
+ saved_result = result;
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "falling back to insecurity proof");
+ val->attributes |= VALATTR_INSECURITY;
+ result = proveunsecure(val, ISC_FALSE);
+ if (result == DNS_R_NOTINSECURE)
+ result = saved_result;
+ }
+ } else if (val->event->rdataset != NULL) {
+ /*
+ * This is either an unsecure subdomain or a response from
+ * a broken server.
+ */
+ INSIST(dns_rdataset_isassociated(val->event->rdataset));
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "attempting insecurity proof");
+
+ val->attributes |= VALATTR_INSECURITY;
+ result = proveunsecure(val, ISC_FALSE);
+ } else if (val->event->rdataset == NULL &&
+ val->event->sigrdataset == NULL)
+ {
+ /*
+ * This is a nonexistence validation.
+ */
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "attempting negative response validation");
+
+ if (val->event->message->rcode == dns_rcode_nxdomain) {
+ val->attributes |= VALATTR_NEEDNOQNAME;
+ val->attributes |= VALATTR_NEEDNOWILDCARD;
+ } else
+ val->attributes |= VALATTR_NEEDNODATA;
+ result = nsecvalidate(val, ISC_FALSE);
+ } else {
+ /*
+ * This shouldn't happen.
+ */
+ INSIST(0);
+ }
+
+ if (result != DNS_R_WAIT) {
+ want_destroy = exit_check(val);
+ validator_done(val, result);
+ }
+
+ UNLOCK(&val->lock);
+ if (want_destroy)
+ destroy(val);
+}
+
+isc_result_t
+dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
+ dns_message_t *message, unsigned int options,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_validator_t **validatorp)
+{
+ isc_result_t result;
+ dns_validator_t *val;
+ isc_task_t *tclone;
+ dns_validatorevent_t *event;
+
+ REQUIRE(name != NULL);
+ REQUIRE(rdataset != NULL ||
+ (rdataset == NULL && sigrdataset == NULL && message != NULL));
+ REQUIRE(validatorp != NULL && *validatorp == NULL);
+
+ tclone = NULL;
+ result = ISC_R_FAILURE;
+
+ val = isc_mem_get(view->mctx, sizeof(*val));
+ if (val == NULL)
+ return (ISC_R_NOMEMORY);
+ val->view = NULL;
+ dns_view_weakattach(view, &val->view);
+ event = (dns_validatorevent_t *)
+ isc_event_allocate(view->mctx, task,
+ DNS_EVENT_VALIDATORSTART,
+ validator_start, NULL,
+ sizeof(dns_validatorevent_t));
+ if (event == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_val;
+ }
+ isc_task_attach(task, &tclone);
+ event->validator = val;
+ event->result = ISC_R_FAILURE;
+ event->name = name;
+ event->type = type;
+ event->rdataset = rdataset;
+ event->sigrdataset = sigrdataset;
+ event->message = message;
+ memset(event->proofs, 0, sizeof(event->proofs));
+ result = isc_mutex_init(&val->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_event;
+ val->event = event;
+ val->options = options;
+ val->attributes = 0;
+ val->fetch = NULL;
+ val->subvalidator = NULL;
+ val->parent = NULL;
+ val->keytable = NULL;
+ dns_keytable_attach(val->view->secroots, &val->keytable);
+ val->keynode = NULL;
+ val->key = NULL;
+ val->siginfo = NULL;
+ val->task = task;
+ val->action = action;
+ val->arg = arg;
+ val->labels = 0;
+ val->currentset = NULL;
+ val->keyset = NULL;
+ val->dsset = NULL;
+ dns_rdataset_init(&val->dlv);
+ val->seensig = ISC_FALSE;
+ val->havedlvsep = ISC_FALSE;
+ val->depth = 0;
+ val->mustbesecure = dns_resolver_getmustbesecure(view->resolver, name);
+ dns_rdataset_init(&val->frdataset);
+ dns_rdataset_init(&val->fsigrdataset);
+ dns_fixedname_init(&val->wild);
+ ISC_LINK_INIT(val, link);
+ val->magic = VALIDATOR_MAGIC;
+
+ if ((options & DNS_VALIDATOR_DEFER) == 0)
+ isc_task_send(task, ISC_EVENT_PTR(&event));
+
+ *validatorp = val;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_event:
+ isc_task_detach(&tclone);
+ isc_event_free(ISC_EVENT_PTR(&event));
+
+ cleanup_val:
+ dns_view_weakdetach(&val->view);
+ isc_mem_put(view->mctx, val, sizeof(*val));
+
+ return (result);
+}
+
+void
+dns_validator_send(dns_validator_t *validator) {
+ isc_event_t *event;
+ REQUIRE(VALID_VALIDATOR(validator));
+
+ LOCK(&validator->lock);
+
+ INSIST((validator->options & DNS_VALIDATOR_DEFER) != 0);
+ event = (isc_event_t *)validator->event;
+ validator->options &= ~DNS_VALIDATOR_DEFER;
+ UNLOCK(&validator->lock);
+
+ isc_task_send(validator->task, ISC_EVENT_PTR(&event));
+}
+
+void
+dns_validator_cancel(dns_validator_t *validator) {
+ REQUIRE(VALID_VALIDATOR(validator));
+
+ LOCK(&validator->lock);
+
+ validator_log(validator, ISC_LOG_DEBUG(3), "dns_validator_cancel");
+
+ if (validator->event != NULL) {
+ if (validator->fetch != NULL)
+ dns_resolver_cancelfetch(validator->fetch);
+
+ if (validator->subvalidator != NULL)
+ dns_validator_cancel(validator->subvalidator);
+ if ((validator->options & DNS_VALIDATOR_DEFER) != 0) {
+ isc_task_t *task = validator->event->ev_sender;
+ validator->options &= ~DNS_VALIDATOR_DEFER;
+ isc_event_free((isc_event_t **)&validator->event);
+ isc_task_detach(&task);
+ }
+ validator->attributes |= VALATTR_CANCELED;
+ }
+ UNLOCK(&validator->lock);
+}
+
+static void
+destroy(dns_validator_t *val) {
+ isc_mem_t *mctx;
+
+ REQUIRE(SHUTDOWN(val));
+ REQUIRE(val->event == NULL);
+ REQUIRE(val->fetch == NULL);
+
+ if (val->keynode != NULL)
+ dns_keytable_detachkeynode(val->keytable, &val->keynode);
+ else if (val->key != NULL)
+ dst_key_free(&val->key);
+ if (val->keytable != NULL)
+ dns_keytable_detach(&val->keytable);
+ if (val->subvalidator != NULL)
+ dns_validator_destroy(&val->subvalidator);
+ if (val->havedlvsep)
+ dns_rdataset_disassociate(&val->dlv);
+ if (dns_rdataset_isassociated(&val->frdataset))
+ dns_rdataset_disassociate(&val->frdataset);
+ if (dns_rdataset_isassociated(&val->fsigrdataset))
+ dns_rdataset_disassociate(&val->fsigrdataset);
+ mctx = val->view->mctx;
+ if (val->siginfo != NULL)
+ isc_mem_put(mctx, val->siginfo, sizeof(*val->siginfo));
+ DESTROYLOCK(&val->lock);
+ dns_view_weakdetach(&val->view);
+ val->magic = 0;
+ isc_mem_put(mctx, val, sizeof(*val));
+}
+
+void
+dns_validator_destroy(dns_validator_t **validatorp) {
+ dns_validator_t *val;
+ isc_boolean_t want_destroy = ISC_FALSE;
+
+ REQUIRE(validatorp != NULL);
+ val = *validatorp;
+ REQUIRE(VALID_VALIDATOR(val));
+
+ LOCK(&val->lock);
+
+ val->attributes |= VALATTR_SHUTDOWN;
+ validator_log(val, ISC_LOG_DEBUG(3), "dns_validator_destroy");
+
+ want_destroy = exit_check(val);
+
+ UNLOCK(&val->lock);
+
+ if (want_destroy)
+ destroy(val);
+
+ *validatorp = NULL;
+}
+
+static void
+validator_logv(dns_validator_t *val, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *fmt, va_list ap)
+{
+ char msgbuf[2048];
+ static const char spaces[] = " *";
+ int depth = val->depth * 2;
+
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+
+ if ((unsigned int) depth >= sizeof spaces)
+ depth = sizeof spaces - 1;
+
+ if (val->event != NULL && val->event->name != NULL) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char typebuf[DNS_RDATATYPE_FORMATSIZE];
+
+ dns_name_format(val->event->name, namebuf, sizeof(namebuf));
+ dns_rdatatype_format(val->event->type, typebuf,
+ sizeof(typebuf));
+ isc_log_write(dns_lctx, category, module, level,
+ "%.*svalidating @%p: %s %s: %s", depth, spaces,
+ val, namebuf, typebuf, msgbuf);
+ } else {
+ isc_log_write(dns_lctx, category, module, level,
+ "%.*svalidator @%p: %s", depth, spaces,
+ val, msgbuf);
+ }
+}
+
+static void
+validator_log(dns_validator_t *val, int level, const char *fmt, ...) {
+ va_list ap;
+
+ if (! isc_log_wouldlog(dns_lctx, level))
+ return;
+
+ va_start(ap, fmt);
+
+ validator_logv(val, DNS_LOGCATEGORY_DNSSEC,
+ DNS_LOGMODULE_VALIDATOR, level, fmt, ap);
+ va_end(ap);
+}
+
+static void
+validator_logcreate(dns_validator_t *val,
+ dns_name_t *name, dns_rdatatype_t type,
+ const char *caller, const char *operation)
+{
+ char namestr[DNS_NAME_FORMATSIZE];
+ char typestr[DNS_RDATATYPE_FORMATSIZE];
+
+ dns_name_format(name, namestr, sizeof(namestr));
+ dns_rdatatype_format(type, typestr, sizeof(typestr));
+ validator_log(val, ISC_LOG_DEBUG(9), "%s: creating %s for %s %s",
+ caller, operation, namestr, typestr);
+}
diff --git a/lib/dns/version.c b/lib/dns/version.c
new file mode 100644
index 0000000..1c03774
--- /dev/null
+++ b/lib/dns/version.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: version.c,v 1.11.18.2 2005/04/29 00:16:07 marka Exp $ */
+
+/*! \file */
+
+#include <dns/version.h>
+
+const char dns_version[] = VERSION;
+
+const unsigned int dns_libinterface = LIBINTERFACE;
+const unsigned int dns_librevision = LIBREVISION;
+const unsigned int dns_libage = LIBAGE;
diff --git a/lib/dns/view.c b/lib/dns/view.c
new file mode 100644
index 0000000..d5a78d5
--- /dev/null
+++ b/lib/dns/view.c
@@ -0,0 +1,1367 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: view.c,v 1.126.18.14 2007/08/28 07:20:05 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/hash.h>
+#include <isc/task.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/util.h>
+
+#include <dns/acache.h>
+#include <dns/acl.h>
+#include <dns/adb.h>
+#include <dns/cache.h>
+#include <dns/db.h>
+#include <dns/dlz.h>
+#include <dns/events.h>
+#include <dns/forward.h>
+#include <dns/keytable.h>
+#include <dns/master.h>
+#include <dns/masterdump.h>
+#include <dns/order.h>
+#include <dns/peer.h>
+#include <dns/rdataset.h>
+#include <dns/request.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+#include <dns/tsig.h>
+#include <dns/zone.h>
+#include <dns/zt.h>
+
+#define RESSHUTDOWN(v) (((v)->attributes & DNS_VIEWATTR_RESSHUTDOWN) != 0)
+#define ADBSHUTDOWN(v) (((v)->attributes & DNS_VIEWATTR_ADBSHUTDOWN) != 0)
+#define REQSHUTDOWN(v) (((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
+
+#define DNS_VIEW_DELONLYHASH 111
+
+static void resolver_shutdown(isc_task_t *task, isc_event_t *event);
+static void adb_shutdown(isc_task_t *task, isc_event_t *event);
+static void req_shutdown(isc_task_t *task, isc_event_t *event);
+
+isc_result_t
+dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
+ const char *name, dns_view_t **viewp)
+{
+ dns_view_t *view;
+ isc_result_t result;
+
+ /*
+ * Create a view.
+ */
+
+ REQUIRE(name != NULL);
+ REQUIRE(viewp != NULL && *viewp == NULL);
+
+ view = isc_mem_get(mctx, sizeof(*view));
+ if (view == NULL)
+ return (ISC_R_NOMEMORY);
+ view->name = isc_mem_strdup(mctx, name);
+ if (view->name == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_view;
+ }
+ result = isc_mutex_init(&view->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_name;
+
+ view->zonetable = NULL;
+ result = dns_zt_create(mctx, rdclass, &view->zonetable);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_zt_create() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_mutex;
+ }
+ view->secroots = NULL;
+ result = dns_keytable_create(mctx, &view->secroots);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_keytable_create() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_zt;
+ }
+ view->trustedkeys = NULL;
+ result = dns_keytable_create(mctx, &view->trustedkeys);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_keytable_create() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_secroots;
+ }
+ view->fwdtable = NULL;
+ result = dns_fwdtable_create(mctx, &view->fwdtable);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_fwdtable_create() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_trustedkeys;
+ }
+
+ view->acache = NULL;
+ view->cache = NULL;
+ view->cachedb = NULL;
+ view->dlzdatabase = NULL;
+ view->hints = NULL;
+ view->resolver = NULL;
+ view->adb = NULL;
+ view->requestmgr = NULL;
+ view->mctx = mctx;
+ view->rdclass = rdclass;
+ view->frozen = ISC_FALSE;
+ view->task = NULL;
+ result = isc_refcount_init(&view->references, 1);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_fwdtable;
+ view->weakrefs = 0;
+ view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
+ DNS_VIEWATTR_REQSHUTDOWN);
+ view->statickeys = NULL;
+ view->dynamickeys = NULL;
+ view->matchclients = NULL;
+ view->matchdestinations = NULL;
+ view->matchrecursiveonly = ISC_FALSE;
+ result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_references;
+ view->peers = NULL;
+ view->order = NULL;
+ view->delonly = NULL;
+ view->rootdelonly = ISC_FALSE;
+ view->rootexclude = NULL;
+
+ /*
+ * Initialize configuration data with default values.
+ */
+ view->recursion = ISC_TRUE;
+ view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
+ view->additionalfromcache = ISC_TRUE;
+ view->additionalfromauth = ISC_TRUE;
+ view->enablednssec = ISC_TRUE;
+ view->enablevalidation = ISC_TRUE;
+ view->acceptexpired = ISC_FALSE;
+ view->minimalresponses = ISC_FALSE;
+ view->transfer_format = dns_one_answer;
+ view->queryacl = NULL;
+ view->recursionacl = NULL;
+ view->sortlist = NULL;
+ view->requestixfr = ISC_TRUE;
+ view->provideixfr = ISC_TRUE;
+ view->maxcachettl = 7 * 24 * 3600;
+ view->maxncachettl = 3 * 3600;
+ view->dstport = 53;
+ view->preferred_glue = 0;
+ view->flush = ISC_FALSE;
+ view->dlv = NULL;
+ view->maxudp = 0;
+ dns_fixedname_init(&view->dlv_fixed);
+
+ result = dns_order_create(view->mctx, &view->order);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_dynkeys;
+
+ result = dns_peerlist_new(view->mctx, &view->peers);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_order;
+
+ result = dns_aclenv_init(view->mctx, &view->aclenv);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_peerlist;
+
+ ISC_LINK_INIT(view, link);
+ ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
+ DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
+ view, NULL, NULL, NULL);
+ ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
+ DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
+ view, NULL, NULL, NULL);
+ ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
+ DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
+ view, NULL, NULL, NULL);
+ view->magic = DNS_VIEW_MAGIC;
+
+ *viewp = view;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_peerlist:
+ dns_peerlist_detach(&view->peers);
+
+ cleanup_order:
+ dns_order_detach(&view->order);
+
+ cleanup_dynkeys:
+ dns_tsigkeyring_destroy(&view->dynamickeys);
+
+ cleanup_references:
+ isc_refcount_destroy(&view->references);
+
+ cleanup_fwdtable:
+ dns_fwdtable_destroy(&view->fwdtable);
+
+ cleanup_trustedkeys:
+ dns_keytable_detach(&view->trustedkeys);
+
+ cleanup_secroots:
+ dns_keytable_detach(&view->secroots);
+
+ cleanup_zt:
+ dns_zt_detach(&view->zonetable);
+
+ cleanup_mutex:
+ DESTROYLOCK(&view->lock);
+
+ cleanup_name:
+ isc_mem_free(mctx, view->name);
+
+ cleanup_view:
+ isc_mem_put(mctx, view, sizeof(*view));
+
+ return (result);
+}
+
+static inline void
+destroy(dns_view_t *view) {
+ REQUIRE(!ISC_LINK_LINKED(view, link));
+ REQUIRE(isc_refcount_current(&view->references) == 0);
+ REQUIRE(view->weakrefs == 0);
+ REQUIRE(RESSHUTDOWN(view));
+ REQUIRE(ADBSHUTDOWN(view));
+ REQUIRE(REQSHUTDOWN(view));
+
+ if (view->order != NULL)
+ dns_order_detach(&view->order);
+ if (view->peers != NULL)
+ dns_peerlist_detach(&view->peers);
+ if (view->dynamickeys != NULL)
+ dns_tsigkeyring_destroy(&view->dynamickeys);
+ if (view->statickeys != NULL)
+ dns_tsigkeyring_destroy(&view->statickeys);
+ if (view->adb != NULL)
+ dns_adb_detach(&view->adb);
+ if (view->resolver != NULL)
+ dns_resolver_detach(&view->resolver);
+ if (view->acache != NULL) {
+ if (view->cachedb != NULL)
+ dns_acache_putdb(view->acache, view->cachedb);
+ dns_acache_detach(&view->acache);
+ }
+ if (view->requestmgr != NULL)
+ dns_requestmgr_detach(&view->requestmgr);
+ if (view->task != NULL)
+ isc_task_detach(&view->task);
+ if (view->hints != NULL)
+ dns_db_detach(&view->hints);
+ if (view->dlzdatabase != NULL)
+ dns_dlzdestroy(&view->dlzdatabase);
+ if (view->cachedb != NULL)
+ dns_db_detach(&view->cachedb);
+ if (view->cache != NULL)
+ dns_cache_detach(&view->cache);
+ if (view->matchclients != NULL)
+ dns_acl_detach(&view->matchclients);
+ if (view->matchdestinations != NULL)
+ dns_acl_detach(&view->matchdestinations);
+ if (view->queryacl != NULL)
+ dns_acl_detach(&view->queryacl);
+ if (view->recursionacl != NULL)
+ dns_acl_detach(&view->recursionacl);
+ if (view->sortlist != NULL)
+ dns_acl_detach(&view->sortlist);
+ if (view->delonly != NULL) {
+ dns_name_t *name;
+ int i;
+
+ for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
+ name = ISC_LIST_HEAD(view->delonly[i]);
+ while (name != NULL) {
+ ISC_LIST_UNLINK(view->delonly[i], name, link);
+ dns_name_free(name, view->mctx);
+ isc_mem_put(view->mctx, name, sizeof(*name));
+ name = ISC_LIST_HEAD(view->delonly[i]);
+ }
+ }
+ isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
+ DNS_VIEW_DELONLYHASH);
+ view->delonly = NULL;
+ }
+ if (view->rootexclude != NULL) {
+ dns_name_t *name;
+ int i;
+
+ for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
+ name = ISC_LIST_HEAD(view->rootexclude[i]);
+ while (name != NULL) {
+ ISC_LIST_UNLINK(view->rootexclude[i],
+ name, link);
+ dns_name_free(name, view->mctx);
+ isc_mem_put(view->mctx, name, sizeof(*name));
+ name = ISC_LIST_HEAD(view->rootexclude[i]);
+ }
+ }
+ isc_mem_put(view->mctx, view->rootexclude,
+ sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
+ view->rootexclude = NULL;
+ }
+ dns_keytable_detach(&view->trustedkeys);
+ dns_keytable_detach(&view->secroots);
+ dns_fwdtable_destroy(&view->fwdtable);
+ dns_aclenv_destroy(&view->aclenv);
+ DESTROYLOCK(&view->lock);
+ isc_refcount_destroy(&view->references);
+ isc_mem_free(view->mctx, view->name);
+ isc_mem_put(view->mctx, view, sizeof(*view));
+}
+
+/*
+ * Return true iff 'view' may be freed.
+ * The caller must be holding the view lock.
+ */
+static isc_boolean_t
+all_done(dns_view_t *view) {
+
+ if (isc_refcount_current(&view->references) == 0 &&
+ view->weakrefs == 0 &&
+ RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+}
+
+void
+dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
+
+ REQUIRE(DNS_VIEW_VALID(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ isc_refcount_increment(&source->references, NULL);
+
+ *targetp = source;
+}
+
+static void
+view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
+ dns_view_t *view;
+ unsigned int refs;
+ isc_boolean_t done = ISC_FALSE;
+
+ REQUIRE(viewp != NULL);
+ view = *viewp;
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ if (flush)
+ view->flush = ISC_TRUE;
+ isc_refcount_decrement(&view->references, &refs);
+ if (refs == 0) {
+ LOCK(&view->lock);
+ if (!RESSHUTDOWN(view))
+ dns_resolver_shutdown(view->resolver);
+ if (!ADBSHUTDOWN(view))
+ dns_adb_shutdown(view->adb);
+ if (!REQSHUTDOWN(view))
+ dns_requestmgr_shutdown(view->requestmgr);
+ if (view->acache != NULL)
+ dns_acache_shutdown(view->acache);
+ if (view->flush)
+ dns_zt_flushanddetach(&view->zonetable);
+ else
+ dns_zt_detach(&view->zonetable);
+ done = all_done(view);
+ UNLOCK(&view->lock);
+ }
+
+ *viewp = NULL;
+
+ if (done)
+ destroy(view);
+}
+
+void
+dns_view_flushanddetach(dns_view_t **viewp) {
+ view_flushanddetach(viewp, ISC_TRUE);
+}
+
+void
+dns_view_detach(dns_view_t **viewp) {
+ view_flushanddetach(viewp, ISC_FALSE);
+}
+
+static isc_result_t
+dialup(dns_zone_t *zone, void *dummy) {
+ UNUSED(dummy);
+ dns_zone_dialup(zone);
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_view_dialup(dns_view_t *view) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ (void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
+}
+
+void
+dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
+
+ REQUIRE(DNS_VIEW_VALID(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ LOCK(&source->lock);
+ source->weakrefs++;
+ UNLOCK(&source->lock);
+
+ *targetp = source;
+}
+
+void
+dns_view_weakdetach(dns_view_t **viewp) {
+ dns_view_t *view;
+ isc_boolean_t done = ISC_FALSE;
+
+ REQUIRE(viewp != NULL);
+ view = *viewp;
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ LOCK(&view->lock);
+
+ INSIST(view->weakrefs > 0);
+ view->weakrefs--;
+ done = all_done(view);
+
+ UNLOCK(&view->lock);
+
+ *viewp = NULL;
+
+ if (done)
+ destroy(view);
+}
+
+static void
+resolver_shutdown(isc_task_t *task, isc_event_t *event) {
+ dns_view_t *view = event->ev_arg;
+ isc_boolean_t done;
+
+ REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(view->task == task);
+
+ UNUSED(task);
+
+ LOCK(&view->lock);
+
+ view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
+ done = all_done(view);
+
+ UNLOCK(&view->lock);
+
+ isc_event_free(&event);
+
+ if (done)
+ destroy(view);
+}
+
+static void
+adb_shutdown(isc_task_t *task, isc_event_t *event) {
+ dns_view_t *view = event->ev_arg;
+ isc_boolean_t done;
+
+ REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(view->task == task);
+
+ UNUSED(task);
+
+ LOCK(&view->lock);
+
+ view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
+ done = all_done(view);
+
+ UNLOCK(&view->lock);
+
+ isc_event_free(&event);
+
+ if (done)
+ destroy(view);
+}
+
+static void
+req_shutdown(isc_task_t *task, isc_event_t *event) {
+ dns_view_t *view = event->ev_arg;
+ isc_boolean_t done;
+
+ REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(view->task == task);
+
+ UNUSED(task);
+
+ LOCK(&view->lock);
+
+ view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
+ done = all_done(view);
+
+ UNLOCK(&view->lock);
+
+ isc_event_free(&event);
+
+ if (done)
+ destroy(view);
+}
+
+isc_result_t
+dns_view_createresolver(dns_view_t *view,
+ isc_taskmgr_t *taskmgr, unsigned int ntasks,
+ isc_socketmgr_t *socketmgr,
+ isc_timermgr_t *timermgr,
+ unsigned int options,
+ dns_dispatchmgr_t *dispatchmgr,
+ dns_dispatch_t *dispatchv4,
+ dns_dispatch_t *dispatchv6)
+{
+ isc_result_t result;
+ isc_event_t *event;
+ isc_mem_t *mctx = NULL;
+
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(!view->frozen);
+ REQUIRE(view->resolver == NULL);
+
+ result = isc_task_create(taskmgr, 0, &view->task);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_task_setname(view->task, "view", view);
+
+ result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
+ timermgr, options, dispatchmgr,
+ dispatchv4, dispatchv6,
+ &view->resolver);
+ if (result != ISC_R_SUCCESS) {
+ isc_task_detach(&view->task);
+ return (result);
+ }
+ event = &view->resevent;
+ dns_resolver_whenshutdown(view->resolver, view->task, &event);
+ view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;
+
+ result = isc_mem_create(0, 0, &mctx);
+ if (result != ISC_R_SUCCESS) {
+ dns_resolver_shutdown(view->resolver);
+ return (result);
+ }
+
+ result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
+ isc_mem_detach(&mctx);
+ if (result != ISC_R_SUCCESS) {
+ dns_resolver_shutdown(view->resolver);
+ return (result);
+ }
+ event = &view->adbevent;
+ dns_adb_whenshutdown(view->adb, view->task, &event);
+ view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
+
+ result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
+ dns_resolver_taskmgr(view->resolver),
+ dns_resolver_dispatchmgr(view->resolver),
+ dns_resolver_dispatchv4(view->resolver),
+ dns_resolver_dispatchv6(view->resolver),
+ &view->requestmgr);
+ if (result != ISC_R_SUCCESS) {
+ dns_adb_shutdown(view->adb);
+ dns_resolver_shutdown(view->resolver);
+ return (result);
+ }
+ event = &view->reqevent;
+ dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
+ view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(!view->frozen);
+
+ if (view->cache != NULL) {
+ if (view->acache != NULL)
+ dns_acache_putdb(view->acache, view->cachedb);
+ dns_db_detach(&view->cachedb);
+ dns_cache_detach(&view->cache);
+ }
+ dns_cache_attach(cache, &view->cache);
+ dns_cache_attachdb(cache, &view->cachedb);
+ INSIST(DNS_DB_VALID(view->cachedb));
+
+ if (view->acache != NULL)
+ dns_acache_setdb(view->acache, view->cachedb);
+}
+
+void
+dns_view_sethints(dns_view_t *view, dns_db_t *hints) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(!view->frozen);
+ REQUIRE(view->hints == NULL);
+ REQUIRE(dns_db_iszone(hints));
+
+ dns_db_attach(hints, &view->hints);
+}
+
+void
+dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(ring != NULL);
+ if (view->statickeys != NULL)
+ dns_tsigkeyring_destroy(&view->statickeys);
+ view->statickeys = ring;
+}
+
+void
+dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ view->dstport = dstport;
+}
+
+isc_result_t
+dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
+ isc_result_t result;
+
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(!view->frozen);
+
+ result = dns_zt_mount(view->zonetable, zone);
+
+ return (result);
+}
+
+void
+dns_view_freeze(dns_view_t *view) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(!view->frozen);
+
+ if (view->resolver != NULL) {
+ INSIST(view->cachedb != NULL);
+ dns_resolver_freeze(view->resolver);
+ }
+ view->frozen = ISC_TRUE;
+}
+
+isc_result_t
+dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
+ isc_result_t result;
+
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
+ if (result == DNS_R_PARTIALMATCH) {
+ dns_zone_detach(zonep);
+ result = ISC_R_NOTFOUND;
+ }
+
+ return (result);
+}
+
+isc_result_t
+dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
+ isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
+ dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ isc_result_t result;
+ dns_db_t *db, *zdb;
+ dns_dbnode_t *node, *znode;
+ isc_boolean_t is_cache;
+ dns_rdataset_t zrdataset, zsigrdataset;
+ dns_zone_t *zone;
+
+ /*
+ * Find an rdataset whose owner name is 'name', and whose type is
+ * 'type'.
+ */
+
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(view->frozen);
+ REQUIRE(type != dns_rdatatype_rrsig);
+ REQUIRE(rdataset != NULL); /* XXXBEW - remove this */
+ REQUIRE(nodep == NULL || *nodep == NULL);
+
+ /*
+ * Initialize.
+ */
+ dns_rdataset_init(&zrdataset);
+ dns_rdataset_init(&zsigrdataset);
+ zdb = NULL;
+ znode = NULL;
+
+ /*
+ * Find a database to answer the query.
+ */
+ zone = NULL;
+ db = NULL;
+ node = NULL;
+ result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+ result = dns_zone_getdb(zone, &db);
+ if (result != ISC_R_SUCCESS && view->cachedb != NULL)
+ dns_db_attach(view->cachedb, &db);
+ else if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ } else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
+ dns_db_attach(view->cachedb, &db);
+ else
+ goto cleanup;
+
+ is_cache = dns_db_iscache(db);
+
+ db_find:
+ /*
+ * Now look for an answer in the database.
+ */
+ result = dns_db_find(db, name, NULL, type, options,
+ now, &node, 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 (node != NULL)
+ dns_db_detachnode(db, &node);
+ if (!is_cache) {
+ dns_db_detach(&db);
+ if (view->cachedb != NULL) {
+ /*
+ * Either the answer is in the cache, or we
+ * don't know it.
+ */
+ is_cache = ISC_TRUE;
+ dns_db_attach(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 = DNS_R_GLUE;
+ if (db != NULL)
+ dns_db_detach(&db);
+ dns_db_attach(zdb, &db);
+ dns_db_attachnode(db, znode, &node);
+ goto cleanup;
+ }
+ }
+ /*
+ * We don't know the answer.
+ */
+ result = ISC_R_NOTFOUND;
+ } else if (result == DNS_R_GLUE) {
+ if (view->cachedb != NULL) {
+ /*
+ * We found an answer, but the cache may be better.
+ * Remember what we've got and go look in the cache.
+ */
+ is_cache = ISC_TRUE;
+ 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_attach(db, &zdb);
+ dns_db_attachnode(zdb, node, &znode);
+ dns_db_detachnode(db, &node);
+ dns_db_detach(&db);
+ dns_db_attach(view->cachedb, &db);
+ goto db_find;
+ }
+ /*
+ * Otherwise, the glue is the best answer.
+ */
+ result = ISC_R_SUCCESS;
+ }
+
+ if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
+ if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+ if (sigrdataset != NULL &&
+ dns_rdataset_isassociated(sigrdataset))
+ dns_rdataset_disassociate(sigrdataset);
+ if (db != NULL) {
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ dns_db_detach(&db);
+ }
+ result = dns_db_find(view->hints, name, NULL, type, options,
+ now, &node, foundname,
+ rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
+ /*
+ * We just used a hint. Let the resolver know it
+ * should consider priming.
+ */
+ dns_resolver_prime(view->resolver);
+ dns_db_attach(view->hints, &db);
+ result = DNS_R_HINT;
+ } else if (result == DNS_R_NXRRSET) {
+ dns_db_attach(view->hints, &db);
+ result = DNS_R_HINTNXRRSET;
+ } else if (result == DNS_R_NXDOMAIN)
+ result = ISC_R_NOTFOUND;
+
+ /*
+ * Cleanup if non-standard hints are used.
+ */
+ if (db == NULL && node != NULL)
+ dns_db_detachnode(view->hints, &node);
+ }
+
+ cleanup:
+ if (result == DNS_R_NXDOMAIN || result == DNS_R_NXRRSET) {
+ /*
+ * We don't care about any DNSSEC proof data in these cases.
+ */
+ if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+ if (sigrdataset != NULL &&
+ dns_rdataset_isassociated(sigrdataset))
+ dns_rdataset_disassociate(sigrdataset);
+ }
+
+ if (dns_rdataset_isassociated(&zrdataset)) {
+ dns_rdataset_disassociate(&zrdataset);
+ if (dns_rdataset_isassociated(&zsigrdataset))
+ dns_rdataset_disassociate(&zsigrdataset);
+ }
+
+ if (zdb != NULL) {
+ if (znode != NULL)
+ dns_db_detachnode(zdb, &znode);
+ dns_db_detach(&zdb);
+ }
+
+ if (db != NULL) {
+ if (node != NULL) {
+ if (nodep != NULL)
+ *nodep = node;
+ else
+ dns_db_detachnode(db, &node);
+ }
+ if (dbp != NULL)
+ *dbp = db;
+ else
+ dns_db_detach(&db);
+ } else
+ INSIST(node == NULL);
+
+ if (zone != NULL)
+ dns_zone_detach(&zone);
+
+ return (result);
+}
+
+isc_result_t
+dns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
+ isc_stdtime_t now, unsigned int options,
+ isc_boolean_t use_hints,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ isc_result_t result;
+ dns_fixedname_t foundname;
+
+ dns_fixedname_init(&foundname);
+ result = dns_view_find(view, name, type, now, options, use_hints,
+ NULL, NULL, dns_fixedname_name(&foundname),
+ rdataset, sigrdataset);
+ if (result == DNS_R_NXDOMAIN) {
+ /*
+ * The rdataset and sigrdataset of the relevant NSEC record
+ * may be returned, but the caller cannot use them because
+ * foundname is not returned by this simplified API. We
+ * disassociate them here to prevent any misuse by the caller.
+ */
+ if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+ if (sigrdataset != NULL &&
+ dns_rdataset_isassociated(sigrdataset))
+ dns_rdataset_disassociate(sigrdataset);
+ } else if (result != ISC_R_SUCCESS &&
+ result != DNS_R_GLUE &&
+ result != DNS_R_HINT &&
+ result != DNS_R_NCACHENXDOMAIN &&
+ result != DNS_R_NCACHENXRRSET &&
+ result != DNS_R_NXRRSET &&
+ result != DNS_R_HINTNXRRSET &&
+ result != ISC_R_NOTFOUND) {
+ if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+ if (sigrdataset != NULL &&
+ dns_rdataset_isassociated(sigrdataset))
+ dns_rdataset_disassociate(sigrdataset);
+ result = ISC_R_NOTFOUND;
+ }
+
+ return (result);
+}
+
+isc_result_t
+dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
+ isc_stdtime_t now, unsigned int options,
+ isc_boolean_t use_hints,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ return(dns_view_findzonecut2(view, name, fname, now, options,
+ use_hints, ISC_TRUE,
+ rdataset, sigrdataset));
+}
+
+isc_result_t
+dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
+ isc_stdtime_t now, unsigned int options,
+ isc_boolean_t use_hints, isc_boolean_t use_cache,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ isc_result_t result;
+ dns_db_t *db;
+ isc_boolean_t is_cache, use_zone, try_hints;
+ dns_zone_t *zone;
+ dns_name_t *zfname;
+ dns_rdataset_t zrdataset, zsigrdataset;
+ dns_fixedname_t zfixedname;
+
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(view->frozen);
+
+ db = NULL;
+ zone = NULL;
+ use_zone = ISC_FALSE;
+ try_hints = ISC_FALSE;
+ zfname = NULL;
+
+ /*
+ * Initialize.
+ */
+ dns_fixedname_init(&zfixedname);
+ dns_rdataset_init(&zrdataset);
+ dns_rdataset_init(&zsigrdataset);
+
+ /*
+ * Find the right database.
+ */
+ result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
+ result = dns_zone_getdb(zone, &db);
+ if (result == ISC_R_NOTFOUND) {
+ /*
+ * We're not directly authoritative for this query name, nor
+ * is it a subdomain of any zone for which we're
+ * authoritative.
+ */
+ if (use_cache && view->cachedb != NULL) {
+ /*
+ * We have a cache; try it.
+ */
+ dns_db_attach(view->cachedb, &db);
+ } else {
+ /*
+ * Maybe we have hints...
+ */
+ try_hints = ISC_TRUE;
+ goto finish;
+ }
+ } else if (result != ISC_R_SUCCESS) {
+ /*
+ * Something is broken.
+ */
+ goto cleanup;
+ }
+ is_cache = dns_db_iscache(db);
+
+ db_find:
+ /*
+ * Look for the zonecut.
+ */
+ if (!is_cache) {
+ result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
+ now, NULL, fname, rdataset, sigrdataset);
+ if (result == DNS_R_DELEGATION)
+ result = ISC_R_SUCCESS;
+ else if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ if (use_cache && view->cachedb != NULL && db != view->hints) {
+ /*
+ * We found an answer, but the cache may be better.
+ */
+ zfname = dns_fixedname_name(&zfixedname);
+ result = dns_name_copy(fname, zfname, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ 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(view->cachedb, &db);
+ is_cache = ISC_TRUE;
+ goto db_find;
+ }
+ } else {
+ result = dns_db_findzonecut(db, name, options, now, NULL,
+ 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) {
+ if (zfname != NULL) {
+ /*
+ * We didn't find anything in the cache, but we
+ * have a zone delegation, so use it.
+ */
+ use_zone = ISC_TRUE;
+ } else {
+ /*
+ * Maybe we have hints...
+ */
+ try_hints = ISC_TRUE;
+ }
+ } else {
+ /*
+ * Something bad happened.
+ */
+ goto cleanup;
+ }
+ }
+
+ finish:
+ if (use_zone) {
+ if (dns_rdataset_isassociated(rdataset)) {
+ dns_rdataset_disassociate(rdataset);
+ if (sigrdataset != NULL &&
+ dns_rdataset_isassociated(sigrdataset))
+ dns_rdataset_disassociate(sigrdataset);
+ }
+ result = dns_name_copy(zfname, fname, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ dns_rdataset_clone(&zrdataset, rdataset);
+ if (sigrdataset != NULL &&
+ dns_rdataset_isassociated(&zrdataset))
+ dns_rdataset_clone(&zsigrdataset, sigrdataset);
+ } else if (try_hints && use_hints && view->hints != NULL) {
+ /*
+ * We've found nothing so far, but we have hints.
+ */
+ result = dns_db_find(view->hints, dns_rootname, NULL,
+ dns_rdatatype_ns, 0, now, NULL, fname,
+ rdataset, NULL);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * We can't even find the hints for the root
+ * nameservers!
+ */
+ if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+ result = ISC_R_NOTFOUND;
+ }
+ }
+
+ cleanup:
+ if (dns_rdataset_isassociated(&zrdataset)) {
+ dns_rdataset_disassociate(&zrdataset);
+ if (dns_rdataset_isassociated(&zsigrdataset))
+ dns_rdataset_disassociate(&zsigrdataset);
+ }
+ if (db != NULL)
+ dns_db_detach(&db);
+ if (zone != NULL)
+ dns_zone_detach(&zone);
+
+ return (result);
+}
+
+isc_result_t
+dns_viewlist_find(dns_viewlist_t *list, const char *name,
+ dns_rdataclass_t rdclass, dns_view_t **viewp)
+{
+ dns_view_t *view;
+
+ REQUIRE(list != NULL);
+
+ for (view = ISC_LIST_HEAD(*list);
+ view != NULL;
+ view = ISC_LIST_NEXT(view, link)) {
+ if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
+ break;
+ }
+ if (view == NULL)
+ return (ISC_R_NOTFOUND);
+
+ dns_view_attach(view, viewp);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_view_load(dns_view_t *view, isc_boolean_t stop) {
+
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ return (dns_zt_load(view->zonetable, stop));
+}
+
+isc_result_t
+dns_view_loadnew(dns_view_t *view, isc_boolean_t stop) {
+
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ return (dns_zt_loadnew(view->zonetable, stop));
+}
+
+isc_result_t
+dns_view_gettsig(dns_view_t *view, dns_name_t *keyname, dns_tsigkey_t **keyp)
+{
+ isc_result_t result;
+ REQUIRE(keyp != NULL && *keyp == NULL);
+
+ result = dns_tsigkey_find(keyp, keyname, NULL,
+ view->statickeys);
+ if (result == ISC_R_NOTFOUND)
+ result = dns_tsigkey_find(keyp, keyname, NULL,
+ view->dynamickeys);
+ return (result);
+}
+
+isc_result_t
+dns_view_getpeertsig(dns_view_t *view, isc_netaddr_t *peeraddr,
+ dns_tsigkey_t **keyp)
+{
+ isc_result_t result;
+ dns_name_t *keyname = NULL;
+ dns_peer_t *peer = NULL;
+
+ result = dns_peerlist_peerbyaddr(view->peers, peeraddr, &peer);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_peer_getkey(peer, &keyname);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ return (dns_view_gettsig(view, keyname, keyp));
+}
+
+isc_result_t
+dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(source != NULL);
+
+ return (dns_tsig_verify(source, msg, view->statickeys,
+ view->dynamickeys));
+}
+
+isc_result_t
+dns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
+ isc_result_t result;
+
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ (void)fprintf(fp, ";\n; Cache dump of view '%s'\n;\n", view->name);
+ result = dns_master_dumptostream(view->mctx, view->cachedb, NULL,
+ &dns_master_style_cache, fp);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_adb_dump(view->adb, fp);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_view_flushcache(dns_view_t *view) {
+ isc_result_t result;
+
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ if (view->cachedb == NULL)
+ return (ISC_R_SUCCESS);
+ result = dns_cache_flush(view->cache);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (view->acache != NULL)
+ dns_acache_putdb(view->acache, view->cachedb);
+ dns_db_detach(&view->cachedb);
+ dns_cache_attachdb(view->cache, &view->cachedb);
+ if (view->acache != NULL)
+ dns_acache_setdb(view->acache, view->cachedb);
+
+ dns_adb_flush(view->adb);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_view_flushname(dns_view_t *view, dns_name_t *name) {
+
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ if (view->adb != NULL)
+ dns_adb_flushname(view->adb, name);
+ if (view->cache == NULL)
+ return (ISC_R_SUCCESS);
+ return (dns_cache_flushname(view->cache, name));
+}
+
+isc_result_t
+dns_view_adddelegationonly(dns_view_t *view, dns_name_t *name) {
+ isc_result_t result;
+ dns_name_t *new;
+ isc_uint32_t hash;
+
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ if (view->delonly == NULL) {
+ view->delonly = isc_mem_get(view->mctx,
+ sizeof(dns_namelist_t) *
+ DNS_VIEW_DELONLYHASH);
+ if (view->delonly == NULL)
+ return (ISC_R_NOMEMORY);
+ for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
+ ISC_LIST_INIT(view->delonly[hash]);
+ }
+ hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
+ new = ISC_LIST_HEAD(view->delonly[hash]);
+ while (new != NULL && !dns_name_equal(new, name))
+ new = ISC_LIST_NEXT(new, link);
+ if (new != NULL)
+ return (ISC_R_SUCCESS);
+ new = isc_mem_get(view->mctx, sizeof(*new));
+ if (new == NULL)
+ return (ISC_R_NOMEMORY);
+ dns_name_init(new, NULL);
+ result = dns_name_dup(name, view->mctx, new);
+ if (result == ISC_R_SUCCESS)
+ ISC_LIST_APPEND(view->delonly[hash], new, link);
+ else
+ isc_mem_put(view->mctx, new, sizeof(*new));
+ return (result);
+}
+
+isc_result_t
+dns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name) {
+ isc_result_t result;
+ dns_name_t *new;
+ isc_uint32_t hash;
+
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ if (view->rootexclude == NULL) {
+ view->rootexclude = isc_mem_get(view->mctx,
+ sizeof(dns_namelist_t) *
+ DNS_VIEW_DELONLYHASH);
+ if (view->rootexclude == NULL)
+ return (ISC_R_NOMEMORY);
+ for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
+ ISC_LIST_INIT(view->rootexclude[hash]);
+ }
+ hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
+ new = ISC_LIST_HEAD(view->rootexclude[hash]);
+ while (new != NULL && !dns_name_equal(new, name))
+ new = ISC_LIST_NEXT(new, link);
+ if (new != NULL)
+ return (ISC_R_SUCCESS);
+ new = isc_mem_get(view->mctx, sizeof(*new));
+ if (new == NULL)
+ return (ISC_R_NOMEMORY);
+ dns_name_init(new, NULL);
+ result = dns_name_dup(name, view->mctx, new);
+ if (result == ISC_R_SUCCESS)
+ ISC_LIST_APPEND(view->rootexclude[hash], new, link);
+ else
+ isc_mem_put(view->mctx, new, sizeof(*new));
+ return (result);
+}
+
+isc_boolean_t
+dns_view_isdelegationonly(dns_view_t *view, dns_name_t *name) {
+ dns_name_t *new;
+ isc_uint32_t hash;
+
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ if (!view->rootdelonly && view->delonly == NULL)
+ return (ISC_FALSE);
+
+ hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
+ if (view->rootdelonly && dns_name_countlabels(name) <= 2) {
+ if (view->rootexclude == NULL)
+ return (ISC_TRUE);
+ new = ISC_LIST_HEAD(view->rootexclude[hash]);
+ while (new != NULL && !dns_name_equal(new, name))
+ new = ISC_LIST_NEXT(new, link);
+ if (new == NULL)
+ return (ISC_TRUE);
+ }
+
+ if (view->delonly == NULL)
+ return (ISC_FALSE);
+
+ new = ISC_LIST_HEAD(view->delonly[hash]);
+ while (new != NULL && !dns_name_equal(new, name))
+ new = ISC_LIST_NEXT(new, link);
+ if (new == NULL)
+ return (ISC_FALSE);
+ return (ISC_TRUE);
+}
+
+void
+dns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ view->rootdelonly = value;
+}
+
+isc_boolean_t
+dns_view_getrootdelonly(dns_view_t *view) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ return (view->rootdelonly);
+}
+
+isc_result_t
+dns_view_freezezones(dns_view_t *view, isc_boolean_t value) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ return (dns_zt_freezezones(view->zonetable, value));
+}
diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c
new file mode 100644
index 0000000..dd7801d
--- /dev/null
+++ b/lib/dns/xfrin.c
@@ -0,0 +1,1470 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: xfrin.c,v 1.135.18.16 2007/10/31 01:59:47 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/diff.h>
+#include <dns/events.h>
+#include <dns/journal.h>
+#include <dns/log.h>
+#include <dns/message.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/result.h>
+#include <dns/soa.h>
+#include <dns/tcpmsg.h>
+#include <dns/timer.h>
+#include <dns/tsig.h>
+#include <dns/view.h>
+#include <dns/xfrin.h>
+#include <dns/zone.h>
+
+#include <dst/dst.h>
+
+/*
+ * Incoming AXFR and IXFR.
+ */
+
+/*%
+ * It would be non-sensical (or at least obtuse) to use FAIL() with an
+ * ISC_R_SUCCESS code, but the test 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)
+
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto failure; \
+ } while (0)
+
+/*%
+ * The states of the *XFR state machine. We handle both IXFR and AXFR
+ * with a single integrated state machine because they cannot be distinguished
+ * immediately - an AXFR response to an IXFR request can only be detected
+ * when the first two (2) response RRs have already been received.
+ */
+typedef enum {
+ XFRST_SOAQUERY,
+ XFRST_GOTSOA,
+ XFRST_INITIALSOA,
+ XFRST_FIRSTDATA,
+ XFRST_IXFR_DELSOA,
+ XFRST_IXFR_DEL,
+ XFRST_IXFR_ADDSOA,
+ XFRST_IXFR_ADD,
+ XFRST_AXFR,
+ XFRST_END
+} xfrin_state_t;
+
+/*%
+ * Incoming zone transfer context.
+ */
+
+struct dns_xfrin_ctx {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ dns_zone_t *zone;
+
+ int refcount;
+
+ isc_task_t *task;
+ isc_timer_t *timer;
+ isc_socketmgr_t *socketmgr;
+
+ int connects; /*%< Connect in progress */
+ int sends; /*%< Send in progress */
+ int recvs; /*%< Receive in progress */
+ isc_boolean_t shuttingdown;
+
+ dns_name_t name; /*%< Name of zone to transfer */
+ dns_rdataclass_t rdclass;
+
+ isc_boolean_t checkid;
+ dns_messageid_t id;
+
+ /*%
+ * Requested transfer type (dns_rdatatype_axfr or
+ * dns_rdatatype_ixfr). The actual transfer type
+ * may differ due to IXFR->AXFR fallback.
+ */
+ dns_rdatatype_t reqtype;
+
+ isc_sockaddr_t masteraddr;
+ isc_sockaddr_t sourceaddr;
+ isc_socket_t *socket;
+
+ /*% Buffer for IXFR/AXFR request message */
+ isc_buffer_t qbuffer;
+ unsigned char qbuffer_data[512];
+
+ /*% Incoming reply TCP message */
+ dns_tcpmsg_t tcpmsg;
+ isc_boolean_t tcpmsg_valid;
+
+ dns_db_t *db;
+ dns_dbversion_t *ver;
+ dns_diff_t diff; /*%< Pending database changes */
+ int difflen; /*%< Number of pending tuples */
+
+ xfrin_state_t state;
+ isc_uint32_t end_serial;
+ isc_boolean_t is_ixfr;
+
+ unsigned int nmsg; /*%< Number of messages recvd */
+
+ dns_tsigkey_t *tsigkey; /*%< Key used to create TSIG */
+ isc_buffer_t *lasttsig; /*%< The last TSIG */
+ dst_context_t *tsigctx; /*%< TSIG verification context */
+ unsigned int sincetsig; /*%< recvd since the last TSIG */
+ dns_xfrindone_t done;
+
+ /*%
+ * AXFR- and IXFR-specific data. Only one is used at a time
+ * according to the is_ixfr flag, so this could be a union,
+ * but keeping them separate makes it a bit simpler to clean
+ * things up when destroying the context.
+ */
+ struct {
+ dns_addrdatasetfunc_t add_func;
+ dns_dbload_t *add_private;
+ } axfr;
+
+ struct {
+ isc_uint32_t request_serial;
+ isc_uint32_t current_serial;
+ dns_journal_t *journal;
+
+ } ixfr;
+};
+
+#define XFRIN_MAGIC ISC_MAGIC('X', 'f', 'r', 'I')
+#define VALID_XFRIN(x) ISC_MAGIC_VALID(x, XFRIN_MAGIC)
+
+/**************************************************************************/
+/*
+ * Forward declarations.
+ */
+
+static isc_result_t
+xfrin_create(isc_mem_t *mctx,
+ dns_zone_t *zone,
+ dns_db_t *db,
+ isc_task_t *task,
+ isc_timermgr_t *timermgr,
+ isc_socketmgr_t *socketmgr,
+ dns_name_t *zonename,
+ dns_rdataclass_t rdclass,
+ dns_rdatatype_t reqtype,
+ isc_sockaddr_t *masteraddr,
+ isc_sockaddr_t *sourceaddr,
+ dns_tsigkey_t *tsigkey,
+ dns_xfrin_ctx_t **xfrp);
+
+static isc_result_t axfr_init(dns_xfrin_ctx_t *xfr);
+static isc_result_t axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp);
+static isc_result_t axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
+ dns_name_t *name, dns_ttl_t ttl,
+ dns_rdata_t *rdata);
+static isc_result_t axfr_apply(dns_xfrin_ctx_t *xfr);
+static isc_result_t axfr_commit(dns_xfrin_ctx_t *xfr);
+
+static isc_result_t ixfr_init(dns_xfrin_ctx_t *xfr);
+static isc_result_t ixfr_apply(dns_xfrin_ctx_t *xfr);
+static isc_result_t ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
+ dns_name_t *name, dns_ttl_t ttl,
+ dns_rdata_t *rdata);
+static isc_result_t ixfr_commit(dns_xfrin_ctx_t *xfr);
+
+static isc_result_t xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name,
+ isc_uint32_t ttl, dns_rdata_t *rdata);
+
+static isc_result_t xfrin_start(dns_xfrin_ctx_t *xfr);
+
+static void xfrin_connect_done(isc_task_t *task, isc_event_t *event);
+static isc_result_t xfrin_send_request(dns_xfrin_ctx_t *xfr);
+static void xfrin_send_done(isc_task_t *task, isc_event_t *event);
+static void xfrin_sendlen_done(isc_task_t *task, isc_event_t *event);
+static void xfrin_recv_done(isc_task_t *task, isc_event_t *event);
+static void xfrin_timeout(isc_task_t *task, isc_event_t *event);
+
+static void maybe_free(dns_xfrin_ctx_t *xfr);
+
+static void
+xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg);
+static isc_result_t
+render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf);
+
+static void
+xfrin_logv(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
+ const char *fmt, va_list ap)
+ ISC_FORMAT_PRINTF(4, 0);
+
+static void
+xfrin_log1(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
+ const char *fmt, ...)
+ ISC_FORMAT_PRINTF(4, 5);
+
+static void
+xfrin_log(dns_xfrin_ctx_t *xfr, int level, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+
+/**************************************************************************/
+/*
+ * AXFR handling
+ */
+
+static isc_result_t
+axfr_init(dns_xfrin_ctx_t *xfr) {
+ isc_result_t result;
+
+ xfr->is_ixfr = ISC_FALSE;
+
+ if (xfr->db != NULL)
+ dns_db_detach(&xfr->db);
+
+ CHECK(axfr_makedb(xfr, &xfr->db));
+ CHECK(dns_db_beginload(xfr->db, &xfr->axfr.add_func,
+ &xfr->axfr.add_private));
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+static isc_result_t
+axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp) {
+ return (dns_db_create(xfr->mctx, /* XXX */
+ "rbt", /* XXX guess */
+ &xfr->name,
+ dns_dbtype_zone,
+ xfr->rdclass,
+ 0, NULL, /* XXX guess */
+ dbp));
+}
+
+static isc_result_t
+axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
+ dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata)
+{
+ isc_result_t result;
+
+ dns_difftuple_t *tuple = NULL;
+
+ CHECK(dns_zone_checknames(xfr->zone, name, rdata));
+ CHECK(dns_difftuple_create(xfr->diff.mctx, op,
+ name, ttl, rdata, &tuple));
+ dns_diff_append(&xfr->diff, &tuple);
+ if (++xfr->difflen > 100)
+ CHECK(axfr_apply(xfr));
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+/*
+ * Store a set of AXFR RRs in the database.
+ */
+static isc_result_t
+axfr_apply(dns_xfrin_ctx_t *xfr) {
+ isc_result_t result;
+
+ CHECK(dns_diff_load(&xfr->diff,
+ xfr->axfr.add_func, xfr->axfr.add_private));
+ xfr->difflen = 0;
+ dns_diff_clear(&xfr->diff);
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+static isc_result_t
+axfr_commit(dns_xfrin_ctx_t *xfr) {
+ isc_result_t result;
+
+ CHECK(axfr_apply(xfr));
+ CHECK(dns_db_endload(xfr->db, &xfr->axfr.add_private));
+ CHECK(dns_zone_replacedb(xfr->zone, xfr->db, ISC_TRUE));
+
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+/**************************************************************************/
+/*
+ * IXFR handling
+ */
+
+static isc_result_t
+ixfr_init(dns_xfrin_ctx_t *xfr) {
+ isc_result_t result;
+ char *journalfile;
+
+ if (xfr->reqtype != dns_rdatatype_ixfr) {
+ xfrin_log(xfr, ISC_LOG_ERROR,
+ "got incremental response to AXFR request");
+ return (DNS_R_FORMERR);
+ }
+
+ xfr->is_ixfr = ISC_TRUE;
+ INSIST(xfr->db != NULL);
+ xfr->difflen = 0;
+
+ journalfile = dns_zone_getjournal(xfr->zone);
+ if (journalfile != NULL)
+ CHECK(dns_journal_open(xfr->mctx, journalfile,
+ ISC_TRUE, &xfr->ixfr.journal));
+
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+static isc_result_t
+ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
+ dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata)
+{
+ isc_result_t result;
+
+ dns_difftuple_t *tuple = NULL;
+ if (op == DNS_DIFFOP_ADD)
+ CHECK(dns_zone_checknames(xfr->zone, name, rdata));
+ CHECK(dns_difftuple_create(xfr->diff.mctx, op,
+ name, ttl, rdata, &tuple));
+ dns_diff_append(&xfr->diff, &tuple);
+ if (++xfr->difflen > 100)
+ CHECK(ixfr_apply(xfr));
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+/*
+ * Apply a set of IXFR changes to the database.
+ */
+static isc_result_t
+ixfr_apply(dns_xfrin_ctx_t *xfr) {
+ isc_result_t result;
+
+ if (xfr->ver == NULL) {
+ CHECK(dns_db_newversion(xfr->db, &xfr->ver));
+ if (xfr->ixfr.journal != NULL)
+ CHECK(dns_journal_begin_transaction(xfr->ixfr.journal));
+ }
+ CHECK(dns_diff_apply(&xfr->diff, xfr->db, xfr->ver));
+ if (xfr->ixfr.journal != NULL) {
+ result = dns_journal_writediff(xfr->ixfr.journal, &xfr->diff);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ }
+ dns_diff_clear(&xfr->diff);
+ xfr->difflen = 0;
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+static isc_result_t
+ixfr_commit(dns_xfrin_ctx_t *xfr) {
+ isc_result_t result;
+
+ CHECK(ixfr_apply(xfr));
+ if (xfr->ver != NULL) {
+ /* XXX enter ready-to-commit state here */
+ if (xfr->ixfr.journal != NULL)
+ CHECK(dns_journal_commit(xfr->ixfr.journal));
+ dns_db_closeversion(xfr->db, &xfr->ver, ISC_TRUE);
+ dns_zone_markdirty(xfr->zone);
+ }
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+/**************************************************************************/
+/*
+ * Common AXFR/IXFR protocol code
+ */
+
+/*
+ * Handle a single incoming resource record according to the current
+ * state.
+ */
+static isc_result_t
+xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, isc_uint32_t ttl,
+ dns_rdata_t *rdata)
+{
+ isc_result_t result;
+
+ redo:
+ switch (xfr->state) {
+ case XFRST_SOAQUERY:
+ if (rdata->type != dns_rdatatype_soa) {
+ xfrin_log(xfr, ISC_LOG_ERROR,
+ "non-SOA response to SOA query");
+ FAIL(DNS_R_FORMERR);
+ }
+ xfr->end_serial = dns_soa_getserial(rdata);
+ if (!DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial) &&
+ !dns_zone_isforced(xfr->zone)) {
+ xfrin_log(xfr, ISC_LOG_DEBUG(3),
+ "requested serial %u, "
+ "master has %u, not updating",
+ xfr->ixfr.request_serial, xfr->end_serial);
+ FAIL(DNS_R_UPTODATE);
+ }
+ xfr->state = XFRST_GOTSOA;
+ break;
+
+ case XFRST_GOTSOA:
+ /*
+ * Skip other records in the answer section.
+ */
+ break;
+
+ case XFRST_INITIALSOA:
+ if (rdata->type != dns_rdatatype_soa) {
+ xfrin_log(xfr, ISC_LOG_ERROR,
+ "first RR in zone transfer must be SOA");
+ FAIL(DNS_R_FORMERR);
+ }
+ /*
+ * Remember the serial number in the initial SOA.
+ * We need it to recognize the end of an IXFR.
+ */
+ xfr->end_serial = dns_soa_getserial(rdata);
+ if (xfr->reqtype == dns_rdatatype_ixfr &&
+ ! DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial)
+ && !dns_zone_isforced(xfr->zone))
+ {
+ /*
+ * This must be the single SOA record that is
+ * sent when the current version on the master
+ * is not newer than the version in the request.
+ */
+ xfrin_log(xfr, ISC_LOG_DEBUG(3),
+ "requested serial %u, "
+ "master has %u, not updating",
+ xfr->ixfr.request_serial, xfr->end_serial);
+ FAIL(DNS_R_UPTODATE);
+ }
+ if (xfr->reqtype == dns_rdatatype_axfr)
+ xfr->checkid = ISC_FALSE;
+ xfr->state = XFRST_FIRSTDATA;
+ break;
+
+ case XFRST_FIRSTDATA:
+ /*
+ * If the transfer begins with one SOA record, it is an AXFR,
+ * if it begins with two SOAs, it is an IXFR.
+ */
+ if (xfr->reqtype == dns_rdatatype_ixfr &&
+ rdata->type == dns_rdatatype_soa &&
+ xfr->ixfr.request_serial == dns_soa_getserial(rdata)) {
+ xfrin_log(xfr, ISC_LOG_DEBUG(3),
+ "got incremental response");
+ CHECK(ixfr_init(xfr));
+ xfr->state = XFRST_IXFR_DELSOA;
+ } else {
+ xfrin_log(xfr, ISC_LOG_DEBUG(3),
+ "got nonincremental response");
+ CHECK(axfr_init(xfr));
+ xfr->state = XFRST_AXFR;
+ }
+ goto redo;
+
+ case XFRST_IXFR_DELSOA:
+ INSIST(rdata->type == dns_rdatatype_soa);
+ CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
+ xfr->state = XFRST_IXFR_DEL;
+ break;
+
+ case XFRST_IXFR_DEL:
+ if (rdata->type == dns_rdatatype_soa) {
+ isc_uint32_t soa_serial = dns_soa_getserial(rdata);
+ xfr->state = XFRST_IXFR_ADDSOA;
+ xfr->ixfr.current_serial = soa_serial;
+ goto redo;
+ }
+ CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
+ break;
+
+ case XFRST_IXFR_ADDSOA:
+ INSIST(rdata->type == dns_rdatatype_soa);
+ CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
+ xfr->state = XFRST_IXFR_ADD;
+ break;
+
+ case XFRST_IXFR_ADD:
+ if (rdata->type == dns_rdatatype_soa) {
+ isc_uint32_t soa_serial = dns_soa_getserial(rdata);
+ if (soa_serial == xfr->end_serial) {
+ CHECK(ixfr_commit(xfr));
+ xfr->state = XFRST_END;
+ break;
+ } else if (soa_serial != xfr->ixfr.current_serial) {
+ xfrin_log(xfr, ISC_LOG_ERROR,
+ "IXFR out of sync: "
+ "expected serial %u, got %u",
+ xfr->ixfr.current_serial, soa_serial);
+ FAIL(DNS_R_FORMERR);
+ } else {
+ CHECK(ixfr_commit(xfr));
+ xfr->state = XFRST_IXFR_DELSOA;
+ goto redo;
+ }
+ }
+ if (rdata->type == dns_rdatatype_ns &&
+ dns_name_iswildcard(name))
+ FAIL(DNS_R_INVALIDNS);
+ CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
+ break;
+
+ case XFRST_AXFR:
+ /*
+ * Old BINDs sent cross class A records for non IN classes.
+ */
+ if (rdata->type == dns_rdatatype_a &&
+ rdata->rdclass != xfr->rdclass &&
+ xfr->rdclass != dns_rdataclass_in)
+ break;
+ CHECK(axfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
+ if (rdata->type == dns_rdatatype_soa) {
+ CHECK(axfr_commit(xfr));
+ xfr->state = XFRST_END;
+ break;
+ }
+ break;
+ case XFRST_END:
+ FAIL(DNS_R_EXTRADATA);
+ default:
+ INSIST(0);
+ break;
+ }
+ result = ISC_R_SUCCESS;
+ failure:
+ return (result);
+}
+
+isc_result_t
+dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
+ isc_sockaddr_t *masteraddr, dns_tsigkey_t *tsigkey,
+ isc_mem_t *mctx, isc_timermgr_t *timermgr,
+ isc_socketmgr_t *socketmgr, isc_task_t *task,
+ dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp)
+{
+ isc_sockaddr_t sourceaddr;
+
+ switch (isc_sockaddr_pf(masteraddr)) {
+ case PF_INET:
+ sourceaddr = *dns_zone_getxfrsource4(zone);
+ break;
+ case PF_INET6:
+ sourceaddr = *dns_zone_getxfrsource6(zone);
+ break;
+ default:
+ INSIST(0);
+ }
+
+ return(dns_xfrin_create2(zone, xfrtype, masteraddr, &sourceaddr,
+ tsigkey, mctx, timermgr, socketmgr,
+ task, done, xfrp));
+}
+
+isc_result_t
+dns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype,
+ isc_sockaddr_t *masteraddr, isc_sockaddr_t *sourceaddr,
+ dns_tsigkey_t *tsigkey, isc_mem_t *mctx,
+ isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
+ isc_task_t *task, dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp)
+{
+ dns_name_t *zonename = dns_zone_getorigin(zone);
+ dns_xfrin_ctx_t *xfr = NULL;
+ isc_result_t result;
+ dns_db_t *db = NULL;
+
+ REQUIRE(xfrp != NULL && *xfrp == NULL);
+
+ (void)dns_zone_getdb(zone, &db);
+
+ if (xfrtype == dns_rdatatype_soa || xfrtype == dns_rdatatype_ixfr)
+ REQUIRE(db != NULL);
+
+ CHECK(xfrin_create(mctx, zone, db, task, timermgr, socketmgr, zonename,
+ dns_zone_getclass(zone), xfrtype, masteraddr,
+ sourceaddr, tsigkey, &xfr));
+
+ CHECK(xfrin_start(xfr));
+
+ xfr->done = done;
+ xfr->refcount++;
+ *xfrp = xfr;
+
+ failure:
+ if (db != NULL)
+ dns_db_detach(&db);
+ if (result != ISC_R_SUCCESS) {
+ char zonetext[DNS_NAME_MAXTEXT+32];
+ dns_zone_name(zone, zonetext, sizeof(zonetext));
+ xfrin_log1(ISC_LOG_ERROR, zonetext, masteraddr,
+ "zone transfer setup failed");
+ }
+ return (result);
+}
+
+void
+dns_xfrin_shutdown(dns_xfrin_ctx_t *xfr) {
+ if (! xfr->shuttingdown)
+ xfrin_fail(xfr, ISC_R_CANCELED, "shut down");
+}
+
+void
+dns_xfrin_attach(dns_xfrin_ctx_t *source, dns_xfrin_ctx_t **target) {
+ REQUIRE(target != NULL && *target == NULL);
+ source->refcount++;
+ *target = source;
+}
+
+void
+dns_xfrin_detach(dns_xfrin_ctx_t **xfrp) {
+ dns_xfrin_ctx_t *xfr = *xfrp;
+ INSIST(xfr->refcount > 0);
+ xfr->refcount--;
+ maybe_free(xfr);
+ *xfrp = NULL;
+}
+
+static void
+xfrin_cancelio(dns_xfrin_ctx_t *xfr) {
+ if (xfr->connects > 0) {
+ isc_socket_cancel(xfr->socket, xfr->task,
+ ISC_SOCKCANCEL_CONNECT);
+ } else if (xfr->recvs > 0) {
+ dns_tcpmsg_cancelread(&xfr->tcpmsg);
+ } else if (xfr->sends > 0) {
+ isc_socket_cancel(xfr->socket, xfr->task,
+ ISC_SOCKCANCEL_SEND);
+ }
+}
+
+static void
+xfrin_reset(dns_xfrin_ctx_t *xfr) {
+ REQUIRE(VALID_XFRIN(xfr));
+
+ xfrin_log(xfr, ISC_LOG_INFO, "resetting");
+
+ xfrin_cancelio(xfr);
+
+ if (xfr->socket != NULL)
+ isc_socket_detach(&xfr->socket);
+
+ if (xfr->lasttsig != NULL)
+ isc_buffer_free(&xfr->lasttsig);
+
+ dns_diff_clear(&xfr->diff);
+ xfr->difflen = 0;
+
+ if (xfr->ixfr.journal != NULL)
+ dns_journal_destroy(&xfr->ixfr.journal);
+
+ if (xfr->axfr.add_private != NULL) {
+ (void)dns_db_endload(xfr->db, &xfr->axfr.add_private);
+ xfr->axfr.add_func = NULL;
+ }
+
+ if (xfr->tcpmsg_valid) {
+ dns_tcpmsg_invalidate(&xfr->tcpmsg);
+ xfr->tcpmsg_valid = ISC_FALSE;
+ }
+
+ if (xfr->ver != NULL)
+ dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE);
+}
+
+
+static void
+xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg) {
+ if (result != DNS_R_UPTODATE) {
+ xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s",
+ msg, isc_result_totext(result));
+ if (xfr->is_ixfr)
+ /* Pass special result code to force AXFR retry */
+ result = DNS_R_BADIXFR;
+ }
+ xfrin_cancelio(xfr);
+ /*
+ * Close the journal.
+ */
+ if (xfr->ixfr.journal != NULL)
+ dns_journal_destroy(&xfr->ixfr.journal);
+ if (xfr->done != NULL) {
+ (xfr->done)(xfr->zone, result);
+ xfr->done = NULL;
+ }
+ xfr->shuttingdown = ISC_TRUE;
+ maybe_free(xfr);
+}
+
+static isc_result_t
+xfrin_create(isc_mem_t *mctx,
+ dns_zone_t *zone,
+ dns_db_t *db,
+ isc_task_t *task,
+ isc_timermgr_t *timermgr,
+ isc_socketmgr_t *socketmgr,
+ dns_name_t *zonename,
+ dns_rdataclass_t rdclass,
+ dns_rdatatype_t reqtype,
+ isc_sockaddr_t *masteraddr,
+ isc_sockaddr_t *sourceaddr,
+ dns_tsigkey_t *tsigkey,
+ dns_xfrin_ctx_t **xfrp)
+{
+ dns_xfrin_ctx_t *xfr = NULL;
+ isc_result_t result;
+ isc_uint32_t tmp;
+
+ xfr = isc_mem_get(mctx, sizeof(*xfr));
+ if (xfr == NULL)
+ return (ISC_R_NOMEMORY);
+ xfr->mctx = mctx;
+ xfr->refcount = 0;
+ xfr->zone = NULL;
+ dns_zone_iattach(zone, &xfr->zone);
+ xfr->task = NULL;
+ isc_task_attach(task, &xfr->task);
+ xfr->timer = NULL;
+ xfr->socketmgr = socketmgr;
+ xfr->done = NULL;
+
+ xfr->connects = 0;
+ xfr->sends = 0;
+ xfr->recvs = 0;
+ xfr->shuttingdown = ISC_FALSE;
+
+ dns_name_init(&xfr->name, NULL);
+ xfr->rdclass = rdclass;
+ isc_random_get(&tmp);
+ xfr->checkid = ISC_TRUE;
+ xfr->id = (isc_uint16_t)(tmp & 0xffff);
+ xfr->reqtype = reqtype;
+
+ /* sockaddr */
+ xfr->socket = NULL;
+ /* qbuffer */
+ /* qbuffer_data */
+ /* tcpmsg */
+ xfr->tcpmsg_valid = ISC_FALSE;
+
+ xfr->db = NULL;
+ if (db != NULL)
+ dns_db_attach(db, &xfr->db);
+ xfr->ver = NULL;
+ dns_diff_init(xfr->mctx, &xfr->diff);
+ xfr->difflen = 0;
+
+ if (reqtype == dns_rdatatype_soa)
+ xfr->state = XFRST_SOAQUERY;
+ else
+ xfr->state = XFRST_INITIALSOA;
+ /* end_serial */
+
+ xfr->nmsg = 0;
+
+ xfr->tsigkey = NULL;
+ if (tsigkey != NULL)
+ dns_tsigkey_attach(tsigkey, &xfr->tsigkey);
+ xfr->lasttsig = NULL;
+ xfr->tsigctx = NULL;
+ xfr->sincetsig = 0;
+ xfr->is_ixfr = ISC_FALSE;
+
+ /* ixfr.request_serial */
+ /* ixfr.current_serial */
+ xfr->ixfr.journal = NULL;
+
+ xfr->axfr.add_func = NULL;
+ xfr->axfr.add_private = NULL;
+
+ CHECK(dns_name_dup(zonename, mctx, &xfr->name));
+
+ CHECK(isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
+ task, xfrin_timeout, xfr, &xfr->timer));
+ CHECK(dns_timer_setidle(xfr->timer,
+ dns_zone_getmaxxfrin(xfr->zone),
+ dns_zone_getidlein(xfr->zone),
+ ISC_FALSE));
+
+ xfr->masteraddr = *masteraddr;
+
+ INSIST(isc_sockaddr_pf(masteraddr) == isc_sockaddr_pf(sourceaddr));
+ xfr->sourceaddr = *sourceaddr;
+ isc_sockaddr_setport(&xfr->sourceaddr, 0);
+
+ isc_buffer_init(&xfr->qbuffer, xfr->qbuffer_data,
+ sizeof(xfr->qbuffer_data));
+
+ xfr->magic = XFRIN_MAGIC;
+ *xfrp = xfr;
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (xfr->timer != NULL)
+ isc_timer_detach(&xfr->timer);
+ if (dns_name_dynamic(&xfr->name))
+ dns_name_free(&xfr->name, xfr->mctx);
+ if (xfr->tsigkey != NULL)
+ dns_tsigkey_detach(&xfr->tsigkey);
+ if (xfr->db != NULL)
+ dns_db_detach(&xfr->db);
+ isc_task_detach(&xfr->task);
+ dns_zone_idetach(&xfr->zone);
+ isc_mem_put(mctx, xfr, sizeof(*xfr));
+
+ return (result);
+}
+
+static isc_result_t
+xfrin_start(dns_xfrin_ctx_t *xfr) {
+ isc_result_t result;
+ CHECK(isc_socket_create(xfr->socketmgr,
+ isc_sockaddr_pf(&xfr->sourceaddr),
+ isc_sockettype_tcp,
+ &xfr->socket));
+#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
+ CHECK(isc_socket_bind(xfr->socket, &xfr->sourceaddr));
+#endif
+ CHECK(isc_socket_connect(xfr->socket, &xfr->masteraddr, xfr->task,
+ xfrin_connect_done, xfr));
+ xfr->connects++;
+ return (ISC_R_SUCCESS);
+ failure:
+ xfrin_fail(xfr, result, "failed setting up socket");
+ return (result);
+}
+
+/* XXX the resolver could use this, too */
+
+static isc_result_t
+render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf) {
+ dns_compress_t cctx;
+ isc_boolean_t cleanup_cctx = ISC_FALSE;
+ isc_result_t result;
+
+ CHECK(dns_compress_init(&cctx, -1, mctx));
+ cleanup_cctx = ISC_TRUE;
+ CHECK(dns_message_renderbegin(msg, &cctx, buf));
+ CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0));
+ CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0));
+ CHECK(dns_message_rendersection(msg, DNS_SECTION_AUTHORITY, 0));
+ CHECK(dns_message_rendersection(msg, DNS_SECTION_ADDITIONAL, 0));
+ CHECK(dns_message_renderend(msg));
+ result = ISC_R_SUCCESS;
+ failure:
+ if (cleanup_cctx)
+ dns_compress_invalidate(&cctx);
+ return (result);
+}
+
+/*
+ * A connection has been established.
+ */
+static void
+xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
+ isc_socket_connev_t *cev = (isc_socket_connev_t *) event;
+ dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
+ isc_result_t evresult = cev->result;
+ isc_result_t result;
+ char sourcetext[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_t sockaddr;
+
+ REQUIRE(VALID_XFRIN(xfr));
+
+ UNUSED(task);
+
+ INSIST(event->ev_type == ISC_SOCKEVENT_CONNECT);
+ isc_event_free(&event);
+
+ xfr->connects--;
+ if (xfr->shuttingdown) {
+ maybe_free(xfr);
+ return;
+ }
+
+ CHECK(evresult);
+ result = isc_socket_getsockname(xfr->socket, &sockaddr);
+ if (result == ISC_R_SUCCESS) {
+ isc_sockaddr_format(&sockaddr, sourcetext, sizeof(sourcetext));
+ } else
+ strcpy(sourcetext, "<UNKNOWN>");
+ xfrin_log(xfr, ISC_LOG_INFO, "connected using %s", sourcetext);
+
+ dns_tcpmsg_init(xfr->mctx, xfr->socket, &xfr->tcpmsg);
+ xfr->tcpmsg_valid = ISC_TRUE;
+
+ CHECK(xfrin_send_request(xfr));
+ failure:
+ if (result != ISC_R_SUCCESS)
+ xfrin_fail(xfr, result, "failed to connect");
+}
+
+/*
+ * Convert a tuple into a dns_name_t suitable for inserting
+ * into the given dns_message_t.
+ */
+static isc_result_t
+tuple2msgname(dns_difftuple_t *tuple, dns_message_t *msg, dns_name_t **target)
+{
+ isc_result_t result;
+ dns_rdata_t *rdata = NULL;
+ dns_rdatalist_t *rdl = NULL;
+ dns_rdataset_t *rds = NULL;
+ dns_name_t *name = NULL;
+
+ REQUIRE(target != NULL && *target == NULL);
+
+ CHECK(dns_message_gettemprdata(msg, &rdata));
+ dns_rdata_init(rdata);
+ dns_rdata_clone(&tuple->rdata, rdata);
+
+ CHECK(dns_message_gettemprdatalist(msg, &rdl));
+ dns_rdatalist_init(rdl);
+ rdl->type = tuple->rdata.type;
+ rdl->rdclass = tuple->rdata.rdclass;
+ rdl->ttl = tuple->ttl;
+ ISC_LIST_APPEND(rdl->rdata, rdata, link);
+
+ CHECK(dns_message_gettemprdataset(msg, &rds));
+ dns_rdataset_init(rds);
+ CHECK(dns_rdatalist_tordataset(rdl, rds));
+
+ CHECK(dns_message_gettempname(msg, &name));
+ dns_name_init(name, NULL);
+ dns_name_clone(&tuple->name, name);
+ ISC_LIST_APPEND(name->list, rds, link);
+
+ *target = name;
+ return (ISC_R_SUCCESS);
+
+ failure:
+
+ if (rds != NULL) {
+ dns_rdataset_disassociate(rds);
+ dns_message_puttemprdataset(msg, &rds);
+ }
+ if (rdl != NULL) {
+ ISC_LIST_UNLINK(rdl->rdata, rdata, link);
+ dns_message_puttemprdatalist(msg, &rdl);
+ }
+ if (rdata != NULL)
+ dns_message_puttemprdata(msg, &rdata);
+
+ return (result);
+}
+
+
+/*
+ * Build an *XFR request and send its length prefix.
+ */
+static isc_result_t
+xfrin_send_request(dns_xfrin_ctx_t *xfr) {
+ isc_result_t result;
+ isc_region_t region;
+ isc_region_t lregion;
+ dns_rdataset_t *qrdataset = NULL;
+ dns_message_t *msg = NULL;
+ unsigned char length[2];
+ dns_difftuple_t *soatuple = NULL;
+ dns_name_t *qname = NULL;
+ dns_dbversion_t *ver = NULL;
+ dns_name_t *msgsoaname = NULL;
+
+ /* Create the request message */
+ CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTRENDER, &msg));
+ CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
+
+ /* Create a name for the question section. */
+ CHECK(dns_message_gettempname(msg, &qname));
+ dns_name_init(qname, NULL);
+ dns_name_clone(&xfr->name, qname);
+
+ /* Formulate the question and attach it to the question name. */
+ CHECK(dns_message_gettemprdataset(msg, &qrdataset));
+ dns_rdataset_init(qrdataset);
+ dns_rdataset_makequestion(qrdataset, xfr->rdclass, xfr->reqtype);
+ ISC_LIST_APPEND(qname->list, qrdataset, link);
+ qrdataset = NULL;
+
+ dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
+ qname = NULL;
+
+ if (xfr->reqtype == dns_rdatatype_ixfr) {
+ /* Get the SOA and add it to the authority section. */
+ /* XXX is using the current version the right thing? */
+ dns_db_currentversion(xfr->db, &ver);
+ CHECK(dns_db_createsoatuple(xfr->db, ver, xfr->mctx,
+ DNS_DIFFOP_EXISTS, &soatuple));
+ xfr->ixfr.request_serial = dns_soa_getserial(&soatuple->rdata);
+ xfr->ixfr.current_serial = xfr->ixfr.request_serial;
+ xfrin_log(xfr, ISC_LOG_DEBUG(3),
+ "requesting IXFR for serial %u",
+ xfr->ixfr.request_serial);
+
+ CHECK(tuple2msgname(soatuple, msg, &msgsoaname));
+ dns_message_addname(msg, msgsoaname, DNS_SECTION_AUTHORITY);
+ } else if (xfr->reqtype == dns_rdatatype_soa)
+ CHECK(dns_db_getsoaserial(xfr->db, NULL,
+ &xfr->ixfr.request_serial));
+
+ xfr->checkid = ISC_TRUE;
+ xfr->id++;
+ xfr->nmsg = 0;
+ msg->id = xfr->id;
+
+ CHECK(render(msg, xfr->mctx, &xfr->qbuffer));
+
+ /*
+ * Free the last tsig, if there is one.
+ */
+ if (xfr->lasttsig != NULL)
+ isc_buffer_free(&xfr->lasttsig);
+
+ /*
+ * Save the query TSIG and don't let message_destroy free it.
+ */
+ CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig));
+
+ isc_buffer_usedregion(&xfr->qbuffer, &region);
+ INSIST(region.length <= 65535);
+
+ length[0] = region.length >> 8;
+ length[1] = region.length & 0xFF;
+ lregion.base = length;
+ lregion.length = 2;
+ CHECK(isc_socket_send(xfr->socket, &lregion, xfr->task,
+ xfrin_sendlen_done, xfr));
+ xfr->sends++;
+
+ failure:
+ if (qname != NULL)
+ dns_message_puttempname(msg, &qname);
+ if (qrdataset != NULL)
+ dns_message_puttemprdataset(msg, &qrdataset);
+ if (msg != NULL)
+ dns_message_destroy(&msg);
+ if (soatuple != NULL)
+ dns_difftuple_free(&soatuple);
+ if (ver != NULL)
+ dns_db_closeversion(xfr->db, &ver, ISC_FALSE);
+ return (result);
+}
+
+/* XXX there should be library support for sending DNS TCP messages */
+
+static void
+xfrin_sendlen_done(isc_task_t *task, isc_event_t *event) {
+ isc_socketevent_t *sev = (isc_socketevent_t *) event;
+ dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
+ isc_result_t evresult = sev->result;
+ isc_result_t result;
+ isc_region_t region;
+
+ REQUIRE(VALID_XFRIN(xfr));
+
+ UNUSED(task);
+
+ INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE);
+ isc_event_free(&event);
+
+ xfr->sends--;
+ if (xfr->shuttingdown) {
+ maybe_free(xfr);
+ return;
+ }
+
+ xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request length prefix");
+ CHECK(evresult);
+
+ isc_buffer_usedregion(&xfr->qbuffer, &region);
+ CHECK(isc_socket_send(xfr->socket, &region, xfr->task,
+ xfrin_send_done, xfr));
+ xfr->sends++;
+ failure:
+ if (result != ISC_R_SUCCESS)
+ xfrin_fail(xfr, result, "failed sending request length prefix");
+}
+
+
+static void
+xfrin_send_done(isc_task_t *task, isc_event_t *event) {
+ isc_socketevent_t *sev = (isc_socketevent_t *) event;
+ dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
+ isc_result_t result;
+
+ REQUIRE(VALID_XFRIN(xfr));
+
+ UNUSED(task);
+
+ INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE);
+
+ xfr->sends--;
+ xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request data");
+ CHECK(sev->result);
+
+ CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
+ xfrin_recv_done, xfr));
+ xfr->recvs++;
+ failure:
+ isc_event_free(&event);
+ if (result != ISC_R_SUCCESS)
+ xfrin_fail(xfr, result, "failed sending request data");
+}
+
+
+static void
+xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
+ dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) ev->ev_arg;
+ isc_result_t result;
+ dns_message_t *msg = NULL;
+ dns_name_t *name;
+ dns_tcpmsg_t *tcpmsg;
+ dns_name_t *tsigowner = NULL;
+
+ REQUIRE(VALID_XFRIN(xfr));
+
+ UNUSED(task);
+
+ INSIST(ev->ev_type == DNS_EVENT_TCPMSG);
+ tcpmsg = ev->ev_sender;
+ isc_event_free(&ev);
+
+ xfr->recvs--;
+ if (xfr->shuttingdown) {
+ maybe_free(xfr);
+ return;
+ }
+
+ CHECK(tcpmsg->result);
+
+ xfrin_log(xfr, ISC_LOG_DEBUG(7), "received %u bytes",
+ tcpmsg->buffer.used);
+
+ CHECK(isc_timer_touch(xfr->timer));
+
+ CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTPARSE, &msg));
+
+ CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
+ CHECK(dns_message_setquerytsig(msg, xfr->lasttsig));
+ msg->tsigctx = xfr->tsigctx;
+ if (xfr->nmsg > 0)
+ msg->tcp_continuation = 1;
+
+ result = dns_message_parse(msg, &tcpmsg->buffer,
+ DNS_MESSAGEPARSE_PRESERVEORDER);
+
+ if (result != ISC_R_SUCCESS || msg->rcode != dns_rcode_noerror ||
+ (xfr->checkid && msg->id != xfr->id)) {
+ if (result == ISC_R_SUCCESS)
+ result = ISC_RESULTCLASS_DNSRCODE + msg->rcode; /*XXX*/
+ if (result == ISC_R_SUCCESS || result == DNS_R_NOERROR)
+ result = DNS_R_UNEXPECTEDID;
+ if (xfr->reqtype == dns_rdatatype_axfr ||
+ xfr->reqtype == dns_rdatatype_soa)
+ FAIL(result);
+ xfrin_log(xfr, ISC_LOG_DEBUG(3), "got %s, retrying with AXFR",
+ isc_result_totext(result));
+ try_axfr:
+ dns_message_destroy(&msg);
+ xfrin_reset(xfr);
+ xfr->reqtype = dns_rdatatype_soa;
+ xfr->state = XFRST_SOAQUERY;
+ (void)xfrin_start(xfr);
+ return;
+ }
+
+ /*
+ * Does the server know about IXFR? If it doesn't we will get
+ * a message with a empty answer section or a potentially a CNAME /
+ * DNAME, the later is handled by xfr_rr() which will return FORMERR
+ * if the first RR in the answer section is not a SOA record.
+ */
+ if (xfr->reqtype == dns_rdatatype_ixfr &&
+ xfr->state == XFRST_INITIALSOA &&
+ msg->counts[DNS_SECTION_ANSWER] == 0) {
+ xfrin_log(xfr, ISC_LOG_DEBUG(3),
+ "empty answer section, retrying with AXFR");
+ goto try_axfr;
+ }
+
+ if (xfr->reqtype == dns_rdatatype_soa &&
+ (msg->flags & DNS_MESSAGEFLAG_AA) == 0) {
+ FAIL(DNS_R_NOTAUTHORITATIVE);
+ }
+
+
+ result = dns_message_checksig(msg, dns_zone_getview(xfr->zone));
+ if (result != ISC_R_SUCCESS) {
+ xfrin_log(xfr, ISC_LOG_DEBUG(3), "TSIG check failed: %s",
+ isc_result_totext(result));
+ FAIL(result);
+ }
+
+ for (result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
+ result == ISC_R_SUCCESS;
+ result = dns_message_nextname(msg, DNS_SECTION_ANSWER))
+ {
+ dns_rdataset_t *rds;
+
+ name = NULL;
+ dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
+ for (rds = ISC_LIST_HEAD(name->list);
+ rds != NULL;
+ rds = ISC_LIST_NEXT(rds, link))
+ {
+ for (result = dns_rdataset_first(rds);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(rds))
+ {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_current(rds, &rdata);
+ CHECK(xfr_rr(xfr, name, rds->ttl, &rdata));
+ }
+ }
+ }
+ if (result != ISC_R_NOMORE)
+ goto failure;
+
+ if (dns_message_gettsig(msg, &tsigowner) != NULL) {
+ /*
+ * Reset the counter.
+ */
+ xfr->sincetsig = 0;
+
+ /*
+ * Free the last tsig, if there is one.
+ */
+ if (xfr->lasttsig != NULL)
+ isc_buffer_free(&xfr->lasttsig);
+
+ /*
+ * Update the last tsig pointer.
+ */
+ CHECK(dns_message_getquerytsig(msg, xfr->mctx,
+ &xfr->lasttsig));
+
+ } else if (dns_message_gettsigkey(msg) != NULL) {
+ xfr->sincetsig++;
+ if (xfr->sincetsig > 100 ||
+ xfr->nmsg == 0 || xfr->state == XFRST_END)
+ {
+ result = DNS_R_EXPECTEDTSIG;
+ goto failure;
+ }
+ }
+
+ /*
+ * Update the number of messages received.
+ */
+ xfr->nmsg++;
+
+ /*
+ * Copy the context back.
+ */
+ xfr->tsigctx = msg->tsigctx;
+
+ dns_message_destroy(&msg);
+
+ if (xfr->state == XFRST_GOTSOA) {
+ xfr->reqtype = dns_rdatatype_axfr;
+ xfr->state = XFRST_INITIALSOA;
+ CHECK(xfrin_send_request(xfr));
+ } else if (xfr->state == XFRST_END) {
+ /*
+ * Close the journal.
+ */
+ if (xfr->ixfr.journal != NULL)
+ dns_journal_destroy(&xfr->ixfr.journal);
+ /*
+ * Inform the caller we succeeded.
+ */
+ if (xfr->done != NULL) {
+ (xfr->done)(xfr->zone, ISC_R_SUCCESS);
+ xfr->done = NULL;
+ }
+ /*
+ * We should have no outstanding events at this
+ * point, thus maybe_free() should succeed.
+ */
+ xfr->shuttingdown = ISC_TRUE;
+ maybe_free(xfr);
+ } else {
+ /*
+ * Read the next message.
+ */
+ CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
+ xfrin_recv_done, xfr));
+ xfr->recvs++;
+ }
+ return;
+
+ failure:
+ if (msg != NULL)
+ dns_message_destroy(&msg);
+ if (result != ISC_R_SUCCESS)
+ xfrin_fail(xfr, result, "failed while receiving responses");
+}
+
+static void
+xfrin_timeout(isc_task_t *task, isc_event_t *event) {
+ dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
+
+ REQUIRE(VALID_XFRIN(xfr));
+
+ UNUSED(task);
+
+ isc_event_free(&event);
+ /*
+ * This will log "giving up: timeout".
+ */
+ xfrin_fail(xfr, ISC_R_TIMEDOUT, "giving up");
+}
+
+static void
+maybe_free(dns_xfrin_ctx_t *xfr) {
+ REQUIRE(VALID_XFRIN(xfr));
+
+ if (! xfr->shuttingdown || xfr->refcount != 0 ||
+ xfr->connects != 0 || xfr->sends != 0 ||
+ xfr->recvs != 0)
+ return;
+
+ xfrin_log(xfr, ISC_LOG_INFO, "end of transfer");
+
+ if (xfr->socket != NULL)
+ isc_socket_detach(&xfr->socket);
+
+ if (xfr->timer != NULL)
+ isc_timer_detach(&xfr->timer);
+
+ if (xfr->task != NULL)
+ isc_task_detach(&xfr->task);
+
+ if (xfr->tsigkey != NULL)
+ dns_tsigkey_detach(&xfr->tsigkey);
+
+ if (xfr->lasttsig != NULL)
+ isc_buffer_free(&xfr->lasttsig);
+
+ dns_diff_clear(&xfr->diff);
+
+ if (xfr->ixfr.journal != NULL)
+ dns_journal_destroy(&xfr->ixfr.journal);
+
+ if (xfr->axfr.add_private != NULL)
+ (void)dns_db_endload(xfr->db, &xfr->axfr.add_private);
+
+ if (xfr->tcpmsg_valid)
+ dns_tcpmsg_invalidate(&xfr->tcpmsg);
+
+ if ((xfr->name.attributes & DNS_NAMEATTR_DYNAMIC) != 0)
+ dns_name_free(&xfr->name, xfr->mctx);
+
+ if (xfr->ver != NULL)
+ dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE);
+
+ if (xfr->db != NULL)
+ dns_db_detach(&xfr->db);
+
+ if (xfr->zone != NULL)
+ dns_zone_idetach(&xfr->zone);
+
+ isc_mem_put(xfr->mctx, xfr, sizeof(*xfr));
+}
+
+/*
+ * Log incoming zone transfer messages in a format like
+ * transfer of <zone> from <address>: <message>
+ */
+static void
+xfrin_logv(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
+ const char *fmt, va_list ap)
+{
+ char mastertext[ISC_SOCKADDR_FORMATSIZE];
+ char msgtext[2048];
+
+ isc_sockaddr_format(masteraddr, mastertext, sizeof(mastertext));
+ vsnprintf(msgtext, sizeof(msgtext), fmt, ap);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_XFER_IN,
+ DNS_LOGMODULE_XFER_IN, level,
+ "transfer of '%s' from %s: %s",
+ zonetext, mastertext, msgtext);
+}
+
+/*
+ * Logging function for use when a xfrin_ctx_t has not yet been created.
+ */
+
+static void
+xfrin_log1(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
+ return;
+
+ va_start(ap, fmt);
+ xfrin_logv(level, zonetext, masteraddr, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Logging function for use when there is a xfrin_ctx_t.
+ */
+
+static void
+xfrin_log(dns_xfrin_ctx_t *xfr, int level, const char *fmt, ...)
+{
+ va_list ap;
+ char zonetext[DNS_NAME_MAXTEXT+32];
+
+ if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
+ return;
+
+ dns_zone_name(xfr->zone, zonetext, sizeof(zonetext));
+
+ va_start(ap, fmt);
+ xfrin_logv(level, zonetext, &xfr->masteraddr, fmt, ap);
+ va_end(ap);
+}
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
new file mode 100644
index 0000000..fa6ac46
--- /dev/null
+++ b/lib/dns/zone.c
@@ -0,0 +1,8043 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: zone.c,v 1.410.18.52 2007/08/30 05:15:03 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/file.h>
+#include <isc/mutex.h>
+#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/ratelimiter.h>
+#include <isc/refcount.h>
+#include <isc/rwlock.h>
+#include <isc/serial.h>
+#include <isc/string.h>
+#include <isc/taskpool.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/acache.h>
+#include <dns/acl.h>
+#include <dns/adb.h>
+#include <dns/callbacks.h>
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/events.h>
+#include <dns/journal.h>
+#include <dns/log.h>
+#include <dns/master.h>
+#include <dns/masterdump.h>
+#include <dns/message.h>
+#include <dns/name.h>
+#include <dns/peer.h>
+#include <dns/rcode.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/rdatatype.h>
+#include <dns/request.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+#include <dns/stats.h>
+#include <dns/ssu.h>
+#include <dns/tsig.h>
+#include <dns/xfrin.h>
+#include <dns/zone.h>
+
+#define ZONE_MAGIC ISC_MAGIC('Z', 'O', 'N', 'E')
+#define DNS_ZONE_VALID(zone) ISC_MAGIC_VALID(zone, ZONE_MAGIC)
+
+#define NOTIFY_MAGIC ISC_MAGIC('N', 't', 'f', 'y')
+#define DNS_NOTIFY_VALID(notify) ISC_MAGIC_VALID(notify, NOTIFY_MAGIC)
+
+#define STUB_MAGIC ISC_MAGIC('S', 't', 'u', 'b')
+#define DNS_STUB_VALID(stub) ISC_MAGIC_VALID(stub, STUB_MAGIC)
+
+#define ZONEMGR_MAGIC ISC_MAGIC('Z', 'm', 'g', 'r')
+#define DNS_ZONEMGR_VALID(stub) ISC_MAGIC_VALID(stub, ZONEMGR_MAGIC)
+
+#define LOAD_MAGIC ISC_MAGIC('L', 'o', 'a', 'd')
+#define DNS_LOAD_VALID(load) ISC_MAGIC_VALID(load, LOAD_MAGIC)
+
+#define FORWARD_MAGIC ISC_MAGIC('F', 'o', 'r', 'w')
+#define DNS_FORWARD_VALID(load) ISC_MAGIC_VALID(load, FORWARD_MAGIC)
+
+#define IO_MAGIC ISC_MAGIC('Z', 'm', 'I', 'O')
+#define DNS_IO_VALID(load) ISC_MAGIC_VALID(load, IO_MAGIC)
+
+/*%
+ * Ensure 'a' is at least 'min' but not more than 'max'.
+ */
+#define RANGE(a, min, max) \
+ (((a) < (min)) ? (min) : ((a) < (max) ? (a) : (max)))
+
+/*
+ * Default values.
+ */
+#define DNS_DEFAULT_IDLEIN 3600 /*%< 1 hour */
+#define DNS_DEFAULT_IDLEOUT 3600 /*%< 1 hour */
+#define MAX_XFER_TIME (2*3600) /*%< Documented default is 2 hours */
+
+#ifndef DNS_MAX_EXPIRE
+#define DNS_MAX_EXPIRE 14515200 /*%< 24 weeks */
+#endif
+
+#ifndef DNS_DUMP_DELAY
+#define DNS_DUMP_DELAY 900 /*%< 15 minutes */
+#endif
+
+typedef struct dns_notify dns_notify_t;
+typedef struct dns_stub dns_stub_t;
+typedef struct dns_load dns_load_t;
+typedef struct dns_forward dns_forward_t;
+typedef struct dns_io dns_io_t;
+typedef ISC_LIST(dns_io_t) dns_iolist_t;
+
+#define DNS_ZONE_CHECKLOCK
+#ifdef DNS_ZONE_CHECKLOCK
+#define LOCK_ZONE(z) \
+ do { LOCK(&(z)->lock); \
+ INSIST((z)->locked == ISC_FALSE); \
+ (z)->locked = ISC_TRUE; \
+ } while (0)
+#define UNLOCK_ZONE(z) \
+ do { (z)->locked = ISC_FALSE; UNLOCK(&(z)->lock); } while (0)
+#define LOCKED_ZONE(z) ((z)->locked)
+#else
+#define LOCK_ZONE(z) LOCK(&(z)->lock)
+#define UNLOCK_ZONE(z) UNLOCK(&(z)->lock)
+#define LOCKED_ZONE(z) ISC_TRUE
+#endif
+
+#ifdef ISC_RWLOCK_USEATOMIC
+#define ZONEDB_INITLOCK(l) isc_rwlock_init((l), 0, 0)
+#define ZONEDB_DESTROYLOCK(l) isc_rwlock_destroy(l)
+#define ZONEDB_LOCK(l, t) RWLOCK((l), (t))
+#define ZONEDB_UNLOCK(l, t) RWUNLOCK((l), (t))
+#else
+#define ZONEDB_INITLOCK(l) isc_mutex_init(l)
+#define ZONEDB_DESTROYLOCK(l) DESTROYLOCK(l)
+#define ZONEDB_LOCK(l, t) LOCK(l)
+#define ZONEDB_UNLOCK(l, t) UNLOCK(l)
+#endif
+
+struct dns_zone {
+ /* Unlocked */
+ unsigned int magic;
+ isc_mutex_t lock;
+#ifdef DNS_ZONE_CHECKLOCK
+ isc_boolean_t locked;
+#endif
+ isc_mem_t *mctx;
+ isc_refcount_t erefs;
+
+#ifdef ISC_RWLOCK_USEATOMIC
+ isc_rwlock_t dblock;
+#else
+ isc_mutex_t dblock;
+#endif
+ dns_db_t *db; /* Locked by dblock */
+
+ /* Locked */
+ dns_zonemgr_t *zmgr;
+ ISC_LINK(dns_zone_t) link; /* Used by zmgr. */
+ isc_timer_t *timer;
+ unsigned int irefs;
+ dns_name_t origin;
+ char *masterfile;
+ dns_masterformat_t masterformat;
+ char *journal;
+ isc_int32_t journalsize;
+ dns_rdataclass_t rdclass;
+ dns_zonetype_t type;
+ unsigned int flags;
+ unsigned int options;
+ unsigned int db_argc;
+ char **db_argv;
+ isc_time_t expiretime;
+ isc_time_t refreshtime;
+ isc_time_t dumptime;
+ isc_time_t loadtime;
+ isc_time_t notifytime;
+ isc_uint32_t serial;
+ isc_uint32_t refresh;
+ isc_uint32_t retry;
+ isc_uint32_t expire;
+ isc_uint32_t minimum;
+ char *keydirectory;
+
+ isc_uint32_t maxrefresh;
+ isc_uint32_t minrefresh;
+ isc_uint32_t maxretry;
+ isc_uint32_t minretry;
+
+ isc_sockaddr_t *masters;
+ dns_name_t **masterkeynames;
+ isc_boolean_t *mastersok;
+ unsigned int masterscnt;
+ unsigned int curmaster;
+ isc_sockaddr_t masteraddr;
+ dns_notifytype_t notifytype;
+ isc_sockaddr_t *notify;
+ unsigned int notifycnt;
+ isc_sockaddr_t notifyfrom;
+ isc_task_t *task;
+ isc_sockaddr_t notifysrc4;
+ isc_sockaddr_t notifysrc6;
+ isc_sockaddr_t xfrsource4;
+ isc_sockaddr_t xfrsource6;
+ isc_sockaddr_t altxfrsource4;
+ isc_sockaddr_t altxfrsource6;
+ isc_sockaddr_t sourceaddr;
+ dns_xfrin_ctx_t *xfr; /* task locked */
+ dns_tsigkey_t *tsigkey; /* key used for xfr */
+ /* Access Control Lists */
+ dns_acl_t *update_acl;
+ dns_acl_t *forward_acl;
+ dns_acl_t *notify_acl;
+ dns_acl_t *query_acl;
+ dns_acl_t *xfr_acl;
+ isc_boolean_t update_disabled;
+ isc_boolean_t zero_no_soa_ttl;
+ dns_severity_t check_names;
+ ISC_LIST(dns_notify_t) notifies;
+ dns_request_t *request;
+ dns_loadctx_t *lctx;
+ dns_io_t *readio;
+ dns_dumpctx_t *dctx;
+ dns_io_t *writeio;
+ isc_uint32_t maxxfrin;
+ isc_uint32_t maxxfrout;
+ isc_uint32_t idlein;
+ isc_uint32_t idleout;
+ isc_event_t ctlevent;
+ dns_ssutable_t *ssutable;
+ isc_uint32_t sigvalidityinterval;
+ dns_view_t *view;
+ dns_acache_t *acache;
+ dns_checkmxfunc_t checkmx;
+ dns_checksrvfunc_t checksrv;
+ dns_checknsfunc_t checkns;
+ /*%
+ * Zones in certain states such as "waiting for zone transfer"
+ * or "zone transfer in progress" are kept on per-state linked lists
+ * in the zone manager using the 'statelink' field. The 'statelist'
+ * field points at the list the zone is currently on. It the zone
+ * is not on any such list, statelist is NULL.
+ */
+ ISC_LINK(dns_zone_t) statelink;
+ dns_zonelist_t *statelist;
+ /*%
+ * Optional per-zone statistics counters (NULL if not present).
+ */
+ isc_uint64_t *counters;
+ isc_uint32_t notifydelay;
+ dns_isselffunc_t isself;
+ void *isselfarg;
+
+ /*%
+ * Serial number for deferred journal compaction.
+ */
+ isc_uint32_t compact_serial;
+};
+
+#define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
+#define DNS_ZONE_SETFLAG(z,f) do { \
+ INSIST(LOCKED_ZONE(z)); \
+ (z)->flags |= (f); \
+ } while (0)
+#define DNS_ZONE_CLRFLAG(z,f) do { \
+ INSIST(LOCKED_ZONE(z)); \
+ (z)->flags &= ~(f); \
+ } while (0)
+ /* XXX MPA these may need to go back into zone.h */
+#define DNS_ZONEFLG_REFRESH 0x00000001U /*%< refresh check in progress */
+#define DNS_ZONEFLG_NEEDDUMP 0x00000002U /*%< zone need consolidation */
+#define DNS_ZONEFLG_USEVC 0x00000004U /*%< use tcp for refresh query */
+#define DNS_ZONEFLG_DUMPING 0x00000008U /*%< a dump is in progress */
+#define DNS_ZONEFLG_HASINCLUDE 0x00000010U /*%< $INCLUDE in zone file */
+#define DNS_ZONEFLG_LOADED 0x00000020U /*%< database has loaded */
+#define DNS_ZONEFLG_EXITING 0x00000040U /*%< zone is being destroyed */
+#define DNS_ZONEFLG_EXPIRED 0x00000080U /*%< zone has expired */
+#define DNS_ZONEFLG_NEEDREFRESH 0x00000100U /*%< refresh check needed */
+#define DNS_ZONEFLG_UPTODATE 0x00000200U /*%< zone contents are
+ * uptodate */
+#define DNS_ZONEFLG_NEEDNOTIFY 0x00000400U /*%< need to send out notify
+ * messages */
+#define DNS_ZONEFLG_DIFFONRELOAD 0x00000800U /*%< generate a journal diff on
+ * reload */
+#define DNS_ZONEFLG_NOMASTERS 0x00001000U /*%< an attempt to refresh a
+ * zone with no masters
+ * occured */
+#define DNS_ZONEFLG_LOADING 0x00002000U /*%< load from disk in progress*/
+#define DNS_ZONEFLG_HAVETIMERS 0x00004000U /*%< timer values have been set
+ * from SOA (if not set, we
+ * are still using
+ * default timer values) */
+#define DNS_ZONEFLG_FORCEXFER 0x00008000U /*%< Force a zone xfer */
+#define DNS_ZONEFLG_NOREFRESH 0x00010000U
+#define DNS_ZONEFLG_DIALNOTIFY 0x00020000U
+#define DNS_ZONEFLG_DIALREFRESH 0x00040000U
+#define DNS_ZONEFLG_SHUTDOWN 0x00080000U
+#define DNS_ZONEFLAG_NOIXFR 0x00100000U /*%< IXFR failed, force AXFR */
+#define DNS_ZONEFLG_FLUSH 0x00200000U
+#define DNS_ZONEFLG_NOEDNS 0x00400000U
+#define DNS_ZONEFLG_USEALTXFRSRC 0x00800000U
+#define DNS_ZONEFLG_SOABEFOREAXFR 0x01000000U
+#define DNS_ZONEFLG_NEEDCOMPACT 0x02000000U
+
+#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
+
+/* Flags for zone_load() */
+#define DNS_ZONELOADFLAG_NOSTAT 0x00000001U /* Do not stat() master files */
+
+struct dns_zonemgr {
+ unsigned int magic;
+ isc_mem_t * mctx;
+ int refs; /* Locked by rwlock */
+ isc_taskmgr_t * taskmgr;
+ isc_timermgr_t * timermgr;
+ isc_socketmgr_t * socketmgr;
+ isc_taskpool_t * zonetasks;
+ isc_task_t * task;
+ isc_ratelimiter_t * rl;
+ isc_rwlock_t rwlock;
+ isc_mutex_t iolock;
+
+ /* Locked by rwlock. */
+ dns_zonelist_t zones;
+ dns_zonelist_t waiting_for_xfrin;
+ dns_zonelist_t xfrin_in_progress;
+
+ /* Configuration data. */
+ isc_uint32_t transfersin;
+ isc_uint32_t transfersperns;
+ unsigned int serialqueryrate;
+
+ /* Locked by iolock */
+ isc_uint32_t iolimit;
+ isc_uint32_t ioactive;
+ dns_iolist_t high;
+ dns_iolist_t low;
+};
+
+/*%
+ * Hold notify state.
+ */
+struct dns_notify {
+ unsigned int magic;
+ unsigned int flags;
+ isc_mem_t *mctx;
+ dns_zone_t *zone;
+ dns_adbfind_t *find;
+ dns_request_t *request;
+ dns_name_t ns;
+ isc_sockaddr_t dst;
+ ISC_LINK(dns_notify_t) link;
+};
+
+#define DNS_NOTIFY_NOSOA 0x0001U
+
+/*%
+ * dns_stub holds state while performing a 'stub' transfer.
+ * 'db' is the zone's 'db' or a new one if this is the initial
+ * transfer.
+ */
+
+struct dns_stub {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ dns_zone_t *zone;
+ dns_db_t *db;
+ dns_dbversion_t *version;
+};
+
+/*%
+ * Hold load state.
+ */
+struct dns_load {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ dns_zone_t *zone;
+ dns_db_t *db;
+ isc_time_t loadtime;
+ dns_rdatacallbacks_t callbacks;
+};
+
+/*%
+ * Hold forward state.
+ */
+struct dns_forward {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ dns_zone_t *zone;
+ isc_buffer_t *msgbuf;
+ dns_request_t *request;
+ isc_uint32_t which;
+ isc_sockaddr_t addr;
+ dns_updatecallback_t callback;
+ void *callback_arg;
+};
+
+/*%
+ * Hold IO request state.
+ */
+struct dns_io {
+ unsigned int magic;
+ dns_zonemgr_t *zmgr;
+ isc_boolean_t high;
+ isc_task_t *task;
+ ISC_LINK(dns_io_t) link;
+ isc_event_t *event;
+};
+
+#define SEND_BUFFER_SIZE 2048
+
+static void zone_settimer(dns_zone_t *, isc_time_t *);
+static void cancel_refresh(dns_zone_t *);
+static void zone_debuglog(dns_zone_t *zone, const char *, int debuglevel,
+ const char *msg, ...) ISC_FORMAT_PRINTF(4, 5);
+static void notify_log(dns_zone_t *zone, int level, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+static void queue_xfrin(dns_zone_t *zone);
+static void zone_unload(dns_zone_t *zone);
+static void zone_expire(dns_zone_t *zone);
+static void zone_iattach(dns_zone_t *source, dns_zone_t **target);
+static void zone_idetach(dns_zone_t **zonep);
+static isc_result_t zone_replacedb(dns_zone_t *zone, dns_db_t *db,
+ isc_boolean_t dump);
+static inline void zone_attachdb(dns_zone_t *zone, dns_db_t *db);
+static inline void zone_detachdb(dns_zone_t *zone);
+static isc_result_t default_journal(dns_zone_t *zone);
+static void zone_xfrdone(dns_zone_t *zone, isc_result_t result);
+static isc_result_t zone_postload(dns_zone_t *zone, dns_db_t *db,
+ isc_time_t loadtime, isc_result_t result);
+static void zone_needdump(dns_zone_t *zone, unsigned int delay);
+static void zone_shutdown(isc_task_t *, isc_event_t *);
+static void zone_loaddone(void *arg, isc_result_t result);
+static isc_result_t zone_startload(dns_db_t *db, dns_zone_t *zone,
+ isc_time_t loadtime);
+
+#if 0
+/* ondestroy example */
+static void dns_zonemgr_dbdestroyed(isc_task_t *task, isc_event_t *event);
+#endif
+
+static void refresh_callback(isc_task_t *, isc_event_t *);
+static void stub_callback(isc_task_t *, isc_event_t *);
+static void queue_soa_query(dns_zone_t *zone);
+static void soa_query(isc_task_t *, isc_event_t *);
+static void ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset,
+ dns_stub_t *stub);
+static int message_count(dns_message_t *msg, dns_section_t section,
+ dns_rdatatype_t type);
+static void notify_cancel(dns_zone_t *zone);
+static void notify_find_address(dns_notify_t *notify);
+static void notify_send(dns_notify_t *notify);
+static isc_result_t notify_createmessage(dns_zone_t *zone,
+ unsigned int flags,
+ dns_message_t **messagep);
+static void notify_done(isc_task_t *task, isc_event_t *event);
+static void notify_send_toaddr(isc_task_t *task, isc_event_t *event);
+static isc_result_t zone_dump(dns_zone_t *, isc_boolean_t);
+static void got_transfer_quota(isc_task_t *task, isc_event_t *event);
+static isc_result_t zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr,
+ dns_zone_t *zone);
+static void zmgr_resume_xfrs(dns_zonemgr_t *zmgr, isc_boolean_t multi);
+static void zonemgr_free(dns_zonemgr_t *zmgr);
+static isc_result_t zonemgr_getio(dns_zonemgr_t *zmgr, isc_boolean_t high,
+ isc_task_t *task, isc_taskaction_t action,
+ void *arg, dns_io_t **iop);
+static void zonemgr_putio(dns_io_t **iop);
+static void zonemgr_cancelio(dns_io_t *io);
+
+static isc_result_t
+zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount,
+ unsigned int *soacount, isc_uint32_t *serial,
+ isc_uint32_t *refresh, isc_uint32_t *retry,
+ isc_uint32_t *expire, isc_uint32_t *minimum,
+ unsigned int *errors);
+
+static void zone_freedbargs(dns_zone_t *zone);
+static void forward_callback(isc_task_t *task, isc_event_t *event);
+static void zone_saveunique(dns_zone_t *zone, const char *path,
+ const char *templat);
+static void zone_maintenance(dns_zone_t *zone);
+static void zone_notify(dns_zone_t *zone, isc_time_t *now);
+static void dump_done(void *arg, isc_result_t result);
+
+#define ENTER zone_debuglog(zone, me, 1, "enter")
+
+static const unsigned int dbargc_default = 1;
+static const char *dbargv_default[] = { "rbt" };
+
+#define DNS_ZONE_JITTER_ADD(a, b, c) \
+ do { \
+ isc_interval_t _i; \
+ isc_uint32_t _j; \
+ _j = isc_random_jitter((b), (b)/4); \
+ isc_interval_set(&_i, _j, 0); \
+ if (isc_time_add((a), &_i, (c)) != ISC_R_SUCCESS) { \
+ dns_zone_log(zone, ISC_LOG_WARNING, \
+ "epoch approaching: upgrade required: " \
+ "now + %s failed", #b); \
+ isc_interval_set(&_i, _j/2, 0); \
+ (void)isc_time_add((a), &_i, (c)); \
+ } \
+ } while (0)
+
+#define DNS_ZONE_TIME_ADD(a, b, c) \
+ do { \
+ isc_interval_t _i; \
+ isc_interval_set(&_i, (b), 0); \
+ if (isc_time_add((a), &_i, (c)) != ISC_R_SUCCESS) { \
+ dns_zone_log(zone, ISC_LOG_WARNING, \
+ "epoch approaching: upgrade required: " \
+ "now + %s failed", #b); \
+ isc_interval_set(&_i, (b)/2, 0); \
+ (void)isc_time_add((a), &_i, (c)); \
+ } \
+ } while (0)
+
+/***
+ *** Public functions.
+ ***/
+
+isc_result_t
+dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
+ isc_result_t result;
+ dns_zone_t *zone;
+ isc_time_t now;
+
+ REQUIRE(zonep != NULL && *zonep == NULL);
+ REQUIRE(mctx != NULL);
+
+ TIME_NOW(&now);
+ zone = isc_mem_get(mctx, sizeof(*zone));
+ if (zone == NULL)
+ return (ISC_R_NOMEMORY);
+
+ zone->mctx = NULL;
+ isc_mem_attach(mctx, &zone->mctx);
+
+ result = isc_mutex_init(&zone->lock);
+ if (result != ISC_R_SUCCESS)
+ goto free_zone;
+
+ result = ZONEDB_INITLOCK(&zone->dblock);
+ if (result != ISC_R_SUCCESS)
+ goto free_mutex;
+
+ /* XXX MPA check that all elements are initialised */
+#ifdef DNS_ZONE_CHECKLOCK
+ zone->locked = ISC_FALSE;
+#endif
+ zone->db = NULL;
+ zone->zmgr = NULL;
+ ISC_LINK_INIT(zone, link);
+ result = isc_refcount_init(&zone->erefs, 1); /* Implicit attach. */
+ if (result != ISC_R_SUCCESS)
+ goto free_dblock;
+ zone->irefs = 0;
+ dns_name_init(&zone->origin, NULL);
+ zone->masterfile = NULL;
+ zone->masterformat = dns_masterformat_none;
+ zone->keydirectory = NULL;
+ zone->journalsize = -1;
+ zone->journal = NULL;
+ zone->rdclass = dns_rdataclass_none;
+ zone->type = dns_zone_none;
+ zone->flags = 0;
+ zone->options = 0;
+ zone->db_argc = 0;
+ zone->db_argv = NULL;
+ isc_time_settoepoch(&zone->expiretime);
+ isc_time_settoepoch(&zone->refreshtime);
+ isc_time_settoepoch(&zone->dumptime);
+ isc_time_settoepoch(&zone->loadtime);
+ zone->notifytime = now;
+ zone->serial = 0;
+ zone->refresh = DNS_ZONE_DEFAULTREFRESH;
+ zone->retry = DNS_ZONE_DEFAULTRETRY;
+ zone->expire = 0;
+ zone->minimum = 0;
+ zone->maxrefresh = DNS_ZONE_MAXREFRESH;
+ zone->minrefresh = DNS_ZONE_MINREFRESH;
+ zone->maxretry = DNS_ZONE_MAXRETRY;
+ zone->minretry = DNS_ZONE_MINRETRY;
+ zone->masters = NULL;
+ zone->masterkeynames = NULL;
+ zone->mastersok = NULL;
+ zone->masterscnt = 0;
+ zone->curmaster = 0;
+ zone->notify = NULL;
+ zone->notifytype = dns_notifytype_yes;
+ zone->notifycnt = 0;
+ zone->task = NULL;
+ zone->update_acl = NULL;
+ zone->forward_acl = NULL;
+ zone->notify_acl = NULL;
+ zone->query_acl = NULL;
+ zone->xfr_acl = NULL;
+ zone->update_disabled = ISC_FALSE;
+ zone->zero_no_soa_ttl = ISC_TRUE;
+ zone->check_names = dns_severity_ignore;
+ zone->request = NULL;
+ zone->lctx = NULL;
+ zone->readio = NULL;
+ zone->dctx = NULL;
+ zone->writeio = NULL;
+ zone->timer = NULL;
+ zone->idlein = DNS_DEFAULT_IDLEIN;
+ zone->idleout = DNS_DEFAULT_IDLEOUT;
+ ISC_LIST_INIT(zone->notifies);
+ isc_sockaddr_any(&zone->notifysrc4);
+ isc_sockaddr_any6(&zone->notifysrc6);
+ isc_sockaddr_any(&zone->xfrsource4);
+ isc_sockaddr_any6(&zone->xfrsource6);
+ isc_sockaddr_any(&zone->altxfrsource4);
+ isc_sockaddr_any6(&zone->altxfrsource6);
+ zone->xfr = NULL;
+ zone->tsigkey = NULL;
+ zone->maxxfrin = MAX_XFER_TIME;
+ zone->maxxfrout = MAX_XFER_TIME;
+ zone->ssutable = NULL;
+ zone->sigvalidityinterval = 30 * 24 * 3600;
+ zone->view = NULL;
+ zone->acache = NULL;
+ zone->checkmx = NULL;
+ zone->checksrv = NULL;
+ zone->checkns = NULL;
+ ISC_LINK_INIT(zone, statelink);
+ zone->statelist = NULL;
+ zone->counters = NULL;
+ zone->notifydelay = 5;
+ zone->isself = NULL;
+ zone->isselfarg = NULL;
+
+ zone->magic = ZONE_MAGIC;
+
+ /* Must be after magic is set. */
+ result = dns_zone_setdbtype(zone, dbargc_default, dbargv_default);
+ if (result != ISC_R_SUCCESS)
+ goto free_erefs;
+
+ ISC_EVENT_INIT(&zone->ctlevent, sizeof(zone->ctlevent), 0, NULL,
+ DNS_EVENT_ZONECONTROL, zone_shutdown, zone, zone,
+ NULL, NULL);
+ *zonep = zone;
+ return (ISC_R_SUCCESS);
+
+ free_erefs:
+ isc_refcount_decrement(&zone->erefs, NULL);
+ isc_refcount_destroy(&zone->erefs);
+
+ free_dblock:
+ ZONEDB_DESTROYLOCK(&zone->dblock);
+
+ free_mutex:
+ DESTROYLOCK(&zone->lock);
+
+ free_zone:
+ isc_mem_putanddetach(&zone->mctx, zone, sizeof(*zone));
+ return (result);
+}
+
+/*
+ * Free a zone. Because we require that there be no more
+ * outstanding events or references, no locking is necessary.
+ */
+static void
+zone_free(dns_zone_t *zone) {
+ isc_mem_t *mctx = NULL;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(isc_refcount_current(&zone->erefs) == 0);
+ REQUIRE(zone->irefs == 0);
+ REQUIRE(!LOCKED_ZONE(zone));
+ REQUIRE(zone->timer == NULL);
+
+ /*
+ * Managed objects. Order is important.
+ */
+ if (zone->request != NULL)
+ dns_request_destroy(&zone->request); /* XXXMPA */
+ INSIST(zone->readio == NULL);
+ INSIST(zone->statelist == NULL);
+ INSIST(zone->writeio == NULL);
+
+ if (zone->task != NULL)
+ isc_task_detach(&zone->task);
+ if (zone->zmgr)
+ dns_zonemgr_releasezone(zone->zmgr, zone);
+
+ /* Unmanaged objects */
+ if (zone->masterfile != NULL)
+ isc_mem_free(zone->mctx, zone->masterfile);
+ zone->masterfile = NULL;
+ if (zone->keydirectory != NULL)
+ isc_mem_free(zone->mctx, zone->keydirectory);
+ zone->keydirectory = NULL;
+ zone->journalsize = -1;
+ if (zone->journal != NULL)
+ isc_mem_free(zone->mctx, zone->journal);
+ zone->journal = NULL;
+ if (zone->counters != NULL)
+ dns_stats_freecounters(zone->mctx, &zone->counters);
+ if (zone->db != NULL)
+ zone_detachdb(zone);
+ if (zone->acache != NULL)
+ dns_acache_detach(&zone->acache);
+ zone_freedbargs(zone);
+ RUNTIME_CHECK(dns_zone_setmasterswithkeys(zone, NULL, NULL, 0)
+ == ISC_R_SUCCESS);
+ RUNTIME_CHECK(dns_zone_setalsonotify(zone, NULL, 0)
+ == ISC_R_SUCCESS);
+ zone->check_names = dns_severity_ignore;
+ if (zone->update_acl != NULL)
+ dns_acl_detach(&zone->update_acl);
+ if (zone->forward_acl != NULL)
+ dns_acl_detach(&zone->forward_acl);
+ if (zone->notify_acl != NULL)
+ dns_acl_detach(&zone->notify_acl);
+ if (zone->query_acl != NULL)
+ dns_acl_detach(&zone->query_acl);
+ if (zone->xfr_acl != NULL)
+ dns_acl_detach(&zone->xfr_acl);
+ if (dns_name_dynamic(&zone->origin))
+ dns_name_free(&zone->origin, zone->mctx);
+ if (zone->ssutable != NULL)
+ dns_ssutable_detach(&zone->ssutable);
+
+ /* last stuff */
+ ZONEDB_DESTROYLOCK(&zone->dblock);
+ DESTROYLOCK(&zone->lock);
+ isc_refcount_destroy(&zone->erefs);
+ zone->magic = 0;
+ mctx = zone->mctx;
+ isc_mem_put(mctx, zone, sizeof(*zone));
+ isc_mem_detach(&mctx);
+}
+
+/*
+ * Single shot.
+ */
+void
+dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(rdclass != dns_rdataclass_none);
+
+ /*
+ * Test and set.
+ */
+ LOCK_ZONE(zone);
+ REQUIRE(zone->rdclass == dns_rdataclass_none ||
+ zone->rdclass == rdclass);
+ zone->rdclass = rdclass;
+ UNLOCK_ZONE(zone);
+}
+
+dns_rdataclass_t
+dns_zone_getclass(dns_zone_t *zone){
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->rdclass);
+}
+
+void
+dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ zone->notifytype = notifytype;
+ UNLOCK_ZONE(zone);
+}
+
+/*
+ * Single shot.
+ */
+void
+dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(type != dns_zone_none);
+
+ /*
+ * Test and set.
+ */
+ LOCK_ZONE(zone);
+ REQUIRE(zone->type == dns_zone_none || zone->type == type);
+ zone->type = type;
+ UNLOCK_ZONE(zone);
+}
+
+static void
+zone_freedbargs(dns_zone_t *zone) {
+ unsigned int i;
+
+ /* Free the old database argument list. */
+ if (zone->db_argv != NULL) {
+ for (i = 0; i < zone->db_argc; i++)
+ isc_mem_free(zone->mctx, zone->db_argv[i]);
+ isc_mem_put(zone->mctx, zone->db_argv,
+ zone->db_argc * sizeof(*zone->db_argv));
+ }
+ zone->db_argc = 0;
+ zone->db_argv = NULL;
+}
+
+isc_result_t
+dns_zone_getdbtype(dns_zone_t *zone, char ***argv, isc_mem_t *mctx) {
+ size_t size = 0;
+ unsigned int i;
+ isc_result_t result = ISC_R_SUCCESS;
+ void *mem;
+ char **tmp, *tmp2;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(argv != NULL && *argv == NULL);
+
+ LOCK_ZONE(zone);
+ size = (zone->db_argc + 1) * sizeof(char *);
+ for (i = 0; i < zone->db_argc; i++)
+ size += strlen(zone->db_argv[i]) + 1;
+ mem = isc_mem_allocate(mctx, size);
+ if (mem != NULL) {
+ tmp = mem;
+ tmp2 = mem;
+ tmp2 += (zone->db_argc + 1) * sizeof(char *);
+ for (i = 0; i < zone->db_argc; i++) {
+ *tmp++ = tmp2;
+ strcpy(tmp2, zone->db_argv[i]);
+ tmp2 += strlen(tmp2) + 1;
+ }
+ *tmp = NULL;
+ } else
+ result = ISC_R_NOMEMORY;
+ UNLOCK_ZONE(zone);
+ *argv = mem;
+ return (result);
+}
+
+isc_result_t
+dns_zone_setdbtype(dns_zone_t *zone,
+ unsigned int dbargc, const char * const *dbargv) {
+ isc_result_t result = ISC_R_SUCCESS;
+ char **new = NULL;
+ unsigned int i;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(dbargc >= 1);
+ REQUIRE(dbargv != NULL);
+
+ LOCK_ZONE(zone);
+
+ /* Set up a new database argument list. */
+ new = isc_mem_get(zone->mctx, dbargc * sizeof(*new));
+ if (new == NULL)
+ goto nomem;
+ for (i = 0; i < dbargc; i++)
+ new[i] = NULL;
+ for (i = 0; i < dbargc; i++) {
+ new[i] = isc_mem_strdup(zone->mctx, dbargv[i]);
+ if (new[i] == NULL)
+ goto nomem;
+ }
+
+ /* Free the old list. */
+ zone_freedbargs(zone);
+
+ zone->db_argc = dbargc;
+ zone->db_argv = new;
+ result = ISC_R_SUCCESS;
+ goto unlock;
+
+ nomem:
+ if (new != NULL) {
+ for (i = 0; i < dbargc; i++)
+ if (new[i] != NULL)
+ isc_mem_free(zone->mctx, new[i]);
+ isc_mem_put(zone->mctx, new, dbargc * sizeof(*new));
+ }
+ result = ISC_R_NOMEMORY;
+
+ unlock:
+ UNLOCK_ZONE(zone);
+ return (result);
+}
+
+void
+dns_zone_setview(dns_zone_t *zone, dns_view_t *view) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->view != NULL)
+ dns_view_weakdetach(&zone->view);
+ dns_view_weakattach(view, &zone->view);
+ UNLOCK_ZONE(zone);
+}
+
+
+dns_view_t *
+dns_zone_getview(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->view);
+}
+
+
+isc_result_t
+dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin) {
+ isc_result_t result;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(origin != NULL);
+
+ LOCK_ZONE(zone);
+ if (dns_name_dynamic(&zone->origin)) {
+ dns_name_free(&zone->origin, zone->mctx);
+ dns_name_init(&zone->origin, NULL);
+ }
+ result = dns_name_dup(origin, zone->mctx, &zone->origin);
+ UNLOCK_ZONE(zone);
+ return (result);
+}
+
+void
+dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(acache != NULL);
+
+ LOCK_ZONE(zone);
+ if (zone->acache != NULL)
+ dns_acache_detach(&zone->acache);
+ dns_acache_attach(acache, &zone->acache);
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db != NULL) {
+ isc_result_t result;
+
+ /*
+ * If the zone reuses an existing DB, the DB needs to be
+ * set in the acache explicitly. We can safely ignore the
+ * case where the DB is already set. If other error happens,
+ * the acache will not work effectively.
+ */
+ result = dns_acache_setdb(acache, zone->db);
+ if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_acache_setdb() failed: %s",
+ isc_result_totext(result));
+ }
+ }
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ UNLOCK_ZONE(zone);
+}
+
+static isc_result_t
+dns_zone_setstring(dns_zone_t *zone, char **field, const char *value) {
+ char *copy;
+
+ if (value != NULL) {
+ copy = isc_mem_strdup(zone->mctx, value);
+ if (copy == NULL)
+ return (ISC_R_NOMEMORY);
+ } else {
+ copy = NULL;
+ }
+
+ if (*field != NULL)
+ isc_mem_free(zone->mctx, *field);
+
+ *field = copy;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_zone_setfile(dns_zone_t *zone, const char *file) {
+ return (dns_zone_setfile2(zone, file, dns_masterformat_text));
+}
+
+isc_result_t
+dns_zone_setfile2(dns_zone_t *zone, const char *file,
+ dns_masterformat_t format) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ result = dns_zone_setstring(zone, &zone->masterfile, file);
+ if (result == ISC_R_SUCCESS) {
+ zone->masterformat = format;
+ result = default_journal(zone);
+ }
+ UNLOCK_ZONE(zone);
+
+ return (result);
+}
+
+const char *
+dns_zone_getfile(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->masterfile);
+}
+
+static isc_result_t
+default_journal(dns_zone_t *zone) {
+ isc_result_t result;
+ char *journal;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(LOCKED_ZONE(zone));
+
+ if (zone->masterfile != NULL) {
+ /* Calculate string length including '\0'. */
+ int len = strlen(zone->masterfile) + sizeof(".jnl");
+ journal = isc_mem_allocate(zone->mctx, len);
+ if (journal == NULL)
+ return (ISC_R_NOMEMORY);
+ strcpy(journal, zone->masterfile);
+ strcat(journal, ".jnl");
+ } else {
+ journal = NULL;
+ }
+ result = dns_zone_setstring(zone, &zone->journal, journal);
+ if (journal != NULL)
+ isc_mem_free(zone->mctx, journal);
+ return (result);
+}
+
+isc_result_t
+dns_zone_setjournal(dns_zone_t *zone, const char *journal) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ result = dns_zone_setstring(zone, &zone->journal, journal);
+ UNLOCK_ZONE(zone);
+
+ return (result);
+}
+
+char *
+dns_zone_getjournal(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->journal);
+}
+
+/*
+ * Return true iff the zone is "dynamic", in the sense that the zone's
+ * master file (if any) is written by the server, rather than being
+ * updated manually and read by the server.
+ *
+ * This is true for slave zones, stub zones, and zones that allow
+ * dynamic updates either by having an update policy ("ssutable")
+ * or an "allow-update" ACL with a value other than exactly "{ none; }".
+ */
+static isc_boolean_t
+zone_isdynamic(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (ISC_TF(zone->type == dns_zone_slave ||
+ zone->type == dns_zone_stub ||
+ (!zone->update_disabled && zone->ssutable != NULL) ||
+ (!zone->update_disabled && zone->update_acl != NULL &&
+ ! (zone->update_acl->length == 1 &&
+ zone->update_acl->elements[0].negative == ISC_TRUE
+ &&
+ zone->update_acl->elements[0].type ==
+ dns_aclelementtype_any))));
+}
+
+
+static isc_result_t
+zone_load(dns_zone_t *zone, unsigned int flags) {
+ isc_result_t result;
+ isc_time_t now;
+ isc_time_t loadtime, filetime;
+ dns_db_t *db = NULL;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ TIME_NOW(&now);
+
+ INSIST(zone->type != dns_zone_none);
+
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADING)) {
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+ }
+
+ if (zone->db != NULL && zone->masterfile == NULL) {
+ /*
+ * The zone has no master file configured, but it already
+ * has a database. It could be the built-in
+ * version.bind. CH zone, a zone with a persistent
+ * database being reloaded, or maybe a zone that
+ * used to have a master file but whose configuration
+ * was changed so that it no longer has one. Do nothing.
+ */
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+ }
+
+ if (zone->db != NULL && zone_isdynamic(zone)) {
+ /*
+ * This is a slave, stub, or dynamically updated
+ * zone being reloaded. Do nothing - the database
+ * we already have is guaranteed to be up-to-date.
+ */
+ if (zone->type == dns_zone_master)
+ result = DNS_R_DYNAMIC;
+ else
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+ }
+
+
+ /*
+ * Store the current time before the zone is loaded, so that if the
+ * file changes between the time of the load and the time that
+ * zone->loadtime is set, then the file will still be reloaded
+ * the next time dns_zone_load is called.
+ */
+ TIME_NOW(&loadtime);
+
+ /*
+ * Don't do the load if the file that stores the zone is older
+ * than the last time the zone was loaded. If the zone has not
+ * been loaded yet, zone->loadtime will be the epoch.
+ */
+ if (zone->masterfile != NULL) {
+ /*
+ * The file is already loaded. If we are just doing a
+ * "rndc reconfig", we are done.
+ */
+ if (!isc_time_isepoch(&zone->loadtime) &&
+ (flags & DNS_ZONELOADFLAG_NOSTAT) != 0) {
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+ }
+
+ result = isc_file_getmodtime(zone->masterfile, &filetime);
+ if (result == ISC_R_SUCCESS) {
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE) &&
+ isc_time_compare(&filetime, &zone->loadtime) <= 0) {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "skipping load: master file "
+ "older than last load");
+ result = DNS_R_UPTODATE;
+ goto cleanup;
+ }
+ loadtime = filetime;
+ }
+ }
+
+ INSIST(zone->db_argc >= 1);
+
+ /*
+ * Built in zones don't need to be reloaded.
+ */
+ if (zone->type == dns_zone_master &&
+ strcmp(zone->db_argv[0], "_builtin") == 0 &&
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) {
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+ }
+
+ if ((zone->type == dns_zone_slave || zone->type == dns_zone_stub) &&
+ (strcmp(zone->db_argv[0], "rbt") == 0 ||
+ strcmp(zone->db_argv[0], "rbt64") == 0)) {
+ if (zone->masterfile == NULL ||
+ !isc_file_exists(zone->masterfile)) {
+ if (zone->masterfile != NULL) {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "no master file");
+ }
+ zone->refreshtime = now;
+ if (zone->task != NULL)
+ zone_settimer(zone, &now);
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+ }
+ }
+
+ dns_zone_log(zone, ISC_LOG_DEBUG(1), "starting load");
+
+ result = dns_db_create(zone->mctx, zone->db_argv[0],
+ &zone->origin, (zone->type == dns_zone_stub) ?
+ dns_dbtype_stub : dns_dbtype_zone,
+ zone->rdclass,
+ zone->db_argc - 1, zone->db_argv + 1,
+ &db);
+
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "loading zone: creating database: %s",
+ isc_result_totext(result));
+ goto cleanup;
+ }
+ dns_db_settask(db, zone->task);
+
+ if (! dns_db_ispersistent(db)) {
+ if (zone->masterfile != NULL) {
+ result = zone_startload(db, zone, loadtime);
+ } else {
+ result = DNS_R_NOMASTERFILE;
+ if (zone->type == dns_zone_master) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "loading zone: "
+ "no master file configured");
+ goto cleanup;
+ }
+ dns_zone_log(zone, ISC_LOG_INFO, "loading zone: "
+ "no master file configured: continuing");
+ }
+ }
+
+ if (result == DNS_R_CONTINUE) {
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADING);
+ goto cleanup;
+ }
+
+ result = zone_postload(zone, db, loadtime, result);
+
+ cleanup:
+ UNLOCK_ZONE(zone);
+ if (db != NULL)
+ dns_db_detach(&db);
+ return (result);
+}
+
+isc_result_t
+dns_zone_load(dns_zone_t *zone) {
+ return (zone_load(zone, 0));
+}
+
+isc_result_t
+dns_zone_loadnew(dns_zone_t *zone) {
+ return (zone_load(zone, DNS_ZONELOADFLAG_NOSTAT));
+}
+
+static void
+zone_gotreadhandle(isc_task_t *task, isc_event_t *event) {
+ dns_load_t *load = event->ev_arg;
+ isc_result_t result = ISC_R_SUCCESS;
+ unsigned int options;
+
+ REQUIRE(DNS_LOAD_VALID(load));
+
+ if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0)
+ result = ISC_R_CANCELED;
+ isc_event_free(&event);
+ if (result == ISC_R_CANCELED)
+ goto fail;
+
+ options = DNS_MASTER_ZONE;
+ if (load->zone->type == dns_zone_slave)
+ options |= DNS_MASTER_SLAVE;
+ if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNS))
+ options |= DNS_MASTER_CHECKNS;
+ if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_FATALNS))
+ options |= DNS_MASTER_FATALNS;
+ if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNAMES))
+ options |= DNS_MASTER_CHECKNAMES;
+ if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNAMESFAIL))
+ options |= DNS_MASTER_CHECKNAMESFAIL;
+ if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKMX))
+ options |= DNS_MASTER_CHECKMX;
+ if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKMXFAIL))
+ options |= DNS_MASTER_CHECKMXFAIL;
+ if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKWILDCARD))
+ options |= DNS_MASTER_CHECKWILDCARD;
+ result = dns_master_loadfileinc2(load->zone->masterfile,
+ dns_db_origin(load->db),
+ dns_db_origin(load->db),
+ load->zone->rdclass,
+ options,
+ &load->callbacks, task,
+ zone_loaddone, load,
+ &load->zone->lctx, load->zone->mctx,
+ load->zone->masterformat);
+ if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE &&
+ result != DNS_R_SEENINCLUDE)
+ goto fail;
+ return;
+
+ fail:
+ zone_loaddone(load, result);
+}
+
+static void
+zone_gotwritehandle(isc_task_t *task, isc_event_t *event) {
+ const char me[] = "zone_gotwritehandle";
+ dns_zone_t *zone = event->ev_arg;
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_dbversion_t *version = NULL;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ INSIST(task == zone->task);
+ ENTER;
+
+ if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0)
+ result = ISC_R_CANCELED;
+ isc_event_free(&event);
+ if (result == ISC_R_CANCELED)
+ goto fail;
+
+ LOCK_ZONE(zone);
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ dns_db_currentversion(zone->db, &version);
+ result = dns_master_dumpinc2(zone->mctx, zone->db, version,
+ &dns_master_style_default,
+ zone->masterfile, zone->task, dump_done,
+ zone, &zone->dctx, zone->masterformat);
+ dns_db_closeversion(zone->db, &version, ISC_FALSE);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ UNLOCK_ZONE(zone);
+ if (result != DNS_R_CONTINUE)
+ goto fail;
+ return;
+
+ fail:
+ dump_done(zone, result);
+}
+
+static isc_result_t
+zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
+ dns_load_t *load;
+ isc_result_t result;
+ isc_result_t tresult;
+ unsigned int options;
+
+ options = DNS_MASTER_ZONE;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS))
+ options |= DNS_MASTER_MANYERRORS;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS))
+ options |= DNS_MASTER_CHECKNS;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS))
+ options |= DNS_MASTER_FATALNS;
+ if (zone->type == dns_zone_slave)
+ options |= DNS_MASTER_SLAVE;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES))
+ options |= DNS_MASTER_CHECKNAMES;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL))
+ options |= DNS_MASTER_CHECKNAMESFAIL;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX))
+ options |= DNS_MASTER_CHECKMX;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL))
+ options |= DNS_MASTER_CHECKMXFAIL;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD))
+ options |= DNS_MASTER_CHECKWILDCARD;
+
+ if (zone->zmgr != NULL && zone->db != NULL && zone->task != NULL) {
+ load = isc_mem_get(zone->mctx, sizeof(*load));
+ if (load == NULL)
+ return (ISC_R_NOMEMORY);
+
+ load->mctx = NULL;
+ load->zone = NULL;
+ load->db = NULL;
+ load->loadtime = loadtime;
+ load->magic = LOAD_MAGIC;
+
+ isc_mem_attach(zone->mctx, &load->mctx);
+ zone_iattach(zone, &load->zone);
+ dns_db_attach(db, &load->db);
+ dns_rdatacallbacks_init(&load->callbacks);
+ result = dns_db_beginload(db, &load->callbacks.add,
+ &load->callbacks.add_private);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = zonemgr_getio(zone->zmgr, ISC_TRUE, zone->task,
+ zone_gotreadhandle, load,
+ &zone->readio);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * We can't report multiple errors so ignore
+ * the result of dns_db_endload().
+ */
+ (void)dns_db_endload(load->db,
+ &load->callbacks.add_private);
+ goto cleanup;
+ } else
+ result = DNS_R_CONTINUE;
+ } else {
+ dns_rdatacallbacks_t callbacks;
+
+ dns_rdatacallbacks_init(&callbacks);
+ result = dns_db_beginload(db, &callbacks.add,
+ &callbacks.add_private);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dns_master_loadfile2(zone->masterfile, &zone->origin,
+ &zone->origin, zone->rdclass,
+ options, &callbacks, zone->mctx,
+ zone->masterformat);
+ tresult = dns_db_endload(db, &callbacks.add_private);
+ if (result == ISC_R_SUCCESS)
+ result = tresult;
+ }
+
+ return (result);
+
+ cleanup:
+ load->magic = 0;
+ dns_db_detach(&load->db);
+ zone_idetach(&load->zone);
+ isc_mem_detach(&load->mctx);
+ isc_mem_put(zone->mctx, load, sizeof(*load));
+ return (result);
+}
+
+static isc_boolean_t
+zone_check_mx(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
+ dns_name_t *owner)
+{
+ isc_result_t result;
+ char ownerbuf[DNS_NAME_FORMATSIZE];
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char altbuf[DNS_NAME_FORMATSIZE];
+ dns_fixedname_t fixed;
+ dns_name_t *foundname;
+ int level;
+
+ /*
+ * Outside of zone.
+ */
+ if (!dns_name_issubdomain(name, &zone->origin)) {
+ if (zone->checkmx != NULL)
+ return ((zone->checkmx)(zone, name, owner));
+ return (ISC_TRUE);
+ }
+
+ if (zone->type == dns_zone_master)
+ level = ISC_LOG_ERROR;
+ else
+ level = ISC_LOG_WARNING;
+
+ dns_fixedname_init(&fixed);
+ foundname = dns_fixedname_name(&fixed);
+
+ result = dns_db_find(db, name, NULL, dns_rdatatype_a,
+ 0, 0, NULL, foundname, NULL, NULL);
+ if (result == ISC_R_SUCCESS)
+ return (ISC_TRUE);
+
+ if (result == DNS_R_NXRRSET) {
+ result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,
+ 0, 0, NULL, foundname, NULL, NULL);
+ if (result == ISC_R_SUCCESS)
+ return (ISC_TRUE);
+ }
+
+ dns_name_format(owner, ownerbuf, sizeof ownerbuf);
+ dns_name_format(name, namebuf, sizeof namebuf);
+ if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN ||
+ result == DNS_R_EMPTYNAME) {
+ dns_zone_log(zone, level,
+ "%s/MX '%s' has no address records (A or AAAA)",
+ ownerbuf, namebuf);
+ /* XXX950 make fatal for 9.5.0. */
+ return (ISC_TRUE);
+ }
+
+ if (result == DNS_R_CNAME) {
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNMXCNAME) ||
+ DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME))
+ level = ISC_LOG_WARNING;
+ if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME))
+ dns_zone_log(zone, level,
+ "%s/MX '%s' is a CNAME (illegal)",
+ ownerbuf, namebuf);
+ return ((level == ISC_LOG_WARNING) ? ISC_TRUE : ISC_FALSE);
+ }
+
+ if (result == DNS_R_DNAME) {
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNMXCNAME) ||
+ DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME))
+ level = ISC_LOG_WARNING;
+ if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME)) {
+ dns_name_format(foundname, altbuf, sizeof altbuf);
+ dns_zone_log(zone, level, "%s/MX '%s' is below a DNAME"
+ " '%s' (illegal)", ownerbuf, namebuf,
+ altbuf);
+ }
+ return ((level == ISC_LOG_WARNING) ? ISC_TRUE : ISC_FALSE);
+ }
+
+ if (zone->checkmx != NULL && result == DNS_R_DELEGATION)
+ return ((zone->checkmx)(zone, name, owner));
+
+ return (ISC_TRUE);
+}
+
+static isc_boolean_t
+zone_check_srv(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
+ dns_name_t *owner)
+{
+ isc_result_t result;
+ char ownerbuf[DNS_NAME_FORMATSIZE];
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char altbuf[DNS_NAME_FORMATSIZE];
+ dns_fixedname_t fixed;
+ dns_name_t *foundname;
+ int level;
+
+ /*
+ * "." means the services does not exist.
+ */
+ if (dns_name_equal(name, dns_rootname))
+ return (ISC_TRUE);
+
+ /*
+ * Outside of zone.
+ */
+ if (!dns_name_issubdomain(name, &zone->origin)) {
+ if (zone->checksrv != NULL)
+ return ((zone->checksrv)(zone, name, owner));
+ return (ISC_TRUE);
+ }
+
+ if (zone->type == dns_zone_master)
+ level = ISC_LOG_ERROR;
+ else
+ level = ISC_LOG_WARNING;
+
+ dns_fixedname_init(&fixed);
+ foundname = dns_fixedname_name(&fixed);
+
+ result = dns_db_find(db, name, NULL, dns_rdatatype_a,
+ 0, 0, NULL, foundname, NULL, NULL);
+ if (result == ISC_R_SUCCESS)
+ return (ISC_TRUE);
+
+ if (result == DNS_R_NXRRSET) {
+ result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,
+ 0, 0, NULL, foundname, NULL, NULL);
+ if (result == ISC_R_SUCCESS)
+ return (ISC_TRUE);
+ }
+
+ dns_name_format(owner, ownerbuf, sizeof ownerbuf);
+ dns_name_format(name, namebuf, sizeof namebuf);
+ if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN ||
+ result == DNS_R_EMPTYNAME) {
+ dns_zone_log(zone, level,
+ "%s/SRV '%s' has no address records (A or AAAA)",
+ ownerbuf, namebuf);
+ /* XXX950 make fatal for 9.5.0. */
+ return (ISC_TRUE);
+ }
+
+ if (result == DNS_R_CNAME) {
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNSRVCNAME) ||
+ DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME))
+ level = ISC_LOG_WARNING;
+ if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME))
+ dns_zone_log(zone, level,
+ "%s/SRV '%s' is a CNAME (illegal)",
+ ownerbuf, namebuf);
+ return ((level == ISC_LOG_WARNING) ? ISC_TRUE : ISC_FALSE);
+ }
+
+ if (result == DNS_R_DNAME) {
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNSRVCNAME) ||
+ DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME))
+ level = ISC_LOG_WARNING;
+ if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME)) {
+ dns_name_format(foundname, altbuf, sizeof altbuf);
+ dns_zone_log(zone, level, "%s/SRV '%s' is below a "
+ "DNAME '%s' (illegal)", ownerbuf, namebuf,
+ altbuf);
+ }
+ return ((level == ISC_LOG_WARNING) ? ISC_TRUE : ISC_FALSE);
+ }
+
+ if (zone->checksrv != NULL && result == DNS_R_DELEGATION)
+ return ((zone->checksrv)(zone, name, owner));
+
+ return (ISC_TRUE);
+}
+
+static isc_boolean_t
+zone_check_glue(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
+ dns_name_t *owner)
+{
+ isc_boolean_t answer = ISC_TRUE;
+ isc_result_t result, tresult;
+ char ownerbuf[DNS_NAME_FORMATSIZE];
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char altbuf[DNS_NAME_FORMATSIZE];
+ dns_fixedname_t fixed;
+ dns_name_t *foundname;
+ dns_rdataset_t a;
+ dns_rdataset_t aaaa;
+ int level;
+
+ /*
+ * Outside of zone.
+ */
+ if (!dns_name_issubdomain(name, &zone->origin)) {
+ if (zone->checkns != NULL)
+ return ((zone->checkns)(zone, name, owner, NULL, NULL));
+ return (ISC_TRUE);
+ }
+
+ if (zone->type == dns_zone_master)
+ level = ISC_LOG_ERROR;
+ else
+ level = ISC_LOG_WARNING;
+
+ dns_fixedname_init(&fixed);
+ foundname = dns_fixedname_name(&fixed);
+ dns_rdataset_init(&a);
+ dns_rdataset_init(&aaaa);
+
+ result = dns_db_find(db, name, NULL, dns_rdatatype_a,
+ DNS_DBFIND_GLUEOK, 0, NULL,
+ foundname, &a, NULL);
+
+ if (result == ISC_R_SUCCESS) {
+ dns_rdataset_disassociate(&a);
+ return (ISC_TRUE);
+ } else if (result == DNS_R_DELEGATION)
+ dns_rdataset_disassociate(&a);
+
+ if (result == DNS_R_NXRRSET || result == DNS_R_DELEGATION ||
+ result == DNS_R_GLUE) {
+ tresult = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,
+ DNS_DBFIND_GLUEOK, 0, NULL,
+ foundname, &aaaa, NULL);
+ if (tresult == ISC_R_SUCCESS) {
+ dns_rdataset_disassociate(&aaaa);
+ return (ISC_TRUE);
+ }
+ if (tresult == DNS_R_DELEGATION)
+ dns_rdataset_disassociate(&aaaa);
+ if (result == DNS_R_GLUE || tresult == DNS_R_GLUE) {
+ /*
+ * Check glue against child zone.
+ */
+ if (zone->checkns != NULL)
+ answer = (zone->checkns)(zone, name, owner,
+ &a, &aaaa);
+ if (dns_rdataset_isassociated(&a))
+ dns_rdataset_disassociate(&a);
+ if (dns_rdataset_isassociated(&aaaa))
+ dns_rdataset_disassociate(&aaaa);
+ return (answer);
+ }
+ } else
+ tresult = result;
+
+ dns_name_format(owner, ownerbuf, sizeof ownerbuf);
+ dns_name_format(name, namebuf, sizeof namebuf);
+ if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN ||
+ result == DNS_R_EMPTYNAME || result == DNS_R_DELEGATION) {
+ const char *what;
+ if (dns_name_issubdomain(name, owner))
+ what = "REQUIRED GLUE ";
+ else if (result == DNS_R_DELEGATION)
+ what = "SIBLING GLUE ";
+ else
+ what = "";
+
+ if (result != DNS_R_DELEGATION ||
+ DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKSIBLING)) {
+ dns_zone_log(zone, level, "%s/NS '%s' has no %s"
+ "address records (A or AAAA)",
+ ownerbuf, namebuf, what);
+ /*
+ * Log missing address record.
+ */
+ if (result == DNS_R_DELEGATION && zone->checkns != NULL)
+ (void)(zone->checkns)(zone, name, owner,
+ &a, &aaaa);
+ /* XXX950 make fatal for 9.5.0. */
+ /* answer = ISC_FALSE; */
+ }
+ } else if (result == DNS_R_CNAME) {
+ dns_zone_log(zone, level, "%s/NS '%s' is a CNAME (illegal)",
+ ownerbuf, namebuf);
+ /* XXX950 make fatal for 9.5.0. */
+ /* answer = ISC_FALSE; */
+ } else if (result == DNS_R_DNAME) {
+ dns_name_format(foundname, altbuf, sizeof altbuf);
+ dns_zone_log(zone, level,
+ "%s/NS '%s' is below a DNAME '%s' (illegal)",
+ ownerbuf, namebuf, altbuf);
+ /* XXX950 make fatal for 9.5.0. */
+ /* answer = ISC_FALSE; */
+ }
+
+ if (dns_rdataset_isassociated(&a))
+ dns_rdataset_disassociate(&a);
+ if (dns_rdataset_isassociated(&aaaa))
+ dns_rdataset_disassociate(&aaaa);
+ return (answer);
+}
+
+static isc_boolean_t
+integrity_checks(dns_zone_t *zone, dns_db_t *db) {
+ dns_dbiterator_t *dbiterator = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_fixedname_t fixed;
+ dns_fixedname_t fixedbottom;
+ dns_rdata_mx_t mx;
+ dns_rdata_ns_t ns;
+ dns_rdata_in_srv_t srv;
+ dns_rdata_t rdata;
+ dns_name_t *name;
+ dns_name_t *bottom;
+ isc_result_t result;
+ isc_boolean_t ok = ISC_TRUE;
+
+ dns_fixedname_init(&fixed);
+ name = dns_fixedname_name(&fixed);
+ dns_fixedname_init(&fixedbottom);
+ bottom = dns_fixedname_name(&fixedbottom);
+ dns_rdataset_init(&rdataset);
+ dns_rdata_init(&rdata);
+
+ result = dns_db_createiterator(db, ISC_FALSE, &dbiterator);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_TRUE);
+
+ result = dns_dbiterator_first(dbiterator);
+ while (result == ISC_R_SUCCESS) {
+ result = dns_dbiterator_current(dbiterator, &node, name);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ /*
+ * Is this name visible in the zone?
+ */
+ if (!dns_name_issubdomain(name, &zone->origin) ||
+ (dns_name_countlabels(bottom) > 0 &&
+ dns_name_issubdomain(name, bottom)))
+ goto next;
+
+ /*
+ * Don't check the NS records at the origin.
+ */
+ if (dns_name_equal(name, &zone->origin))
+ goto checkmx;
+
+ result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ns,
+ 0, 0, &rdataset, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto checkmx;
+ /*
+ * Remember bottom of zone.
+ */
+ dns_name_copy(name, bottom, NULL);
+
+ result = dns_rdataset_first(&rdataset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &ns, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ if (!zone_check_glue(zone, db, &ns.name, name))
+ ok = ISC_FALSE;
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(&rdataset);
+ }
+ dns_rdataset_disassociate(&rdataset);
+
+ checkmx:
+ result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_mx,
+ 0, 0, &rdataset, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto checksrv;
+ result = dns_rdataset_first(&rdataset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &mx, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ if (!zone_check_mx(zone, db, &mx.mx, name))
+ ok = ISC_FALSE;
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(&rdataset);
+ }
+ dns_rdataset_disassociate(&rdataset);
+
+ checksrv:
+ if (zone->rdclass != dns_rdataclass_in)
+ goto next;
+ result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_srv,
+ 0, 0, &rdataset, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto next;
+ result = dns_rdataset_first(&rdataset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &srv, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ if (!zone_check_srv(zone, db, &srv.target, name))
+ ok = ISC_FALSE;
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(&rdataset);
+ }
+ dns_rdataset_disassociate(&rdataset);
+
+ next:
+ dns_db_detachnode(db, &node);
+ result = dns_dbiterator_next(dbiterator);
+ }
+
+ cleanup:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ dns_dbiterator_destroy(&dbiterator);
+
+ return (ok);
+}
+
+/*
+ * OpenSSL verification of RSA keys with exponent 3 is known to be
+ * broken prior OpenSSL 0.9.8c/0.9.7k. Look for such keys and warn
+ * if they are in use.
+ */
+static void
+zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) {
+ dns_dbnode_t *node = NULL;
+ dns_dbversion_t *version = NULL;
+ dns_rdata_dnskey_t dnskey;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+ isc_boolean_t logit, foundrsa = ISC_FALSE, foundmd5 = ISC_FALSE;
+ const char *algorithm;
+
+ result = dns_db_findnode(db, &zone->origin, ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ dns_db_currentversion(db, &version);
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey,
+ dns_rdatatype_none, 0, &rdataset, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset))
+ {
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
+ INSIST(result == ISC_R_SUCCESS);
+
+ if ((dnskey.algorithm == DST_ALG_RSASHA1 ||
+ dnskey.algorithm == DST_ALG_RSAMD5) &&
+ dnskey.datalen > 1 && dnskey.data[0] == 1 &&
+ dnskey.data[1] == 3)
+ {
+ if (dnskey.algorithm == DST_ALG_RSASHA1) {
+ logit = !foundrsa;
+ foundrsa = ISC_TRUE;
+ algorithm = "RSASHA1";
+ } else {
+ logit = !foundmd5;
+ foundmd5 = ISC_TRUE;
+ algorithm = "RSAMD5";
+ }
+ if (logit)
+ dns_zone_log(zone, ISC_LOG_WARNING,
+ "weak %s (%u) key found "
+ "(exponent=3)", algorithm,
+ dnskey.algorithm);
+ if (foundrsa && foundmd5)
+ break;
+ }
+ dns_rdata_reset(&rdata);
+ }
+ dns_rdataset_disassociate(&rdataset);
+
+ cleanup:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ if (version != NULL)
+ dns_db_closeversion(db, &version, ISC_FALSE);
+
+}
+
+static isc_result_t
+zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
+ isc_result_t result)
+{
+ unsigned int soacount = 0;
+ unsigned int nscount = 0;
+ unsigned int errors = 0;
+ isc_uint32_t serial, refresh, retry, expire, minimum;
+ isc_time_t now;
+ isc_boolean_t needdump = ISC_FALSE;
+ isc_boolean_t hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE);
+
+ TIME_NOW(&now);
+
+ /*
+ * Initiate zone transfer? We may need a error code that
+ * indicates that the "permanent" form does not exist.
+ * XXX better error feedback to log.
+ */
+ if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) {
+ if (zone->type == dns_zone_slave ||
+ zone->type == dns_zone_stub) {
+ if (result == ISC_R_FILENOTFOUND)
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "no master file");
+ else if (result != DNS_R_NOMASTERFILE)
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "loading from master file %s "
+ "failed: %s",
+ zone->masterfile,
+ dns_result_totext(result));
+ } else
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "loading from master file %s failed: %s",
+ zone->masterfile,
+ dns_result_totext(result));
+ goto cleanup;
+ }
+
+ dns_zone_log(zone, ISC_LOG_DEBUG(2),
+ "number of nodes in database: %u",
+ dns_db_nodecount(db));
+
+ if (result == DNS_R_SEENINCLUDE)
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HASINCLUDE);
+ else
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HASINCLUDE);
+
+ /*
+ * Apply update log, if any, on initial load.
+ */
+ if (zone->journal != NULL &&
+ ! DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOMERGE) &&
+ ! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED))
+ {
+ result = dns_journal_rollforward(zone->mctx, db,
+ zone->journal);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND &&
+ result != DNS_R_UPTODATE && result != DNS_R_NOJOURNAL &&
+ result != ISC_R_RANGE) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "journal rollforward failed: %s",
+ dns_result_totext(result));
+ goto cleanup;
+ }
+ if (result == ISC_R_NOTFOUND || result == ISC_R_RANGE) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "journal rollforward failed: "
+ "journal out of sync with zone");
+ goto cleanup;
+ }
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "journal rollforward completed "
+ "successfully: %s",
+ dns_result_totext(result));
+ if (result == ISC_R_SUCCESS)
+ needdump = ISC_TRUE;
+ }
+
+ zone->loadtime = loadtime;
+
+ dns_zone_log(zone, ISC_LOG_DEBUG(1), "loaded");
+
+ /*
+ * Obtain ns, soa and cname counts for top of zone.
+ */
+ INSIST(db != NULL);
+ result = zone_get_from_db(zone, db, &nscount, &soacount, &serial,
+ &refresh, &retry, &expire, &minimum,
+ &errors);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "could not find NS and/or SOA records");
+ }
+
+ /*
+ * Master / Slave / Stub zones require both NS and SOA records at
+ * the top of the zone.
+ */
+
+ switch (zone->type) {
+ case dns_zone_master:
+ case dns_zone_slave:
+ case dns_zone_stub:
+ if (soacount != 1) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "has %d SOA records", soacount);
+ result = DNS_R_BADZONE;
+ }
+ if (nscount == 0) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "has no NS records");
+ result = DNS_R_BADZONE;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ if (zone->type == dns_zone_master && errors != 0) {
+ result = DNS_R_BADZONE;
+ goto cleanup;
+ }
+ if (zone->type == dns_zone_master &&
+ DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKINTEGRITY) &&
+ !integrity_checks(zone, db)) {
+ result = DNS_R_BADZONE;
+ goto cleanup;
+ }
+
+ if (zone->db != NULL) {
+ /*
+ * This is checked in zone_replacedb() for slave zones
+ * as they don't reload from disk.
+ */
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) &&
+ !isc_serial_gt(serial, zone->serial)) {
+ isc_uint32_t serialmin, serialmax;
+
+ INSIST(zone->type == dns_zone_master);
+
+ serialmin = (zone->serial + 1) & 0xffffffffU;
+ serialmax = (zone->serial + 0x7fffffffU) &
+ 0xffffffffU;
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "ixfr-from-differences: "
+ "new serial (%u) out of range "
+ "[%u - %u]", serial, serialmin,
+ serialmax);
+ result = DNS_R_BADZONE;
+ goto cleanup;
+ } else if (!isc_serial_ge(serial, zone->serial))
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone serial has gone backwards");
+ else if (serial == zone->serial && !hasinclude)
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone serial unchanged. "
+ "zone may fail to transfer "
+ "to slaves.");
+ }
+ zone->serial = serial;
+ zone->refresh = RANGE(refresh,
+ zone->minrefresh, zone->maxrefresh);
+ zone->retry = RANGE(retry,
+ zone->minretry, zone->maxretry);
+ zone->expire = RANGE(expire, zone->refresh + zone->retry,
+ DNS_MAX_EXPIRE);
+ zone->minimum = minimum;
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS);
+
+ if (zone->type == dns_zone_slave ||
+ zone->type == dns_zone_stub) {
+ isc_time_t t;
+ isc_uint32_t delay;
+
+ result = isc_file_getmodtime(zone->journal, &t);
+ if (result != ISC_R_SUCCESS)
+ result = isc_file_getmodtime(zone->masterfile,
+ &t);
+ if (result == ISC_R_SUCCESS)
+ DNS_ZONE_TIME_ADD(&t, zone->expire,
+ &zone->expiretime);
+ else
+ DNS_ZONE_TIME_ADD(&now, zone->retry,
+ &zone->expiretime);
+
+ delay = isc_random_jitter(zone->retry,
+ (zone->retry * 3) / 4);
+ DNS_ZONE_TIME_ADD(&now, delay, &zone->refreshtime);
+ if (isc_time_compare(&zone->refreshtime,
+ &zone->expiretime) >= 0)
+ zone->refreshtime = now;
+ }
+ break;
+ default:
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "unexpected zone type %d", zone->type);
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+
+ /*
+ * Check for weak DNSKEY's.
+ */
+ if (zone->type == dns_zone_master)
+ zone_check_dnskeys(zone, db);
+
+#if 0
+ /* destroy notification example. */
+ {
+ isc_event_t *e = isc_event_allocate(zone->mctx, NULL,
+ DNS_EVENT_DBDESTROYED,
+ dns_zonemgr_dbdestroyed,
+ zone,
+ sizeof(isc_event_t));
+ dns_db_ondestroy(db, zone->task, &e);
+ }
+#endif
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write);
+ if (zone->db != NULL) {
+ result = zone_replacedb(zone, db, ISC_FALSE);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ } else {
+ zone_attachdb(zone, db);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
+ DNS_ZONE_SETFLAG(zone,
+ DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY);
+ }
+ result = ISC_R_SUCCESS;
+ if (needdump)
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ if (zone->task != NULL)
+ zone_settimer(zone, &now);
+
+ if (! dns_db_ispersistent(db))
+ dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u%s",
+ zone->serial,
+ dns_db_issecure(db) ? " (signed)" : "");
+
+ return (result);
+
+ cleanup:
+ if (zone->type == dns_zone_slave ||
+ zone->type == dns_zone_stub) {
+ if (zone->journal != NULL)
+ zone_saveunique(zone, zone->journal, "jn-XXXXXXXX");
+ if (zone->masterfile != NULL)
+ zone_saveunique(zone, zone->masterfile, "db-XXXXXXXX");
+
+ /* Mark the zone for immediate refresh. */
+ zone->refreshtime = now;
+ if (zone->task != NULL)
+ zone_settimer(zone, &now);
+ result = ISC_R_SUCCESS;
+ }
+ return (result);
+}
+
+static isc_boolean_t
+exit_check(dns_zone_t *zone) {
+
+ REQUIRE(LOCKED_ZONE(zone));
+
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SHUTDOWN) &&
+ zone->irefs == 0)
+ {
+ /*
+ * DNS_ZONEFLG_SHUTDOWN can only be set if erefs == 0.
+ */
+ INSIST(isc_refcount_current(&zone->erefs) == 0);
+ return (ISC_TRUE);
+ }
+ return (ISC_FALSE);
+}
+
+static isc_boolean_t
+zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_name_t *name) {
+ isc_result_t result;
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char altbuf[DNS_NAME_FORMATSIZE];
+ dns_fixedname_t fixed;
+ dns_name_t *foundname;
+ int level;
+
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOCHECKNS))
+ return (ISC_TRUE);
+
+ if (zone->type == dns_zone_master)
+ level = ISC_LOG_ERROR;
+ else
+ level = ISC_LOG_WARNING;
+
+ dns_fixedname_init(&fixed);
+ foundname = dns_fixedname_name(&fixed);
+
+ result = dns_db_find(db, name, NULL, dns_rdatatype_a,
+ 0, 0, NULL, foundname, NULL, NULL);
+ if (result == ISC_R_SUCCESS)
+ return (ISC_TRUE);
+
+ if (result == DNS_R_NXRRSET) {
+ result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,
+ 0, 0, NULL, foundname, NULL, NULL);
+ if (result == ISC_R_SUCCESS)
+ return (ISC_TRUE);
+ }
+
+ dns_name_format(name, namebuf, sizeof namebuf);
+ if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN ||
+ result == DNS_R_EMPTYNAME) {
+ dns_zone_log(zone, level,
+ "NS '%s' has no address records (A or AAAA)",
+ namebuf);
+ /* XXX950 Make fatal ISC_FALSE for 9.5.0. */
+ return (ISC_TRUE);
+ }
+
+ if (result == DNS_R_CNAME) {
+ dns_zone_log(zone, level, "NS '%s' is a CNAME (illegal)",
+ namebuf);
+ /* XXX950 Make fatal ISC_FALSE for 9.5.0. */
+ return (ISC_TRUE);
+ }
+
+ if (result == DNS_R_DNAME) {
+ dns_name_format(foundname, altbuf, sizeof altbuf);
+ dns_zone_log(zone, level,
+ "NS '%s' is below a DNAME '%s' (illegal)",
+ namebuf, altbuf);
+ /* XXX950 Make fatal ISC_FALSE for 9.5.0. */
+ return (ISC_TRUE);
+ }
+
+ return (ISC_TRUE);
+}
+
+static isc_result_t
+zone_count_ns_rr(dns_zone_t *zone, dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version, unsigned int *nscount,
+ unsigned int *errors)
+{
+ isc_result_t result;
+ unsigned int count = 0;
+ unsigned int ecount = 0;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata;
+ dns_rdata_ns_t ns;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(db, node, version, dns_rdatatype_ns,
+ dns_rdatatype_none, 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND)
+ goto success;
+ if (result != ISC_R_SUCCESS)
+ goto invalidate_rdataset;
+
+ result = dns_rdataset_first(&rdataset);
+ while (result == ISC_R_SUCCESS) {
+ if (errors != NULL && zone->rdclass == dns_rdataclass_in &&
+ (zone->type == dns_zone_master ||
+ zone->type == dns_zone_slave)) {
+ dns_rdata_init(&rdata);
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &ns, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ if (dns_name_issubdomain(&ns.name, &zone->origin) &&
+ !zone_check_ns(zone, db, &ns.name))
+ ecount++;
+ }
+ count++;
+ result = dns_rdataset_next(&rdataset);
+ }
+ dns_rdataset_disassociate(&rdataset);
+
+ success:
+ if (nscount != NULL)
+ *nscount = count;
+ if (errors != NULL)
+ *errors = ecount;
+
+ result = ISC_R_SUCCESS;
+
+ invalidate_rdataset:
+ dns_rdataset_invalidate(&rdataset);
+
+ return (result);
+}
+
+static isc_result_t
+zone_load_soa_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ unsigned int *soacount,
+ isc_uint32_t *serial, isc_uint32_t *refresh,
+ isc_uint32_t *retry, isc_uint32_t *expire,
+ isc_uint32_t *minimum)
+{
+ isc_result_t result;
+ unsigned int count;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_soa_t soa;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa,
+ dns_rdatatype_none, 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND) {
+ if (soacount != NULL)
+ *soacount = 0;
+ if (serial != NULL)
+ *serial = 0;
+ if (refresh != NULL)
+ *refresh = 0;
+ if (retry != NULL)
+ *retry = 0;
+ if (expire != NULL)
+ *expire = 0;
+ if (minimum != NULL)
+ *minimum = 0;
+ result = ISC_R_SUCCESS;
+ goto invalidate_rdataset;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto invalidate_rdataset;
+
+ count = 0;
+ result = dns_rdataset_first(&rdataset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdata_init(&rdata);
+ dns_rdataset_current(&rdataset, &rdata);
+ count++;
+ if (count == 1) {
+ result = dns_rdata_tostruct(&rdata, &soa, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ }
+
+ result = dns_rdataset_next(&rdataset);
+ dns_rdata_reset(&rdata);
+ }
+ dns_rdataset_disassociate(&rdataset);
+
+ if (soacount != NULL)
+ *soacount = count;
+
+ if (count > 0) {
+ if (serial != NULL)
+ *serial = soa.serial;
+ if (refresh != NULL)
+ *refresh = soa.refresh;
+ if (retry != NULL)
+ *retry = soa.retry;
+ if (expire != NULL)
+ *expire = soa.expire;
+ if (minimum != NULL)
+ *minimum = soa.minimum;
+ }
+
+ result = ISC_R_SUCCESS;
+
+ invalidate_rdataset:
+ dns_rdataset_invalidate(&rdataset);
+
+ return (result);
+}
+
+/*
+ * zone must be locked.
+ */
+static isc_result_t
+zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount,
+ unsigned int *soacount, isc_uint32_t *serial,
+ isc_uint32_t *refresh, isc_uint32_t *retry,
+ isc_uint32_t *expire, isc_uint32_t *minimum,
+ unsigned int *errors)
+{
+ dns_dbversion_t *version;
+ isc_result_t result;
+ isc_result_t answer = ISC_R_SUCCESS;
+ dns_dbnode_t *node;
+
+ REQUIRE(db != NULL);
+ REQUIRE(zone != NULL);
+
+ version = NULL;
+ dns_db_currentversion(db, &version);
+
+ node = NULL;
+ result = dns_db_findnode(db, &zone->origin, ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS) {
+ answer = result;
+ goto closeversion;
+ }
+
+ if (nscount != NULL || errors != NULL) {
+ result = zone_count_ns_rr(zone, db, node, version,
+ nscount, errors);
+ if (result != ISC_R_SUCCESS)
+ answer = result;
+ }
+
+ if (soacount != NULL || serial != NULL || refresh != NULL
+ || retry != NULL || expire != NULL || minimum != NULL) {
+ result = zone_load_soa_rr(db, node, version, soacount,
+ serial, refresh, retry, expire,
+ minimum);
+ if (result != ISC_R_SUCCESS)
+ answer = result;
+ }
+
+ dns_db_detachnode(db, &node);
+ closeversion:
+ dns_db_closeversion(db, &version, ISC_FALSE);
+
+ return (answer);
+}
+
+void
+dns_zone_attach(dns_zone_t *source, dns_zone_t **target) {
+ REQUIRE(DNS_ZONE_VALID(source));
+ REQUIRE(target != NULL && *target == NULL);
+ isc_refcount_increment(&source->erefs, NULL);
+ *target = source;
+}
+
+void
+dns_zone_detach(dns_zone_t **zonep) {
+ dns_zone_t *zone;
+ unsigned int refs;
+ isc_boolean_t free_now = ISC_FALSE;
+
+ REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep));
+
+ zone = *zonep;
+
+ isc_refcount_decrement(&zone->erefs, &refs);
+
+ if (refs == 0) {
+ LOCK_ZONE(zone);
+ /*
+ * We just detached the last external reference.
+ */
+ if (zone->task != NULL) {
+ /*
+ * This zone is being managed. Post
+ * its control event and let it clean
+ * up synchronously in the context of
+ * its task.
+ */
+ isc_event_t *ev = &zone->ctlevent;
+ isc_task_send(zone->task, &ev);
+ } else {
+ /*
+ * This zone is not being managed; it has
+ * no task and can have no outstanding
+ * events. Free it immediately.
+ */
+ /*
+ * Unmanaged zones should not have non-null views;
+ * we have no way of detaching from the view here
+ * without causing deadlock because this code is called
+ * with the view already locked.
+ */
+ INSIST(zone->view == NULL);
+ free_now = ISC_TRUE;
+ }
+ UNLOCK_ZONE(zone);
+ }
+ *zonep = NULL;
+ if (free_now)
+ zone_free(zone);
+}
+
+void
+dns_zone_iattach(dns_zone_t *source, dns_zone_t **target) {
+ REQUIRE(DNS_ZONE_VALID(source));
+ REQUIRE(target != NULL && *target == NULL);
+ LOCK_ZONE(source);
+ zone_iattach(source, target);
+ UNLOCK_ZONE(source);
+}
+
+static void
+zone_iattach(dns_zone_t *source, dns_zone_t **target) {
+
+ /*
+ * 'source' locked by caller.
+ */
+ REQUIRE(LOCKED_ZONE(source));
+ REQUIRE(DNS_ZONE_VALID(source));
+ REQUIRE(target != NULL && *target == NULL);
+ INSIST(source->irefs + isc_refcount_current(&source->erefs) > 0);
+ source->irefs++;
+ INSIST(source->irefs != 0);
+ *target = source;
+}
+
+static void
+zone_idetach(dns_zone_t **zonep) {
+ dns_zone_t *zone;
+
+ /*
+ * 'zone' locked by caller.
+ */
+ REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep));
+ zone = *zonep;
+ REQUIRE(LOCKED_ZONE(*zonep));
+ *zonep = NULL;
+
+ INSIST(zone->irefs > 0);
+ zone->irefs--;
+ INSIST(zone->irefs + isc_refcount_current(&zone->erefs) > 0);
+}
+
+void
+dns_zone_idetach(dns_zone_t **zonep) {
+ dns_zone_t *zone;
+ isc_boolean_t free_needed;
+
+ REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep));
+ zone = *zonep;
+ *zonep = NULL;
+
+ LOCK_ZONE(zone);
+ INSIST(zone->irefs > 0);
+ zone->irefs--;
+ free_needed = exit_check(zone);
+ UNLOCK_ZONE(zone);
+ if (free_needed)
+ zone_free(zone);
+}
+
+isc_mem_t *
+dns_zone_getmctx(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->mctx);
+}
+
+dns_zonemgr_t *
+dns_zone_getmgr(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->zmgr);
+}
+
+void
+dns_zone_setflag(dns_zone_t *zone, unsigned int flags, isc_boolean_t value) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (value)
+ DNS_ZONE_SETFLAG(zone, flags);
+ else
+ DNS_ZONE_CLRFLAG(zone, flags);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_setoption(dns_zone_t *zone, unsigned int option, isc_boolean_t value)
+{
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (value)
+ zone->options |= option;
+ else
+ zone->options &= ~option;
+ UNLOCK_ZONE(zone);
+}
+
+unsigned int
+dns_zone_getoptions(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->options);
+}
+
+isc_result_t
+dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ zone->xfrsource4 = *xfrsource;
+ UNLOCK_ZONE(zone);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_sockaddr_t *
+dns_zone_getxfrsource4(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (&zone->xfrsource4);
+}
+
+isc_result_t
+dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ zone->xfrsource6 = *xfrsource;
+ UNLOCK_ZONE(zone);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_sockaddr_t *
+dns_zone_getxfrsource6(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (&zone->xfrsource6);
+}
+
+isc_result_t
+dns_zone_setaltxfrsource4(dns_zone_t *zone,
+ const isc_sockaddr_t *altxfrsource)
+{
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ zone->altxfrsource4 = *altxfrsource;
+ UNLOCK_ZONE(zone);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_sockaddr_t *
+dns_zone_getaltxfrsource4(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (&zone->altxfrsource4);
+}
+
+isc_result_t
+dns_zone_setaltxfrsource6(dns_zone_t *zone,
+ const isc_sockaddr_t *altxfrsource)
+{
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ zone->altxfrsource6 = *altxfrsource;
+ UNLOCK_ZONE(zone);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_sockaddr_t *
+dns_zone_getaltxfrsource6(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (&zone->altxfrsource6);
+}
+
+isc_result_t
+dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ zone->notifysrc4 = *notifysrc;
+ UNLOCK_ZONE(zone);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_sockaddr_t *
+dns_zone_getnotifysrc4(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (&zone->notifysrc4);
+}
+
+isc_result_t
+dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ zone->notifysrc6 = *notifysrc;
+ UNLOCK_ZONE(zone);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_sockaddr_t *
+dns_zone_getnotifysrc6(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (&zone->notifysrc6);
+}
+
+isc_result_t
+dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify,
+ isc_uint32_t count)
+{
+ isc_sockaddr_t *new;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(count == 0 || notify != NULL);
+
+ LOCK_ZONE(zone);
+ if (zone->notify != NULL) {
+ isc_mem_put(zone->mctx, zone->notify,
+ zone->notifycnt * sizeof(*new));
+ zone->notify = NULL;
+ zone->notifycnt = 0;
+ }
+ if (count != 0) {
+ new = isc_mem_get(zone->mctx, count * sizeof(*new));
+ if (new == NULL) {
+ UNLOCK_ZONE(zone);
+ return (ISC_R_NOMEMORY);
+ }
+ memcpy(new, notify, count * sizeof(*new));
+ zone->notify = new;
+ zone->notifycnt = count;
+ }
+ UNLOCK_ZONE(zone);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_zone_setmasters(dns_zone_t *zone, const isc_sockaddr_t *masters,
+ isc_uint32_t count)
+{
+ isc_result_t result;
+
+ result = dns_zone_setmasterswithkeys(zone, masters, NULL, count);
+ return (result);
+}
+
+static isc_boolean_t
+same_masters(const isc_sockaddr_t *old, const isc_sockaddr_t *new,
+ isc_uint32_t count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++)
+ if (!isc_sockaddr_equal(&old[i], &new[i]))
+ return (ISC_FALSE);
+ return (ISC_TRUE);
+}
+
+static isc_boolean_t
+same_keynames(dns_name_t **old, dns_name_t **new, isc_uint32_t count) {
+ unsigned int i;
+
+ if (old == NULL && new == NULL)
+ return (ISC_TRUE);
+ if (old == NULL || new == NULL)
+ return (ISC_FALSE);
+
+ for (i = 0; i < count; i++) {
+ if (old[i] == NULL && new[i] == NULL)
+ continue;
+ if (old[i] == NULL || new[i] == NULL ||
+ !dns_name_equal(old[i], new[i]))
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+isc_result_t
+dns_zone_setmasterswithkeys(dns_zone_t *zone,
+ const isc_sockaddr_t *masters,
+ dns_name_t **keynames,
+ isc_uint32_t count)
+{
+ isc_sockaddr_t *new;
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_name_t **newname;
+ isc_boolean_t *newok;
+ unsigned int i;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(count == 0 || masters != NULL);
+ if (keynames != NULL) {
+ REQUIRE(count != 0);
+ }
+
+ LOCK_ZONE(zone);
+ /*
+ * The refresh code assumes that 'masters' wouldn't change under it.
+ * If it will change then kill off any current refresh in progress
+ * and update the masters info. If it won't change then we can just
+ * unlock and exit.
+ */
+ if (count != zone->masterscnt ||
+ !same_masters(zone->masters, masters, count) ||
+ !same_keynames(zone->masterkeynames, keynames, count)) {
+ if (zone->request != NULL)
+ dns_request_cancel(zone->request);
+ } else
+ goto unlock;
+ if (zone->masters != NULL) {
+ isc_mem_put(zone->mctx, zone->masters,
+ zone->masterscnt * sizeof(*new));
+ zone->masters = NULL;
+ }
+ if (zone->masterkeynames != NULL) {
+ for (i = 0; i < zone->masterscnt; i++) {
+ if (zone->masterkeynames[i] != NULL) {
+ dns_name_free(zone->masterkeynames[i],
+ zone->mctx);
+ isc_mem_put(zone->mctx,
+ zone->masterkeynames[i],
+ sizeof(dns_name_t));
+ zone->masterkeynames[i] = NULL;
+ }
+ }
+ isc_mem_put(zone->mctx, zone->masterkeynames,
+ zone->masterscnt * sizeof(dns_name_t *));
+ zone->masterkeynames = NULL;
+ }
+ if (zone->mastersok != NULL) {
+ isc_mem_put(zone->mctx, zone->mastersok,
+ zone->masterscnt * sizeof(isc_boolean_t));
+ zone->mastersok = NULL;
+ }
+ zone->masterscnt = 0;
+ /*
+ * If count == 0, don't allocate any space for masters, mastersok or
+ * keynames so internally, those pointers are NULL if count == 0
+ */
+ if (count == 0)
+ goto unlock;
+
+ /*
+ * masters must countain count elements!
+ */
+ new = isc_mem_get(zone->mctx, count * sizeof(*new));
+ if (new == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto unlock;
+ }
+ memcpy(new, masters, count * sizeof(*new));
+
+ /*
+ * Similarly for mastersok.
+ */
+ newok = isc_mem_get(zone->mctx, count * sizeof(*newok));
+ if (newok == NULL) {
+ result = ISC_R_NOMEMORY;
+ isc_mem_put(zone->mctx, new, count * sizeof(*new));
+ goto unlock;
+ };
+ for (i = 0; i < count; i++)
+ newok[i] = ISC_FALSE;
+
+ /*
+ * if keynames is non-NULL, it must contain count elements!
+ */
+ newname = NULL;
+ if (keynames != NULL) {
+ newname = isc_mem_get(zone->mctx, count * sizeof(*newname));
+ if (newname == NULL) {
+ result = ISC_R_NOMEMORY;
+ isc_mem_put(zone->mctx, new, count * sizeof(*new));
+ isc_mem_put(zone->mctx, newok, count * sizeof(*newok));
+ goto unlock;
+ }
+ for (i = 0; i < count; i++)
+ newname[i] = NULL;
+ for (i = 0; i < count; i++) {
+ if (keynames[i] != NULL) {
+ newname[i] = isc_mem_get(zone->mctx,
+ sizeof(dns_name_t));
+ if (newname[i] == NULL)
+ goto allocfail;
+ dns_name_init(newname[i], NULL);
+ result = dns_name_dup(keynames[i], zone->mctx,
+ newname[i]);
+ if (result != ISC_R_SUCCESS) {
+ allocfail:
+ for (i = 0; i < count; i++)
+ if (newname[i] != NULL)
+ dns_name_free(
+ newname[i],
+ zone->mctx);
+ isc_mem_put(zone->mctx, new,
+ count * sizeof(*new));
+ isc_mem_put(zone->mctx, newok,
+ count * sizeof(*newok));
+ isc_mem_put(zone->mctx, newname,
+ count * sizeof(*newname));
+ goto unlock;
+ }
+ }
+ }
+ }
+
+ /*
+ * Everything is ok so attach to the zone.
+ */
+ zone->masters = new;
+ zone->mastersok = newok;
+ zone->masterkeynames = newname;
+ zone->masterscnt = count;
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS);
+
+ unlock:
+ UNLOCK_ZONE(zone);
+ return (result);
+}
+
+isc_result_t
+dns_zone_getdb(dns_zone_t *zone, dns_db_t **dpb) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db == NULL)
+ result = DNS_R_NOTLOADED;
+ else
+ dns_db_attach(zone->db, dpb);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+ return (result);
+}
+
+/*
+ * Co-ordinates the starting of routine jobs.
+ */
+
+void
+dns_zone_maintenance(dns_zone_t *zone) {
+ const char me[] = "dns_zone_maintenance";
+ isc_time_t now;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ ENTER;
+
+ LOCK_ZONE(zone);
+ TIME_NOW(&now);
+ zone_settimer(zone, &now);
+ UNLOCK_ZONE(zone);
+}
+
+static inline isc_boolean_t
+was_dumping(dns_zone_t *zone) {
+ isc_boolean_t dumping;
+
+ REQUIRE(LOCKED_ZONE(zone));
+
+ dumping = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING);
+ if (!dumping) {
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
+ isc_time_settoepoch(&zone->dumptime);
+ }
+ return (dumping);
+}
+
+static void
+zone_maintenance(dns_zone_t *zone) {
+ const char me[] = "zone_maintenance";
+ isc_time_t now;
+ isc_result_t result;
+ isc_boolean_t dumping;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ ENTER;
+
+ /*
+ * Configuring the view of this zone may have
+ * failed, for example because the config file
+ * had a syntax error. In that case, the view
+ * adb or resolver, and we had better not try
+ * to do maintenance on it.
+ */
+ if (zone->view == NULL || zone->view->adb == NULL)
+ return;
+
+ TIME_NOW(&now);
+
+ /*
+ * Expire check.
+ */
+ switch (zone->type) {
+ case dns_zone_slave:
+ case dns_zone_stub:
+ LOCK_ZONE(zone);
+ if (isc_time_compare(&now, &zone->expiretime) >= 0 &&
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) {
+ zone_expire(zone);
+ zone->refreshtime = now;
+ }
+ UNLOCK_ZONE(zone);
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Up to date check.
+ */
+ switch (zone->type) {
+ case dns_zone_slave:
+ case dns_zone_stub:
+ if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH) &&
+ isc_time_compare(&now, &zone->refreshtime) >= 0)
+ dns_zone_refresh(zone);
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Do we need to consolidate the backing store?
+ */
+ switch (zone->type) {
+ case dns_zone_master:
+ case dns_zone_slave:
+ LOCK_ZONE(zone);
+ if (zone->masterfile != NULL &&
+ isc_time_compare(&now, &zone->dumptime) >= 0 &&
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) &&
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP)) {
+ dumping = was_dumping(zone);
+ } else
+ dumping = ISC_TRUE;
+ UNLOCK_ZONE(zone);
+ if (!dumping) {
+ result = zone_dump(zone, ISC_TRUE); /* task locked */
+ if (result != ISC_R_SUCCESS)
+ dns_zone_log(zone, ISC_LOG_WARNING,
+ "dump failed: %s",
+ dns_result_totext(result));
+ }
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Do we need to send out notify messages?
+ */
+ switch (zone->type) {
+ case dns_zone_master:
+ case dns_zone_slave:
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) &&
+ isc_time_compare(&now, &zone->notifytime) >= 0)
+ zone_notify(zone, &now);
+ break;
+ default:
+ break;
+ }
+ zone_settimer(zone, &now);
+}
+
+void
+dns_zone_markdirty(dns_zone_t *zone) {
+
+ LOCK_ZONE(zone);
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_expire(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ zone_expire(zone);
+ UNLOCK_ZONE(zone);
+}
+
+static void
+zone_expire(dns_zone_t *zone) {
+ /*
+ * 'zone' locked by caller.
+ */
+
+ REQUIRE(LOCKED_ZONE(zone));
+
+ dns_zone_log(zone, ISC_LOG_WARNING, "expired");
+
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_EXPIRED);
+ zone->refresh = DNS_ZONE_DEFAULTREFRESH;
+ zone->retry = DNS_ZONE_DEFAULTRETRY;
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS);
+ zone_unload(zone);
+}
+
+void
+dns_zone_refresh(dns_zone_t *zone) {
+ isc_interval_t i;
+ isc_uint32_t oldflags;
+ unsigned int j;
+ isc_result_t result;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING))
+ return;
+
+ /*
+ * Set DNS_ZONEFLG_REFRESH so that there is only one refresh operation
+ * in progress at a time.
+ */
+
+ LOCK_ZONE(zone);
+ oldflags = zone->flags;
+ if (zone->masterscnt == 0) {
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOMASTERS);
+ if ((oldflags & DNS_ZONEFLG_NOMASTERS) == 0)
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "cannot refresh: no masters");
+ goto unlock;
+ }
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC);
+ if ((oldflags & (DNS_ZONEFLG_REFRESH|DNS_ZONEFLG_LOADING)) != 0)
+ goto unlock;
+
+ /*
+ * Set the next refresh time as if refresh check has failed.
+ * Setting this to the retry time will do that. XXXMLG
+ * If we are successful it will be reset using zone->refresh.
+ */
+ isc_interval_set(&i, isc_random_jitter(zone->retry, zone->retry / 4),
+ 0);
+ result = isc_time_nowplusinterval(&zone->refreshtime, &i);
+ if (result |= ISC_R_SUCCESS)
+ dns_zone_log(zone, ISC_LOG_WARNING,
+ "isc_time_nowplusinterval() failed: %s",
+ dns_result_totext(result));
+
+ /*
+ * When lacking user-specified timer values from the SOA,
+ * do exponential backoff of the retry time up to a
+ * maximum of six hours.
+ */
+ if (! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HAVETIMERS))
+ zone->retry = ISC_MIN(zone->retry * 2, 6 * 3600);
+
+ zone->curmaster = 0;
+ for (j = 0; j < zone->masterscnt; j++)
+ zone->mastersok[j] = ISC_FALSE;
+ /* initiate soa query */
+ queue_soa_query(zone);
+ unlock:
+ UNLOCK_ZONE(zone);
+}
+
+isc_result_t
+dns_zone_flush(dns_zone_t *zone) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_boolean_t dumping;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_FLUSH);
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
+ zone->masterfile != NULL) {
+ result = ISC_R_ALREADYRUNNING;
+ dumping = was_dumping(zone);
+ } else
+ dumping = ISC_TRUE;
+ UNLOCK_ZONE(zone);
+ if (!dumping)
+ result = zone_dump(zone, ISC_FALSE); /* Unknown task. */
+ return (result);
+}
+
+isc_result_t
+dns_zone_dump(dns_zone_t *zone) {
+ isc_result_t result = ISC_R_ALREADYRUNNING;
+ isc_boolean_t dumping;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ dumping = was_dumping(zone);
+ UNLOCK_ZONE(zone);
+ if (!dumping)
+ result = zone_dump(zone, ISC_FALSE); /* Unknown task. */
+ return (result);
+}
+
+static void
+zone_needdump(dns_zone_t *zone, unsigned int delay) {
+ isc_time_t dumptime;
+ isc_time_t now;
+
+ /*
+ * 'zone' locked by caller
+ */
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(LOCKED_ZONE(zone));
+
+ /*
+ * Do we have a place to dump to and are we loaded?
+ */
+ if (zone->masterfile == NULL ||
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) == 0)
+ return;
+
+ TIME_NOW(&now);
+ /* add some noise */
+ DNS_ZONE_JITTER_ADD(&now, delay, &dumptime);
+
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
+ if (isc_time_isepoch(&zone->dumptime) ||
+ isc_time_compare(&zone->dumptime, &dumptime) > 0)
+ zone->dumptime = dumptime;
+ if (zone->task != NULL)
+ zone_settimer(zone, &now);
+}
+
+static void
+dump_done(void *arg, isc_result_t result) {
+ const char me[] = "dump_done";
+ dns_zone_t *zone = arg;
+ dns_db_t *db;
+ dns_dbversion_t *version;
+ isc_boolean_t again = ISC_FALSE;
+ isc_boolean_t compact = ISC_FALSE;
+ isc_uint32_t serial;
+ isc_result_t tresult;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ ENTER;
+
+ if (result == ISC_R_SUCCESS && zone->journal != NULL &&
+ zone->journalsize != -1) {
+
+ /*
+ * We don't own these, zone->dctx must stay valid.
+ */
+ db = dns_dumpctx_db(zone->dctx);
+ version = dns_dumpctx_version(zone->dctx);
+
+ tresult = dns_db_getsoaserial(db, version, &serial);
+ /*
+ * Note: we are task locked here so we can test
+ * zone->xfr safely.
+ */
+ if (tresult == ISC_R_SUCCESS && zone->xfr == NULL) {
+ tresult = dns_journal_compact(zone->mctx,
+ zone->journal,
+ serial,
+ zone->journalsize);
+ switch (tresult) {
+ case ISC_R_SUCCESS:
+ case ISC_R_NOSPACE:
+ case ISC_R_NOTFOUND:
+ dns_zone_log(zone, ISC_LOG_DEBUG(3),
+ "dns_journal_compact: %s",
+ dns_result_totext(tresult));
+ break;
+ default:
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "dns_journal_compact failed: %s",
+ dns_result_totext(tresult));
+ break;
+ }
+ } else if (tresult == ISC_R_SUCCESS) {
+ compact = ISC_TRUE;
+ zone->compact_serial = serial;
+ }
+ }
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_DUMPING);
+ if (compact)
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDCOMPACT);
+ if (result != ISC_R_SUCCESS && result != ISC_R_CANCELED) {
+ /*
+ * Try again in a short while.
+ */
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ } else if (result == ISC_R_SUCCESS &&
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FLUSH) &&
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) {
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING);
+ isc_time_settoepoch(&zone->dumptime);
+ again = ISC_TRUE;
+ } else if (result == ISC_R_SUCCESS)
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_FLUSH);
+
+ if (zone->dctx != NULL)
+ dns_dumpctx_detach(&zone->dctx);
+ zonemgr_putio(&zone->writeio);
+ UNLOCK_ZONE(zone);
+ if (again)
+ (void)zone_dump(zone, ISC_FALSE);
+ dns_zone_idetach(&zone);
+}
+
+static isc_result_t
+zone_dump(dns_zone_t *zone, isc_boolean_t compact) {
+ const char me[] = "zone_dump";
+ isc_result_t result;
+ dns_dbversion_t *version = NULL;
+ isc_boolean_t again;
+ dns_db_t *db = NULL;
+ char *masterfile = NULL;
+ dns_masterformat_t masterformat = dns_masterformat_none;
+
+/*
+ * 'compact' MUST only be set if we are task locked.
+ */
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ ENTER;
+
+ redo:
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db != NULL)
+ dns_db_attach(zone->db, &db);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ LOCK_ZONE(zone);
+ if (zone->masterfile != NULL) {
+ masterfile = isc_mem_strdup(zone->mctx, zone->masterfile);
+ masterformat = zone->masterformat;
+ }
+ UNLOCK_ZONE(zone);
+ if (db == NULL) {
+ result = DNS_R_NOTLOADED;
+ goto fail;
+ }
+ if (masterfile == NULL) {
+ result = DNS_R_NOMASTERFILE;
+ goto fail;
+ }
+
+ if (compact) {
+ dns_zone_t *dummy = NULL;
+ LOCK_ZONE(zone);
+ zone_iattach(zone, &dummy);
+ result = zonemgr_getio(zone->zmgr, ISC_FALSE, zone->task,
+ zone_gotwritehandle, zone,
+ &zone->writeio);
+ if (result != ISC_R_SUCCESS)
+ zone_idetach(&dummy);
+ else
+ result = DNS_R_CONTINUE;
+ UNLOCK_ZONE(zone);
+ } else {
+ dns_db_currentversion(db, &version);
+ result = dns_master_dump2(zone->mctx, db, version,
+ &dns_master_style_default,
+ masterfile, masterformat);
+ dns_db_closeversion(db, &version, ISC_FALSE);
+ }
+ fail:
+ if (db != NULL)
+ dns_db_detach(&db);
+ if (masterfile != NULL)
+ isc_mem_free(zone->mctx, masterfile);
+ masterfile = NULL;
+
+ if (result == DNS_R_CONTINUE)
+ return (ISC_R_SUCCESS); /* XXXMPA */
+
+ again = ISC_FALSE;
+ LOCK_ZONE(zone);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_DUMPING);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * Try again in a short while.
+ */
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FLUSH) &&
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) {
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING);
+ isc_time_settoepoch(&zone->dumptime);
+ again = ISC_TRUE;
+ } else
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_FLUSH);
+ UNLOCK_ZONE(zone);
+ if (again)
+ goto redo;
+
+ return (result);
+}
+
+static isc_result_t
+dumptostream(dns_zone_t *zone, FILE *fd, const dns_master_style_t *style,
+ dns_masterformat_t format)
+{
+ isc_result_t result;
+ dns_dbversion_t *version = NULL;
+ dns_db_t *db = NULL;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db != NULL)
+ dns_db_attach(zone->db, &db);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ if (db == NULL)
+ return (DNS_R_NOTLOADED);
+
+ dns_db_currentversion(db, &version);
+ result = dns_master_dumptostream2(zone->mctx, db, version, style,
+ format, fd);
+ dns_db_closeversion(db, &version, ISC_FALSE);
+ dns_db_detach(&db);
+ return (result);
+}
+
+isc_result_t
+dns_zone_dumptostream2(dns_zone_t *zone, FILE *fd, dns_masterformat_t format,
+ const dns_master_style_t *style) {
+ return dumptostream(zone, fd, style, format);
+}
+
+isc_result_t
+dns_zone_dumptostream(dns_zone_t *zone, FILE *fd) {
+ return dumptostream(zone, fd, &dns_master_style_default,
+ dns_masterformat_text);
+}
+
+isc_result_t
+dns_zone_fulldumptostream(dns_zone_t *zone, FILE *fd) {
+ return dumptostream(zone, fd, &dns_master_style_full,
+ dns_masterformat_text);
+}
+
+void
+dns_zone_unload(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ zone_unload(zone);
+ UNLOCK_ZONE(zone);
+}
+
+static void
+notify_cancel(dns_zone_t *zone) {
+ dns_notify_t *notify;
+
+ /*
+ * 'zone' locked by caller.
+ */
+
+ REQUIRE(LOCKED_ZONE(zone));
+
+ for (notify = ISC_LIST_HEAD(zone->notifies);
+ notify != NULL;
+ notify = ISC_LIST_NEXT(notify, link)) {
+ if (notify->find != NULL)
+ dns_adb_cancelfind(notify->find);
+ if (notify->request != NULL)
+ dns_request_cancel(notify->request);
+ }
+}
+
+static void
+zone_unload(dns_zone_t *zone) {
+
+ /*
+ * 'zone' locked by caller.
+ */
+
+ REQUIRE(LOCKED_ZONE(zone));
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write);
+ zone_detachdb(zone);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADED);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
+}
+
+void
+dns_zone_setminrefreshtime(dns_zone_t *zone, isc_uint32_t val) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(val > 0);
+
+ zone->minrefresh = val;
+}
+
+void
+dns_zone_setmaxrefreshtime(dns_zone_t *zone, isc_uint32_t val) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(val > 0);
+
+ zone->maxrefresh = val;
+}
+
+void
+dns_zone_setminretrytime(dns_zone_t *zone, isc_uint32_t val) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(val > 0);
+
+ zone->minretry = val;
+}
+
+void
+dns_zone_setmaxretrytime(dns_zone_t *zone, isc_uint32_t val) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(val > 0);
+
+ zone->maxretry = val;
+}
+
+static isc_boolean_t
+notify_isqueued(dns_zone_t *zone, dns_name_t *name, isc_sockaddr_t *addr) {
+ dns_notify_t *notify;
+
+ for (notify = ISC_LIST_HEAD(zone->notifies);
+ notify != NULL;
+ notify = ISC_LIST_NEXT(notify, link)) {
+ if (notify->request != NULL)
+ continue;
+ if (name != NULL && dns_name_dynamic(&notify->ns) &&
+ dns_name_equal(name, &notify->ns))
+ return (ISC_TRUE);
+ if (addr != NULL && isc_sockaddr_equal(addr, &notify->dst))
+ return (ISC_TRUE);
+ }
+ return (ISC_FALSE);
+}
+
+static isc_boolean_t
+notify_isself(dns_zone_t *zone, isc_sockaddr_t *dst) {
+ dns_tsigkey_t *key = NULL;
+ isc_sockaddr_t src;
+ isc_sockaddr_t any;
+ isc_boolean_t isself;
+ isc_netaddr_t dstaddr;
+
+ if (zone->view == NULL || zone->isself == NULL)
+ return (ISC_FALSE);
+
+ switch (isc_sockaddr_pf(dst)) {
+ case PF_INET:
+ src = zone->notifysrc4;
+ isc_sockaddr_any(&any);
+ break;
+ case PF_INET6:
+ src = zone->notifysrc6;
+ isc_sockaddr_any6(&any);
+ break;
+ default:
+ return (ISC_FALSE);
+ }
+
+ /*
+ * When sending from any the kernel will assign a source address
+ * that matches the destination address.
+ */
+ if (isc_sockaddr_eqaddr(&any, &src))
+ src = *dst;
+
+ isc_netaddr_fromsockaddr(&dstaddr, dst);
+ (void)dns_view_getpeertsig(zone->view, &dstaddr, &key);
+ isself = (zone->isself)(zone->view, key, &src, dst, zone->rdclass,
+ zone->isselfarg);
+ if (key != NULL)
+ dns_tsigkey_detach(&key);
+ return (isself);
+}
+
+static void
+notify_destroy(dns_notify_t *notify, isc_boolean_t locked) {
+ isc_mem_t *mctx;
+
+ /*
+ * Caller holds zone lock.
+ */
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+
+ if (notify->zone != NULL) {
+ if (!locked)
+ LOCK_ZONE(notify->zone);
+ REQUIRE(LOCKED_ZONE(notify->zone));
+ if (ISC_LINK_LINKED(notify, link))
+ ISC_LIST_UNLINK(notify->zone->notifies, notify, link);
+ if (!locked)
+ UNLOCK_ZONE(notify->zone);
+ if (locked)
+ zone_idetach(&notify->zone);
+ else
+ dns_zone_idetach(&notify->zone);
+ }
+ if (notify->find != NULL)
+ dns_adb_destroyfind(&notify->find);
+ if (notify->request != NULL)
+ dns_request_destroy(&notify->request);
+ if (dns_name_dynamic(&notify->ns))
+ dns_name_free(&notify->ns, notify->mctx);
+ mctx = notify->mctx;
+ isc_mem_put(notify->mctx, notify, sizeof(*notify));
+ isc_mem_detach(&mctx);
+}
+
+static isc_result_t
+notify_create(isc_mem_t *mctx, unsigned int flags, dns_notify_t **notifyp) {
+ dns_notify_t *notify;
+
+ REQUIRE(notifyp != NULL && *notifyp == NULL);
+
+ notify = isc_mem_get(mctx, sizeof(*notify));
+ if (notify == NULL)
+ return (ISC_R_NOMEMORY);
+
+ notify->mctx = NULL;
+ isc_mem_attach(mctx, &notify->mctx);
+ notify->flags = flags;
+ notify->zone = NULL;
+ notify->find = NULL;
+ notify->request = NULL;
+ isc_sockaddr_any(&notify->dst);
+ dns_name_init(&notify->ns, NULL);
+ ISC_LINK_INIT(notify, link);
+ notify->magic = NOTIFY_MAGIC;
+ *notifyp = notify;
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * XXXAG should check for DNS_ZONEFLG_EXITING
+ */
+static void
+process_adb_event(isc_task_t *task, isc_event_t *ev) {
+ dns_notify_t *notify;
+ isc_eventtype_t result;
+
+ UNUSED(task);
+
+ notify = ev->ev_arg;
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+ INSIST(task == notify->zone->task);
+ result = ev->ev_type;
+ isc_event_free(&ev);
+ if (result == DNS_EVENT_ADBMOREADDRESSES) {
+ dns_adb_destroyfind(&notify->find);
+ notify_find_address(notify);
+ return;
+ }
+ if (result == DNS_EVENT_ADBNOMOREADDRESSES) {
+ LOCK_ZONE(notify->zone);
+ notify_send(notify);
+ UNLOCK_ZONE(notify->zone);
+ }
+ notify_destroy(notify, ISC_FALSE);
+}
+
+static void
+notify_find_address(dns_notify_t *notify) {
+ isc_result_t result;
+ unsigned int options;
+
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+ options = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_INET |
+ DNS_ADBFIND_INET6 | DNS_ADBFIND_RETURNLAME;
+
+ if (notify->zone->view->adb == NULL)
+ goto destroy;
+
+ result = dns_adb_createfind(notify->zone->view->adb,
+ notify->zone->task,
+ process_adb_event, notify,
+ &notify->ns, dns_rootname, 0,
+ options, 0, NULL,
+ notify->zone->view->dstport,
+ &notify->find);
+
+ /* Something failed? */
+ if (result != ISC_R_SUCCESS)
+ goto destroy;
+
+ /* More addresses pending? */
+ if ((notify->find->options & DNS_ADBFIND_WANTEVENT) != 0)
+ return;
+
+ /* We have as many addresses as we can get. */
+ LOCK_ZONE(notify->zone);
+ notify_send(notify);
+ UNLOCK_ZONE(notify->zone);
+
+ destroy:
+ notify_destroy(notify, ISC_FALSE);
+}
+
+
+static isc_result_t
+notify_send_queue(dns_notify_t *notify) {
+ isc_event_t *e;
+ isc_result_t result;
+
+ e = isc_event_allocate(notify->mctx, NULL,
+ DNS_EVENT_NOTIFYSENDTOADDR,
+ notify_send_toaddr,
+ notify, sizeof(isc_event_t));
+ if (e == NULL)
+ return (ISC_R_NOMEMORY);
+ e->ev_arg = notify;
+ e->ev_sender = NULL;
+ result = isc_ratelimiter_enqueue(notify->zone->zmgr->rl,
+ notify->zone->task, &e);
+ if (result != ISC_R_SUCCESS)
+ isc_event_free(&e);
+ return (result);
+}
+
+static void
+notify_send_toaddr(isc_task_t *task, isc_event_t *event) {
+ dns_notify_t *notify;
+ isc_result_t result;
+ dns_message_t *message = NULL;
+ isc_netaddr_t dstip;
+ dns_tsigkey_t *key = NULL;
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_t src;
+ int timeout;
+ isc_boolean_t have_notifysource = ISC_FALSE;
+
+ notify = event->ev_arg;
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+
+ UNUSED(task);
+
+ LOCK_ZONE(notify->zone);
+
+ if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_LOADED) == 0) {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0 ||
+ DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_EXITING) ||
+ notify->zone->view->requestmgr == NULL ||
+ notify->zone->db == NULL) {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ /*
+ * The raw IPv4 address should also exist. Don't send to the
+ * mapped form.
+ */
+ if (isc_sockaddr_pf(&notify->dst) == PF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED(&notify->dst.type.sin6.sin6_addr)) {
+ isc_sockaddr_format(&notify->dst, addrbuf, sizeof(addrbuf));
+ notify_log(notify->zone, ISC_LOG_DEBUG(3),
+ "notify: ignoring IPv6 mapped IPV4 address: %s",
+ addrbuf);
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ result = notify_createmessage(notify->zone, notify->flags, &message);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ isc_netaddr_fromsockaddr(&dstip, &notify->dst);
+ (void)dns_view_getpeertsig(notify->zone->view, &dstip, &key);
+
+ isc_sockaddr_format(&notify->dst, addrbuf, sizeof(addrbuf));
+ notify_log(notify->zone, ISC_LOG_DEBUG(3), "sending notify to %s",
+ addrbuf);
+ if (notify->zone->view->peers != NULL) {
+ dns_peer_t *peer = NULL;
+ result = dns_peerlist_peerbyaddr(notify->zone->view->peers,
+ &dstip, &peer);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_peer_getnotifysource(peer, &src);
+ if (result == ISC_R_SUCCESS)
+ have_notifysource = ISC_TRUE;
+ }
+ }
+ switch (isc_sockaddr_pf(&notify->dst)) {
+ case PF_INET:
+ if (!have_notifysource)
+ src = notify->zone->notifysrc4;
+ break;
+ case PF_INET6:
+ if (!have_notifysource)
+ src = notify->zone->notifysrc6;
+ break;
+ default:
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup_key;
+ }
+ timeout = 15;
+ if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_DIALNOTIFY))
+ timeout = 30;
+ result = dns_request_createvia2(notify->zone->view->requestmgr,
+ message, &src, &notify->dst, 0, key,
+ timeout * 3, timeout,
+ notify->zone->task, notify_done,
+ notify, &notify->request);
+ cleanup_key:
+ if (key != NULL)
+ dns_tsigkey_detach(&key);
+ dns_message_destroy(&message);
+ cleanup:
+ UNLOCK_ZONE(notify->zone);
+ if (result != ISC_R_SUCCESS)
+ notify_destroy(notify, ISC_FALSE);
+ isc_event_free(&event);
+}
+
+static void
+notify_send(dns_notify_t *notify) {
+ dns_adbaddrinfo_t *ai;
+ isc_sockaddr_t dst;
+ isc_result_t result;
+ dns_notify_t *new = NULL;
+
+ /*
+ * Zone lock held by caller.
+ */
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+ REQUIRE(LOCKED_ZONE(notify->zone));
+
+ for (ai = ISC_LIST_HEAD(notify->find->list);
+ ai != NULL;
+ ai = ISC_LIST_NEXT(ai, publink)) {
+ dst = ai->sockaddr;
+ if (notify_isqueued(notify->zone, NULL, &dst))
+ continue;
+ if (notify_isself(notify->zone, &dst))
+ continue;
+ new = NULL;
+ result = notify_create(notify->mctx,
+ (notify->flags & DNS_NOTIFY_NOSOA),
+ &new);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ zone_iattach(notify->zone, &new->zone);
+ ISC_LIST_APPEND(new->zone->notifies, new, link);
+ new->dst = dst;
+ result = notify_send_queue(new);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ new = NULL;
+ }
+
+ cleanup:
+ if (new != NULL)
+ notify_destroy(new, ISC_TRUE);
+}
+
+void
+dns_zone_notify(dns_zone_t *zone) {
+ isc_time_t now;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
+
+ TIME_NOW(&now);
+ zone_settimer(zone, &now);
+ UNLOCK_ZONE(zone);
+}
+
+static void
+zone_notify(dns_zone_t *zone, isc_time_t *now) {
+ dns_dbnode_t *node = NULL;
+ dns_db_t *zonedb = NULL;
+ dns_dbversion_t *version = NULL;
+ dns_name_t *origin = NULL;
+ dns_name_t master;
+ dns_rdata_ns_t ns;
+ dns_rdata_soa_t soa;
+ isc_uint32_t serial;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t nsrdset;
+ dns_rdataset_t soardset;
+ isc_result_t result;
+ dns_notify_t *notify = NULL;
+ unsigned int i;
+ isc_sockaddr_t dst;
+ isc_boolean_t isqueued;
+ dns_notifytype_t notifytype;
+ unsigned int flags = 0;
+ isc_boolean_t loggednotify = ISC_FALSE;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
+ notifytype = zone->notifytype;
+ DNS_ZONE_TIME_ADD(now, zone->notifydelay, &zone->notifytime);
+ UNLOCK_ZONE(zone);
+
+ if (! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED))
+ return;
+
+ if (notifytype == dns_notifytype_no)
+ return;
+
+ if (notifytype == dns_notifytype_masteronly &&
+ zone->type != dns_zone_master)
+ return;
+
+ origin = &zone->origin;
+
+ /*
+ * If the zone is dialup we are done as we don't want to send
+ * the current soa so as to force a refresh query.
+ */
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY))
+ flags |= DNS_NOTIFY_NOSOA;
+
+ /*
+ * Get SOA RRset.
+ */
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db != NULL)
+ dns_db_attach(zone->db, &zonedb);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zonedb == NULL)
+ return;
+ dns_db_currentversion(zonedb, &version);
+ result = dns_db_findnode(zonedb, origin, ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup1;
+
+ dns_rdataset_init(&soardset);
+ result = dns_db_findrdataset(zonedb, node, version, dns_rdatatype_soa,
+ dns_rdatatype_none, 0, &soardset, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup2;
+
+ /*
+ * Find serial and master server's name.
+ */
+ dns_name_init(&master, NULL);
+ result = dns_rdataset_first(&soardset);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup3;
+ dns_rdataset_current(&soardset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &soa, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ dns_rdata_reset(&rdata);
+ result = dns_name_dup(&soa.origin, zone->mctx, &master);
+ serial = soa.serial;
+ dns_rdataset_disassociate(&soardset);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup3;
+
+ /*
+ * Enqueue notify requests for 'also-notify' servers.
+ */
+ LOCK_ZONE(zone);
+ for (i = 0; i < zone->notifycnt; i++) {
+ dst = zone->notify[i];
+ if (notify_isqueued(zone, NULL, &dst))
+ continue;
+ result = notify_create(zone->mctx, flags, &notify);
+ if (result != ISC_R_SUCCESS)
+ continue;
+ zone_iattach(zone, &notify->zone);
+ notify->dst = dst;
+ ISC_LIST_APPEND(zone->notifies, notify, link);
+ result = notify_send_queue(notify);
+ if (result != ISC_R_SUCCESS)
+ notify_destroy(notify, ISC_TRUE);
+ if (!loggednotify) {
+ notify_log(zone, ISC_LOG_INFO,
+ "sending notifies (serial %u)",
+ serial);
+ loggednotify = ISC_TRUE;
+ }
+ notify = NULL;
+ }
+ UNLOCK_ZONE(zone);
+
+ if (notifytype == dns_notifytype_explicit)
+ goto cleanup3;
+
+ /*
+ * Process NS RRset to generate notifies.
+ */
+
+ dns_rdataset_init(&nsrdset);
+ result = dns_db_findrdataset(zonedb, node, version, dns_rdatatype_ns,
+ dns_rdatatype_none, 0, &nsrdset, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup3;
+
+ result = dns_rdataset_first(&nsrdset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&nsrdset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &ns, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ dns_rdata_reset(&rdata);
+ /*
+ * don't notify the master server.
+ */
+ if (dns_name_compare(&master, &ns.name) == 0) {
+ result = dns_rdataset_next(&nsrdset);
+ continue;
+ }
+
+ if (!loggednotify) {
+ notify_log(zone, ISC_LOG_INFO,
+ "sending notifies (serial %u)",
+ serial);
+ loggednotify = ISC_TRUE;
+ }
+
+ LOCK_ZONE(zone);
+ isqueued = notify_isqueued(zone, &ns.name, NULL);
+ UNLOCK_ZONE(zone);
+ if (isqueued) {
+ result = dns_rdataset_next(&nsrdset);
+ continue;
+ }
+ result = notify_create(zone->mctx, flags, &notify);
+ if (result != ISC_R_SUCCESS)
+ continue;
+ dns_zone_iattach(zone, &notify->zone);
+ result = dns_name_dup(&ns.name, zone->mctx, &notify->ns);
+ if (result != ISC_R_SUCCESS) {
+ LOCK_ZONE(zone);
+ notify_destroy(notify, ISC_TRUE);
+ UNLOCK_ZONE(zone);
+ continue;
+ }
+ LOCK_ZONE(zone);
+ ISC_LIST_APPEND(zone->notifies, notify, link);
+ UNLOCK_ZONE(zone);
+ notify_find_address(notify);
+ notify = NULL;
+ result = dns_rdataset_next(&nsrdset);
+ }
+ dns_rdataset_disassociate(&nsrdset);
+
+ cleanup3:
+ if (dns_name_dynamic(&master))
+ dns_name_free(&master, zone->mctx);
+ cleanup2:
+ dns_db_detachnode(zonedb, &node);
+ cleanup1:
+ dns_db_closeversion(zonedb, &version, ISC_FALSE);
+ dns_db_detach(&zonedb);
+}
+
+/***
+ *** Private
+ ***/
+
+static inline isc_result_t
+save_nsrrset(dns_message_t *message, dns_name_t *name,
+ dns_db_t *db, dns_dbversion_t *version)
+{
+ dns_rdataset_t *nsrdataset = NULL;
+ dns_rdataset_t *rdataset = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_rdata_ns_t ns;
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ /*
+ * Extract NS RRset from message.
+ */
+ result = dns_message_findname(message, DNS_SECTION_ANSWER, name,
+ dns_rdatatype_ns, dns_rdatatype_none,
+ NULL, &nsrdataset);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+
+ /*
+ * Add NS rdataset.
+ */
+ result = dns_db_findnode(db, name, ISC_TRUE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+ result = dns_db_addrdataset(db, node, version, 0,
+ nsrdataset, 0, NULL);
+ dns_db_detachnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+ /*
+ * Add glue rdatasets.
+ */
+ for (result = dns_rdataset_first(nsrdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(nsrdataset)) {
+ dns_rdataset_current(nsrdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &ns, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ dns_rdata_reset(&rdata);
+ if (!dns_name_issubdomain(&ns.name, name))
+ continue;
+ rdataset = NULL;
+ result = dns_message_findname(message, DNS_SECTION_ADDITIONAL,
+ &ns.name, dns_rdatatype_aaaa,
+ dns_rdatatype_none, NULL,
+ &rdataset);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_db_findnode(db, &ns.name,
+ ISC_TRUE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+ result = dns_db_addrdataset(db, node, version, 0,
+ rdataset, 0, NULL);
+ dns_db_detachnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+ }
+ rdataset = NULL;
+ result = dns_message_findname(message, DNS_SECTION_ADDITIONAL,
+ &ns.name, dns_rdatatype_a,
+ dns_rdatatype_none, NULL,
+ &rdataset);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_db_findnode(db, &ns.name,
+ ISC_TRUE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+ result = dns_db_addrdataset(db, node, version, 0,
+ rdataset, 0, NULL);
+ dns_db_detachnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+ }
+ }
+ if (result != ISC_R_NOMORE)
+ goto fail;
+
+ return (ISC_R_SUCCESS);
+
+fail:
+ return (result);
+}
+
+static void
+stub_callback(isc_task_t *task, isc_event_t *event) {
+ const char me[] = "stub_callback";
+ dns_requestevent_t *revent = (dns_requestevent_t *)event;
+ dns_stub_t *stub = NULL;
+ dns_message_t *msg = NULL;
+ dns_zone_t *zone = NULL;
+ char master[ISC_SOCKADDR_FORMATSIZE];
+ char source[ISC_SOCKADDR_FORMATSIZE];
+ isc_uint32_t nscnt, cnamecnt;
+ isc_result_t result;
+ isc_time_t now;
+ isc_boolean_t exiting = ISC_FALSE;
+ isc_interval_t i;
+ unsigned int j;
+
+ stub = revent->ev_arg;
+ INSIST(DNS_STUB_VALID(stub));
+
+ UNUSED(task);
+
+ zone = stub->zone;
+
+ ENTER;
+
+ TIME_NOW(&now);
+
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
+ zone_debuglog(zone, me, 1, "exiting");
+ exiting = ISC_TRUE;
+ goto next_master;
+ }
+
+ isc_sockaddr_format(&zone->masteraddr, master, sizeof(master));
+ isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source));
+
+ if (revent->result != ISC_R_SUCCESS) {
+ if (revent->result == ISC_R_TIMEDOUT &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) {
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS);
+ UNLOCK_ZONE(zone);
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "refreshing stub: timeout retrying "
+ " without EDNS master %s (source %s)",
+ master, source);
+ goto same_master;
+ }
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "could not refresh stub from master %s"
+ " (source %s): %s", master, source,
+ dns_result_totext(revent->result));
+ goto next_master;
+ }
+
+ result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg);
+ if (result != ISC_R_SUCCESS)
+ goto next_master;
+
+ result = dns_request_getresponse(revent->request, msg, 0);
+ if (result != ISC_R_SUCCESS)
+ goto next_master;
+
+ /*
+ * Unexpected rcode.
+ */
+ if (msg->rcode != dns_rcode_noerror) {
+ char rcode[128];
+ isc_buffer_t rb;
+
+ isc_buffer_init(&rb, rcode, sizeof(rcode));
+ (void)dns_rcode_totext(msg->rcode, &rb);
+
+ if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS) &&
+ (msg->rcode == dns_rcode_servfail ||
+ msg->rcode == dns_rcode_notimp ||
+ msg->rcode == dns_rcode_formerr)) {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "refreshing stub: rcode (%.*s) retrying "
+ "without EDNS master %s (source %s)",
+ (int)rb.used, rcode, master, source);
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS);
+ UNLOCK_ZONE(zone);
+ goto same_master;
+ }
+
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refreshing stub: "
+ "unexpected rcode (%.*s) from %s (source %s)",
+ (int)rb.used, rcode, master, source);
+ goto next_master;
+ }
+
+ /*
+ * We need complete messages.
+ */
+ if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
+ if (dns_request_usedtcp(revent->request)) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refreshing stub: truncated TCP "
+ "response from master %s (source %s)",
+ master, source);
+ goto next_master;
+ }
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEVC);
+ UNLOCK_ZONE(zone);
+ goto same_master;
+ }
+
+ /*
+ * If non-auth log and next master.
+ */
+ if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) {
+ dns_zone_log(zone, ISC_LOG_INFO, "refreshing stub: "
+ "non-authoritative answer from "
+ "master %s (source %s)", master, source);
+ goto next_master;
+ }
+
+ /*
+ * Sanity checks.
+ */
+ cnamecnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_cname);
+ nscnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_ns);
+
+ if (cnamecnt != 0) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refreshing stub: unexpected CNAME response "
+ "from master %s (source %s)", master, source);
+ goto next_master;
+ }
+
+ if (nscnt == 0) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refreshing stub: no NS records in response "
+ "from master %s (source %s)", master, source);
+ goto next_master;
+ }
+
+ /*
+ * Save answer.
+ */
+ result = save_nsrrset(msg, &zone->origin, stub->db, stub->version);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refreshing stub: unable to save NS records "
+ "from master %s (source %s)", master, source);
+ goto next_master;
+ }
+
+ /*
+ * Tidy up.
+ */
+ dns_db_closeversion(stub->db, &stub->version, ISC_TRUE);
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write);
+ if (zone->db == NULL)
+ zone_attachdb(zone, stub->db);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
+ dns_db_detach(&stub->db);
+
+ if (zone->masterfile != NULL) {
+ dns_zone_dump(zone);
+ TIME_NOW(&zone->loadtime);
+ }
+
+ dns_message_destroy(&msg);
+ isc_event_free(&event);
+ LOCK_ZONE(zone);
+ dns_request_destroy(&zone->request);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH);
+ DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime);
+ isc_interval_set(&i, zone->expire, 0);
+ DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime);
+ zone_settimer(zone, &now);
+ UNLOCK_ZONE(zone);
+ goto free_stub;
+
+ next_master:
+ if (stub->version != NULL)
+ dns_db_closeversion(stub->db, &stub->version, ISC_FALSE);
+ if (stub->db != NULL)
+ dns_db_detach(&stub->db);
+ if (msg != NULL)
+ dns_message_destroy(&msg);
+ isc_event_free(&event);
+ LOCK_ZONE(zone);
+ dns_request_destroy(&zone->request);
+ /*
+ * Skip to next failed / untried master.
+ */
+ do {
+ zone->curmaster++;
+ } while (zone->curmaster < zone->masterscnt &&
+ zone->mastersok[zone->curmaster]);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS);
+ if (exiting || zone->curmaster >= zone->masterscnt) {
+ isc_boolean_t done = ISC_TRUE;
+ if (!exiting &&
+ DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) {
+ /*
+ * Did we get a good answer from all the masters?
+ */
+ for (j = 0; j < zone->masterscnt; j++)
+ if (zone->mastersok[j] == ISC_FALSE) {
+ done = ISC_FALSE;
+ break;
+ }
+ } else
+ done = ISC_TRUE;
+ if (!done) {
+ zone->curmaster = 0;
+ /*
+ * Find the next failed master.
+ */
+ while (zone->curmaster < zone->masterscnt &&
+ zone->mastersok[zone->curmaster])
+ zone->curmaster++;
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC);
+ } else {
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH);
+
+ zone_settimer(zone, &now);
+ UNLOCK_ZONE(zone);
+ goto free_stub;
+ }
+ }
+ queue_soa_query(zone);
+ UNLOCK_ZONE(zone);
+ goto free_stub;
+
+ same_master:
+ if (msg != NULL)
+ dns_message_destroy(&msg);
+ isc_event_free(&event);
+ LOCK_ZONE(zone);
+ dns_request_destroy(&zone->request);
+ UNLOCK_ZONE(zone);
+ ns_query(zone, NULL, stub);
+ goto done;
+
+ free_stub:
+ stub->magic = 0;
+ dns_zone_idetach(&stub->zone);
+ INSIST(stub->db == NULL);
+ INSIST(stub->version == NULL);
+ isc_mem_put(stub->mctx, stub, sizeof(*stub));
+
+ done:
+ INSIST(event == NULL);
+ return;
+}
+
+/*
+ * An SOA query has finished (successfully or not).
+ */
+static void
+refresh_callback(isc_task_t *task, isc_event_t *event) {
+ const char me[] = "refresh_callback";
+ dns_requestevent_t *revent = (dns_requestevent_t *)event;
+ dns_zone_t *zone;
+ dns_message_t *msg = NULL;
+ isc_uint32_t soacnt, cnamecnt, soacount, nscount;
+ isc_time_t now;
+ char master[ISC_SOCKADDR_FORMATSIZE];
+ char source[ISC_SOCKADDR_FORMATSIZE];
+ dns_rdataset_t *rdataset = NULL;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_soa_t soa;
+ isc_result_t result;
+ isc_uint32_t serial;
+ unsigned int j;
+
+ zone = revent->ev_arg;
+ INSIST(DNS_ZONE_VALID(zone));
+
+ UNUSED(task);
+
+ ENTER;
+
+ /*
+ * if timeout log and next master;
+ */
+
+ isc_sockaddr_format(&zone->masteraddr, master, sizeof(master));
+ isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source));
+
+ TIME_NOW(&now);
+
+ if (revent->result != ISC_R_SUCCESS) {
+ if (revent->result == ISC_R_TIMEDOUT &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) {
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS);
+ UNLOCK_ZONE(zone);
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "refresh: timeout retrying without EDNS "
+ "master %s (source %s)", master, source);
+ goto same_master;
+ }
+ if (revent->result == ISC_R_TIMEDOUT &&
+ !dns_request_usedtcp(revent->request)) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: retry limit for "
+ "master %s exceeded (source %s)",
+ master, source);
+ /* Try with slave with TCP. */
+ if (zone->type == dns_zone_slave) {
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone,
+ DNS_ZONEFLG_SOABEFOREAXFR);
+ UNLOCK_ZONE(zone);
+ goto tcp_transfer;
+ }
+ } else
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: failure trying master "
+ "%s (source %s): %s", master, source,
+ dns_result_totext(revent->result));
+ goto next_master;
+ }
+
+ result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg);
+ if (result != ISC_R_SUCCESS)
+ goto next_master;
+ result = dns_request_getresponse(revent->request, msg, 0);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: failure trying master "
+ "%s (source %s): %s", master, source,
+ dns_result_totext(result));
+ goto next_master;
+ }
+
+ /*
+ * Unexpected rcode.
+ */
+ if (msg->rcode != dns_rcode_noerror) {
+ char rcode[128];
+ isc_buffer_t rb;
+
+ isc_buffer_init(&rb, rcode, sizeof(rcode));
+ (void)dns_rcode_totext(msg->rcode, &rb);
+
+ if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS) &&
+ (msg->rcode == dns_rcode_servfail ||
+ msg->rcode == dns_rcode_notimp ||
+ msg->rcode == dns_rcode_formerr)) {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "refresh: rcode (%.*s) retrying without "
+ "EDNS master %s (source %s)",
+ (int)rb.used, rcode, master, source);
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS);
+ UNLOCK_ZONE(zone);
+ goto same_master;
+ }
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: unexpected rcode (%.*s) from "
+ "master %s (source %s)", (int)rb.used, rcode,
+ master, source);
+ /*
+ * Perhaps AXFR/IXFR is allowed even if SOA queries arn't.
+ */
+ if (msg->rcode == dns_rcode_refused &&
+ zone->type == dns_zone_slave)
+ goto tcp_transfer;
+ goto next_master;
+ }
+
+ /*
+ * If truncated punt to zone transfer which will query again.
+ */
+ if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
+ if (zone->type == dns_zone_slave) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: truncated UDP answer, "
+ "initiating TCP zone xfer "
+ "for master %s (source %s)",
+ master, source);
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR);
+ UNLOCK_ZONE(zone);
+ goto tcp_transfer;
+ } else {
+ INSIST(zone->type == dns_zone_stub);
+ if (dns_request_usedtcp(revent->request)) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: truncated TCP response "
+ "from master %s (source %s)",
+ master, source);
+ goto next_master;
+ }
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEVC);
+ UNLOCK_ZONE(zone);
+ goto same_master;
+ }
+ }
+
+ /*
+ * if non-auth log and next master;
+ */
+ if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: non-authoritative answer from "
+ "master %s (source %s)", master, source);
+ goto next_master;
+ }
+
+ cnamecnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_cname);
+ soacnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_soa);
+ nscount = message_count(msg, DNS_SECTION_AUTHORITY, dns_rdatatype_ns);
+ soacount = message_count(msg, DNS_SECTION_AUTHORITY,
+ dns_rdatatype_soa);
+
+ /*
+ * There should not be a CNAME record at top of zone.
+ */
+ if (cnamecnt != 0) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: CNAME at top of zone "
+ "in master %s (source %s)", master, source);
+ goto next_master;
+ }
+
+ /*
+ * if referral log and next master;
+ */
+ if (soacnt == 0 && soacount == 0 && nscount != 0) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: referral response "
+ "from master %s (source %s)", master, source);
+ goto next_master;
+ }
+
+ /*
+ * if nodata log and next master;
+ */
+ if (soacnt == 0 && (nscount == 0 || soacount != 0)) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: NODATA response "
+ "from master %s (source %s)", master, source);
+ goto next_master;
+ }
+
+ /*
+ * Only one soa at top of zone.
+ */
+ if (soacnt != 1) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: answer SOA count (%d) != 1 "
+ "from master %s (source %s)",
+ soacnt, master, source);
+ goto next_master;
+ }
+ /*
+ * Extract serial
+ */
+ rdataset = NULL;
+ result = dns_message_findname(msg, DNS_SECTION_ANSWER, &zone->origin,
+ dns_rdatatype_soa, dns_rdatatype_none,
+ NULL, &rdataset);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: unable to get SOA record "
+ "from master %s (source %s)", master, source);
+ goto next_master;
+ }
+
+ result = dns_rdataset_first(rdataset);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refresh: dns_rdataset_first() failed");
+ goto next_master;
+ }
+
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &soa, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ serial = soa.serial;
+
+ zone_debuglog(zone, me, 1, "serial: new %u, old %u",
+ serial, zone->serial);
+ if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) ||
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) ||
+ isc_serial_gt(serial, zone->serial)) {
+ tcp_transfer:
+ isc_event_free(&event);
+ LOCK_ZONE(zone);
+ dns_request_destroy(&zone->request);
+ UNLOCK_ZONE(zone);
+ if (zone->type == dns_zone_slave) {
+ queue_xfrin(zone);
+ } else {
+ INSIST(zone->type == dns_zone_stub);
+ ns_query(zone, rdataset, NULL);
+ }
+ if (msg != NULL)
+ dns_message_destroy(&msg);
+ } else if (isc_serial_eq(soa.serial, zone->serial)) {
+ if (zone->masterfile != NULL) {
+ result = ISC_R_FAILURE;
+ if (zone->journal != NULL)
+ result = isc_file_settime(zone->journal, &now);
+ if (result == ISC_R_SUCCESS &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) {
+ result = isc_file_settime(zone->masterfile,
+ &now);
+ } else if (result != ISC_R_SUCCESS)
+ result = isc_file_settime(zone->masterfile,
+ &now);
+ /* Someone removed the file from underneath us! */
+ if (result == ISC_R_FILENOTFOUND) {
+ LOCK_ZONE(zone);
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ UNLOCK_ZONE(zone);
+ } else if (result != ISC_R_SUCCESS)
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "refresh: could not set file "
+ "modification time of '%s': %s",
+ zone->masterfile,
+ dns_result_totext(result));
+ }
+ DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime);
+ DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime);
+ zone->mastersok[zone->curmaster] = ISC_TRUE;
+ goto next_master;
+ } else {
+ if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MULTIMASTER))
+ dns_zone_log(zone, ISC_LOG_INFO, "serial number (%u) "
+ "received from master %s < ours (%u)",
+ soa.serial, master, zone->serial);
+ else
+ zone_debuglog(zone, me, 1, "ahead");
+ zone->mastersok[zone->curmaster] = ISC_TRUE;
+ goto next_master;
+ }
+ if (msg != NULL)
+ dns_message_destroy(&msg);
+ goto detach;
+
+ next_master:
+ if (msg != NULL)
+ dns_message_destroy(&msg);
+ isc_event_free(&event);
+ LOCK_ZONE(zone);
+ dns_request_destroy(&zone->request);
+ /*
+ * Skip to next failed / untried master.
+ */
+ do {
+ zone->curmaster++;
+ } while (zone->curmaster < zone->masterscnt &&
+ zone->mastersok[zone->curmaster]);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS);
+ if (zone->curmaster >= zone->masterscnt) {
+ isc_boolean_t done = ISC_TRUE;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) {
+ /*
+ * Did we get a good answer from all the masters?
+ */
+ for (j = 0; j < zone->masterscnt; j++)
+ if (zone->mastersok[j] == ISC_FALSE) {
+ done = ISC_FALSE;
+ break;
+ }
+ } else
+ done = ISC_TRUE;
+ if (!done) {
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC);
+ zone->curmaster = 0;
+ /*
+ * Find the next failed master.
+ */
+ while (zone->curmaster < zone->masterscnt &&
+ zone->mastersok[zone->curmaster])
+ zone->curmaster++;
+ goto requeue;
+ }
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH);
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDREFRESH)) {
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDREFRESH);
+ zone->refreshtime = now;
+ }
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC);
+ zone_settimer(zone, &now);
+ UNLOCK_ZONE(zone);
+ goto detach;
+ }
+
+ requeue:
+ queue_soa_query(zone);
+ UNLOCK_ZONE(zone);
+ goto detach;
+
+ same_master:
+ if (msg != NULL)
+ dns_message_destroy(&msg);
+ isc_event_free(&event);
+ LOCK_ZONE(zone);
+ dns_request_destroy(&zone->request);
+ queue_soa_query(zone);
+ UNLOCK_ZONE(zone);
+
+ detach:
+ dns_zone_idetach(&zone);
+ return;
+}
+
+static void
+queue_soa_query(dns_zone_t *zone) {
+ const char me[] = "queue_soa_query";
+ isc_event_t *e;
+ dns_zone_t *dummy = NULL;
+ isc_result_t result;
+
+ ENTER;
+ /*
+ * Locked by caller
+ */
+ REQUIRE(LOCKED_ZONE(zone));
+
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
+ cancel_refresh(zone);
+ return;
+ }
+
+ e = isc_event_allocate(zone->mctx, NULL, DNS_EVENT_ZONE,
+ soa_query, zone, sizeof(isc_event_t));
+ if (e == NULL) {
+ cancel_refresh(zone);
+ return;
+ }
+
+ /*
+ * Attach so that we won't clean up
+ * until the event is delivered.
+ */
+ zone_iattach(zone, &dummy);
+
+ e->ev_arg = zone;
+ e->ev_sender = NULL;
+ result = isc_ratelimiter_enqueue(zone->zmgr->rl, zone->task, &e);
+ if (result != ISC_R_SUCCESS) {
+ zone_idetach(&dummy);
+ isc_event_free(&e);
+ cancel_refresh(zone);
+ }
+}
+
+static inline isc_result_t
+create_query(dns_zone_t *zone, dns_rdatatype_t rdtype,
+ dns_message_t **messagep)
+{
+ dns_message_t *message = NULL;
+ dns_name_t *qname = NULL;
+ dns_rdataset_t *qrdataset = NULL;
+ isc_result_t result;
+
+ result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER,
+ &message);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ message->opcode = dns_opcode_query;
+ message->rdclass = zone->rdclass;
+
+ result = dns_message_gettempname(message, &qname);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = dns_message_gettemprdataset(message, &qrdataset);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ /*
+ * Make question.
+ */
+ dns_name_init(qname, NULL);
+ dns_name_clone(&zone->origin, qname);
+ dns_rdataset_init(qrdataset);
+ dns_rdataset_makequestion(qrdataset, zone->rdclass, rdtype);
+ ISC_LIST_APPEND(qname->list, qrdataset, link);
+ dns_message_addname(message, qname, DNS_SECTION_QUESTION);
+
+ *messagep = message;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (qname != NULL)
+ dns_message_puttempname(message, &qname);
+ if (qrdataset != NULL)
+ dns_message_puttemprdataset(message, &qrdataset);
+ if (message != NULL)
+ dns_message_destroy(&message);
+ return (result);
+}
+
+static isc_result_t
+add_opt(dns_message_t *message, isc_uint16_t udpsize) {
+ dns_rdataset_t *rdataset = NULL;
+ dns_rdatalist_t *rdatalist = NULL;
+ dns_rdata_t *rdata = NULL;
+ isc_result_t result;
+
+ result = dns_message_gettemprdatalist(message, &rdatalist);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_message_gettemprdata(message, &rdata);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_message_gettemprdataset(message, &rdataset);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ dns_rdataset_init(rdataset);
+
+ rdatalist->type = dns_rdatatype_opt;
+ rdatalist->covers = 0;
+
+ /*
+ * Set Maximum UDP buffer size.
+ */
+ rdatalist->rdclass = udpsize;
+
+ /*
+ * Set EXTENDED-RCODE, VERSION, DO and Z to 0.
+ */
+ rdatalist->ttl = 0;
+
+ /*
+ * No EDNS options.
+ */
+ rdata->data = NULL;
+ rdata->length = 0;
+ rdata->rdclass = rdatalist->rdclass;
+ rdata->type = rdatalist->type;
+ rdata->flags = 0;
+
+ ISC_LIST_INIT(rdatalist->rdata);
+ ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
+ RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset)
+ == ISC_R_SUCCESS);
+
+ return (dns_message_setopt(message, rdataset));
+
+ cleanup:
+ if (rdatalist != NULL)
+ dns_message_puttemprdatalist(message, &rdatalist);
+ if (rdataset != NULL)
+ dns_message_puttemprdataset(message, &rdataset);
+ if (rdata != NULL)
+ dns_message_puttemprdata(message, &rdata);
+
+ return (result);
+}
+
+static void
+soa_query(isc_task_t *task, isc_event_t *event) {
+ const char me[] = "soa_query";
+ isc_result_t result = ISC_R_FAILURE;
+ dns_message_t *message = NULL;
+ dns_zone_t *zone = event->ev_arg;
+ dns_zone_t *dummy = NULL;
+ isc_netaddr_t masterip;
+ dns_tsigkey_t *key = NULL;
+ isc_uint32_t options;
+ isc_boolean_t cancel = ISC_TRUE;
+ int timeout;
+ isc_boolean_t have_xfrsource;
+ isc_uint16_t udpsize = SEND_BUFFER_SIZE;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ UNUSED(task);
+
+ ENTER;
+
+ LOCK_ZONE(zone);
+ if (((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0) ||
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) ||
+ zone->view->requestmgr == NULL) {
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING))
+ cancel = ISC_FALSE;
+ goto cleanup;
+ }
+
+ /*
+ * XXX Optimisation: Create message when zone is setup and reuse.
+ */
+ result = create_query(zone, dns_rdatatype_soa, &message);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ again:
+ INSIST(zone->masterscnt > 0);
+ INSIST(zone->curmaster < zone->masterscnt);
+
+ zone->masteraddr = zone->masters[zone->curmaster];
+
+ isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr);
+ /*
+ * First, look for a tsig key in the master statement, then
+ * try for a server key.
+ */
+ if ((zone->masterkeynames != NULL) &&
+ (zone->masterkeynames[zone->curmaster] != NULL)) {
+ dns_view_t *view = dns_zone_getview(zone);
+ dns_name_t *keyname = zone->masterkeynames[zone->curmaster];
+ result = dns_view_gettsig(view, keyname, &key);
+ if (result != ISC_R_SUCCESS) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_name_format(keyname, namebuf, sizeof(namebuf));
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "unable to find key: %s", namebuf);
+ }
+ }
+ if (key == NULL)
+ (void)dns_view_getpeertsig(zone->view, &masterip, &key);
+
+ have_xfrsource = ISC_FALSE;
+ if (zone->view->peers != NULL) {
+ dns_peer_t *peer = NULL;
+ isc_boolean_t edns;
+ result = dns_peerlist_peerbyaddr(zone->view->peers,
+ &masterip, &peer);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_peer_getsupportedns(peer, &edns);
+ if (result == ISC_R_SUCCESS && !edns)
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS);
+ result = dns_peer_gettransfersource(peer,
+ &zone->sourceaddr);
+ if (result == ISC_R_SUCCESS)
+ have_xfrsource = ISC_TRUE;
+ if (zone->view->resolver != NULL)
+ udpsize =
+ dns_resolver_getudpsize(zone->view->resolver);
+ (void)dns_peer_getudpsize(peer, &udpsize);
+ }
+ }
+
+ switch (isc_sockaddr_pf(&zone->masteraddr)) {
+ case PF_INET:
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) {
+ if (isc_sockaddr_equal(&zone->altxfrsource4,
+ &zone->xfrsource4))
+ goto skip_master;
+ zone->sourceaddr = zone->altxfrsource4;
+ } else if (!have_xfrsource)
+ zone->sourceaddr = zone->xfrsource4;
+ break;
+ case PF_INET6:
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) {
+ if (isc_sockaddr_equal(&zone->altxfrsource6,
+ &zone->xfrsource6))
+ goto skip_master;
+ zone->sourceaddr = zone->altxfrsource6;
+ } else if (!have_xfrsource)
+ zone->sourceaddr = zone->xfrsource6;
+ break;
+ default:
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+
+ options = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEVC) ?
+ DNS_REQUESTOPT_TCP : 0;
+
+ if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) {
+ result = add_opt(message, udpsize);
+ if (result != ISC_R_SUCCESS)
+ zone_debuglog(zone, me, 1,
+ "unable to add opt record: %s",
+ dns_result_totext(result));
+ }
+
+ zone_iattach(zone, &dummy);
+ timeout = 15;
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH))
+ timeout = 30;
+ result = dns_request_createvia2(zone->view->requestmgr, message,
+ &zone->sourceaddr, &zone->masteraddr,
+ options, key, timeout * 3, timeout,
+ zone->task, refresh_callback, zone,
+ &zone->request);
+ if (result != ISC_R_SUCCESS) {
+ zone_idetach(&dummy);
+ zone_debuglog(zone, me, 1,
+ "dns_request_createvia2() failed: %s",
+ dns_result_totext(result));
+ goto cleanup;
+ }
+ cancel = ISC_FALSE;
+
+ cleanup:
+ if (key != NULL)
+ dns_tsigkey_detach(&key);
+ if (result != ISC_R_SUCCESS)
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH);
+ if (message != NULL)
+ dns_message_destroy(&message);
+ if (cancel)
+ cancel_refresh(zone);
+ isc_event_free(&event);
+ UNLOCK_ZONE(zone);
+ dns_zone_idetach(&zone);
+ return;
+
+ skip_master:
+ if (key != NULL)
+ dns_tsigkey_detach(&key);
+ /*
+ * Skip to next failed / untried master.
+ */
+ do {
+ zone->curmaster++;
+ } while (zone->curmaster < zone->masterscnt &&
+ zone->mastersok[zone->curmaster]);
+ if (zone->curmaster < zone->masterscnt)
+ goto again;
+ zone->curmaster = 0;
+ goto cleanup;
+}
+
+static void
+ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
+ const char me[] = "ns_query";
+ isc_result_t result;
+ dns_message_t *message = NULL;
+ isc_netaddr_t masterip;
+ dns_tsigkey_t *key = NULL;
+ dns_dbnode_t *node = NULL;
+ int timeout;
+ isc_boolean_t have_xfrsource = ISC_FALSE;
+ isc_uint16_t udpsize = SEND_BUFFER_SIZE;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE((soardataset != NULL && stub == NULL) ||
+ (soardataset == NULL && stub != NULL));
+ REQUIRE(stub == NULL || DNS_STUB_VALID(stub));
+
+ ENTER;
+
+ LOCK_ZONE(zone);
+ if (stub == NULL) {
+ stub = isc_mem_get(zone->mctx, sizeof(*stub));
+ if (stub == NULL)
+ goto cleanup;
+ stub->magic = STUB_MAGIC;
+ stub->mctx = zone->mctx;
+ stub->zone = NULL;
+ stub->db = NULL;
+ stub->version = NULL;
+
+ /*
+ * Attach so that the zone won't disappear from under us.
+ */
+ zone_iattach(zone, &stub->zone);
+
+ /*
+ * If a db exists we will update it, otherwise we create a
+ * new one and attach it to the zone once we have the NS
+ * RRset and glue.
+ */
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db != NULL) {
+ dns_db_attach(zone->db, &stub->db);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ } else {
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+ INSIST(zone->db_argc >= 1);
+ result = dns_db_create(zone->mctx, zone->db_argv[0],
+ &zone->origin, dns_dbtype_stub,
+ zone->rdclass,
+ zone->db_argc - 1,
+ zone->db_argv + 1,
+ &stub->db);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "refreshing stub: "
+ "could not create "
+ "database: %s",
+ dns_result_totext(result));
+ goto cleanup;
+ }
+ dns_db_settask(stub->db, zone->task);
+ }
+
+ dns_db_newversion(stub->db, &stub->version);
+
+ /*
+ * Update SOA record.
+ */
+ result = dns_db_findnode(stub->db, &zone->origin, ISC_TRUE,
+ &node);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refreshing stub: "
+ "dns_db_findnode() failed: %s",
+ dns_result_totext(result));
+ goto cleanup;
+ }
+
+ result = dns_db_addrdataset(stub->db, node, stub->version, 0,
+ soardataset, 0, NULL);
+ dns_db_detachnode(stub->db, &node);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refreshing stub: "
+ "dns_db_addrdataset() failed: %s",
+ dns_result_totext(result));
+ goto cleanup;
+ }
+ }
+
+ /*
+ * XXX Optimisation: Create message when zone is setup and reuse.
+ */
+ result = create_query(zone, dns_rdatatype_ns, &message);
+
+ INSIST(zone->masterscnt > 0);
+ INSIST(zone->curmaster < zone->masterscnt);
+ zone->masteraddr = zone->masters[zone->curmaster];
+
+ isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr);
+ /*
+ * First, look for a tsig key in the master statement, then
+ * try for a server key.
+ */
+ if ((zone->masterkeynames != NULL) &&
+ (zone->masterkeynames[zone->curmaster] != NULL)) {
+ dns_view_t *view = dns_zone_getview(zone);
+ dns_name_t *keyname = zone->masterkeynames[zone->curmaster];
+ result = dns_view_gettsig(view, keyname, &key);
+ if (result != ISC_R_SUCCESS) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_name_format(keyname, namebuf, sizeof(namebuf));
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "unable to find key: %s", namebuf);
+ }
+ }
+ if (key == NULL)
+ (void)dns_view_getpeertsig(zone->view, &masterip, &key);
+
+ if (zone->view->peers != NULL) {
+ dns_peer_t *peer = NULL;
+ isc_boolean_t edns;
+ result = dns_peerlist_peerbyaddr(zone->view->peers,
+ &masterip, &peer);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_peer_getsupportedns(peer, &edns);
+ if (result == ISC_R_SUCCESS && !edns)
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS);
+ result = dns_peer_gettransfersource(peer,
+ &zone->sourceaddr);
+ if (result == ISC_R_SUCCESS)
+ have_xfrsource = ISC_TRUE;
+ if (zone->view->resolver != NULL)
+ udpsize =
+ dns_resolver_getudpsize(zone->view->resolver);
+ (void)dns_peer_getudpsize(peer, &udpsize);
+ }
+
+ }
+ if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) {
+ result = add_opt(message, udpsize);
+ if (result != ISC_R_SUCCESS)
+ zone_debuglog(zone, me, 1,
+ "unable to add opt record: %s",
+ dns_result_totext(result));
+ }
+
+ /*
+ * Always use TCP so that we shouldn't truncate in additional section.
+ */
+ switch (isc_sockaddr_pf(&zone->masteraddr)) {
+ case PF_INET:
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC))
+ zone->sourceaddr = zone->altxfrsource4;
+ else if (!have_xfrsource)
+ zone->sourceaddr = zone->xfrsource4;
+ break;
+ case PF_INET6:
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC))
+ zone->sourceaddr = zone->altxfrsource6;
+ else if (!have_xfrsource)
+ zone->sourceaddr = zone->xfrsource6;
+ break;
+ default:
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+ timeout = 15;
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH))
+ timeout = 30;
+ result = dns_request_createvia2(zone->view->requestmgr, message,
+ &zone->sourceaddr, &zone->masteraddr,
+ DNS_REQUESTOPT_TCP, key, timeout * 3,
+ timeout, zone->task, stub_callback,
+ stub, &zone->request);
+ if (result != ISC_R_SUCCESS) {
+ zone_debuglog(zone, me, 1,
+ "dns_request_createvia() failed: %s",
+ dns_result_totext(result));
+ goto cleanup;
+ }
+ dns_message_destroy(&message);
+ goto unlock;
+
+ cleanup:
+ cancel_refresh(zone);
+ if (stub != NULL) {
+ stub->magic = 0;
+ if (stub->version != NULL)
+ dns_db_closeversion(stub->db, &stub->version,
+ ISC_FALSE);
+ if (stub->db != NULL)
+ dns_db_detach(&stub->db);
+ if (stub->zone != NULL)
+ zone_idetach(&stub->zone);
+ isc_mem_put(stub->mctx, stub, sizeof(*stub));
+ }
+ if (message != NULL)
+ dns_message_destroy(&message);
+ unlock:
+ if (key != NULL)
+ dns_tsigkey_detach(&key);
+ UNLOCK_ZONE(zone);
+ return;
+}
+
+/*
+ * Handle the control event. Note that although this event causes the zone
+ * to shut down, it is not a shutdown event in the sense of the task library.
+ */
+static void
+zone_shutdown(isc_task_t *task, isc_event_t *event) {
+ dns_zone_t *zone = (dns_zone_t *) event->ev_arg;
+ isc_boolean_t free_needed, linked = ISC_FALSE;
+
+ UNUSED(task);
+ REQUIRE(DNS_ZONE_VALID(zone));
+ INSIST(event->ev_type == DNS_EVENT_ZONECONTROL);
+ INSIST(isc_refcount_current(&zone->erefs) == 0);
+ zone_debuglog(zone, "zone_shutdown", 3, "shutting down");
+
+ /*
+ * Stop things being restarted after we cancel them below.
+ */
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_EXITING);
+ UNLOCK_ZONE(zone);
+
+ /*
+ * If we were waiting for xfrin quota, step out of
+ * the queue.
+ * If there's no zone manager, we can't be waiting for the
+ * xfrin quota
+ */
+ if (zone->zmgr != NULL) {
+ RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
+ if (zone->statelist == &zone->zmgr->waiting_for_xfrin) {
+ ISC_LIST_UNLINK(zone->zmgr->waiting_for_xfrin, zone,
+ statelink);
+ linked = ISC_TRUE;
+ zone->statelist = NULL;
+ }
+ RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
+ }
+
+ /*
+ * In task context, no locking required. See zone_xfrdone().
+ */
+ if (zone->xfr != NULL)
+ dns_xfrin_shutdown(zone->xfr);
+
+ LOCK_ZONE(zone);
+ if (linked) {
+ INSIST(zone->irefs > 0);
+ zone->irefs--;
+ }
+ if (zone->request != NULL) {
+ dns_request_cancel(zone->request);
+ }
+
+ if (zone->readio != NULL)
+ zonemgr_cancelio(zone->readio);
+
+ if (zone->lctx != NULL)
+ dns_loadctx_cancel(zone->lctx);
+
+ if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FLUSH) ||
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) {
+ if (zone->writeio != NULL)
+ zonemgr_cancelio(zone->writeio);
+
+ if (zone->dctx != NULL)
+ dns_dumpctx_cancel(zone->dctx);
+ }
+
+ notify_cancel(zone);
+
+ if (zone->timer != NULL) {
+ isc_timer_detach(&zone->timer);
+ INSIST(zone->irefs > 0);
+ zone->irefs--;
+ }
+
+ if (zone->view != NULL)
+ dns_view_weakdetach(&zone->view);
+
+ /*
+ * We have now canceled everything set the flag to allow exit_check()
+ * to succeed. We must not unlock between setting this flag and
+ * calling exit_check().
+ */
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SHUTDOWN);
+ free_needed = exit_check(zone);
+ UNLOCK_ZONE(zone);
+ if (free_needed)
+ zone_free(zone);
+}
+
+static void
+zone_timer(isc_task_t *task, isc_event_t *event) {
+ const char me[] = "zone_timer";
+ dns_zone_t *zone = (dns_zone_t *)event->ev_arg;
+
+ UNUSED(task);
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ ENTER;
+
+ zone_maintenance(zone);
+
+ isc_event_free(&event);
+}
+
+static void
+zone_settimer(dns_zone_t *zone, isc_time_t *now) {
+ const char me[] = "zone_settimer";
+ isc_time_t next;
+ isc_result_t result;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING))
+ return;
+
+ isc_time_settoepoch(&next);
+
+ switch (zone->type) {
+ case dns_zone_master:
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY))
+ next = zone->notifytime;
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) {
+ INSIST(!isc_time_isepoch(&zone->dumptime));
+ if (isc_time_isepoch(&next) ||
+ isc_time_compare(&zone->dumptime, &next) < 0)
+ next = zone->dumptime;
+ }
+ break;
+
+ case dns_zone_slave:
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY))
+ next = zone->notifytime;
+ /*FALLTHROUGH*/
+
+ case dns_zone_stub:
+ if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOMASTERS) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOREFRESH) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADING)) {
+ INSIST(!isc_time_isepoch(&zone->refreshtime));
+ if (isc_time_isepoch(&next) ||
+ isc_time_compare(&zone->refreshtime, &next) < 0)
+ next = zone->refreshtime;
+ }
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) {
+ INSIST(!isc_time_isepoch(&zone->expiretime));
+ if (isc_time_isepoch(&next) ||
+ isc_time_compare(&zone->expiretime, &next) < 0)
+ next = zone->expiretime;
+ }
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) {
+ INSIST(!isc_time_isepoch(&zone->dumptime));
+ if (isc_time_isepoch(&next) ||
+ isc_time_compare(&zone->dumptime, &next) < 0)
+ next = zone->dumptime;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (isc_time_isepoch(&next)) {
+ zone_debuglog(zone, me, 10, "settimer inactive");
+ result = isc_timer_reset(zone->timer, isc_timertype_inactive,
+ NULL, NULL, ISC_TRUE);
+ if (result != ISC_R_SUCCESS)
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "could not deactivate zone timer: %s",
+ isc_result_totext(result));
+ } else {
+ if (isc_time_compare(&next, now) <= 0)
+ next = *now;
+ result = isc_timer_reset(zone->timer, isc_timertype_once,
+ &next, NULL, ISC_TRUE);
+ if (result != ISC_R_SUCCESS)
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "could not reset zone timer: %s",
+ isc_result_totext(result));
+ }
+}
+
+static void
+cancel_refresh(dns_zone_t *zone) {
+ const char me[] = "cancel_refresh";
+ isc_time_t now;
+
+ /*
+ * 'zone' locked by caller.
+ */
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(LOCKED_ZONE(zone));
+
+ ENTER;
+
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH);
+ TIME_NOW(&now);
+ zone_settimer(zone, &now);
+}
+
+static isc_result_t
+notify_createmessage(dns_zone_t *zone, unsigned int flags,
+ dns_message_t **messagep)
+{
+ dns_db_t *zonedb = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_dbversion_t *version = NULL;
+ dns_message_t *message = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ dns_name_t *tempname = NULL;
+ dns_rdata_t *temprdata = NULL;
+ dns_rdatalist_t *temprdatalist = NULL;
+ dns_rdataset_t *temprdataset = NULL;
+
+ isc_result_t result;
+ isc_region_t r;
+ isc_buffer_t *b = NULL;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(messagep != NULL && *messagep == NULL);
+
+ result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER,
+ &message);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ message->opcode = dns_opcode_notify;
+ message->flags |= DNS_MESSAGEFLAG_AA;
+ message->rdclass = zone->rdclass;
+
+ result = dns_message_gettempname(message, &tempname);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = dns_message_gettemprdataset(message, &temprdataset);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ /*
+ * Make question.
+ */
+ dns_name_init(tempname, NULL);
+ dns_name_clone(&zone->origin, tempname);
+ dns_rdataset_init(temprdataset);
+ dns_rdataset_makequestion(temprdataset, zone->rdclass,
+ dns_rdatatype_soa);
+ ISC_LIST_APPEND(tempname->list, temprdataset, link);
+ dns_message_addname(message, tempname, DNS_SECTION_QUESTION);
+ tempname = NULL;
+ temprdataset = NULL;
+
+ if ((flags & DNS_NOTIFY_NOSOA) != 0)
+ goto done;
+
+ result = dns_message_gettempname(message, &tempname);
+ if (result != ISC_R_SUCCESS)
+ goto soa_cleanup;
+ result = dns_message_gettemprdata(message, &temprdata);
+ if (result != ISC_R_SUCCESS)
+ goto soa_cleanup;
+ result = dns_message_gettemprdataset(message, &temprdataset);
+ if (result != ISC_R_SUCCESS)
+ goto soa_cleanup;
+ result = dns_message_gettemprdatalist(message, &temprdatalist);
+ if (result != ISC_R_SUCCESS)
+ goto soa_cleanup;
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ INSIST(zone->db != NULL); /* XXXJT: is this assumption correct? */
+ dns_db_attach(zone->db, &zonedb);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+ dns_name_init(tempname, NULL);
+ dns_name_clone(&zone->origin, tempname);
+ dns_db_currentversion(zonedb, &version);
+ result = dns_db_findnode(zonedb, tempname, ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto soa_cleanup;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(zonedb, node, version,
+ dns_rdatatype_soa,
+ dns_rdatatype_none, 0, &rdataset,
+ NULL);
+ if (result != ISC_R_SUCCESS)
+ goto soa_cleanup;
+ result = dns_rdataset_first(&rdataset);
+ if (result != ISC_R_SUCCESS)
+ goto soa_cleanup;
+ dns_rdataset_current(&rdataset, &rdata);
+ dns_rdata_toregion(&rdata, &r);
+ result = isc_buffer_allocate(zone->mctx, &b, r.length);
+ if (result != ISC_R_SUCCESS)
+ goto soa_cleanup;
+ isc_buffer_putmem(b, r.base, r.length);
+ isc_buffer_usedregion(b, &r);
+ dns_rdata_init(temprdata);
+ dns_rdata_fromregion(temprdata, rdata.rdclass, rdata.type, &r);
+ dns_message_takebuffer(message, &b);
+ result = dns_rdataset_next(&rdataset);
+ dns_rdataset_disassociate(&rdataset);
+ if (result != ISC_R_NOMORE)
+ goto soa_cleanup;
+ temprdatalist->rdclass = rdata.rdclass;
+ temprdatalist->type = rdata.type;
+ temprdatalist->covers = 0;
+ temprdatalist->ttl = rdataset.ttl;
+ ISC_LIST_INIT(temprdatalist->rdata);
+ ISC_LIST_APPEND(temprdatalist->rdata, temprdata, link);
+
+ dns_rdataset_init(temprdataset);
+ result = dns_rdatalist_tordataset(temprdatalist, temprdataset);
+ if (result != ISC_R_SUCCESS)
+ goto soa_cleanup;
+
+ ISC_LIST_APPEND(tempname->list, temprdataset, link);
+ dns_message_addname(message, tempname, DNS_SECTION_ANSWER);
+ temprdatalist = NULL;
+ temprdataset = NULL;
+ temprdata = NULL;
+ tempname = NULL;
+
+ soa_cleanup:
+ if (node != NULL)
+ dns_db_detachnode(zonedb, &node);
+ if (version != NULL)
+ dns_db_closeversion(zonedb, &version, ISC_FALSE);
+ if (zonedb != NULL)
+ dns_db_detach(&zonedb);
+ if (tempname != NULL)
+ dns_message_puttempname(message, &tempname);
+ if (temprdata != NULL)
+ dns_message_puttemprdata(message, &temprdata);
+ if (temprdataset != NULL)
+ dns_message_puttemprdataset(message, &temprdataset);
+ if (temprdatalist != NULL)
+ dns_message_puttemprdatalist(message, &temprdatalist);
+
+ done:
+ *messagep = message;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (tempname != NULL)
+ dns_message_puttempname(message, &tempname);
+ if (temprdataset != NULL)
+ dns_message_puttemprdataset(message, &temprdataset);
+ dns_message_destroy(&message);
+ return (result);
+}
+
+isc_result_t
+dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
+ dns_message_t *msg)
+{
+ unsigned int i;
+ dns_rdata_soa_t soa;
+ dns_rdataset_t *rdataset = NULL;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_result_t result;
+ char fromtext[ISC_SOCKADDR_FORMATSIZE];
+ int match = 0;
+ isc_netaddr_t netaddr;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ /*
+ * If type != T_SOA return DNS_R_REFUSED. We don't yet support
+ * ROLLOVER.
+ *
+ * SOA: RFC1996
+ * Check that 'from' is a valid notify source, (zone->masters).
+ * Return DNS_R_REFUSED if not.
+ *
+ * If the notify message contains a serial number check it
+ * against the zones serial and return if <= current serial
+ *
+ * If a refresh check is progress, if so just record the
+ * fact we received a NOTIFY and from where and return.
+ * We will perform a new refresh check when the current one
+ * completes. Return ISC_R_SUCCESS.
+ *
+ * Otherwise initiate a refresh check using 'from' as the
+ * first address to check. Return ISC_R_SUCCESS.
+ */
+
+ isc_sockaddr_format(from, fromtext, sizeof(fromtext));
+
+ /*
+ * We only handle NOTIFY (SOA) at the present.
+ */
+ LOCK_ZONE(zone);
+ if (msg->counts[DNS_SECTION_QUESTION] == 0 ||
+ dns_message_findname(msg, DNS_SECTION_QUESTION, &zone->origin,
+ dns_rdatatype_soa, dns_rdatatype_none,
+ NULL, NULL) != ISC_R_SUCCESS) {
+ UNLOCK_ZONE(zone);
+ if (msg->counts[DNS_SECTION_QUESTION] == 0) {
+ dns_zone_log(zone, ISC_LOG_NOTICE,
+ "NOTIFY with no "
+ "question section from: %s", fromtext);
+ return (DNS_R_FORMERR);
+ }
+ dns_zone_log(zone, ISC_LOG_NOTICE,
+ "NOTIFY zone does not match");
+ return (DNS_R_NOTIMP);
+ }
+
+ /*
+ * If we are a master zone just succeed.
+ */
+ if (zone->type == dns_zone_master) {
+ UNLOCK_ZONE(zone);
+ return (ISC_R_SUCCESS);
+ }
+
+ isc_netaddr_fromsockaddr(&netaddr, from);
+ for (i = 0; i < zone->masterscnt; i++) {
+ if (isc_sockaddr_eqaddr(from, &zone->masters[i]))
+ break;
+ if (zone->view->aclenv.match_mapped &&
+ IN6_IS_ADDR_V4MAPPED(&from->type.sin6.sin6_addr) &&
+ isc_sockaddr_pf(&zone->masters[i]) == AF_INET) {
+ isc_netaddr_t na1, na2;
+ isc_netaddr_fromv4mapped(&na1, &netaddr);
+ isc_netaddr_fromsockaddr(&na2, &zone->masters[i]);
+ if (isc_netaddr_equal(&na1, &na2))
+ break;
+ }
+ }
+
+ /*
+ * Accept notify requests from non masters if they are on
+ * 'zone->notify_acl'.
+ */
+ if (i >= zone->masterscnt && zone->notify_acl != NULL &&
+ dns_acl_match(&netaddr, NULL, zone->notify_acl,
+ &zone->view->aclenv,
+ &match, NULL) == ISC_R_SUCCESS &&
+ match > 0)
+ {
+ /* Accept notify. */
+ } else if (i >= zone->masterscnt) {
+ UNLOCK_ZONE(zone);
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "refused notify from non-master: %s", fromtext);
+ return (DNS_R_REFUSED);
+ }
+
+ /*
+ * If the zone is loaded and there are answers check the serial
+ * to see if we need to do a refresh. Do not worry about this
+ * check if we are a dialup zone as we use the notify request
+ * to trigger a refresh check.
+ */
+ if (msg->counts[DNS_SECTION_ANSWER] > 0 &&
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOREFRESH)) {
+ result = dns_message_findname(msg, DNS_SECTION_ANSWER,
+ &zone->origin,
+ dns_rdatatype_soa,
+ dns_rdatatype_none, NULL,
+ &rdataset);
+ if (result == ISC_R_SUCCESS)
+ result = dns_rdataset_first(rdataset);
+ if (result == ISC_R_SUCCESS) {
+ isc_uint32_t serial = 0;
+
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &soa, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ serial = soa.serial;
+ if (isc_serial_le(serial, zone->serial)) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "notify from %s: "
+ "zone is up to date",
+ fromtext);
+ UNLOCK_ZONE(zone);
+ return (ISC_R_SUCCESS);
+ }
+ }
+ }
+
+ /*
+ * If we got this far and there was a refresh in progress just
+ * let it complete. Record where we got the notify from so we
+ * can perform a refresh check when the current one completes
+ */
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) {
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDREFRESH);
+ zone->notifyfrom = *from;
+ UNLOCK_ZONE(zone);
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "notify from %s: refresh in progress, "
+ "refresh check queued",
+ fromtext);
+ return (ISC_R_SUCCESS);
+ }
+ zone->notifyfrom = *from;
+ UNLOCK_ZONE(zone);
+ dns_zone_refresh(zone);
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_zone_setnotifyacl(dns_zone_t *zone, dns_acl_t *acl) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->notify_acl != NULL)
+ dns_acl_detach(&zone->notify_acl);
+ dns_acl_attach(acl, &zone->notify_acl);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_setqueryacl(dns_zone_t *zone, dns_acl_t *acl) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->query_acl != NULL)
+ dns_acl_detach(&zone->query_acl);
+ dns_acl_attach(acl, &zone->query_acl);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_setupdateacl(dns_zone_t *zone, dns_acl_t *acl) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->update_acl != NULL)
+ dns_acl_detach(&zone->update_acl);
+ dns_acl_attach(acl, &zone->update_acl);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_setforwardacl(dns_zone_t *zone, dns_acl_t *acl) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->forward_acl != NULL)
+ dns_acl_detach(&zone->forward_acl);
+ dns_acl_attach(acl, &zone->forward_acl);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_setxfracl(dns_zone_t *zone, dns_acl_t *acl) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->xfr_acl != NULL)
+ dns_acl_detach(&zone->xfr_acl);
+ dns_acl_attach(acl, &zone->xfr_acl);
+ UNLOCK_ZONE(zone);
+}
+
+dns_acl_t *
+dns_zone_getnotifyacl(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->notify_acl);
+}
+
+dns_acl_t *
+dns_zone_getqueryacl(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->query_acl);
+}
+
+dns_acl_t *
+dns_zone_getupdateacl(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->update_acl);
+}
+
+dns_acl_t *
+dns_zone_getforwardacl(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->forward_acl);
+}
+
+dns_acl_t *
+dns_zone_getxfracl(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->xfr_acl);
+}
+
+void
+dns_zone_clearupdateacl(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->update_acl != NULL)
+ dns_acl_detach(&zone->update_acl);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_clearforwardacl(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->forward_acl != NULL)
+ dns_acl_detach(&zone->forward_acl);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_clearnotifyacl(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->notify_acl != NULL)
+ dns_acl_detach(&zone->notify_acl);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_clearqueryacl(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->query_acl != NULL)
+ dns_acl_detach(&zone->query_acl);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_clearxfracl(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->xfr_acl != NULL)
+ dns_acl_detach(&zone->xfr_acl);
+ UNLOCK_ZONE(zone);
+}
+
+isc_boolean_t
+dns_zone_getupdatedisabled(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (zone->update_disabled);
+
+}
+
+void
+dns_zone_setupdatedisabled(dns_zone_t *zone, isc_boolean_t state) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ zone->update_disabled = state;
+}
+
+isc_boolean_t
+dns_zone_getzeronosoattl(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (zone->zero_no_soa_ttl);
+
+}
+
+void
+dns_zone_setzeronosoattl(dns_zone_t *zone, isc_boolean_t state) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ zone->zero_no_soa_ttl = state;
+}
+
+void
+dns_zone_setchecknames(dns_zone_t *zone, dns_severity_t severity) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ zone->check_names = severity;
+}
+
+dns_severity_t
+dns_zone_getchecknames(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->check_names);
+}
+
+void
+dns_zone_setjournalsize(dns_zone_t *zone, isc_int32_t size) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ zone->journalsize = size;
+}
+
+isc_int32_t
+dns_zone_getjournalsize(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->journalsize);
+}
+
+static void
+zone_tostr(dns_zone_t *zone, char *buf, size_t length) {
+ isc_result_t result = ISC_R_FAILURE;
+ isc_buffer_t buffer;
+
+ REQUIRE(buf != NULL);
+ REQUIRE(length > 1U);
+
+ /*
+ * Leave space for terminating '\0'.
+ */
+ isc_buffer_init(&buffer, buf, length - 1);
+ if (dns_name_dynamic(&zone->origin))
+ result = dns_name_totext(&zone->origin, ISC_TRUE, &buffer);
+ if (result != ISC_R_SUCCESS &&
+ isc_buffer_availablelength(&buffer) >= (sizeof("<UNKNOWN>") - 1))
+ isc_buffer_putstr(&buffer, "<UNKNOWN>");
+
+ if (isc_buffer_availablelength(&buffer) > 0)
+ isc_buffer_putstr(&buffer, "/");
+ (void)dns_rdataclass_totext(zone->rdclass, &buffer);
+
+ if (zone->view != NULL && strcmp(zone->view->name, "_bind") != 0 &&
+ strcmp(zone->view->name, "_default") != 0 &&
+ strlen(zone->view->name) < isc_buffer_availablelength(&buffer)) {
+ isc_buffer_putstr(&buffer, "/");
+ isc_buffer_putstr(&buffer, zone->view->name);
+ }
+
+ buf[isc_buffer_usedlength(&buffer)] = '\0';
+}
+
+void
+dns_zone_name(dns_zone_t *zone, char *buf, size_t length) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(buf != NULL);
+ zone_tostr(zone, buf, length);
+}
+
+static void
+notify_log(dns_zone_t *zone, int level, const char *fmt, ...) {
+ va_list ap;
+ char message[4096];
+ char namebuf[1024+32];
+
+ if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
+ return;
+
+ zone_tostr(zone, namebuf, sizeof(namebuf));
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_NOTIFY, DNS_LOGMODULE_ZONE,
+ level, "zone %s: %s", namebuf, message);
+}
+
+void
+dns_zone_logc(dns_zone_t *zone, isc_logcategory_t *category,
+ int level, const char *fmt, ...) {
+ va_list ap;
+ char message[4096];
+ char namebuf[1024+32];
+
+ if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
+ return;
+
+ zone_tostr(zone, namebuf, sizeof(namebuf));
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+ isc_log_write(dns_lctx, category, DNS_LOGMODULE_ZONE,
+ level, "zone %s: %s", namebuf, message);
+}
+
+void
+dns_zone_log(dns_zone_t *zone, int level, const char *fmt, ...) {
+ va_list ap;
+ char message[4096];
+ char namebuf[1024+32];
+
+ if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
+ return;
+
+ zone_tostr(zone, namebuf, sizeof(namebuf));
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
+ level, "zone %s: %s", namebuf, message);
+}
+
+static void
+zone_debuglog(dns_zone_t *zone, const char *me, int debuglevel,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char message[4096];
+ char namebuf[1024+32];
+ int level = ISC_LOG_DEBUG(debuglevel);
+
+ if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
+ return;
+
+ zone_tostr(zone, namebuf, sizeof(namebuf));
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
+ level, "%s: zone %s: %s", me, namebuf, message);
+}
+
+static int
+message_count(dns_message_t *msg, dns_section_t section, dns_rdatatype_t type)
+{
+ isc_result_t result;
+ dns_name_t *name;
+ dns_rdataset_t *curr;
+ int count = 0;
+
+ result = dns_message_firstname(msg, section);
+ while (result == ISC_R_SUCCESS) {
+ name = NULL;
+ dns_message_currentname(msg, section, &name);
+
+ for (curr = ISC_LIST_TAIL(name->list); curr != NULL;
+ curr = ISC_LIST_PREV(curr, link)) {
+ if (curr->type == type)
+ count++;
+ }
+ result = dns_message_nextname(msg, section);
+ }
+
+ return (count);
+}
+
+void
+dns_zone_setmaxxfrin(dns_zone_t *zone, isc_uint32_t maxxfrin) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ zone->maxxfrin = maxxfrin;
+}
+
+isc_uint32_t
+dns_zone_getmaxxfrin(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->maxxfrin);
+}
+
+void
+dns_zone_setmaxxfrout(dns_zone_t *zone, isc_uint32_t maxxfrout) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ zone->maxxfrout = maxxfrout;
+}
+
+isc_uint32_t
+dns_zone_getmaxxfrout(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->maxxfrout);
+}
+
+dns_zonetype_t
+dns_zone_gettype(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->type);
+}
+
+dns_name_t *
+dns_zone_getorigin(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (&zone->origin);
+}
+
+void
+dns_zone_settask(dns_zone_t *zone, isc_task_t *task) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->task != NULL)
+ isc_task_detach(&zone->task);
+ isc_task_attach(task, &zone->task);
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db != NULL)
+ dns_db_settask(zone->db, zone->task);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_gettask(dns_zone_t *zone, isc_task_t **target) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ isc_task_attach(zone->task, target);
+}
+
+void
+dns_zone_setidlein(dns_zone_t *zone, isc_uint32_t idlein) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ if (idlein == 0)
+ idlein = DNS_DEFAULT_IDLEIN;
+ zone->idlein = idlein;
+}
+
+isc_uint32_t
+dns_zone_getidlein(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->idlein);
+}
+
+void
+dns_zone_setidleout(dns_zone_t *zone, isc_uint32_t idleout) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ zone->idleout = idleout;
+}
+
+isc_uint32_t
+dns_zone_getidleout(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->idleout);
+}
+
+static void
+notify_done(isc_task_t *task, isc_event_t *event) {
+ dns_requestevent_t *revent = (dns_requestevent_t *)event;
+ dns_notify_t *notify;
+ isc_result_t result;
+ dns_message_t *message = NULL;
+ isc_buffer_t buf;
+ char rcode[128];
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+
+ UNUSED(task);
+
+ notify = event->ev_arg;
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+ INSIST(task == notify->zone->task);
+
+ isc_buffer_init(&buf, rcode, sizeof(rcode));
+ isc_sockaddr_format(&notify->dst, addrbuf, sizeof(addrbuf));
+
+ result = revent->result;
+ if (result == ISC_R_SUCCESS)
+ result = dns_message_create(notify->zone->mctx,
+ DNS_MESSAGE_INTENTPARSE, &message);
+ if (result == ISC_R_SUCCESS)
+ result = dns_request_getresponse(revent->request, message,
+ DNS_MESSAGEPARSE_PRESERVEORDER);
+ if (result == ISC_R_SUCCESS)
+ result = dns_rcode_totext(message->rcode, &buf);
+ if (result == ISC_R_SUCCESS)
+ notify_log(notify->zone, ISC_LOG_DEBUG(3),
+ "notify response from %s: %.*s",
+ addrbuf, (int)buf.used, rcode);
+ else
+ notify_log(notify->zone, ISC_LOG_DEBUG(2),
+ "notify to %s failed: %s", addrbuf,
+ dns_result_totext(result));
+
+ /*
+ * Old bind's return formerr if they see a soa record. Retry w/o
+ * the soa if we see a formerr and had sent a SOA.
+ */
+ isc_event_free(&event);
+ if (message != NULL && message->rcode == dns_rcode_formerr &&
+ (notify->flags & DNS_NOTIFY_NOSOA) == 0) {
+ notify->flags |= DNS_NOTIFY_NOSOA;
+ dns_request_destroy(&notify->request);
+ result = notify_send_queue(notify);
+ if (result != ISC_R_SUCCESS)
+ notify_destroy(notify, ISC_FALSE);
+ } else {
+ if (result == ISC_R_TIMEDOUT)
+ notify_log(notify->zone, ISC_LOG_DEBUG(1),
+ "notify to %s: retries exceeded", addrbuf);
+ notify_destroy(notify, ISC_FALSE);
+ }
+ if (message != NULL)
+ dns_message_destroy(&message);
+}
+
+isc_result_t
+dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
+ isc_result_t result;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ LOCK_ZONE(zone);
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write);
+ result = zone_replacedb(zone, db, dump);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
+ UNLOCK_ZONE(zone);
+ return (result);
+}
+
+static isc_result_t
+zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
+ dns_dbversion_t *ver;
+ isc_result_t result;
+ unsigned int soacount = 0;
+ unsigned int nscount = 0;
+
+ /*
+ * 'zone' and 'zonedb' locked by caller.
+ */
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(LOCKED_ZONE(zone));
+
+ result = zone_get_from_db(zone, db, &nscount, &soacount,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (result == ISC_R_SUCCESS) {
+ if (soacount != 1) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "has %d SOA records", soacount);
+ result = DNS_R_BADZONE;
+ }
+ if (nscount == 0) {
+ dns_zone_log(zone, ISC_LOG_ERROR, "has no NS records");
+ result = DNS_R_BADZONE;
+ }
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "retrieving SOA and NS records failed: %s",
+ dns_result_totext(result));
+ return (result);
+ }
+
+ ver = NULL;
+ dns_db_currentversion(db, &ver);
+
+ /*
+ * The initial version of a slave zone is always dumped;
+ * subsequent versions may be journalled instead if this
+ * is enabled in the configuration.
+ */
+ if (zone->db != NULL && zone->journal != NULL &&
+ DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) {
+ isc_uint32_t serial;
+
+ dns_zone_log(zone, ISC_LOG_DEBUG(3), "generating diffs");
+
+ result = dns_db_getsoaserial(db, ver, &serial);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "ixfr-from-differences: unable to get "
+ "new serial");
+ goto fail;
+ }
+
+ /*
+ * This is checked in zone_postload() for master zones.
+ */
+ if (zone->type == dns_zone_slave &&
+ !isc_serial_gt(serial, zone->serial)) {
+ isc_uint32_t serialmin, serialmax;
+ serialmin = (zone->serial + 1) & 0xffffffffU;
+ serialmax = (zone->serial + 0x7fffffffU) & 0xffffffffU;
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "ixfr-from-differences: failed: "
+ "new serial (%u) out of range [%u - %u]",
+ serial, serialmin, serialmax);
+ result = ISC_R_RANGE;
+ goto fail;
+ }
+
+ result = dns_db_diff(zone->mctx, db, ver, zone->db, NULL,
+ zone->journal);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+ if (dump)
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ else if (zone->journalsize != -1) {
+ result = dns_journal_compact(zone->mctx, zone->journal,
+ serial, zone->journalsize);
+ switch (result) {
+ case ISC_R_SUCCESS:
+ case ISC_R_NOSPACE:
+ case ISC_R_NOTFOUND:
+ dns_zone_log(zone, ISC_LOG_DEBUG(3),
+ "dns_journal_compact: %s",
+ dns_result_totext(result));
+ break;
+ default:
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "dns_journal_compact failed: %s",
+ dns_result_totext(result));
+ break;
+ }
+ }
+ } else {
+ if (dump && zone->masterfile != NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
+ "dumping new zone version");
+ result = dns_db_dump2(db, ver, zone->masterfile,
+ zone->masterformat);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+
+ /*
+ * Update the time the zone was updated, so
+ * dns_zone_load can avoid loading it when
+ * the server is reloaded. If isc_time_now
+ * fails for some reason, all that happens is
+ * the timestamp is not updated.
+ */
+ TIME_NOW(&zone->loadtime);
+ }
+
+ if (dump && zone->journal != NULL) {
+ /*
+ * The in-memory database just changed, and
+ * because 'dump' is set, it didn't change by
+ * being loaded from disk. Also, we have not
+ * journalled diffs for this change.
+ * Therefore, the on-disk journal is missing
+ * the deltas for this change. Since it can
+ * no longer be used to bring the zone
+ * up-to-date, it is useless and should be
+ * removed.
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
+ "removing journal file");
+ (void)remove(zone->journal);
+ }
+ }
+
+ dns_db_closeversion(db, &ver, ISC_FALSE);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
+ "replacing zone database");
+
+ if (zone->db != NULL)
+ zone_detachdb(zone);
+ zone_attachdb(zone, db);
+ dns_db_settask(zone->db, zone->task);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY);
+ return (ISC_R_SUCCESS);
+
+ fail:
+ dns_db_closeversion(db, &ver, ISC_FALSE);
+ return (result);
+}
+
+/* The caller must hold the dblock as a writer. */
+static inline void
+zone_attachdb(dns_zone_t *zone, dns_db_t *db) {
+ REQUIRE(zone->db == NULL && db != NULL);
+
+ dns_db_attach(db, &zone->db);
+ if (zone->acache != NULL) {
+ isc_result_t result;
+ result = dns_acache_setdb(zone->acache, db);
+ if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_acache_setdb() failed: %s",
+ isc_result_totext(result));
+ }
+ }
+}
+
+/* The caller must hold the dblock as a writer. */
+static inline void
+zone_detachdb(dns_zone_t *zone) {
+ REQUIRE(zone->db != NULL);
+
+ if (zone->acache != NULL)
+ (void)dns_acache_putdb(zone->acache, zone->db);
+ dns_db_detach(&zone->db);
+}
+
+static void
+zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
+ isc_time_t now;
+ isc_boolean_t again = ISC_FALSE;
+ unsigned int soacount;
+ unsigned int nscount;
+ isc_uint32_t serial, refresh, retry, expire, minimum;
+ isc_result_t xfrresult = result;
+ isc_boolean_t free_needed;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "zone transfer finished: %s", dns_result_totext(result));
+
+ LOCK_ZONE(zone);
+ INSIST((zone->flags & DNS_ZONEFLG_REFRESH) != 0);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR);
+
+ TIME_NOW(&now);
+ switch (result) {
+ case ISC_R_SUCCESS:
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
+ /*FALLTHROUGH*/
+ case DNS_R_UPTODATE:
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_FORCEXFER);
+ /*
+ * Has the zone expired underneath us?
+ */
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db == NULL) {
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ goto same_master;
+ }
+
+ /*
+ * Update the zone structure's data from the actual
+ * SOA received.
+ */
+ nscount = 0;
+ soacount = 0;
+ INSIST(zone->db != NULL);
+ result = zone_get_from_db(zone, zone->db, &nscount,
+ &soacount, &serial, &refresh,
+ &retry, &expire, &minimum, NULL);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ if (result == ISC_R_SUCCESS) {
+ if (soacount != 1)
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "transferred zone "
+ "has %d SOA record%s", soacount,
+ (soacount != 0) ? "s" : "");
+ if (nscount == 0) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "transferred zone "
+ "has no NS records");
+ if (DNS_ZONE_FLAG(zone,
+ DNS_ZONEFLG_HAVETIMERS)) {
+ zone->refresh = DNS_ZONE_DEFAULTREFRESH;
+ zone->retry = DNS_ZONE_DEFAULTRETRY;
+ }
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS);
+ zone_unload(zone);
+ goto next_master;
+ }
+ zone->serial = serial;
+ zone->refresh = RANGE(refresh, zone->minrefresh,
+ zone->maxrefresh);
+ zone->retry = RANGE(retry, zone->minretry,
+ zone->maxretry);
+ zone->expire = RANGE(expire,
+ zone->refresh + zone->retry,
+ DNS_MAX_EXPIRE);
+ zone->minimum = minimum;
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS);
+ }
+
+ /*
+ * Set our next update/expire times.
+ */
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDREFRESH)) {
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDREFRESH);
+ zone->refreshtime = now;
+ DNS_ZONE_TIME_ADD(&now, zone->expire,
+ &zone->expiretime);
+ } else {
+ DNS_ZONE_JITTER_ADD(&now, zone->refresh,
+ &zone->refreshtime);
+ DNS_ZONE_TIME_ADD(&now, zone->expire,
+ &zone->expiretime);
+ }
+ if (result == ISC_R_SUCCESS && xfrresult == ISC_R_SUCCESS) {
+ char buf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")];
+ if (zone->tsigkey != NULL) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_name_format(&zone->tsigkey->name, namebuf,
+ sizeof(namebuf));
+ snprintf(buf, sizeof(buf), ": TSIG '%s'",
+ namebuf);
+ } else
+ buf[0] = '\0';
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "transferred serial %u%s",
+ zone->serial, buf);
+ }
+
+ /*
+ * This is not neccessary if we just performed a AXFR
+ * however it is necessary for an IXFR / UPTODATE and
+ * won't hurt with an AXFR.
+ */
+ if (zone->masterfile != NULL || zone->journal != NULL) {
+ result = ISC_R_FAILURE;
+ if (zone->journal != NULL)
+ result = isc_file_settime(zone->journal, &now);
+ if (result != ISC_R_SUCCESS &&
+ zone->masterfile != NULL)
+ result = isc_file_settime(zone->masterfile,
+ &now);
+ /* Someone removed the file from underneath us! */
+ if (result == ISC_R_FILENOTFOUND &&
+ zone->masterfile != NULL)
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ else if (result != ISC_R_SUCCESS)
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "transfer: could not set file "
+ "modification time of '%s': %s",
+ zone->masterfile,
+ dns_result_totext(result));
+ }
+
+ break;
+
+ case DNS_R_BADIXFR:
+ /* Force retry with AXFR. */
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLAG_NOIXFR);
+ goto same_master;
+
+ default:
+ next_master:
+ /*
+ * Skip to next failed / untried master.
+ */
+ do {
+ zone->curmaster++;
+ } while (zone->curmaster < zone->masterscnt &&
+ zone->mastersok[zone->curmaster]);
+ /* FALLTHROUGH */
+ same_master:
+ if (zone->curmaster >= zone->masterscnt) {
+ zone->curmaster = 0;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) {
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC);
+ while (zone->curmaster < zone->masterscnt &&
+ zone->mastersok[zone->curmaster])
+ zone->curmaster++;
+ again = ISC_TRUE;
+ } else
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC);
+ } else {
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH);
+ again = ISC_TRUE;
+ }
+ break;
+ }
+ zone_settimer(zone, &now);
+
+ /*
+ * If creating the transfer object failed, zone->xfr is NULL.
+ * Otherwise, we are called as the done callback of a zone
+ * transfer object that just entered its shutting-down
+ * state. Since we are no longer responsible for shutting
+ * it down, we can detach our reference.
+ */
+ if (zone->xfr != NULL)
+ dns_xfrin_detach(&zone->xfr);
+
+ if (zone->tsigkey != NULL)
+ dns_tsigkey_detach(&zone->tsigkey);
+
+ /*
+ * Handle any deferred journal compaction.
+ */
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDCOMPACT)) {
+ result = dns_journal_compact(zone->mctx, zone->journal,
+ zone->compact_serial,
+ zone->journalsize);
+ switch (result) {
+ case ISC_R_SUCCESS:
+ case ISC_R_NOSPACE:
+ case ISC_R_NOTFOUND:
+ dns_zone_log(zone, ISC_LOG_DEBUG(3),
+ "dns_journal_compact: %s",
+ dns_result_totext(result));
+ break;
+ default:
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "dns_journal_compact failed: %s",
+ dns_result_totext(result));
+ break;
+ }
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDCOMPACT);
+ }
+
+ /*
+ * This transfer finishing freed up a transfer quota slot.
+ * Let any other zones waiting for quota have it.
+ */
+ RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
+ ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, statelink);
+ zone->statelist = NULL;
+ zmgr_resume_xfrs(zone->zmgr, ISC_FALSE);
+ RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
+
+ /*
+ * Retry with a different server if necessary.
+ */
+ if (again && !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING))
+ queue_soa_query(zone);
+
+ INSIST(zone->irefs > 0);
+ zone->irefs--;
+ free_needed = exit_check(zone);
+ UNLOCK_ZONE(zone);
+ if (free_needed)
+ zone_free(zone);
+}
+
+static void
+zone_loaddone(void *arg, isc_result_t result) {
+ static char me[] = "zone_loaddone";
+ dns_load_t *load = arg;
+ dns_zone_t *zone;
+ isc_result_t tresult;
+
+ REQUIRE(DNS_LOAD_VALID(load));
+ zone = load->zone;
+
+ ENTER;
+
+ tresult = dns_db_endload(load->db, &load->callbacks.add_private);
+ if (tresult != ISC_R_SUCCESS &&
+ (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE))
+ result = tresult;
+
+ LOCK_ZONE(load->zone);
+ (void)zone_postload(load->zone, load->db, load->loadtime, result);
+ zonemgr_putio(&load->zone->readio);
+ DNS_ZONE_CLRFLAG(load->zone, DNS_ZONEFLG_LOADING);
+ UNLOCK_ZONE(load->zone);
+
+ load->magic = 0;
+ dns_db_detach(&load->db);
+ if (load->zone->lctx != NULL)
+ dns_loadctx_detach(&load->zone->lctx);
+ dns_zone_idetach(&load->zone);
+ isc_mem_putanddetach(&load->mctx, load, sizeof(*load));
+}
+
+void
+dns_zone_getssutable(dns_zone_t *zone, dns_ssutable_t **table) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(table != NULL);
+ REQUIRE(*table == NULL);
+
+ LOCK_ZONE(zone);
+ if (zone->ssutable != NULL)
+ dns_ssutable_attach(zone->ssutable, table);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_setssutable(dns_zone_t *zone, dns_ssutable_t *table) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->ssutable != NULL)
+ dns_ssutable_detach(&zone->ssutable);
+ if (table != NULL)
+ dns_ssutable_attach(table, &zone->ssutable);
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_setsigvalidityinterval(dns_zone_t *zone, isc_uint32_t interval) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ zone->sigvalidityinterval = interval;
+}
+
+isc_uint32_t
+dns_zone_getsigvalidityinterval(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->sigvalidityinterval);
+}
+
+static void
+queue_xfrin(dns_zone_t *zone) {
+ const char me[] = "queue_xfrin";
+ isc_result_t result;
+ dns_zonemgr_t *zmgr = zone->zmgr;
+
+ ENTER;
+
+ INSIST(zone->statelist == NULL);
+
+ RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+ ISC_LIST_APPEND(zmgr->waiting_for_xfrin, zone, statelink);
+ LOCK_ZONE(zone);
+ zone->irefs++;
+ UNLOCK_ZONE(zone);
+ zone->statelist = &zmgr->waiting_for_xfrin;
+ result = zmgr_start_xfrin_ifquota(zmgr, zone);
+ RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+
+ if (result == ISC_R_QUOTA) {
+ dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO,
+ "zone transfer deferred due to quota");
+ } else if (result != ISC_R_SUCCESS) {
+ dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_ERROR,
+ "starting zone transfer: %s",
+ isc_result_totext(result));
+ }
+}
+
+/*
+ * This event callback is called when a zone has received
+ * any necessary zone transfer quota. This is the time
+ * to go ahead and start the transfer.
+ */
+static void
+got_transfer_quota(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ dns_peer_t *peer = NULL;
+ char mastertext[256];
+ dns_rdatatype_t xfrtype;
+ dns_zone_t *zone = event->ev_arg;
+ isc_netaddr_t masterip;
+ isc_sockaddr_t sourceaddr;
+ isc_sockaddr_t masteraddr;
+
+ UNUSED(task);
+
+ INSIST(task == zone->task);
+
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ isc_sockaddr_format(&zone->masteraddr, mastertext, sizeof(mastertext));
+
+ isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr);
+ (void)dns_peerlist_peerbyaddr(zone->view->peers,
+ &masterip, &peer);
+
+ /*
+ * Decide whether we should request IXFR or AXFR.
+ */
+ if (zone->db == NULL) {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "no database exists yet, "
+ "requesting AXFR of "
+ "initial version from %s", mastertext);
+ xfrtype = dns_rdatatype_axfr;
+ } else if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS)) {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1), "ixfr-from-differences "
+ "set, requesting AXFR from %s", mastertext);
+ xfrtype = dns_rdatatype_axfr;
+ } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "forced reload, requesting AXFR of "
+ "initial version from %s", mastertext);
+ xfrtype = dns_rdatatype_axfr;
+ } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLAG_NOIXFR)) {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "retrying with AXFR from %s due to "
+ "previous IXFR failure", mastertext);
+ xfrtype = dns_rdatatype_axfr;
+ LOCK_ZONE(zone);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLAG_NOIXFR);
+ UNLOCK_ZONE(zone);
+ } else {
+ isc_boolean_t use_ixfr = ISC_TRUE;
+ if (peer != NULL &&
+ dns_peer_getrequestixfr(peer, &use_ixfr) ==
+ ISC_R_SUCCESS) {
+ ; /* Using peer setting */
+ } else {
+ use_ixfr = zone->view->requestixfr;
+ }
+ if (use_ixfr == ISC_FALSE) {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "IXFR disabled, "
+ "requesting AXFR from %s",
+ mastertext);
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR))
+ xfrtype = dns_rdatatype_soa;
+ else
+ xfrtype = dns_rdatatype_axfr;
+ } else {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "requesting IXFR from %s",
+ mastertext);
+ xfrtype = dns_rdatatype_ixfr;
+ }
+ }
+
+ /*
+ * Determine if we should attempt to sign the request with TSIG.
+ */
+ result = ISC_R_NOTFOUND;
+ /*
+ * First, look for a tsig key in the master statement, then
+ * try for a server key.
+ */
+ if ((zone->masterkeynames != NULL) &&
+ (zone->masterkeynames[zone->curmaster] != NULL)) {
+ dns_view_t *view = dns_zone_getview(zone);
+ dns_name_t *keyname = zone->masterkeynames[zone->curmaster];
+ result = dns_view_gettsig(view, keyname, &zone->tsigkey);
+ }
+ if (zone->tsigkey == NULL)
+ result = dns_view_getpeertsig(zone->view, &masterip,
+ &zone->tsigkey);
+
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "could not get TSIG key "
+ "for zone transfer: %s",
+ isc_result_totext(result));
+ }
+
+ LOCK_ZONE(zone);
+ masteraddr = zone->masteraddr;
+ sourceaddr = zone->sourceaddr;
+ UNLOCK_ZONE(zone);
+ INSIST(isc_sockaddr_pf(&masteraddr) == isc_sockaddr_pf(&sourceaddr));
+ result = dns_xfrin_create2(zone, xfrtype, &masteraddr, &sourceaddr,
+ zone->tsigkey, zone->mctx,
+ zone->zmgr->timermgr, zone->zmgr->socketmgr,
+ zone->task, zone_xfrdone, &zone->xfr);
+ cleanup:
+ /*
+ * Any failure in this function is handled like a failed
+ * zone transfer. This ensures that we get removed from
+ * zmgr->xfrin_in_progress.
+ */
+ if (result != ISC_R_SUCCESS)
+ zone_xfrdone(zone, result);
+
+ isc_event_free(&event);
+}
+
+/*
+ * Update forwarding support.
+ */
+
+static void
+forward_destroy(dns_forward_t *forward) {
+
+ forward->magic = 0;
+ if (forward->request != NULL)
+ dns_request_destroy(&forward->request);
+ if (forward->msgbuf != NULL)
+ isc_buffer_free(&forward->msgbuf);
+ if (forward->zone != NULL)
+ dns_zone_idetach(&forward->zone);
+ isc_mem_putanddetach(&forward->mctx, forward, sizeof(*forward));
+}
+
+static isc_result_t
+sendtomaster(dns_forward_t *forward) {
+ isc_result_t result;
+ isc_sockaddr_t src;
+
+ LOCK_ZONE(forward->zone);
+ if (forward->which >= forward->zone->masterscnt) {
+ UNLOCK_ZONE(forward->zone);
+ return (ISC_R_NOMORE);
+ }
+
+ forward->addr = forward->zone->masters[forward->which];
+ /*
+ * Always use TCP regardless of whether the original update
+ * used TCP.
+ * XXX The timeout may but a bit small if we are far down a
+ * transfer graph and the master has to try several masters.
+ */
+ switch (isc_sockaddr_pf(&forward->addr)) {
+ case PF_INET:
+ src = forward->zone->xfrsource4;
+ break;
+ case PF_INET6:
+ src = forward->zone->xfrsource6;
+ break;
+ default:
+ result = ISC_R_NOTIMPLEMENTED;
+ goto unlock;
+ }
+ result = dns_request_createraw(forward->zone->view->requestmgr,
+ forward->msgbuf,
+ &src, &forward->addr,
+ DNS_REQUESTOPT_TCP, 15 /* XXX */,
+ forward->zone->task,
+ forward_callback, forward,
+ &forward->request);
+ unlock:
+ UNLOCK_ZONE(forward->zone);
+ return (result);
+}
+
+static void
+forward_callback(isc_task_t *task, isc_event_t *event) {
+ const char me[] = "forward_callback";
+ dns_requestevent_t *revent = (dns_requestevent_t *)event;
+ dns_message_t *msg = NULL;
+ char master[ISC_SOCKADDR_FORMATSIZE];
+ isc_result_t result;
+ dns_forward_t *forward;
+ dns_zone_t *zone;
+
+ UNUSED(task);
+
+ forward = revent->ev_arg;
+ INSIST(DNS_FORWARD_VALID(forward));
+ zone = forward->zone;
+ INSIST(DNS_ZONE_VALID(zone));
+
+ ENTER;
+
+ isc_sockaddr_format(&forward->addr, master, sizeof(master));
+
+ if (revent->result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "could not forward dynamic update to %s: %s",
+ master, dns_result_totext(revent->result));
+ goto next_master;
+ }
+
+ result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg);
+ if (result != ISC_R_SUCCESS)
+ goto next_master;
+
+ result = dns_request_getresponse(revent->request, msg,
+ DNS_MESSAGEPARSE_PRESERVEORDER |
+ DNS_MESSAGEPARSE_CLONEBUFFER);
+ if (result != ISC_R_SUCCESS)
+ goto next_master;
+
+ switch (msg->rcode) {
+ /*
+ * Pass these rcodes back to client.
+ */
+ case dns_rcode_noerror:
+ case dns_rcode_yxdomain:
+ case dns_rcode_yxrrset:
+ case dns_rcode_nxrrset:
+ case dns_rcode_refused:
+ case dns_rcode_nxdomain:
+ break;
+
+ /* These should not occur if the masters/zone are valid. */
+ case dns_rcode_notzone:
+ case dns_rcode_notauth: {
+ char rcode[128];
+ isc_buffer_t rb;
+
+ isc_buffer_init(&rb, rcode, sizeof(rcode));
+ (void)dns_rcode_totext(msg->rcode, &rb);
+ dns_zone_log(zone, ISC_LOG_WARNING,
+ "forwarding dynamic update: "
+ "unexpected response: master %s returned: %.*s",
+ master, (int)rb.used, rcode);
+ goto next_master;
+ }
+
+ /* Try another server for these rcodes. */
+ case dns_rcode_formerr:
+ case dns_rcode_servfail:
+ case dns_rcode_notimp:
+ case dns_rcode_badvers:
+ default:
+ goto next_master;
+ }
+
+ /* call callback */
+ (forward->callback)(forward->callback_arg, ISC_R_SUCCESS, msg);
+ msg = NULL;
+ dns_request_destroy(&forward->request);
+ forward_destroy(forward);
+ isc_event_free(&event);
+ return;
+
+ next_master:
+ if (msg != NULL)
+ dns_message_destroy(&msg);
+ isc_event_free(&event);
+ forward->which++;
+ dns_request_destroy(&forward->request);
+ result = sendtomaster(forward);
+ if (result != ISC_R_SUCCESS) {
+ /* call callback */
+ dns_zone_log(zone, ISC_LOG_DEBUG(3),
+ "exhausted dynamic update forwarder list");
+ (forward->callback)(forward->callback_arg, result, NULL);
+ forward_destroy(forward);
+ }
+}
+
+isc_result_t
+dns_zone_forwardupdate(dns_zone_t *zone, dns_message_t *msg,
+ dns_updatecallback_t callback, void *callback_arg)
+{
+ dns_forward_t *forward;
+ isc_result_t result;
+ isc_region_t *mr;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(msg != NULL);
+ REQUIRE(callback != NULL);
+
+ forward = isc_mem_get(zone->mctx, sizeof(*forward));
+ if (forward == NULL)
+ return (ISC_R_NOMEMORY);
+
+ forward->request = NULL;
+ forward->zone = NULL;
+ forward->msgbuf = NULL;
+ forward->which = 0;
+ forward->mctx = 0;
+ forward->callback = callback;
+ forward->callback_arg = callback_arg;
+ forward->magic = FORWARD_MAGIC;
+
+ mr = dns_message_getrawmessage(msg);
+ if (mr == NULL) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto cleanup;
+ }
+
+ result = isc_buffer_allocate(zone->mctx, &forward->msgbuf, mr->length);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = isc_buffer_copyregion(forward->msgbuf, mr);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ isc_mem_attach(zone->mctx, &forward->mctx);
+ dns_zone_iattach(zone, &forward->zone);
+ result = sendtomaster(forward);
+
+ cleanup:
+ if (result != ISC_R_SUCCESS) {
+ forward_destroy(forward);
+ }
+ return (result);
+}
+
+isc_result_t
+dns_zone_next(dns_zone_t *zone, dns_zone_t **next) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(next != NULL && *next == NULL);
+
+ *next = ISC_LIST_NEXT(zone, link);
+ if (*next == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_zone_first(dns_zonemgr_t *zmgr, dns_zone_t **first) {
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+ REQUIRE(first != NULL && *first == NULL);
+
+ *first = ISC_LIST_HEAD(zmgr->zones);
+ if (*first == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+/***
+ *** Zone manager.
+ ***/
+
+isc_result_t
+dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
+ isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
+ dns_zonemgr_t **zmgrp)
+{
+ dns_zonemgr_t *zmgr;
+ isc_result_t result;
+ isc_interval_t interval;
+
+ zmgr = isc_mem_get(mctx, sizeof(*zmgr));
+ if (zmgr == NULL)
+ return (ISC_R_NOMEMORY);
+ zmgr->mctx = NULL;
+ zmgr->refs = 1;
+ isc_mem_attach(mctx, &zmgr->mctx);
+ zmgr->taskmgr = taskmgr;
+ zmgr->timermgr = timermgr;
+ zmgr->socketmgr = socketmgr;
+ zmgr->zonetasks = NULL;
+ zmgr->task = NULL;
+ zmgr->rl = NULL;
+ ISC_LIST_INIT(zmgr->zones);
+ ISC_LIST_INIT(zmgr->waiting_for_xfrin);
+ ISC_LIST_INIT(zmgr->xfrin_in_progress);
+ result = isc_rwlock_init(&zmgr->rwlock, 0, 0);
+ if (result != ISC_R_SUCCESS)
+ goto free_mem;
+
+ zmgr->transfersin = 10;
+ zmgr->transfersperns = 2;
+
+ /* Create the zone task pool. */
+ result = isc_taskpool_create(taskmgr, mctx,
+ 8 /* XXX */, 2, &zmgr->zonetasks);
+ if (result != ISC_R_SUCCESS)
+ goto free_rwlock;
+
+ /* Create a single task for queueing of SOA queries. */
+ result = isc_task_create(taskmgr, 1, &zmgr->task);
+ if (result != ISC_R_SUCCESS)
+ goto free_taskpool;
+ isc_task_setname(zmgr->task, "zmgr", zmgr);
+ result = isc_ratelimiter_create(mctx, timermgr, zmgr->task,
+ &zmgr->rl);
+ if (result != ISC_R_SUCCESS)
+ goto free_task;
+ /* default to 20 refresh queries / notifies per second. */
+ isc_interval_set(&interval, 0, 1000000000/2);
+ result = isc_ratelimiter_setinterval(zmgr->rl, &interval);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ isc_ratelimiter_setpertic(zmgr->rl, 10);
+
+ zmgr->iolimit = 1;
+ zmgr->ioactive = 0;
+ ISC_LIST_INIT(zmgr->high);
+ ISC_LIST_INIT(zmgr->low);
+
+ result = isc_mutex_init(&zmgr->iolock);
+ if (result != ISC_R_SUCCESS)
+ goto free_rl;
+
+ zmgr->magic = ZONEMGR_MAGIC;
+
+ *zmgrp = zmgr;
+ return (ISC_R_SUCCESS);
+
+#if 0
+ free_iolock:
+ DESTROYLOCK(&zmgr->iolock);
+#endif
+ free_rl:
+ isc_ratelimiter_detach(&zmgr->rl);
+ free_task:
+ isc_task_detach(&zmgr->task);
+ free_taskpool:
+ isc_taskpool_destroy(&zmgr->zonetasks);
+ free_rwlock:
+ isc_rwlock_destroy(&zmgr->rwlock);
+ free_mem:
+ isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr));
+ isc_mem_detach(&mctx);
+ return (result);
+}
+
+isc_result_t
+dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
+ isc_result_t result;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+ LOCK_ZONE(zone);
+ REQUIRE(zone->task == NULL);
+ REQUIRE(zone->timer == NULL);
+ REQUIRE(zone->zmgr == NULL);
+
+ isc_taskpool_gettask(zmgr->zonetasks,
+ dns_name_hash(dns_zone_getorigin(zone),
+ ISC_FALSE),
+ &zone->task);
+
+ /*
+ * Set the task name. The tag will arbitrarily point to one
+ * of the zones sharing the task (in practice, the one
+ * to be managed last).
+ */
+ isc_task_setname(zone->task, "zone", zone);
+
+ result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive,
+ NULL, NULL,
+ zone->task, zone_timer, zone,
+ &zone->timer);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_task;
+ /*
+ * The timer "holds" a iref.
+ */
+ zone->irefs++;
+ INSIST(zone->irefs != 0);
+
+ ISC_LIST_APPEND(zmgr->zones, zone, link);
+ zone->zmgr = zmgr;
+ zmgr->refs++;
+
+ goto unlock;
+
+ cleanup_task:
+ isc_task_detach(&zone->task);
+
+ unlock:
+ UNLOCK_ZONE(zone);
+ RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+ return (result);
+}
+
+void
+dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
+ isc_boolean_t free_now = ISC_FALSE;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+ REQUIRE(zone->zmgr == zmgr);
+
+ RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+ LOCK_ZONE(zone);
+
+ ISC_LIST_UNLINK(zmgr->zones, zone, link);
+ zone->zmgr = NULL;
+ zmgr->refs--;
+ if (zmgr->refs == 0)
+ free_now = ISC_TRUE;
+
+ UNLOCK_ZONE(zone);
+ RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+
+ if (free_now)
+ zonemgr_free(zmgr);
+ ENSURE(zone->zmgr == NULL);
+}
+
+void
+dns_zonemgr_attach(dns_zonemgr_t *source, dns_zonemgr_t **target) {
+ REQUIRE(DNS_ZONEMGR_VALID(source));
+ REQUIRE(target != NULL && *target == NULL);
+
+ RWLOCK(&source->rwlock, isc_rwlocktype_write);
+ REQUIRE(source->refs > 0);
+ source->refs++;
+ INSIST(source->refs > 0);
+ RWUNLOCK(&source->rwlock, isc_rwlocktype_write);
+ *target = source;
+}
+
+void
+dns_zonemgr_detach(dns_zonemgr_t **zmgrp) {
+ dns_zonemgr_t *zmgr;
+ isc_boolean_t free_now = ISC_FALSE;
+
+ REQUIRE(zmgrp != NULL);
+ zmgr = *zmgrp;
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+ zmgr->refs--;
+ if (zmgr->refs == 0)
+ free_now = ISC_TRUE;
+ RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+
+ if (free_now)
+ zonemgr_free(zmgr);
+}
+
+isc_result_t
+dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr) {
+ dns_zone_t *p;
+
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ RWLOCK(&zmgr->rwlock, isc_rwlocktype_read);
+ for (p = ISC_LIST_HEAD(zmgr->zones);
+ p != NULL;
+ p = ISC_LIST_NEXT(p, link))
+ {
+ dns_zone_maintenance(p);
+ }
+ RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read);
+
+ /*
+ * Recent configuration changes may have increased the
+ * amount of available transfers quota. Make sure any
+ * transfers currently blocked on quota get started if
+ * possible.
+ */
+ RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+ zmgr_resume_xfrs(zmgr, ISC_TRUE);
+ RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_zonemgr_resumexfrs(dns_zonemgr_t *zmgr) {
+
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+ zmgr_resume_xfrs(zmgr, ISC_TRUE);
+ RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+}
+
+void
+dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) {
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ isc_ratelimiter_shutdown(zmgr->rl);
+
+ if (zmgr->task != NULL)
+ isc_task_destroy(&zmgr->task);
+ if (zmgr->zonetasks != NULL)
+ isc_taskpool_destroy(&zmgr->zonetasks);
+}
+
+static void
+zonemgr_free(dns_zonemgr_t *zmgr) {
+ isc_mem_t *mctx;
+
+ INSIST(zmgr->refs == 0);
+ INSIST(ISC_LIST_EMPTY(zmgr->zones));
+
+ zmgr->magic = 0;
+
+ DESTROYLOCK(&zmgr->iolock);
+ isc_ratelimiter_detach(&zmgr->rl);
+
+ isc_rwlock_destroy(&zmgr->rwlock);
+ mctx = zmgr->mctx;
+ isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr));
+ isc_mem_detach(&mctx);
+}
+
+void
+dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, isc_uint32_t value) {
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ zmgr->transfersin = value;
+}
+
+isc_uint32_t
+dns_zonemgr_getttransfersin(dns_zonemgr_t *zmgr) {
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ return (zmgr->transfersin);
+}
+
+void
+dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, isc_uint32_t value) {
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ zmgr->transfersperns = value;
+}
+
+isc_uint32_t
+dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr) {
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ return (zmgr->transfersperns);
+}
+
+/*
+ * Try to start a new incoming zone transfer to fill a quota
+ * slot that was just vacated.
+ *
+ * Requires:
+ * The zone manager is locked by the caller.
+ */
+static void
+zmgr_resume_xfrs(dns_zonemgr_t *zmgr, isc_boolean_t multi) {
+ dns_zone_t *zone;
+ dns_zone_t *next;
+
+ for (zone = ISC_LIST_HEAD(zmgr->waiting_for_xfrin);
+ zone != NULL;
+ zone = next)
+ {
+ isc_result_t result;
+ next = ISC_LIST_NEXT(zone, statelink);
+ result = zmgr_start_xfrin_ifquota(zmgr, zone);
+ if (result == ISC_R_SUCCESS) {
+ if (multi)
+ continue;
+ /*
+ * We successfully filled the slot. We're done.
+ */
+ break;
+ } else if (result == ISC_R_QUOTA) {
+ /*
+ * Not enough quota. This is probably the per-server
+ * quota, because we usually get called when a unit of
+ * global quota has just been freed. Try the next
+ * zone, it may succeed if it uses another master.
+ */
+ continue;
+ } else {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "starting zone transfer: %s",
+ isc_result_totext(result));
+ break;
+ }
+ }
+}
+
+/*
+ * Try to start an incoming zone transfer for 'zone', quota permitting.
+ *
+ * Requires:
+ * The zone manager is locked by the caller.
+ *
+ * Returns:
+ * ISC_R_SUCCESS There was enough quota and we attempted to
+ * start a transfer. zone_xfrdone() has been or will
+ * be called.
+ * ISC_R_QUOTA Not enough quota.
+ * Others Failure.
+ */
+static isc_result_t
+zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
+ dns_peer_t *peer = NULL;
+ isc_netaddr_t masterip;
+ isc_uint32_t nxfrsin, nxfrsperns;
+ dns_zone_t *x;
+ isc_uint32_t maxtransfersin, maxtransfersperns;
+ isc_event_t *e;
+
+ /*
+ * Find any configured information about the server we'd
+ * like to transfer this zone from.
+ */
+ isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr);
+ (void)dns_peerlist_peerbyaddr(zone->view->peers,
+ &masterip, &peer);
+
+ /*
+ * Determine the total maximum number of simultaneous
+ * transfers allowed, and the maximum for this specific
+ * master.
+ */
+ maxtransfersin = zmgr->transfersin;
+ maxtransfersperns = zmgr->transfersperns;
+ if (peer != NULL)
+ (void)dns_peer_gettransfers(peer, &maxtransfersperns);
+
+ /*
+ * Count the total number of transfers that are in progress,
+ * and the number of transfers in progress from this master.
+ * We linearly scan a list of all transfers; if this turns
+ * out to be too slow, we could hash on the master address.
+ */
+ nxfrsin = nxfrsperns = 0;
+ for (x = ISC_LIST_HEAD(zmgr->xfrin_in_progress);
+ x != NULL;
+ x = ISC_LIST_NEXT(x, statelink))
+ {
+ isc_netaddr_t xip;
+ isc_netaddr_fromsockaddr(&xip, &x->masteraddr);
+ nxfrsin++;
+ if (isc_netaddr_equal(&xip, &masterip))
+ nxfrsperns++;
+ }
+
+ /* Enforce quota. */
+ if (nxfrsin >= maxtransfersin)
+ return (ISC_R_QUOTA);
+
+ if (nxfrsperns >= maxtransfersperns)
+ return (ISC_R_QUOTA);
+
+ /*
+ * We have sufficient quota. Move the zone to the "xfrin_in_progress"
+ * list and send it an event to let it start the actual transfer in the
+ * context of its own task.
+ */
+ e = isc_event_allocate(zmgr->mctx, zmgr,
+ DNS_EVENT_ZONESTARTXFRIN,
+ got_transfer_quota, zone,
+ sizeof(isc_event_t));
+ if (e == NULL)
+ return (ISC_R_NOMEMORY);
+
+ LOCK_ZONE(zone);
+ INSIST(zone->statelist == &zmgr->waiting_for_xfrin);
+ ISC_LIST_UNLINK(zmgr->waiting_for_xfrin, zone, statelink);
+ ISC_LIST_APPEND(zmgr->xfrin_in_progress, zone, statelink);
+ zone->statelist = &zmgr->xfrin_in_progress;
+ isc_task_send(zone->task, &e);
+ dns_zone_log(zone, ISC_LOG_INFO, "Transfer started.");
+ UNLOCK_ZONE(zone);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_zonemgr_setiolimit(dns_zonemgr_t *zmgr, isc_uint32_t iolimit) {
+
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+ REQUIRE(iolimit > 0);
+
+ zmgr->iolimit = iolimit;
+}
+
+isc_uint32_t
+dns_zonemgr_getiolimit(dns_zonemgr_t *zmgr) {
+
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ return (zmgr->iolimit);
+}
+
+/*
+ * Get permission to request a file handle from the OS.
+ * An event will be sent to action when one is available.
+ * There are two queues available (high and low), the high
+ * queue will be serviced before the low one.
+ *
+ * zonemgr_putio() must be called after the event is delivered to
+ * 'action'.
+ */
+
+static isc_result_t
+zonemgr_getio(dns_zonemgr_t *zmgr, isc_boolean_t high,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_io_t **iop)
+{
+ dns_io_t *io;
+ isc_boolean_t queue;
+
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+ REQUIRE(iop != NULL && *iop == NULL);
+
+ io = isc_mem_get(zmgr->mctx, sizeof(*io));
+ if (io == NULL)
+ return (ISC_R_NOMEMORY);
+ io->event = isc_event_allocate(zmgr->mctx, task, DNS_EVENT_IOREADY,
+ action, arg, sizeof(*io->event));
+ if (io->event == NULL) {
+ isc_mem_put(zmgr->mctx, io, sizeof(*io));
+ return (ISC_R_NOMEMORY);
+ }
+ io->zmgr = zmgr;
+ io->high = high;
+ io->task = NULL;
+ isc_task_attach(task, &io->task);
+ ISC_LINK_INIT(io, link);
+ io->magic = IO_MAGIC;
+
+ LOCK(&zmgr->iolock);
+ zmgr->ioactive++;
+ queue = ISC_TF(zmgr->ioactive > zmgr->iolimit);
+ if (queue) {
+ if (io->high)
+ ISC_LIST_APPEND(zmgr->high, io, link);
+ else
+ ISC_LIST_APPEND(zmgr->low, io, link);
+ }
+ UNLOCK(&zmgr->iolock);
+ *iop = io;
+
+ if (!queue) {
+ isc_task_send(io->task, &io->event);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static void
+zonemgr_putio(dns_io_t **iop) {
+ dns_io_t *io;
+ dns_io_t *next;
+ dns_zonemgr_t *zmgr;
+
+ REQUIRE(iop != NULL);
+ io = *iop;
+ REQUIRE(DNS_IO_VALID(io));
+
+ *iop = NULL;
+
+ INSIST(!ISC_LINK_LINKED(io, link));
+ INSIST(io->event == NULL);
+
+ zmgr = io->zmgr;
+ isc_task_detach(&io->task);
+ io->magic = 0;
+ isc_mem_put(zmgr->mctx, io, sizeof(*io));
+
+ LOCK(&zmgr->iolock);
+ INSIST(zmgr->ioactive > 0);
+ zmgr->ioactive--;
+ next = HEAD(zmgr->high);
+ if (next == NULL)
+ next = HEAD(zmgr->low);
+ if (next != NULL) {
+ if (next->high)
+ ISC_LIST_UNLINK(zmgr->high, next, link);
+ else
+ ISC_LIST_UNLINK(zmgr->low, next, link);
+ INSIST(next->event != NULL);
+ }
+ UNLOCK(&zmgr->iolock);
+ if (next != NULL)
+ isc_task_send(next->task, &next->event);
+}
+
+static void
+zonemgr_cancelio(dns_io_t *io) {
+ isc_boolean_t send_event = ISC_FALSE;
+
+ REQUIRE(DNS_IO_VALID(io));
+
+ /*
+ * If we are queued to be run then dequeue.
+ */
+ LOCK(&io->zmgr->iolock);
+ if (ISC_LINK_LINKED(io, link)) {
+ if (io->high)
+ ISC_LIST_UNLINK(io->zmgr->high, io, link);
+ else
+ ISC_LIST_UNLINK(io->zmgr->low, io, link);
+
+ send_event = ISC_TRUE;
+ INSIST(io->event != NULL);
+ }
+ UNLOCK(&io->zmgr->iolock);
+ if (send_event) {
+ io->event->ev_attributes |= ISC_EVENTATTR_CANCELED;
+ isc_task_send(io->task, &io->event);
+ }
+}
+
+static void
+zone_saveunique(dns_zone_t *zone, const char *path, const char *templat) {
+ char *buf;
+ int buflen;
+ isc_result_t result;
+
+ buflen = strlen(path) + strlen(templat) + 2;
+
+ buf = isc_mem_get(zone->mctx, buflen);
+ if (buf == NULL)
+ return;
+
+ result = isc_file_template(path, templat, buf, buflen);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ result = isc_file_renameunique(path, buf);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ dns_zone_log(zone, ISC_LOG_INFO, "saved '%s' as '%s'",
+ path, buf);
+
+ cleanup:
+ isc_mem_put(zone->mctx, buf, buflen);
+}
+
+#if 0
+/* Hook for ondestroy notifcation from a database. */
+
+static void
+dns_zonemgr_dbdestroyed(isc_task_t *task, isc_event_t *event) {
+ dns_db_t *db = event->sender;
+ UNUSED(task);
+
+ isc_event_free(&event);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
+ "database (%p) destroyed", (void*) db);
+}
+#endif
+
+void
+dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) {
+ isc_interval_t interval;
+ isc_uint32_t s, ns;
+ isc_uint32_t pertic;
+ isc_result_t result;
+
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ if (value == 0)
+ value = 1;
+
+ if (value == 1) {
+ s = 1;
+ ns = 0;
+ pertic = 1;
+ } else if (value <= 10) {
+ s = 0;
+ ns = 1000000000 / value;
+ pertic = 1;
+ } else {
+ s = 0;
+ ns = (1000000000 / value) * 10;
+ pertic = 10;
+ }
+
+ isc_interval_set(&interval, s, ns);
+ result = isc_ratelimiter_setinterval(zmgr->rl, &interval);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ isc_ratelimiter_setpertic(zmgr->rl, pertic);
+
+ zmgr->serialqueryrate = value;
+}
+
+unsigned int
+dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr) {
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ return (zmgr->serialqueryrate);
+}
+
+void
+dns_zone_forcereload(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ if (zone->type == dns_zone_master)
+ return;
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_FORCEXFER);
+ UNLOCK_ZONE(zone);
+ dns_zone_refresh(zone);
+}
+
+isc_boolean_t
+dns_zone_isforced(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER));
+}
+
+isc_result_t
+dns_zone_setstatistics(dns_zone_t *zone, isc_boolean_t on) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ LOCK_ZONE(zone);
+ if (on) {
+ if (zone->counters != NULL)
+ goto done;
+ result = dns_stats_alloccounters(zone->mctx, &zone->counters);
+ } else {
+ if (zone->counters == NULL)
+ goto done;
+ dns_stats_freecounters(zone->mctx, &zone->counters);
+ }
+ done:
+ UNLOCK_ZONE(zone);
+ return (result);
+}
+
+isc_uint64_t *
+dns_zone_getstatscounters(dns_zone_t *zone) {
+ return (zone->counters);
+}
+
+void
+dns_zone_dialup(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ zone_debuglog(zone, "dns_zone_dialup", 3,
+ "notify = %d, refresh = %d",
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY),
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH));
+
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY))
+ dns_zone_notify(zone);
+ if (zone->type != dns_zone_master &&
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH))
+ dns_zone_refresh(zone);
+}
+
+void
+dns_zone_setdialup(dns_zone_t *zone, dns_dialuptype_t dialup) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_DIALNOTIFY |
+ DNS_ZONEFLG_DIALREFRESH |
+ DNS_ZONEFLG_NOREFRESH);
+ switch (dialup) {
+ case dns_dialuptype_no:
+ break;
+ case dns_dialuptype_yes:
+ DNS_ZONE_SETFLAG(zone, (DNS_ZONEFLG_DIALNOTIFY |
+ DNS_ZONEFLG_DIALREFRESH |
+ DNS_ZONEFLG_NOREFRESH));
+ break;
+ case dns_dialuptype_notify:
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALNOTIFY);
+ break;
+ case dns_dialuptype_notifypassive:
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALNOTIFY);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH);
+ break;
+ case dns_dialuptype_refresh:
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALREFRESH);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH);
+ break;
+ case dns_dialuptype_passive:
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH);
+ break;
+ default:
+ INSIST(0);
+ }
+ UNLOCK_ZONE(zone);
+}
+
+isc_result_t
+dns_zone_setkeydirectory(dns_zone_t *zone, const char *directory) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ result = dns_zone_setstring(zone, &zone->keydirectory, directory);
+ UNLOCK_ZONE(zone);
+
+ return (result);
+}
+
+const char *
+dns_zone_getkeydirectory(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->keydirectory);
+}
+
+unsigned int
+dns_zonemgr_getcount(dns_zonemgr_t *zmgr, int state) {
+ dns_zone_t *zone;
+ unsigned int count = 0;
+
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ RWLOCK(&zmgr->rwlock, isc_rwlocktype_read);
+ switch (state) {
+ case DNS_ZONESTATE_XFERRUNNING:
+ for (zone = ISC_LIST_HEAD(zmgr->xfrin_in_progress);
+ zone != NULL;
+ zone = ISC_LIST_NEXT(zone, statelink))
+ count++;
+ break;
+ case DNS_ZONESTATE_XFERDEFERRED:
+ for (zone = ISC_LIST_HEAD(zmgr->waiting_for_xfrin);
+ zone != NULL;
+ zone = ISC_LIST_NEXT(zone, statelink))
+ count++;
+ break;
+ case DNS_ZONESTATE_SOAQUERY:
+ for (zone = ISC_LIST_HEAD(zmgr->zones);
+ zone != NULL;
+ zone = ISC_LIST_NEXT(zone, link))
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH))
+ count++;
+ break;
+ case DNS_ZONESTATE_ANY:
+ for (zone = ISC_LIST_HEAD(zmgr->zones);
+ zone != NULL;
+ zone = ISC_LIST_NEXT(zone, link)) {
+ dns_view_t *view = zone->view;
+ if (view != NULL && strcmp(view->name, "_bind") == 0)
+ continue;
+ count++;
+ }
+ break;
+ default:
+ INSIST(0);
+ }
+
+ RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read);
+
+ return (count);
+}
+
+isc_result_t
+dns_zone_checknames(dns_zone_t *zone, dns_name_t *name, dns_rdata_t *rdata) {
+ isc_boolean_t ok = ISC_TRUE;
+ isc_boolean_t fail = ISC_FALSE;
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char namebuf2[DNS_NAME_FORMATSIZE];
+ char typebuf[DNS_RDATATYPE_FORMATSIZE];
+ int level = ISC_LOG_WARNING;
+ dns_name_t bad;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES))
+ return (ISC_R_SUCCESS);
+
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL)) {
+ level = ISC_LOG_ERROR;
+ fail = ISC_TRUE;
+ }
+
+ ok = dns_rdata_checkowner(name, rdata->rdclass, rdata->type, ISC_TRUE);
+ if (!ok) {
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf));
+ dns_zone_log(zone, level, "%s/%s: %s", namebuf, typebuf,
+ dns_result_totext(DNS_R_BADOWNERNAME));
+ if (fail)
+ return (DNS_R_BADOWNERNAME);
+ }
+
+ dns_name_init(&bad, NULL);
+ ok = dns_rdata_checknames(rdata, name, &bad);
+ if (!ok) {
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ dns_name_format(&bad, namebuf2, sizeof(namebuf2));
+ dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf));
+ dns_zone_log(zone, level, "%s/%s: %s: %s ", namebuf, typebuf,
+ namebuf2, dns_result_totext(DNS_R_BADNAME));
+ if (fail)
+ return (DNS_R_BADNAME);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ zone->checkmx = checkmx;
+}
+
+void
+dns_zone_setchecksrv(dns_zone_t *zone, dns_checksrvfunc_t checksrv) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ zone->checksrv = checksrv;
+}
+
+void
+dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ zone->checkns = checkns;
+}
+
+void
+dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ zone->isself = isself;
+ zone->isselfarg = arg;
+ UNLOCK_ZONE(zone);
+}
+
+void
+dns_zone_setnotifydelay(dns_zone_t *zone, isc_uint32_t delay) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ zone->notifydelay = delay;
+ UNLOCK_ZONE(zone);
+}
+
+isc_uint32_t
+dns_zone_getnotifydelay(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->notifydelay);
+}
diff --git a/lib/dns/zonekey.c b/lib/dns/zonekey.c
new file mode 100644
index 0000000..0ed63bb
--- /dev/null
+++ b/lib/dns/zonekey.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2004, 2005 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: zonekey.c,v 1.5.18.2 2005/04/29 00:16:08 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/result.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <dns/keyvalues.h>
+#include <dns/rdata.h>
+#include <dns/rdatastruct.h>
+#include <dns/types.h>
+#include <dns/zonekey.h>
+
+isc_boolean_t
+dns_zonekey_iszonekey(dns_rdata_t *keyrdata) {
+ isc_result_t result;
+ dns_rdata_dnskey_t key;
+ isc_boolean_t iszonekey = ISC_TRUE;
+
+ REQUIRE(keyrdata != NULL);
+
+ result = dns_rdata_tostruct(keyrdata, &key, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_FALSE);
+
+ if ((key.flags & DNS_KEYTYPE_NOAUTH) != 0)
+ iszonekey = ISC_FALSE;
+ if ((key.flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
+ iszonekey = ISC_FALSE;
+ if (key.protocol != DNS_KEYPROTO_DNSSEC &&
+ key.protocol != DNS_KEYPROTO_ANY)
+ iszonekey = ISC_FALSE;
+
+ return (iszonekey);
+}
diff --git a/lib/dns/zt.c b/lib/dns/zt.c
new file mode 100644
index 0000000..4cb8f3f
--- /dev/null
+++ b/lib/dns/zt.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2004, 2005 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: zt.c,v 1.38.18.5 2005/11/30 03:44:39 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/file.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/log.h>
+#include <dns/name.h>
+#include <dns/rbt.h>
+#include <dns/rdataclass.h>
+#include <dns/result.h>
+#include <dns/view.h>
+#include <dns/zone.h>
+#include <dns/zt.h>
+
+struct dns_zt {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t *mctx;
+ dns_rdataclass_t rdclass;
+ isc_rwlock_t rwlock;
+ /* Locked by lock. */
+ isc_uint32_t references;
+ dns_rbt_t *table;
+};
+
+#define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l')
+#define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC)
+
+static void
+auto_detach(void *, void *);
+
+static isc_result_t
+load(dns_zone_t *zone, void *uap);
+
+static isc_result_t
+loadnew(dns_zone_t *zone, void *uap);
+
+static isc_result_t
+freezezones(dns_zone_t *zone, void *uap);
+
+isc_result_t
+dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) {
+ dns_zt_t *zt;
+ isc_result_t result;
+
+ REQUIRE(ztp != NULL && *ztp == NULL);
+
+ zt = isc_mem_get(mctx, sizeof(*zt));
+ if (zt == NULL)
+ return (ISC_R_NOMEMORY);
+
+ zt->table = NULL;
+ result = dns_rbt_create(mctx, auto_detach, zt, &zt->table);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_zt;
+
+ result = isc_rwlock_init(&zt->rwlock, 0, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_rbt;
+
+ zt->mctx = mctx;
+ zt->references = 1;
+ zt->rdclass = rdclass;
+ zt->magic = ZTMAGIC;
+ *ztp = zt;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_rbt:
+ dns_rbt_destroy(&zt->table);
+
+ cleanup_zt:
+ isc_mem_put(mctx, zt, sizeof(*zt));
+
+ return (result);
+}
+
+isc_result_t
+dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) {
+ isc_result_t result;
+ dns_zone_t *dummy = NULL;
+ dns_name_t *name;
+
+ REQUIRE(VALID_ZT(zt));
+
+ name = dns_zone_getorigin(zone);
+
+ RWLOCK(&zt->rwlock, isc_rwlocktype_write);
+
+ result = dns_rbt_addname(zt->table, name, zone);
+ if (result == ISC_R_SUCCESS)
+ dns_zone_attach(zone, &dummy);
+
+ RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
+
+ return (result);
+}
+
+isc_result_t
+dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) {
+ isc_result_t result;
+ dns_name_t *name;
+
+ REQUIRE(VALID_ZT(zt));
+
+ name = dns_zone_getorigin(zone);
+
+ RWLOCK(&zt->rwlock, isc_rwlocktype_write);
+
+ result = dns_rbt_deletename(zt->table, name, ISC_FALSE);
+
+ RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
+
+ return (result);
+}
+
+isc_result_t
+dns_zt_find(dns_zt_t *zt, dns_name_t *name, unsigned int options,
+ dns_name_t *foundname, dns_zone_t **zonep)
+{
+ isc_result_t result;
+ dns_zone_t *dummy = NULL;
+ unsigned int rbtoptions = 0;
+
+ REQUIRE(VALID_ZT(zt));
+
+ if ((options & DNS_ZTFIND_NOEXACT) != 0)
+ rbtoptions |= DNS_RBTFIND_NOEXACT;
+
+ RWLOCK(&zt->rwlock, isc_rwlocktype_read);
+
+ result = dns_rbt_findname(zt->table, name, rbtoptions, foundname,
+ (void **) (void*)&dummy);
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
+ dns_zone_attach(dummy, zonep);
+
+ RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
+
+ return (result);
+}
+
+void
+dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) {
+
+ REQUIRE(VALID_ZT(zt));
+ REQUIRE(ztp != NULL && *ztp == NULL);
+
+ RWLOCK(&zt->rwlock, isc_rwlocktype_write);
+
+ INSIST(zt->references > 0);
+ zt->references++;
+ INSIST(zt->references != 0);
+
+ RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
+
+ *ztp = zt;
+}
+
+static isc_result_t
+flush(dns_zone_t *zone, void *uap) {
+ UNUSED(uap);
+ return (dns_zone_flush(zone));
+}
+
+static void
+zt_flushanddetach(dns_zt_t **ztp, isc_boolean_t need_flush) {
+ isc_boolean_t destroy = ISC_FALSE;
+ dns_zt_t *zt;
+
+ REQUIRE(ztp != NULL && VALID_ZT(*ztp));
+
+ zt = *ztp;
+
+ RWLOCK(&zt->rwlock, isc_rwlocktype_write);
+
+ INSIST(zt->references > 0);
+ zt->references--;
+ if (zt->references == 0)
+ destroy = ISC_TRUE;
+
+ RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
+
+ if (destroy) {
+ if (need_flush)
+ (void)dns_zt_apply(zt, ISC_FALSE, flush, NULL);
+ dns_rbt_destroy(&zt->table);
+ isc_rwlock_destroy(&zt->rwlock);
+ zt->magic = 0;
+ isc_mem_put(zt->mctx, zt, sizeof(*zt));
+ }
+
+ *ztp = NULL;
+}
+
+void
+dns_zt_flushanddetach(dns_zt_t **ztp) {
+ zt_flushanddetach(ztp, ISC_TRUE);
+}
+
+void
+dns_zt_detach(dns_zt_t **ztp) {
+ zt_flushanddetach(ztp, ISC_FALSE);
+}
+
+isc_result_t
+dns_zt_load(dns_zt_t *zt, isc_boolean_t stop) {
+ isc_result_t result;
+
+ REQUIRE(VALID_ZT(zt));
+
+ RWLOCK(&zt->rwlock, isc_rwlocktype_read);
+ result = dns_zt_apply(zt, stop, load, NULL);
+ RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
+ return (result);
+}
+
+static isc_result_t
+load(dns_zone_t *zone, void *uap) {
+ isc_result_t result;
+ UNUSED(uap);
+ result = dns_zone_load(zone);
+ if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE)
+ result = ISC_R_SUCCESS;
+ return (result);
+}
+
+isc_result_t
+dns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop) {
+ isc_result_t result;
+
+ REQUIRE(VALID_ZT(zt));
+
+ RWLOCK(&zt->rwlock, isc_rwlocktype_read);
+ result = dns_zt_apply(zt, stop, loadnew, NULL);
+ RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
+ return (result);
+}
+
+static isc_result_t
+loadnew(dns_zone_t *zone, void *uap) {
+ isc_result_t result;
+ UNUSED(uap);
+ result = dns_zone_loadnew(zone);
+ if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE ||
+ result == DNS_R_DYNAMIC)
+ result = ISC_R_SUCCESS;
+ return (result);
+}
+
+isc_result_t
+dns_zt_freezezones(dns_zt_t *zt, isc_boolean_t freeze) {
+ isc_result_t result, tresult;
+
+ REQUIRE(VALID_ZT(zt));
+
+ RWLOCK(&zt->rwlock, isc_rwlocktype_read);
+ result = dns_zt_apply2(zt, ISC_FALSE, &tresult, freezezones, &freeze);
+ RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
+ return ((result == ISC_R_SUCCESS) ? tresult : result);
+}
+
+static isc_result_t
+freezezones(dns_zone_t *zone, void *uap) {
+ isc_boolean_t freeze = *(isc_boolean_t *)uap;
+ isc_boolean_t frozen;
+ isc_result_t result = ISC_R_SUCCESS;
+ char classstr[DNS_RDATACLASS_FORMATSIZE];
+ char zonename[DNS_NAME_FORMATSIZE];
+ dns_view_t *view;
+ char *journal;
+ const char *vname;
+ const char *sep;
+ int level;
+
+ if (dns_zone_gettype(zone) != dns_zone_master)
+ return (ISC_R_SUCCESS);
+
+ frozen = dns_zone_getupdatedisabled(zone);
+ if (freeze) {
+ if (frozen)
+ result = DNS_R_FROZEN;
+ if (result == ISC_R_SUCCESS)
+ result = dns_zone_flush(zone);
+ if (result == ISC_R_SUCCESS) {
+ journal = dns_zone_getjournal(zone);
+ if (journal != NULL)
+ (void)isc_file_remove(journal);
+ }
+ } else {
+ if (frozen) {
+ result = dns_zone_load(zone);
+ if (result == DNS_R_CONTINUE ||
+ result == DNS_R_UPTODATE)
+ result = ISC_R_SUCCESS;
+ }
+ }
+ if (result == ISC_R_SUCCESS)
+ dns_zone_setupdatedisabled(zone, freeze);
+ view = dns_zone_getview(zone);
+ if (strcmp(view->name, "_bind") == 0 ||
+ strcmp(view->name, "_default") == 0)
+ {
+ vname = "";
+ sep = "";
+ } else {
+ vname = view->name;
+ sep = " ";
+ }
+ dns_rdataclass_format(dns_zone_getclass(zone), classstr,
+ sizeof(classstr));
+ dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
+ level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
+ level, "%s zone '%s/%s'%s%s: %s",
+ freeze ? "freezing" : "thawing",
+ zonename, classstr, sep, vname,
+ isc_result_totext(result));
+ return (result);
+}
+
+isc_result_t
+dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop,
+ isc_result_t (*action)(dns_zone_t *, void *), void *uap)
+{
+ return (dns_zt_apply2(zt, stop, NULL, action, uap));
+}
+
+isc_result_t
+dns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub,
+ isc_result_t (*action)(dns_zone_t *, void *), void *uap)
+{
+ dns_rbtnode_t *node;
+ dns_rbtnodechain_t chain;
+ isc_result_t result, tresult = ISC_R_SUCCESS;
+ dns_zone_t *zone;
+
+ REQUIRE(VALID_ZT(zt));
+ REQUIRE(action != NULL);
+
+ dns_rbtnodechain_init(&chain, zt->mctx);
+ result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
+ if (result == ISC_R_NOTFOUND) {
+ /*
+ * The tree is empty.
+ */
+ result = ISC_R_NOMORE;
+ }
+ while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
+ result = dns_rbtnodechain_current(&chain, NULL, NULL,
+ &node);
+ if (result == ISC_R_SUCCESS) {
+ zone = node->data;
+ if (zone != NULL)
+ result = (action)(zone, uap);
+ if (result != ISC_R_SUCCESS && stop) {
+ tresult = result;
+ goto cleanup; /* don't break */
+ } else if (result != ISC_R_SUCCESS &&
+ tresult == ISC_R_SUCCESS)
+ tresult = result;
+ }
+ result = dns_rbtnodechain_next(&chain, NULL, NULL);
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ cleanup:
+ dns_rbtnodechain_invalidate(&chain);
+ if (sub != NULL)
+ *sub = tresult;
+
+ return (result);
+}
+
+/***
+ *** Private
+ ***/
+
+static void
+auto_detach(void *data, void *arg) {
+ dns_zone_t *zone = data;
+
+ UNUSED(arg);
+
+ dns_zone_detach(&zone);
+}
diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in
new file mode 100644
index 0000000..71e4252
--- /dev/null
+++ b/lib/isc/Makefile.in
@@ -0,0 +1,112 @@
+# Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-2003 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.81.18.8 2007/09/14 23:46:18 tbox Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+@LIBISC_API@
+
+CINCLUDES = -I${srcdir}/unix/include \
+ -I${srcdir}/@ISC_THREAD_DIR@/include \
+ -I${srcdir}/@ISC_ARCH_DIR@/include \
+ -I./include \
+ -I${srcdir}/include
+CDEFINES =
+CWARNINGS =
+
+# Alphabetically
+UNIXOBJS = @ISC_ISCIPV6_O@ \
+ unix/app.@O@ unix/dir.@O@ unix/entropy.@O@ \
+ unix/errno2result.@O@ unix/file.@O@ unix/fsaccess.@O@ \
+ unix/interfaceiter.@O@ unix/keyboard.@O@ unix/net.@O@ \
+ unix/os.@O@ unix/resource.@O@ unix/socket.@O@ unix/stdio.@O@ \
+ unix/stdtime.@O@ unix/strerror.@O@ unix/syslog.@O@ unix/time.@O@
+
+
+NLSOBJS = nls/msgcat.@O@
+
+THREADOBJS = @ISC_THREAD_DIR@/condition.@O@ @ISC_THREAD_DIR@/mutex.@O@ \
+ @ISC_THREAD_DIR@/thread.@O@
+
+WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \
+ win32/fsaccess.@O@ win32/once.@O@ win32/stdtime.@O@ \
+ win32/thread.@O@ win32/time.@O@
+
+# Alphabetically
+OBJS = @ISC_EXTRA_OBJS@ \
+ assertions.@O@ base64.@O@ bitstring.@O@ buffer.@O@ \
+ bufferlist.@O@ commandline.@O@ error.@O@ event.@O@ \
+ hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@\
+ lex.@O@ lfsr.@O@ lib.@O@ log.@O@ md5.@O@ \
+ mem.@O@ mutexblock.@O@ netaddr.@O@ netscope.@O@ ondestroy.@O@ \
+ parseint.@O@ quota.@O@ random.@O@ \
+ ratelimiter.@O@ refcount.@O@ region.@O@ result.@O@ rwlock.@O@ \
+ serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ string.@O@ \
+ strtoul.@O@ symtab.@O@ task.@O@ taskpool.@O@ timer.@O@ \
+ version.@O@ ${UNIXOBJS} ${NLSOBJS} ${THREADOBJS}
+
+# Alphabetically
+SRCS = @ISC_EXTRA_SRCS@ \
+ assertions.c base64.c bitstring.c buffer.c \
+ bufferlist.c commandline.c error.c event.c \
+ heap.c hex.c hmacmd5.c hmacsha.c \
+ lex.c lfsr.c lib.c log.c \
+ md5.c mem.c mutexblock.c netaddr.c netscope.c ondestroy.c \
+ parseint.c quota.c random.c \
+ ratelimiter.c refcount.c region.c result.c rwlock.c \
+ serial.c sha1.c sha2.c sockaddr.c string.c strtoul.c symtab.c \
+ task.c taskpool.c timer.c version.c
+
+LIBS = @LIBS@
+
+SUBDIRS = include unix nls @ISC_THREAD_DIR@ @ISC_ARCH_DIR@
+TARGETS = timestamp
+
+@BIND9_MAKE_RULES@
+
+version.@O@: version.c
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \
+ -DVERSION=\"${VERSION}\" \
+ -DLIBINTERFACE=${LIBINTERFACE} \
+ -DLIBREVISION=${LIBREVISION} \
+ -DLIBAGE=${LIBAGE} \
+ -c ${srcdir}/version.c
+
+libisc.@SA@: ${OBJS}
+ ${AR} ${ARFLAGS} $@ ${OBJS}
+ ${RANLIB} $@
+
+libisc.la: ${OBJS}
+ ${LIBTOOL_MODE_LINK} \
+ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc.la -rpath ${libdir} \
+ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ ${OBJS} ${LIBS}
+
+timestamp: libisc.@A@
+ touch timestamp
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+
+install:: timestamp installdirs
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libisc.@A@ ${DESTDIR}${libdir}
+
+clean distclean::
+ rm -f libisc.@A@ libisc.la timestamp
diff --git a/lib/isc/alpha/Makefile.in b/lib/isc/alpha/Makefile.in
new file mode 100644
index 0000000..c8e77e4
--- /dev/null
+++ b/lib/isc/alpha/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/alpha/include/Makefile.in b/lib/isc/alpha/include/Makefile.in
new file mode 100644
index 0000000..f4dd2f6
--- /dev/null
+++ b/lib/isc/alpha/include/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/alpha/include/isc/Makefile.in b/lib/isc/alpha/include/isc/Makefile.in
new file mode 100644
index 0000000..6760ce6
--- /dev/null
+++ b/lib/isc/alpha/include/isc/Makefile.in
@@ -0,0 +1,36 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc ; \
+ done
diff --git a/lib/isc/alpha/include/isc/atomic.h b/lib/isc/alpha/include/isc/atomic.h
new file mode 100644
index 0000000..a4b9b15
--- /dev/null
+++ b/lib/isc/alpha/include/isc/atomic.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.2.2.2 2005/06/16 22:01:01 jinmei Exp $ */
+
+/*
+ * This code was written based on FreeBSD's kernel source whose copyright
+ * follows:
+ */
+
+/*-
+ * Copyright (c) 1998 Doug Rabson
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEOSFASM
+#include <c_asm.h>
+
+#pragma intrinsic(asm)
+
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ */
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+ return (asm("1:"
+ "ldl_l %t0, 0(%a0);" /* load old value */
+ "mov %t0, %v0;" /* copy the old value */
+ "addl %t0, %a1, %t0;" /* calculate new value */
+ "stl_c %t0, 0(%a0);" /* attempt to store */
+ "beq %t0, 1b;", /* spin if failed */
+ p, val));
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+ (void)asm("1:"
+ "ldl_l %t0, 0(%a0);" /* load old value */
+ "mov %a1, %t0;" /* value to store */
+ "stl_c %t0, 0(%a0);" /* attempt to store */
+ "beq %t0, 1b;", /* spin if failed */
+ p, val);
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+
+ return(asm("1:"
+ "ldl_l %t0, 0(%a0);" /* load old value */
+ "mov %t0, %v0;" /* copy the old value */
+ "cmpeq %t0, %a1, %t0;" /* compare */
+ "beq %t0, 2f;" /* exit if not equal */
+ "mov %a2, %t0;" /* value to store */
+ "stl_c %t0, 0(%a0);" /* attempt to store */
+ "beq %t0, 1b;" /* if it failed, spin */
+ "2:",
+ p, cmpval, val));
+}
+#elif defined (ISC_PLATFORM_USEGCCASM)
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+ isc_int32_t temp, prev;
+
+ __asm__ volatile(
+ "1:"
+ "ldl_l %0, %1;" /* load old value */
+ "mov %0, %2;" /* copy the old value */
+ "addl %0, %3, %0;" /* calculate new value */
+ "stl_c %0, %1;" /* attempt to store */
+ "beq %0, 1b;" /* spin if failed */
+ : "=&r"(temp), "+m"(*p), "=r"(prev)
+ : "r"(val)
+ : "memory");
+
+ return (prev);
+}
+
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+ isc_int32_t temp;
+
+ __asm__ volatile(
+ "1:"
+ "ldl_l %0, %1;" /* load old value */
+ "mov %2, %0;" /* value to store */
+ "stl_c %0, %1;" /* attempt to store */
+ "beq %0, 1b;" /* if it failed, spin */
+ : "=&r"(temp), "+m"(*p)
+ : "r"(val)
+ : "memory");
+}
+
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+ isc_int32_t temp, prev;
+
+ __asm__ volatile(
+ "1:"
+ "ldl_l %0, %1;" /* load old value */
+ "mov %0, %2;" /* copy the old value */
+ "cmpeq %0, %3, %0;" /* compare */
+ "beq %0, 2f;" /* exit if not equal */
+ "mov %4, %0;" /* value to store */
+ "stl_c %0, %1;" /* attempt to store */
+ "beq %0, 1b;" /* if it failed, spin */
+ "2:"
+ : "=&r"(temp), "+m"(*p), "=r"(prev)
+ : "r"(cmpval), "r"(val)
+ : "memory");
+
+ return (prev);
+}
+#else
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/api b/lib/isc/api
new file mode 100644
index 0000000..ecadc93
--- /dev/null
+++ b/lib/isc/api
@@ -0,0 +1,3 @@
+LIBINTERFACE = 32
+LIBREVISION = 5
+LIBAGE = 0
diff --git a/lib/isc/arm/include/isc/atomic.h b/lib/isc/arm/include/isc/atomic.h
new file mode 100644
index 0000000..4c519ee
--- /dev/null
+++ b/lib/isc/arm/include/isc/atomic.h
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2007 Warner Losh
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+#include <machine/atomic.h>
+
+#ifdef __FreeBSD__
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val)
+{
+ return atomic_fetchadd_int(p, val);
+}
+
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val)
+{
+ atomic_store_rel_int(p, val);
+}
+
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val)
+{
+ register int done, ras_start;
+
+ __asm __volatile("1:\n"
+ "adr %1, 1b\n"
+ "mov %0, #0xe0000004\n"
+ "str %1, [%0]\n"
+ "mov %0, #0xe0000008\n"
+ "adr %1, 2f\n"
+ "str %1, [%0]\n"
+ "ldr %1, [%2]\n"
+ "cmp %1, %3\n"
+ "streq %4, [%2]\n"
+ "2:\n"
+ "mov %3, #0\n"
+ "mov %0, #0xe0000004\n"
+ "str %3, [%0]\n"
+ "mov %3, #0xffffffff\n"
+ "mov %0, #0xe0000008\n"
+ "str %3, [%0]\n"
+ : "=r" (ras_start), "=r" (done)
+ ,"+r" (p), "+r" (cmpval), "+r" (val) : : "memory");
+ return (done);
+
+}
+#else /* !FreeBSD */
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/assertions.c b/lib/isc/assertions.c
new file mode 100644
index 0000000..b3fcf4a
--- /dev/null
+++ b/lib/isc/assertions.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-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: assertions.c,v 1.17.18.2 2005/04/29 00:16:44 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <isc/assertions.h>
+#include <isc/msgs.h>
+
+/*%
+ * Forward.
+ */
+static void
+default_callback(const char *, int, isc_assertiontype_t, const char *);
+
+/*%
+ * Public.
+ */
+
+LIBISC_EXTERNAL_DATA isc_assertioncallback_t isc_assertion_failed =
+ default_callback;
+
+/*% Set callback. */
+void
+isc_assertion_setcallback(isc_assertioncallback_t cb) {
+ if (cb == NULL)
+ isc_assertion_failed = default_callback;
+ else
+ isc_assertion_failed = cb;
+}
+
+/*% Type to Text */
+const char *
+isc_assertion_typetotext(isc_assertiontype_t type) {
+ const char *result;
+
+ /*
+ * These strings have purposefully not been internationalized
+ * because they are considered to essentially be keywords of
+ * the ISC development environment.
+ */
+ switch (type) {
+ case isc_assertiontype_require:
+ result = "REQUIRE";
+ break;
+ case isc_assertiontype_ensure:
+ result = "ENSURE";
+ break;
+ case isc_assertiontype_insist:
+ result = "INSIST";
+ break;
+ case isc_assertiontype_invariant:
+ result = "INVARIANT";
+ break;
+ default:
+ result = NULL;
+ }
+ return (result);
+}
+
+/*
+ * Private.
+ */
+
+static void
+default_callback(const char *file, int line, isc_assertiontype_t type,
+ const char *cond)
+{
+ fprintf(stderr, "%s:%d: %s(%s) %s.\n",
+ file, line, isc_assertion_typetotext(type), cond,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ fflush(stderr);
+ abort();
+ /* NOTREACHED */
+}
diff --git a/lib/isc/base64.c b/lib/isc/base64.c
new file mode 100644
index 0000000..faeae92
--- /dev/null
+++ b/lib/isc/base64.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2004, 2005 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: base64.c,v 1.28.18.2 2005/04/29 00:16:44 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/base64.h>
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define RETERR(x) do { \
+ isc_result_t _r = (x); \
+ if (_r != ISC_R_SUCCESS) \
+ return (_r); \
+ } while (0)
+
+
+/*@{*/
+/*!
+ * These static functions are also present in lib/dns/rdata.c. I'm not
+ * sure where they should go. -- bwelling
+ */
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target);
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
+
+static const char base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+/*@}*/
+
+isc_result_t
+isc_base64_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target)
+{
+ char buf[5];
+ unsigned int loops = 0;
+
+ if (wordlength < 4)
+ wordlength = 4;
+
+ memset(buf, 0, sizeof(buf));
+ while (source->length > 2) {
+ buf[0] = base64[(source->base[0]>>2)&0x3f];
+ buf[1] = base64[((source->base[0]<<4)&0x30)|
+ ((source->base[1]>>4)&0x0f)];
+ buf[2] = base64[((source->base[1]<<2)&0x3c)|
+ ((source->base[2]>>6)&0x03)];
+ buf[3] = base64[source->base[2]&0x3f];
+ RETERR(str_totext(buf, target));
+ isc_region_consume(source, 3);
+
+ loops++;
+ if (source->length != 0 &&
+ (int)((loops + 1) * 4) >= wordlength)
+ {
+ loops = 0;
+ RETERR(str_totext(wordbreak, target));
+ }
+ }
+ if (source->length == 2) {
+ buf[0] = base64[(source->base[0]>>2)&0x3f];
+ buf[1] = base64[((source->base[0]<<4)&0x30)|
+ ((source->base[1]>>4)&0x0f)];
+ buf[2] = base64[((source->base[1]<<2)&0x3c)];
+ buf[3] = '=';
+ RETERR(str_totext(buf, target));
+ } else if (source->length == 1) {
+ buf[0] = base64[(source->base[0]>>2)&0x3f];
+ buf[1] = base64[((source->base[0]<<4)&0x30)];
+ buf[2] = buf[3] = '=';
+ RETERR(str_totext(buf, target));
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * State of a base64 decoding process in progress.
+ */
+typedef struct {
+ int length; /*%< Desired length of binary data or -1 */
+ isc_buffer_t *target; /*%< Buffer for resulting binary data */
+ int digits; /*%< Number of buffered base64 digits */
+ isc_boolean_t seen_end; /*%< True if "=" end marker seen */
+ int val[4];
+} base64_decode_ctx_t;
+
+static inline void
+base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target)
+{
+ ctx->digits = 0;
+ ctx->seen_end = ISC_FALSE;
+ ctx->length = length;
+ ctx->target = target;
+}
+
+static inline isc_result_t
+base64_decode_char(base64_decode_ctx_t *ctx, int c) {
+ char *s;
+
+ if (ctx->seen_end)
+ return (ISC_R_BADBASE64);
+ if ((s = strchr(base64, c)) == NULL)
+ return (ISC_R_BADBASE64);
+ ctx->val[ctx->digits++] = s - base64;
+ if (ctx->digits == 4) {
+ int n;
+ unsigned char buf[3];
+ if (ctx->val[0] == 64 || ctx->val[1] == 64)
+ return (ISC_R_BADBASE64);
+ if (ctx->val[2] == 64 && ctx->val[3] != 64)
+ return (ISC_R_BADBASE64);
+ /*
+ * Check that bits that should be zero are.
+ */
+ if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0)
+ return (ISC_R_BADBASE64);
+ /*
+ * We don't need to test for ctx->val[2] != 64 as
+ * the bottom two bits of 64 are zero.
+ */
+ if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0)
+ return (ISC_R_BADBASE64);
+ n = (ctx->val[2] == 64) ? 1 :
+ (ctx->val[3] == 64) ? 2 : 3;
+ if (n != 3) {
+ ctx->seen_end = ISC_TRUE;
+ if (ctx->val[2] == 64)
+ ctx->val[2] = 0;
+ if (ctx->val[3] == 64)
+ ctx->val[3] = 0;
+ }
+ buf[0] = (ctx->val[0]<<2)|(ctx->val[1]>>4);
+ buf[1] = (ctx->val[1]<<4)|(ctx->val[2]>>2);
+ buf[2] = (ctx->val[2]<<6)|(ctx->val[3]);
+ RETERR(mem_tobuffer(ctx->target, buf, n));
+ if (ctx->length >= 0) {
+ if (n > ctx->length)
+ return (ISC_R_BADBASE64);
+ else
+ ctx->length -= n;
+ }
+ ctx->digits = 0;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+base64_decode_finish(base64_decode_ctx_t *ctx) {
+ if (ctx->length > 0)
+ return (ISC_R_UNEXPECTEDEND);
+ if (ctx->digits != 0)
+ return (ISC_R_BADBASE64);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+ base64_decode_ctx_t ctx;
+ isc_textregion_t *tr;
+ isc_token_t token;
+ isc_boolean_t eol;
+
+ base64_decode_init(&ctx, length, target);
+
+ while (!ctx.seen_end && (ctx.length != 0)) {
+ unsigned int i;
+
+ if (length > 0)
+ eol = ISC_FALSE;
+ else
+ eol = ISC_TRUE;
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string, eol));
+ if (token.type != isc_tokentype_string)
+ break;
+ tr = &token.value.as_textregion;
+ for (i = 0; i < tr->length; i++)
+ RETERR(base64_decode_char(&ctx, tr->base[i]));
+ }
+ if (ctx.length < 0 && !ctx.seen_end)
+ isc_lex_ungettoken(lexer, &token);
+ RETERR(base64_decode_finish(&ctx));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base64_decodestring(const char *cstr, isc_buffer_t *target) {
+ base64_decode_ctx_t ctx;
+
+ base64_decode_init(&ctx, -1, target);
+ for (;;) {
+ int c = *cstr++;
+ if (c == '\0')
+ break;
+ if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
+ continue;
+ RETERR(base64_decode_char(&ctx, c));
+ }
+ RETERR(base64_decode_finish(&ctx));
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target) {
+ unsigned int l;
+ isc_region_t region;
+
+ isc_buffer_availableregion(target, &region);
+ l = strlen(source);
+
+ if (l > region.length)
+ return (ISC_R_NOSPACE);
+
+ memcpy(region.base, source, l);
+ isc_buffer_add(target, l);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
+ isc_region_t tr;
+
+ isc_buffer_availableregion(target, &tr);
+ if (length > tr.length)
+ return (ISC_R_NOSPACE);
+ memcpy(tr.base, base, length);
+ isc_buffer_add(target, length);
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/bitstring.c b/lib/isc/bitstring.c
new file mode 100644
index 0000000..105b5aa
--- /dev/null
+++ b/lib/isc/bitstring.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2004, 2005 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: bitstring.c,v 1.13.18.2 2005/04/29 00:16:44 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/magic.h>
+#include <isc/bitstring.h>
+#include <isc/util.h>
+
+#define DIV8(x) ((x) >> 3)
+#define MOD8(x) ((x) & 0x00000007U)
+#define OCTETS(n) (((n) + 7) >> 3)
+#define PADDED(n) ((((n) + 7) >> 3) << 3)
+#define BITSET(bs, n) (((bs)->data[DIV8(n)] & \
+ (1 << (7 - MOD8(n)))) != 0)
+#define SETBIT(bs, n) (bs)->data[DIV8(n)] |= (1 << (7 - MOD8(n)))
+#define CLEARBIT(bs, n) (bs)->data[DIV8(n)] &= ~(1 << (7 - MOD8(n)))
+
+#define BITSTRING_MAGIC ISC_MAGIC('B', 'S', 't', 'r')
+#define VALID_BITSTRING(b) ISC_MAGIC_VALID(b, BITSTRING_MAGIC)
+
+void
+isc_bitstring_init(isc_bitstring_t *bitstring, unsigned char *data,
+ unsigned int length, unsigned int size, isc_boolean_t lsb0)
+{
+ /*
+ * Make 'bitstring' refer to the bitstring of 'size' bits starting
+ * at 'data'. 'length' bits of the bitstring are valid. If 'lsb0'
+ * is set then, bit 0 refers to the least significant bit of the
+ * bitstring. Otherwise bit 0 is the most significant bit.
+ */
+
+ REQUIRE(bitstring != NULL);
+ REQUIRE(data != NULL);
+ REQUIRE(length <= size);
+
+ bitstring->magic = BITSTRING_MAGIC;
+ bitstring->data = data;
+ bitstring->length = length;
+ bitstring->size = size;
+ bitstring->lsb0 = lsb0;
+}
+
+void
+isc_bitstring_invalidate(isc_bitstring_t *bitstring) {
+
+ /*
+ * Invalidate 'bitstring'.
+ */
+
+ REQUIRE(VALID_BITSTRING(bitstring));
+
+ bitstring->magic = 0;
+ bitstring->data = NULL;
+ bitstring->length = 0;
+ bitstring->size = 0;
+ bitstring->lsb0 = ISC_FALSE;
+}
+
+void
+isc_bitstring_copy(isc_bitstring_t *source, unsigned int sbitpos,
+ isc_bitstring_t *target, unsigned int tbitpos,
+ unsigned int n)
+{
+ unsigned int tlast;
+
+ /*
+ * Starting at bit 'sbitpos', copy 'n' bits from 'source' to
+ * the 'n' bits of 'target' starting at 'tbitpos'.
+ */
+
+ REQUIRE(VALID_BITSTRING(source));
+ REQUIRE(VALID_BITSTRING(target));
+ REQUIRE(source->lsb0 == target->lsb0);
+ if (source->lsb0) {
+ REQUIRE(sbitpos <= source->length);
+ sbitpos = PADDED(source->size) - sbitpos;
+ REQUIRE(sbitpos >= n);
+ sbitpos -= n;
+ } else
+ REQUIRE(sbitpos + n <= source->length);
+ tlast = tbitpos + n;
+ if (target->lsb0) {
+ REQUIRE(tbitpos <= target->length);
+ tbitpos = PADDED(target->size) - tbitpos;
+ REQUIRE(tbitpos >= n);
+ tbitpos -= n;
+ } else
+ REQUIRE(tlast <= target->size);
+
+ if (tlast > target->length)
+ target->length = tlast;
+
+ /*
+ * This is far from optimal...
+ */
+
+ while (n > 0) {
+ if (BITSET(source, sbitpos))
+ SETBIT(target, tbitpos);
+ else
+ CLEARBIT(target, tbitpos);
+ sbitpos++;
+ tbitpos++;
+ n--;
+ }
+}
diff --git a/lib/isc/buffer.c b/lib/isc/buffer.c
new file mode 100644
index 0000000..fc07c00
--- /dev/null
+++ b/lib/isc/buffer.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: buffer.c,v 1.40.18.2 2005/04/29 00:16:44 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/buffer.h>
+#include <isc/mem.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+void
+isc__buffer_init(isc_buffer_t *b, const void *base, unsigned int length) {
+ /*
+ * Make 'b' refer to the 'length'-byte region starting at 'base'.
+ * XXXDCL see the comment in buffer.h about base being const.
+ */
+
+ REQUIRE(b != NULL);
+
+ ISC__BUFFER_INIT(b, base, length);
+}
+
+void
+isc__buffer_invalidate(isc_buffer_t *b) {
+ /*
+ * Make 'b' an invalid buffer.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(!ISC_LINK_LINKED(b, link));
+ REQUIRE(b->mctx == NULL);
+
+ ISC__BUFFER_INVALIDATE(b);
+}
+
+void
+isc__buffer_region(isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_REGION(b, r);
+}
+
+void
+isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the used region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_USEDREGION(b, r);
+}
+
+void
+isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the available region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_AVAILABLEREGION(b, r);
+}
+
+void
+isc__buffer_add(isc_buffer_t *b, unsigned int n) {
+ /*
+ * Increase the 'used' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used + n <= b->length);
+
+ ISC__BUFFER_ADD(b, n);
+}
+
+void
+isc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
+ /*
+ * Decrease the 'used' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used >= n);
+
+ ISC__BUFFER_SUBTRACT(b, n);
+}
+
+void
+isc__buffer_clear(isc_buffer_t *b) {
+ /*
+ * Make the used region empty.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+
+ ISC__BUFFER_CLEAR(b);
+}
+
+void
+isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the consumed region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_CONSUMEDREGION(b, r);
+}
+
+void
+isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the remaining region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_REMAININGREGION(b, r);
+}
+
+void
+isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
+ /*
+ * Make 'r' refer to the active region of 'b'.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ ISC__BUFFER_ACTIVEREGION(b, r);
+}
+
+void
+isc__buffer_setactive(isc_buffer_t *b, unsigned int n) {
+ /*
+ * Sets the end of the active region 'n' bytes after current.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->current + n <= b->used);
+
+ ISC__BUFFER_SETACTIVE(b, n);
+}
+
+void
+isc__buffer_first(isc_buffer_t *b) {
+ /*
+ * Make the consumed region empty.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+
+ ISC__BUFFER_FIRST(b);
+}
+
+void
+isc__buffer_forward(isc_buffer_t *b, unsigned int n) {
+ /*
+ * Increase the 'consumed' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->current + n <= b->used);
+
+ ISC__BUFFER_FORWARD(b, n);
+}
+
+void
+isc__buffer_back(isc_buffer_t *b, unsigned int n) {
+ /*
+ * Decrease the 'consumed' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(n <= b->current);
+
+ ISC__BUFFER_BACK(b, n);
+}
+
+void
+isc_buffer_compact(isc_buffer_t *b) {
+ unsigned int length;
+ void *src;
+
+ /*
+ * Compact the used region by moving the remaining region so it occurs
+ * at the start of the buffer. The used region is shrunk by the size
+ * of the consumed region, and the consumed region is then made empty.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+
+ src = isc_buffer_current(b);
+ length = isc_buffer_remaininglength(b);
+ (void)memmove(b->base, src, (size_t)length);
+
+ if (b->active > b->current)
+ b->active -= b->current;
+ else
+ b->active = 0;
+ b->current = 0;
+ b->used = length;
+}
+
+isc_uint8_t
+isc_buffer_getuint8(isc_buffer_t *b) {
+ unsigned char *cp;
+ isc_uint8_t result;
+
+ /*
+ * Read an unsigned 8-bit integer from 'b' and return it.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 1);
+
+ cp = isc_buffer_current(b);
+ b->current += 1;
+ result = ((isc_uint8_t)(cp[0]));
+
+ return (result);
+}
+
+void
+isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val) {
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used + 1 <= b->length);
+
+ ISC__BUFFER_PUTUINT8(b, val);
+}
+
+isc_uint16_t
+isc_buffer_getuint16(isc_buffer_t *b) {
+ unsigned char *cp;
+ isc_uint16_t result;
+
+ /*
+ * Read an unsigned 16-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 2);
+
+ cp = isc_buffer_current(b);
+ b->current += 2;
+ result = ((unsigned int)(cp[0])) << 8;
+ result |= ((unsigned int)(cp[1]));
+
+ return (result);
+}
+
+void
+isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val) {
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used + 2 <= b->length);
+
+ ISC__BUFFER_PUTUINT16(b, val);
+}
+
+isc_uint32_t
+isc_buffer_getuint32(isc_buffer_t *b) {
+ unsigned char *cp;
+ isc_uint32_t result;
+
+ /*
+ * Read an unsigned 32-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ */
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 4);
+
+ cp = isc_buffer_current(b);
+ b->current += 4;
+ result = ((unsigned int)(cp[0])) << 24;
+ result |= ((unsigned int)(cp[1])) << 16;
+ result |= ((unsigned int)(cp[2])) << 8;
+ result |= ((unsigned int)(cp[3]));
+
+ return (result);
+}
+
+void
+isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val) {
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used + 4 <= b->length);
+
+ ISC__BUFFER_PUTUINT32(b, val);
+}
+
+void
+isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
+ unsigned int length)
+{
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used + length <= b->length);
+
+ ISC__BUFFER_PUTMEM(b, base, length);
+}
+
+void
+isc__buffer_putstr(isc_buffer_t *b, const char *source) {
+ unsigned int l;
+ unsigned char *cp;
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(source != NULL);
+
+ /*
+ * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
+ */
+ l = strlen(source);
+
+ REQUIRE(l <= isc_buffer_availablelength(b));
+
+ cp = isc_buffer_used(b);
+ memcpy(cp, source, l);
+ b->used += l;
+}
+
+isc_result_t
+isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
+ unsigned char *base;
+ unsigned int available;
+
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(r != NULL);
+
+ /*
+ * XXXDCL
+ */
+ base = isc_buffer_used(b);
+ available = isc_buffer_availablelength(b);
+ if (r->length > available)
+ return (ISC_R_NOSPACE);
+ memcpy(base, r->base, r->length);
+ b->used += r->length;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
+ unsigned int length)
+{
+ isc_buffer_t *dbuf;
+
+ REQUIRE(dynbuffer != NULL);
+ REQUIRE(*dynbuffer == NULL);
+
+ dbuf = isc_mem_get(mctx, length + sizeof(isc_buffer_t));
+ if (dbuf == NULL)
+ return (ISC_R_NOMEMORY);
+
+ isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t),
+ length);
+ dbuf->mctx = mctx;
+
+ *dynbuffer = dbuf;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_buffer_free(isc_buffer_t **dynbuffer) {
+ unsigned int real_length;
+ isc_buffer_t *dbuf;
+ isc_mem_t *mctx;
+
+ REQUIRE(dynbuffer != NULL);
+ REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
+ REQUIRE((*dynbuffer)->mctx != NULL);
+
+ dbuf = *dynbuffer;
+ *dynbuffer = NULL; /* destroy external reference */
+
+ real_length = dbuf->length + sizeof(isc_buffer_t);
+ mctx = dbuf->mctx;
+ dbuf->mctx = NULL;
+ isc_buffer_invalidate(dbuf);
+
+ isc_mem_put(mctx, dbuf, real_length);
+}
diff --git a/lib/isc/bufferlist.c b/lib/isc/bufferlist.c
new file mode 100644
index 0000000..773d075
--- /dev/null
+++ b/lib/isc/bufferlist.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2004, 2005 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: bufferlist.c,v 1.13.18.2 2005/04/29 00:16:45 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/buffer.h>
+#include <isc/bufferlist.h>
+#include <isc/util.h>
+
+unsigned int
+isc_bufferlist_usedcount(isc_bufferlist_t *bl) {
+ isc_buffer_t *buffer;
+ unsigned int length;
+
+ REQUIRE(bl != NULL);
+
+ length = 0;
+ buffer = ISC_LIST_HEAD(*bl);
+ while (buffer != NULL) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ length += isc_buffer_usedlength(buffer);
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ return (length);
+}
+
+unsigned int
+isc_bufferlist_availablecount(isc_bufferlist_t *bl) {
+ isc_buffer_t *buffer;
+ unsigned int length;
+
+ REQUIRE(bl != NULL);
+
+ length = 0;
+ buffer = ISC_LIST_HEAD(*bl);
+ while (buffer != NULL) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ length += isc_buffer_availablelength(buffer);
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ return (length);
+}
diff --git a/lib/isc/commandline.c b/lib/isc/commandline.c
new file mode 100644
index 0000000..679ed6d
--- /dev/null
+++ b/lib/isc/commandline.c
@@ -0,0 +1,222 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions 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.
+ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * 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.
+ */
+
+/* $Id: commandline.c,v 1.16.18.2 2005/04/29 00:16:45 marka Exp $ */
+
+/*! \file
+ * This file was adapted from the NetBSD project's source tree, RCS ID:
+ * NetBSD: getopt.c,v 1.15 1999/09/20 04:39:37 lukem Exp
+ *
+ * The primary change has been to rename items to the ISC namespace
+ * and format in the ISC coding style.
+ */
+
+/*
+ * \author Principal Authors: Computer Systems Research Group at UC Berkeley
+ * \author Principal ISC caretaker: DCL
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <isc/commandline.h>
+#include <isc/msgs.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/*% Index into parent argv vector. */
+LIBISC_EXTERNAL_DATA int isc_commandline_index = 1;
+/*% Character checked for validity. */
+LIBISC_EXTERNAL_DATA int isc_commandline_option;
+/*% Argument associated with option. */
+LIBISC_EXTERNAL_DATA char *isc_commandline_argument;
+/*% For printing error messages. */
+LIBISC_EXTERNAL_DATA char *isc_commandline_progname;
+/*% Print error messages. */
+LIBISC_EXTERNAL_DATA isc_boolean_t isc_commandline_errprint = ISC_TRUE;
+/*% Reset processing. */
+LIBISC_EXTERNAL_DATA isc_boolean_t isc_commandline_reset = ISC_TRUE;
+
+static char endopt = '\0';
+
+#define BADOPT '?'
+#define BADARG ':'
+#define ENDOPT &endopt
+
+/*!
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+isc_commandline_parse(int argc, char * const *argv, const char *options) {
+ static char *place = ENDOPT;
+ char *option; /* Index into *options of option. */
+
+ REQUIRE(argc >= 0 && argv != NULL && options != NULL);
+
+ /*
+ * Update scanning pointer, either because a reset was requested or
+ * the previous argv was finished.
+ */
+ if (isc_commandline_reset || *place == '\0') {
+ isc_commandline_reset = ISC_FALSE;
+
+ if (isc_commandline_progname == NULL)
+ isc_commandline_progname = argv[0];
+
+ if (isc_commandline_index >= argc ||
+ *(place = argv[isc_commandline_index]) != '-') {
+ /*
+ * Index out of range or points to non-option.
+ */
+ place = ENDOPT;
+ return (-1);
+ }
+
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ /*
+ * Found '--' to signal end of options. Advance
+ * index to next argv, the first non-option.
+ */
+ isc_commandline_index++;
+ place = ENDOPT;
+ return (-1);
+ }
+ }
+
+ isc_commandline_option = *place++;
+ option = strchr(options, isc_commandline_option);
+
+ /*
+ * Ensure valid option has been passed as specified by options string.
+ * '-:' is never a valid command line option because it could not
+ * distinguish ':' from the argument specifier in the options string.
+ */
+ if (isc_commandline_option == ':' || option == NULL) {
+ if (*place == '\0')
+ isc_commandline_index++;
+
+ if (isc_commandline_errprint && *options != ':')
+ fprintf(stderr, "%s: %s -- %c\n",
+ isc_commandline_progname,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_COMMANDLINE,
+ ISC_MSG_ILLEGALOPT,
+ "illegal option"),
+ isc_commandline_option);
+
+ return (BADOPT);
+ }
+
+ if (*++option != ':') {
+ /*
+ * Option does not take an argument.
+ */
+ isc_commandline_argument = NULL;
+
+ /*
+ * Skip to next argv if at the end of the current argv.
+ */
+ if (*place == '\0')
+ ++isc_commandline_index;
+
+ } else {
+ /*
+ * Option needs an argument.
+ */
+ if (*place != '\0')
+ /*
+ * Option is in this argv, -D1 style.
+ */
+ isc_commandline_argument = place;
+
+ else if (argc > ++isc_commandline_index)
+ /*
+ * Option is next argv, -D 1 style.
+ */
+ isc_commandline_argument = argv[isc_commandline_index];
+
+ else {
+ /*
+ * Argument needed, but no more argv.
+ */
+ place = ENDOPT;
+
+ /*
+ * Silent failure with "missing argument" return
+ * when ':' starts options string, per historical spec.
+ */
+ if (*options == ':')
+ return (BADARG);
+
+ if (isc_commandline_errprint)
+ fprintf(stderr, "%s: %s -- %c\n",
+ isc_commandline_progname,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_COMMANDLINE,
+ ISC_MSG_OPTNEEDARG,
+ "option requires "
+ "an argument"),
+ isc_commandline_option);
+
+ return (BADOPT);
+ }
+
+ place = ENDOPT;
+
+ /*
+ * Point to argv that follows argument.
+ */
+ isc_commandline_index++;
+ }
+
+ return (isc_commandline_option);
+}
diff --git a/lib/isc/entropy.c b/lib/isc/entropy.c
new file mode 100644
index 0000000..3e87d87
--- /dev/null
+++ b/lib/isc/entropy.c
@@ -0,0 +1,1263 @@
+/*
+ * Copyright (C) 2004, 2005 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: entropy.c,v 1.11.18.3 2005/07/12 01:22:28 marka Exp $ */
+
+/*! \file
+ * \brief
+ * This is the system independent part of the entropy module. It is
+ * compiled via inclusion from the relevant OS source file, ie,
+ * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c.
+ *
+ * \author Much of this code is modeled after the NetBSD /dev/random implementation,
+ * written by Michael Graff <explorer@netbsd.org>.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <isc/buffer.h>
+#include <isc/entropy.h>
+#include <isc/keyboard.h>
+#include <isc/list.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/platform.h>
+#include <isc/region.h>
+#include <isc/sha1.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+
+#define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
+#define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
+
+#define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
+#define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
+
+/***
+ *** "constants." Do not change these unless you _really_ know what
+ *** you are doing.
+ ***/
+
+/*%
+ * Size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
+ */
+#define RND_POOLWORDS 128
+/*% Pool in bytes. */
+#define RND_POOLBYTES (RND_POOLWORDS * 4)
+/*% Pool in bits. */
+#define RND_POOLBITS (RND_POOLWORDS * 32)
+
+/*%
+ * Number of bytes returned per hash. This must be true:
+ * threshold * 2 <= digest_size_in_bytes
+ */
+#define RND_ENTROPY_THRESHOLD 10
+#define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
+
+/*%
+ * Size of the input event queue in samples.
+ */
+#define RND_EVENTQSIZE 32
+
+/*%
+ * The number of times we'll "reseed" for pseudorandom seeds. This is an
+ * extremely weak pseudorandom seed. If the caller is using lots of
+ * pseudorandom data and they cannot provide a stronger random source,
+ * there is little we can do other than hope they're smart enough to
+ * call _adddata() with something better than we can come up with.
+ */
+#define RND_INITIALIZE 128
+
+/*% Entropy Pool */
+typedef struct {
+ isc_uint32_t cursor; /*%< current add point in the pool */
+ isc_uint32_t entropy; /*%< current entropy estimate in bits */
+ isc_uint32_t pseudo; /*%< bits extracted in pseudorandom */
+ isc_uint32_t rotate; /*%< how many bits to rotate by */
+ isc_uint32_t pool[RND_POOLWORDS]; /*%< random pool data */
+} isc_entropypool_t;
+
+struct isc_entropy {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ unsigned int refcnt;
+ isc_uint32_t initialized;
+ isc_uint32_t initcount;
+ isc_entropypool_t pool;
+ unsigned int nsources;
+ isc_entropysource_t *nextsource;
+ ISC_LIST(isc_entropysource_t) sources;
+};
+
+/*% Sample Queue */
+typedef struct {
+ isc_uint32_t last_time; /*%< last time recorded */
+ isc_uint32_t last_delta; /*%< last delta value */
+ isc_uint32_t last_delta2; /*%< last delta2 value */
+ isc_uint32_t nsamples; /*%< number of samples filled in */
+ isc_uint32_t *samples; /*%< the samples */
+ isc_uint32_t *extra; /*%< extra samples added in */
+} sample_queue_t;
+
+typedef struct {
+ sample_queue_t samplequeue;
+} isc_entropysamplesource_t;
+
+typedef struct {
+ isc_boolean_t start_called;
+ isc_entropystart_t startfunc;
+ isc_entropyget_t getfunc;
+ isc_entropystop_t stopfunc;
+ void *arg;
+ sample_queue_t samplequeue;
+} isc_cbsource_t;
+
+typedef struct {
+ FILESOURCE_HANDLE_TYPE handle;
+} isc_entropyfilesource_t;
+
+struct isc_entropysource {
+ unsigned int magic;
+ unsigned int type;
+ isc_entropy_t *ent;
+ isc_uint32_t total; /*%< entropy from this source */
+ ISC_LINK(isc_entropysource_t) link;
+ char name[32];
+ isc_boolean_t bad;
+ isc_boolean_t warn_keyboard;
+ isc_keyboard_t kbd;
+ union {
+ isc_entropysamplesource_t sample;
+ isc_entropyfilesource_t file;
+ isc_cbsource_t callback;
+ isc_entropyusocketsource_t usocket;
+ } sources;
+};
+
+#define ENTROPY_SOURCETYPE_SAMPLE 1 /*%< Type is a sample source */
+#define ENTROPY_SOURCETYPE_FILE 2 /*%< Type is a file source */
+#define ENTROPY_SOURCETYPE_CALLBACK 3 /*%< Type is a callback source */
+#define ENTROPY_SOURCETYPE_USOCKET 4 /*%< Type is a Unix socket source */
+
+/*@{*/
+/*%
+ * The random pool "taps"
+ */
+#define TAP1 99
+#define TAP2 59
+#define TAP3 31
+#define TAP4 9
+#define TAP5 7
+/*@}*/
+
+/*@{*/
+/*%
+ * Declarations for function provided by the system dependent sources that
+ * include this file.
+ */
+static void
+fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
+
+static int
+wait_for_sources(isc_entropy_t *);
+
+static void
+destroyfilesource(isc_entropyfilesource_t *source);
+
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source);
+
+/*@}*/
+
+static void
+samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
+ REQUIRE(sq->samples != NULL);
+ REQUIRE(sq->extra != NULL);
+
+ isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
+ isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
+ sq->samples = NULL;
+ sq->extra = NULL;
+}
+
+static isc_result_t
+samplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
+ sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
+ if (sq->samples == NULL)
+ return (ISC_R_NOMEMORY);
+
+ sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
+ if (sq->extra == NULL) {
+ isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
+ sq->samples = NULL;
+ return (ISC_R_NOMEMORY);
+ }
+
+ sq->nsamples = 0;
+
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Add in entropy, even when the value we're adding in could be
+ * very large.
+ */
+static inline void
+add_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
+ /* clamp input. Yes, this must be done. */
+ entropy = ISC_MIN(entropy, RND_POOLBITS);
+ /* Add in the entropy we already have. */
+ entropy += ent->pool.entropy;
+ /* Clamp. */
+ ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
+}
+
+/*%
+ * Decrement the amount of entropy the pool has.
+ */
+static inline void
+subtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
+ entropy = ISC_MIN(entropy, ent->pool.entropy);
+ ent->pool.entropy -= entropy;
+}
+
+/*!
+ * Add in entropy, even when the value we're adding in could be
+ * very large.
+ */
+static inline void
+add_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
+ /* clamp input. Yes, this must be done. */
+ pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
+ /* Add in the pseudo we already have. */
+ pseudo += ent->pool.pseudo;
+ /* Clamp. */
+ ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
+}
+
+/*!
+ * Decrement the amount of pseudo the pool has.
+ */
+static inline void
+subtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
+ pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
+ ent->pool.pseudo -= pseudo;
+}
+
+/*!
+ * Add one word to the pool, rotating the input as needed.
+ */
+static inline void
+entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
+ /*
+ * Steal some values out of the pool, and xor them into the
+ * word we were given.
+ *
+ * Mix the new value into the pool using xor. This will
+ * prevent the actual values from being known to the caller
+ * since the previous values are assumed to be unknown as well.
+ */
+ val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
+ val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
+ val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
+ val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
+ val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
+ rp->pool[rp->cursor++] ^=
+ ((val << rp->rotate) | (val >> (32 - rp->rotate)));
+
+ /*
+ * If we have looped around the pool, increment the rotate
+ * variable so the next value will get xored in rotated to
+ * a different position.
+ * Increment by a value that is relativly prime to the word size
+ * to try to spread the bits throughout the pool quickly when the
+ * pool is empty.
+ */
+ if (rp->cursor == RND_POOLWORDS) {
+ rp->cursor = 0;
+ rp->rotate = (rp->rotate + 7) & 31;
+ }
+}
+
+/*!
+ * Add a buffer's worth of data to the pool.
+ *
+ * Requires that the lock is held on the entropy pool.
+ */
+static void
+entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
+ isc_uint32_t entropy)
+{
+ isc_uint32_t val;
+ unsigned long addr;
+ isc_uint8_t *buf;
+
+ addr = (unsigned long)p;
+ buf = p;
+
+ if ((addr & 0x03U) != 0U) {
+ val = 0;
+ switch (len) {
+ case 3:
+ val = *buf++;
+ len--;
+ case 2:
+ val = val << 8 | *buf++;
+ len--;
+ case 1:
+ val = val << 8 | *buf++;
+ len--;
+ }
+
+ entropypool_add_word(&ent->pool, val);
+ }
+
+ for (; len > 3; len -= 4) {
+ val = *((isc_uint32_t *)buf);
+
+ entropypool_add_word(&ent->pool, val);
+ buf += 4;
+ }
+
+ if (len != 0) {
+ val = 0;
+ switch (len) {
+ case 3:
+ val = *buf++;
+ case 2:
+ val = val << 8 | *buf++;
+ case 1:
+ val = val << 8 | *buf++;
+ }
+
+ entropypool_add_word(&ent->pool, val);
+ }
+
+ add_entropy(ent, entropy);
+ subtract_pseudo(ent, entropy);
+}
+
+static inline void
+reseed(isc_entropy_t *ent) {
+ isc_time_t t;
+ pid_t pid;
+
+ if (ent->initcount == 0) {
+ pid = getpid();
+ entropypool_adddata(ent, &pid, sizeof(pid), 0);
+ pid = getppid();
+ entropypool_adddata(ent, &pid, sizeof(pid), 0);
+ }
+
+ /*!
+ * After we've reseeded 100 times, only add new timing info every
+ * 50 requests. This will keep us from using lots and lots of
+ * CPU just to return bad pseudorandom data anyway.
+ */
+ if (ent->initcount > 100)
+ if ((ent->initcount % 50) != 0)
+ return;
+
+ TIME_NOW(&t);
+ entropypool_adddata(ent, &t, sizeof(t), 0);
+ ent->initcount++;
+}
+
+static inline unsigned int
+estimate_entropy(sample_queue_t *sq, isc_uint32_t t) {
+ isc_int32_t delta;
+ isc_int32_t delta2;
+ isc_int32_t delta3;
+
+ /*!
+ * If the time counter has overflowed, calculate the real difference.
+ * If it has not, it is simpler.
+ */
+ if (t < sq->last_time)
+ delta = UINT_MAX - sq->last_time + t;
+ else
+ delta = sq->last_time - t;
+
+ if (delta < 0)
+ delta = -delta;
+
+ /*
+ * Calculate the second and third order differentials
+ */
+ delta2 = sq->last_delta - delta;
+ if (delta2 < 0)
+ delta2 = -delta2;
+
+ delta3 = sq->last_delta2 - delta2;
+ if (delta3 < 0)
+ delta3 = -delta3;
+
+ sq->last_time = t;
+ sq->last_delta = delta;
+ sq->last_delta2 = delta2;
+
+ /*
+ * If any delta is 0, we got no entropy. If all are non-zero, we
+ * might have something.
+ */
+ if (delta == 0 || delta2 == 0 || delta3 == 0)
+ return 0;
+
+ /*
+ * We could find the smallest delta and claim we got log2(delta)
+ * bits, but for now return that we found 1 bit.
+ */
+ return 1;
+}
+
+static unsigned int
+crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
+ unsigned int ns;
+ unsigned int added;
+
+ if (sq->nsamples < 6)
+ return (0);
+
+ added = 0;
+ sq->last_time = sq->samples[0];
+ sq->last_delta = 0;
+ sq->last_delta2 = 0;
+
+ /*
+ * Prime the values by adding in the first 4 samples in. This
+ * should completely initialize the delta calculations.
+ */
+ for (ns = 0; ns < 4; ns++)
+ (void)estimate_entropy(sq, sq->samples[ns]);
+
+ for (ns = 4; ns < sq->nsamples; ns++)
+ added += estimate_entropy(sq, sq->samples[ns]);
+
+ entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
+ entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
+
+ /*
+ * Move the last 4 samples into the first 4 positions, and start
+ * adding new samples from that point.
+ */
+ for (ns = 0; ns < 4; ns++) {
+ sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
+ sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
+ }
+
+ sq->nsamples = 4;
+
+ return (added);
+}
+
+static unsigned int
+get_from_callback(isc_entropysource_t *source, unsigned int desired,
+ isc_boolean_t blocking)
+{
+ isc_entropy_t *ent = source->ent;
+ isc_cbsource_t *cbs = &source->sources.callback;
+ unsigned int added;
+ unsigned int got;
+ isc_result_t result;
+
+ if (desired == 0)
+ return (0);
+
+ if (source->bad)
+ return (0);
+
+ if (!cbs->start_called && cbs->startfunc != NULL) {
+ result = cbs->startfunc(source, cbs->arg, blocking);
+ if (result != ISC_R_SUCCESS)
+ return (0);
+ cbs->start_called = ISC_TRUE;
+ }
+
+ added = 0;
+ result = ISC_R_SUCCESS;
+ while (desired > 0 && result == ISC_R_SUCCESS) {
+ result = cbs->getfunc(source, cbs->arg, blocking);
+ if (result == ISC_R_QUEUEFULL) {
+ got = crunchsamples(ent, &cbs->samplequeue);
+ added += got;
+ desired -= ISC_MIN(got, desired);
+ result = ISC_R_SUCCESS;
+ } else if (result != ISC_R_SUCCESS &&
+ result != ISC_R_NOTBLOCKING)
+ source->bad = ISC_TRUE;
+
+ }
+
+ return (added);
+}
+
+/*
+ * Extract some number of bytes from the random pool, decreasing the
+ * estimate of randomness as each byte is extracted.
+ *
+ * Do this by stiring the pool and returning a part of hash as randomness.
+ * Note that no secrets are given away here since parts of the hash are
+ * xored together before returned.
+ *
+ * Honor the request from the caller to only return good data, any data,
+ * etc.
+ */
+isc_result_t
+isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
+ unsigned int *returned, unsigned int flags)
+{
+ unsigned int i;
+ isc_sha1_t hash;
+ unsigned char digest[ISC_SHA1_DIGESTLENGTH];
+ isc_uint32_t remain, deltae, count, total;
+ isc_uint8_t *buf;
+ isc_boolean_t goodonly, partial, blocking;
+
+ REQUIRE(VALID_ENTROPY(ent));
+ REQUIRE(data != NULL);
+ REQUIRE(length > 0);
+
+ goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
+ partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
+ blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
+
+ REQUIRE(!partial || returned != NULL);
+
+ LOCK(&ent->lock);
+
+ remain = length;
+ buf = data;
+ total = 0;
+ while (remain != 0) {
+ count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
+
+ /*
+ * If we are extracting good data only, make certain we
+ * have enough data in our pool for this pass. If we don't,
+ * get some, and fail if we can't, and partial returns
+ * are not ok.
+ */
+ if (goodonly) {
+ unsigned int fillcount;
+
+ fillcount = ISC_MAX(remain * 8, count * 8);
+
+ /*
+ * If, however, we have at least THRESHOLD_BITS
+ * of entropy in the pool, don't block here. It is
+ * better to drain the pool once in a while and
+ * then refill it than it is to constantly keep the
+ * pool full.
+ */
+ if (ent->pool.entropy >= THRESHOLD_BITS)
+ fillpool(ent, fillcount, ISC_FALSE);
+ else
+ fillpool(ent, fillcount, blocking);
+
+ /*
+ * Verify that we got enough entropy to do one
+ * extraction. If we didn't, bail.
+ */
+ if (ent->pool.entropy < THRESHOLD_BITS) {
+ if (!partial)
+ goto zeroize;
+ else
+ goto partial_output;
+ }
+ } else {
+ /*
+ * If we've extracted half our pool size in bits
+ * since the last refresh, try to refresh here.
+ */
+ if (ent->initialized < THRESHOLD_BITS)
+ fillpool(ent, THRESHOLD_BITS, blocking);
+ else
+ fillpool(ent, 0, ISC_FALSE);
+
+ /*
+ * If we've not initialized with enough good random
+ * data, seed with our crappy code.
+ */
+ if (ent->initialized < THRESHOLD_BITS)
+ reseed(ent);
+ }
+
+ isc_sha1_init(&hash);
+ isc_sha1_update(&hash, (void *)(ent->pool.pool),
+ RND_POOLBYTES);
+ isc_sha1_final(&hash, digest);
+
+ /*
+ * Stir the extracted data (all of it) back into the pool.
+ */
+ entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
+
+ for (i = 0; i < count; i++)
+ buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
+
+ buf += count;
+ remain -= count;
+
+ deltae = count * 8;
+ deltae = ISC_MIN(deltae, ent->pool.entropy);
+ total += deltae;
+ subtract_entropy(ent, deltae);
+ add_pseudo(ent, count * 8);
+ }
+
+ partial_output:
+ memset(digest, 0, sizeof(digest));
+
+ if (returned != NULL)
+ *returned = (length - remain);
+
+ UNLOCK(&ent->lock);
+
+ return (ISC_R_SUCCESS);
+
+ zeroize:
+ /* put the entropy we almost extracted back */
+ add_entropy(ent, total);
+ memset(data, 0, length);
+ memset(digest, 0, sizeof(digest));
+ if (returned != NULL)
+ *returned = 0;
+
+ UNLOCK(&ent->lock);
+
+ return (ISC_R_NOENTROPY);
+}
+
+static void
+isc_entropypool_init(isc_entropypool_t *pool) {
+ pool->cursor = RND_POOLWORDS - 1;
+ pool->entropy = 0;
+ pool->pseudo = 0;
+ pool->rotate = 0;
+ memset(pool->pool, 0, RND_POOLBYTES);
+}
+
+static void
+isc_entropypool_invalidate(isc_entropypool_t *pool) {
+ pool->cursor = 0;
+ pool->entropy = 0;
+ pool->pseudo = 0;
+ pool->rotate = 0;
+ memset(pool->pool, 0, RND_POOLBYTES);
+}
+
+isc_result_t
+isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
+ isc_result_t result;
+ isc_entropy_t *ent;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(entp != NULL && *entp == NULL);
+
+ ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
+ if (ent == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /*
+ * We need a lock.
+ */
+ result = isc_mutex_init(&ent->lock);
+ if (result != ISC_R_SUCCESS)
+ goto errout;
+
+ /*
+ * From here down, no failures will/can occur.
+ */
+ ISC_LIST_INIT(ent->sources);
+ ent->nextsource = NULL;
+ ent->nsources = 0;
+ ent->mctx = NULL;
+ isc_mem_attach(mctx, &ent->mctx);
+ ent->refcnt = 1;
+ ent->initialized = 0;
+ ent->initcount = 0;
+ ent->magic = ENTROPY_MAGIC;
+
+ isc_entropypool_init(&ent->pool);
+
+ *entp = ent;
+ return (ISC_R_SUCCESS);
+
+ errout:
+ isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
+
+ return (result);
+}
+
+/*!
+ * Requires "ent" be locked.
+ */
+static void
+destroysource(isc_entropysource_t **sourcep) {
+ isc_entropysource_t *source;
+ isc_entropy_t *ent;
+ isc_cbsource_t *cbs;
+
+ source = *sourcep;
+ *sourcep = NULL;
+ ent = source->ent;
+
+ ISC_LIST_UNLINK(ent->sources, source, link);
+ ent->nextsource = NULL;
+ REQUIRE(ent->nsources > 0);
+ ent->nsources--;
+
+ switch (source->type) {
+ case ENTROPY_SOURCETYPE_FILE:
+ if (! source->bad)
+ destroyfilesource(&source->sources.file);
+ break;
+ case ENTROPY_SOURCETYPE_USOCKET:
+ if (! source->bad)
+ destroyusocketsource(&source->sources.usocket);
+ break;
+ case ENTROPY_SOURCETYPE_SAMPLE:
+ samplequeue_release(ent, &source->sources.sample.samplequeue);
+ break;
+ case ENTROPY_SOURCETYPE_CALLBACK:
+ cbs = &source->sources.callback;
+ if (cbs->start_called && cbs->stopfunc != NULL) {
+ cbs->stopfunc(source, cbs->arg);
+ cbs->start_called = ISC_FALSE;
+ }
+ samplequeue_release(ent, &cbs->samplequeue);
+ break;
+ }
+
+ memset(source, 0, sizeof(isc_entropysource_t));
+
+ isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
+}
+
+static inline isc_boolean_t
+destroy_check(isc_entropy_t *ent) {
+ isc_entropysource_t *source;
+
+ if (ent->refcnt > 0)
+ return (ISC_FALSE);
+
+ source = ISC_LIST_HEAD(ent->sources);
+ while (source != NULL) {
+ switch (source->type) {
+ case ENTROPY_SOURCETYPE_FILE:
+ case ENTROPY_SOURCETYPE_USOCKET:
+ break;
+ default:
+ return (ISC_FALSE);
+ }
+ source = ISC_LIST_NEXT(source, link);
+ }
+
+ return (ISC_TRUE);
+}
+
+static void
+destroy(isc_entropy_t **entp) {
+ isc_entropy_t *ent;
+ isc_entropysource_t *source;
+ isc_mem_t *mctx;
+
+ REQUIRE(entp != NULL && *entp != NULL);
+ ent = *entp;
+ *entp = NULL;
+
+ LOCK(&ent->lock);
+
+ REQUIRE(ent->refcnt == 0);
+
+ /*
+ * Here, detach non-sample sources.
+ */
+ source = ISC_LIST_HEAD(ent->sources);
+ while (source != NULL) {
+ switch(source->type) {
+ case ENTROPY_SOURCETYPE_FILE:
+ case ENTROPY_SOURCETYPE_USOCKET:
+ destroysource(&source);
+ break;
+ }
+ source = ISC_LIST_HEAD(ent->sources);
+ }
+
+ /*
+ * If there are other types of sources, we've found a bug.
+ */
+ REQUIRE(ISC_LIST_EMPTY(ent->sources));
+
+ mctx = ent->mctx;
+
+ isc_entropypool_invalidate(&ent->pool);
+
+ UNLOCK(&ent->lock);
+
+ DESTROYLOCK(&ent->lock);
+
+ memset(ent, 0, sizeof(isc_entropy_t));
+ isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
+ isc_mem_detach(&mctx);
+}
+
+void
+isc_entropy_destroysource(isc_entropysource_t **sourcep) {
+ isc_entropysource_t *source;
+ isc_entropy_t *ent;
+ isc_boolean_t killit;
+
+ REQUIRE(sourcep != NULL);
+ REQUIRE(VALID_SOURCE(*sourcep));
+
+ source = *sourcep;
+ *sourcep = NULL;
+
+ ent = source->ent;
+ REQUIRE(VALID_ENTROPY(ent));
+
+ LOCK(&ent->lock);
+
+ destroysource(&source);
+
+ killit = destroy_check(ent);
+
+ UNLOCK(&ent->lock);
+
+ if (killit)
+ destroy(&ent);
+}
+
+isc_result_t
+isc_entropy_createcallbacksource(isc_entropy_t *ent,
+ isc_entropystart_t start,
+ isc_entropyget_t get,
+ isc_entropystop_t stop,
+ void *arg,
+ isc_entropysource_t **sourcep)
+{
+ isc_result_t result;
+ isc_entropysource_t *source;
+ isc_cbsource_t *cbs;
+
+ REQUIRE(VALID_ENTROPY(ent));
+ REQUIRE(get != NULL);
+ REQUIRE(sourcep != NULL && *sourcep == NULL);
+
+ LOCK(&ent->lock);
+
+ source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
+ if (source == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto errout;
+ }
+ source->bad = ISC_FALSE;
+
+ cbs = &source->sources.callback;
+
+ result = samplesource_allocate(ent, &cbs->samplequeue);
+ if (result != ISC_R_SUCCESS)
+ goto errout;
+
+ cbs->start_called = ISC_FALSE;
+ cbs->startfunc = start;
+ cbs->getfunc = get;
+ cbs->stopfunc = stop;
+ cbs->arg = arg;
+
+ /*
+ * From here down, no failures can occur.
+ */
+ source->magic = SOURCE_MAGIC;
+ source->type = ENTROPY_SOURCETYPE_CALLBACK;
+ source->ent = ent;
+ source->total = 0;
+ memset(source->name, 0, sizeof(source->name));
+ ISC_LINK_INIT(source, link);
+
+ /*
+ * Hook it into the entropy system.
+ */
+ ISC_LIST_APPEND(ent->sources, source, link);
+ ent->nsources++;
+
+ *sourcep = source;
+
+ UNLOCK(&ent->lock);
+ return (ISC_R_SUCCESS);
+
+ errout:
+ if (source != NULL)
+ isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
+
+ UNLOCK(&ent->lock);
+
+ return (result);
+}
+
+void
+isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
+ isc_entropysource_t *source;
+ isc_cbsource_t *cbs;
+
+ REQUIRE(VALID_ENTROPY(ent));
+
+ LOCK(&ent->lock);
+
+ source = ISC_LIST_HEAD(ent->sources);
+ while (source != NULL) {
+ if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
+ cbs = &source->sources.callback;
+ if (cbs->start_called && cbs->stopfunc != NULL) {
+ cbs->stopfunc(source, cbs->arg);
+ cbs->start_called = ISC_FALSE;
+ }
+ }
+
+ source = ISC_LIST_NEXT(source, link);
+ }
+
+ UNLOCK(&ent->lock);
+}
+
+isc_result_t
+isc_entropy_createsamplesource(isc_entropy_t *ent,
+ isc_entropysource_t **sourcep)
+{
+ isc_result_t result;
+ isc_entropysource_t *source;
+ sample_queue_t *sq;
+
+ REQUIRE(VALID_ENTROPY(ent));
+ REQUIRE(sourcep != NULL && *sourcep == NULL);
+
+ LOCK(&ent->lock);
+
+ source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
+ if (source == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto errout;
+ }
+
+ sq = &source->sources.sample.samplequeue;
+ result = samplesource_allocate(ent, sq);
+ if (result != ISC_R_SUCCESS)
+ goto errout;
+
+ /*
+ * From here down, no failures can occur.
+ */
+ source->magic = SOURCE_MAGIC;
+ source->type = ENTROPY_SOURCETYPE_SAMPLE;
+ source->ent = ent;
+ source->total = 0;
+ memset(source->name, 0, sizeof(source->name));
+ ISC_LINK_INIT(source, link);
+
+ /*
+ * Hook it into the entropy system.
+ */
+ ISC_LIST_APPEND(ent->sources, source, link);
+ ent->nsources++;
+
+ *sourcep = source;
+
+ UNLOCK(&ent->lock);
+ return (ISC_R_SUCCESS);
+
+ errout:
+ if (source != NULL)
+ isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
+
+ UNLOCK(&ent->lock);
+
+ return (result);
+}
+
+/*!
+ * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
+ * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
+ * queue was full when this function was called.
+ */
+static isc_result_t
+addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
+ if (sq->nsamples >= RND_EVENTQSIZE)
+ return (ISC_R_NOMORE);
+
+ sq->samples[sq->nsamples] = sample;
+ sq->extra[sq->nsamples] = extra;
+ sq->nsamples++;
+
+ if (sq->nsamples >= RND_EVENTQSIZE)
+ return (ISC_R_QUEUEFULL);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
+ isc_uint32_t extra)
+{
+ isc_entropy_t *ent;
+ sample_queue_t *sq;
+ unsigned int entropy;
+ isc_result_t result;
+
+ REQUIRE(VALID_SOURCE(source));
+
+ ent = source->ent;
+
+ LOCK(&ent->lock);
+
+ sq = &source->sources.sample.samplequeue;
+ result = addsample(sq, sample, extra);
+ if (result == ISC_R_QUEUEFULL) {
+ entropy = crunchsamples(ent, sq);
+ add_entropy(ent, entropy);
+ }
+
+ UNLOCK(&ent->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
+ isc_uint32_t extra)
+{
+ sample_queue_t *sq;
+ isc_result_t result;
+
+ REQUIRE(VALID_SOURCE(source));
+ REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
+
+ sq = &source->sources.callback.samplequeue;
+ result = addsample(sq, sample, extra);
+
+ return (result);
+}
+
+void
+isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
+ isc_uint32_t entropy)
+{
+ REQUIRE(VALID_ENTROPY(ent));
+
+ LOCK(&ent->lock);
+
+ entropypool_adddata(ent, data, length, entropy);
+
+ if (ent->initialized < THRESHOLD_BITS)
+ ent->initialized = THRESHOLD_BITS;
+
+ UNLOCK(&ent->lock);
+}
+
+static void
+dumpstats(isc_entropy_t *ent, FILE *out) {
+ fprintf(out,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
+ ISC_MSG_ENTROPYSTATS,
+ "Entropy pool %p: refcnt %u cursor %u,"
+ " rotate %u entropy %u pseudo %u nsources %u"
+ " nextsource %p initialized %u initcount %u\n"),
+ ent, ent->refcnt,
+ ent->pool.cursor, ent->pool.rotate,
+ ent->pool.entropy, ent->pool.pseudo,
+ ent->nsources, ent->nextsource, ent->initialized,
+ ent->initcount);
+}
+
+/*
+ * This function ignores locking. Use at your own risk.
+ */
+void
+isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
+ REQUIRE(VALID_ENTROPY(ent));
+
+ LOCK(&ent->lock);
+ dumpstats(ent, out);
+ UNLOCK(&ent->lock);
+}
+
+void
+isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
+ REQUIRE(VALID_ENTROPY(ent));
+ REQUIRE(entp != NULL && *entp == NULL);
+
+ LOCK(&ent->lock);
+
+ ent->refcnt++;
+ *entp = ent;
+
+ UNLOCK(&ent->lock);
+}
+
+void
+isc_entropy_detach(isc_entropy_t **entp) {
+ isc_entropy_t *ent;
+ isc_boolean_t killit;
+
+ REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
+ ent = *entp;
+ *entp = NULL;
+
+ LOCK(&ent->lock);
+
+ REQUIRE(ent->refcnt > 0);
+ ent->refcnt--;
+
+ killit = destroy_check(ent);
+
+ UNLOCK(&ent->lock);
+
+ if (killit)
+ destroy(&ent);
+}
+
+static isc_result_t
+kbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
+ /*
+ * The intent of "first" is to provide a warning message only once
+ * during the run of a program that might try to gather keyboard
+ * entropy multiple times.
+ */
+ static isc_boolean_t first = ISC_TRUE;
+
+ UNUSED(arg);
+
+ if (! blocking)
+ return (ISC_R_NOENTROPY);
+
+ if (first) {
+ if (source->warn_keyboard)
+ fprintf(stderr, "You must use the keyboard to create "
+ "entropy, since your system is lacking\n"
+ "/dev/random (or equivalent)\n\n");
+ first = ISC_FALSE;
+ }
+ fprintf(stderr, "start typing:\n");
+
+ return (isc_keyboard_open(&source->kbd));
+}
+
+static void
+kbdstop(isc_entropysource_t *source, void *arg) {
+
+ UNUSED(arg);
+
+ if (! isc_keyboard_canceled(&source->kbd))
+ fprintf(stderr, "stop typing.\r\n");
+
+ (void)isc_keyboard_close(&source->kbd, 3);
+}
+
+static isc_result_t
+kbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
+ isc_result_t result;
+ isc_time_t t;
+ isc_uint32_t sample;
+ isc_uint32_t extra;
+ unsigned char c;
+
+ UNUSED(arg);
+
+ if (!blocking)
+ return (ISC_R_NOTBLOCKING);
+
+ result = isc_keyboard_getchar(&source->kbd, &c);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ TIME_NOW(&t);
+
+ sample = isc_time_nanoseconds(&t);
+ extra = c;
+
+ result = isc_entropy_addcallbacksample(source, sample, extra);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "\r\n");
+ return (result);
+ }
+
+ fprintf(stderr, ".");
+ fflush(stderr);
+
+ return (result);
+}
+
+isc_result_t
+isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
+ const char *randomfile, int use_keyboard)
+{
+ isc_result_t result;
+ isc_result_t final_result = ISC_R_NOENTROPY;
+ isc_boolean_t userfile = ISC_TRUE;
+
+ REQUIRE(VALID_ENTROPY(ectx));
+ REQUIRE(source != NULL && *source == NULL);
+ REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
+ use_keyboard == ISC_ENTROPY_KEYBOARDNO ||
+ use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
+
+#ifdef PATH_RANDOMDEV
+ if (randomfile == NULL) {
+ randomfile = PATH_RANDOMDEV;
+ userfile = ISC_FALSE;
+ }
+#endif
+
+ if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
+ result = isc_entropy_createfilesource(ectx, randomfile);
+ if (result == ISC_R_SUCCESS &&
+ use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
+ use_keyboard = ISC_ENTROPY_KEYBOARDNO;
+ if (result != ISC_R_SUCCESS && userfile)
+ return (result);
+
+ final_result = result;
+ }
+
+ if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
+ result = isc_entropy_createcallbacksource(ectx, kbdstart,
+ kbdget, kbdstop,
+ NULL, source);
+ if (result == ISC_R_SUCCESS)
+ (*source)->warn_keyboard =
+ ISC_TF(use_keyboard ==
+ ISC_ENTROPY_KEYBOARDMAYBE);
+
+ if (final_result != ISC_R_SUCCESS)
+ final_result = result;
+ }
+
+ /*
+ * final_result is ISC_R_SUCCESS if at least one source of entropy
+ * could be started, otherwise it is the error from the most recently
+ * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
+ * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
+ */
+ return (final_result);
+}
diff --git a/lib/isc/error.c b/lib/isc/error.c
new file mode 100644
index 0000000..282986c
--- /dev/null
+++ b/lib/isc/error.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: error.c,v 1.17.18.2 2005/04/29 00:16:45 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <isc/error.h>
+#include <isc/msgs.h>
+
+/*% Default unexpected callback. */
+static void
+default_unexpected_callback(const char *, int, const char *, va_list)
+ ISC_FORMAT_PRINTF(3, 0);
+
+/*% Default fatal callback. */
+static void
+default_fatal_callback(const char *, int, const char *, va_list)
+ ISC_FORMAT_PRINTF(3, 0);
+
+/*% unexpected_callback */
+static isc_errorcallback_t unexpected_callback = default_unexpected_callback;
+static isc_errorcallback_t fatal_callback = default_fatal_callback;
+
+void
+isc_error_setunexpected(isc_errorcallback_t cb) {
+ if (cb == NULL)
+ unexpected_callback = default_unexpected_callback;
+ else
+ unexpected_callback = cb;
+}
+
+void
+isc_error_setfatal(isc_errorcallback_t cb) {
+ if (cb == NULL)
+ fatal_callback = default_fatal_callback;
+ else
+ fatal_callback = cb;
+}
+
+void
+isc_error_unexpected(const char *file, int line, const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ (unexpected_callback)(file, line, format, args);
+ va_end(args);
+}
+
+void
+isc_error_fatal(const char *file, int line, const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ (fatal_callback)(file, line, format, args);
+ va_end(args);
+ abort();
+}
+
+void
+isc_error_runtimecheck(const char *file, int line, const char *expression) {
+ isc_error_fatal(file, line, "RUNTIME_CHECK(%s) %s", expression,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+}
+
+static void
+default_unexpected_callback(const char *file, int line, const char *format,
+ va_list args)
+{
+ fprintf(stderr, "%s:%d: ", file, line);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+}
+
+static void
+default_fatal_callback(const char *file, int line, const char *format,
+ va_list args)
+{
+ fprintf(stderr, "%s:%d: %s: ", file, line,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FATALERROR, "fatal error"));
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+}
diff --git a/lib/isc/event.c b/lib/isc/event.c
new file mode 100644
index 0000000..7931061
--- /dev/null
+++ b/lib/isc/event.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: event.c,v 1.17.18.2 2005/04/29 00:16:45 marka Exp $ */
+
+/*!
+ * \file
+ * \author Principal Author: Bob Halley
+ */
+
+#include <config.h>
+
+#include <isc/event.h>
+#include <isc/mem.h>
+#include <isc/util.h>
+
+/***
+ *** Events.
+ ***/
+
+static void
+destroy(isc_event_t *event) {
+ isc_mem_t *mctx = event->ev_destroy_arg;
+
+ isc_mem_put(mctx, event, event->ev_size);
+}
+
+isc_event_t *
+isc_event_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
+ isc_taskaction_t action, const void *arg, size_t size)
+{
+ isc_event_t *event;
+ void *deconst_arg;
+
+ REQUIRE(size >= sizeof(struct isc_event));
+ REQUIRE(action != NULL);
+
+ event = isc_mem_get(mctx, size);
+ if (event == NULL)
+ return (NULL);
+
+ /*
+ * Removing the const attribute from "arg" is the best of two
+ * evils here. If the event->ev_arg member is made const, then
+ * it affects a great many users of the task/event subsystem
+ * which are not passing in an "arg" which starts its life as
+ * const. Changing isc_event_allocate() and isc_task_onshutdown()
+ * to not have "arg" prototyped as const (which is quite legitimate,
+ * because neither of those functions modify arg) can cause
+ * compiler whining anytime someone does want to use a const
+ * arg that they themselves never modify, such as with
+ * gcc -Wwrite-strings and using a string "arg".
+ */
+ DE_CONST(arg, deconst_arg);
+
+ ISC_EVENT_INIT(event, size, 0, NULL, type, action, deconst_arg,
+ sender, destroy, mctx);
+
+ return (event);
+}
+
+void
+isc_event_free(isc_event_t **eventp) {
+ isc_event_t *event;
+
+ REQUIRE(eventp != NULL);
+ event = *eventp;
+ REQUIRE(event != NULL);
+
+ if (event->ev_destroy != NULL)
+ (event->ev_destroy)(event);
+
+ *eventp = NULL;
+}
diff --git a/lib/isc/fsaccess.c b/lib/isc/fsaccess.c
new file mode 100644
index 0000000..cdab3d8
--- /dev/null
+++ b/lib/isc/fsaccess.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2004, 2005 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: fsaccess.c,v 1.6.18.2 2005/04/29 00:16:45 marka Exp $ */
+
+/*! \file
+ * \brief
+ * This file contains the OS-independent functionality of the API.
+ */
+#include <isc/fsaccess.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+/*!
+ * Shorthand. Maybe ISC__FSACCESS_PERMISSIONBITS should not even be in
+ * <isc/fsaccess.h>. Could check consistency with sizeof(isc_fsaccess_t)
+ * and the number of bits in each function.
+ */
+#define STEP (ISC__FSACCESS_PERMISSIONBITS)
+#define GROUP (STEP)
+#define OTHER (STEP * 2)
+
+void
+isc_fsaccess_add(int trustee, int permission, isc_fsaccess_t *access) {
+ REQUIRE(trustee <= 0x7);
+ REQUIRE(permission <= 0xFF);
+
+ if ((trustee & ISC_FSACCESS_OWNER) != 0)
+ *access |= permission;
+
+ if ((trustee & ISC_FSACCESS_GROUP) != 0)
+ *access |= (permission << GROUP);
+
+ if ((trustee & ISC_FSACCESS_OTHER) != 0)
+ *access |= (permission << OTHER);
+}
+
+void
+isc_fsaccess_remove(int trustee, int permission, isc_fsaccess_t *access) {
+ REQUIRE(trustee <= 0x7);
+ REQUIRE(permission <= 0xFF);
+
+
+ if ((trustee & ISC_FSACCESS_OWNER) != 0)
+ *access &= ~permission;
+
+ if ((trustee & ISC_FSACCESS_GROUP) != 0)
+ *access &= ~(permission << GROUP);
+
+ if ((trustee & ISC_FSACCESS_OTHER) != 0)
+ *access &= ~(permission << OTHER);
+}
+
+static isc_result_t
+check_bad_bits(isc_fsaccess_t access, isc_boolean_t is_dir) {
+ isc_fsaccess_t bits;
+
+ /*
+ * Check for disallowed user bits.
+ */
+ if (is_dir)
+ bits = ISC_FSACCESS_READ |
+ ISC_FSACCESS_WRITE |
+ ISC_FSACCESS_EXECUTE;
+ else
+ bits = ISC_FSACCESS_CREATECHILD |
+ ISC_FSACCESS_ACCESSCHILD |
+ ISC_FSACCESS_DELETECHILD |
+ ISC_FSACCESS_LISTDIRECTORY;
+
+ /*
+ * Set group bad bits.
+ */
+ bits |= bits << STEP;
+ /*
+ * Set other bad bits.
+ */
+ bits |= bits << STEP;
+
+ if ((access & bits) != 0) {
+ if (is_dir)
+ return (ISC_R_NOTFILE);
+ else
+ return (ISC_R_NOTDIRECTORY);
+ }
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/hash.c b/lib/isc/hash.c
new file mode 100644
index 0000000..4b6dc06
--- /dev/null
+++ b/lib/isc/hash.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: hash.c,v 1.6.18.5 2006/01/04 00:37:23 marka Exp $ */
+
+/*! \file
+ * Some portion of this code was derived from universal hash function
+ * libraries of Rice University.
+\section license UH Universal Hashing Library
+
+Copyright ((c)) 2002, Rice University
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * Neither the name of Rice University (RICE) 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 RICE and the contributors on an "as is"
+basis, without any representations or warranties of any kind, express
+or implied including, but not limited to, representations or
+warranties of non-infringement, merchantability or fitness for a
+particular purpose. In no event shall RICE or contributors be liable
+for any direct, indirect, incidental, special, exemplary, or
+consequential damages (including, but not limited to, procurement of
+substitute goods or services; loss of use, data, or profits; or
+business interruption) however caused and on any theory of liability,
+whether in contract, strict liability, or tort (including negligence
+or otherwise) arising in any way out of the use of this software, even
+if advised of the possibility of such damage.
+*/
+
+#include <config.h>
+
+#include <isc/entropy.h>
+#include <isc/hash.h>
+#include <isc/mem.h>
+#include <isc/magic.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/random.h>
+#include <isc/refcount.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define HASH_MAGIC ISC_MAGIC('H', 'a', 's', 'h')
+#define VALID_HASH(h) ISC_MAGIC_VALID((h), HASH_MAGIC)
+
+/*%
+ * A large 32-bit prime number that specifies the range of the hash output.
+ */
+#define PRIME32 0xFFFFFFFB /* 2^32 - 5 */
+
+/*@{*/
+/*%
+ * Types of random seed and hash accumulator. Perhaps they can be system
+ * dependent.
+ */
+typedef isc_uint32_t hash_accum_t;
+typedef isc_uint16_t hash_random_t;
+/*@}*/
+
+/*% isc hash structure */
+struct isc_hash {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ isc_boolean_t initialized;
+ isc_refcount_t refcnt;
+ isc_entropy_t *entropy; /*%< entropy source */
+ unsigned int limit; /*%< upper limit of key length */
+ size_t vectorlen; /*%< size of the vector below */
+ hash_random_t *rndvector; /*%< random vector for universal hashing */
+};
+
+static isc_mutex_t createlock;
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_hash_t *hash = NULL;
+
+static unsigned char maptolower[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+isc_result_t
+isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy,
+ unsigned int limit, isc_hash_t **hctxp)
+{
+ isc_result_t result;
+ isc_hash_t *hctx;
+ size_t vlen;
+ hash_random_t *rv;
+ hash_accum_t overflow_limit;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(hctxp != NULL && *hctxp == NULL);
+
+ /*
+ * Overflow check. Since our implementation only does a modulo
+ * operation at the last stage of hash calculation, the accumulator
+ * must not overflow.
+ */
+ overflow_limit =
+ 1 << (((sizeof(hash_accum_t) - sizeof(hash_random_t))) * 8);
+ if (overflow_limit < (limit + 1) * 0xff)
+ return (ISC_R_RANGE);
+
+ hctx = isc_mem_get(mctx, sizeof(isc_hash_t));
+ if (hctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ vlen = sizeof(hash_random_t) * (limit + 1);
+ rv = isc_mem_get(mctx, vlen);
+ if (rv == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto errout;
+ }
+
+ /*
+ * We need a lock.
+ */
+ result = isc_mutex_init(&hctx->lock);
+ if (result != ISC_R_SUCCESS)
+ goto errout;
+
+ /*
+ * From here down, no failures will/can occur.
+ */
+ hctx->magic = HASH_MAGIC;
+ hctx->mctx = NULL;
+ isc_mem_attach(mctx, &hctx->mctx);
+ hctx->initialized = ISC_FALSE;
+ result = isc_refcount_init(&hctx->refcnt, 1);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+ hctx->entropy = NULL;
+ hctx->limit = limit;
+ hctx->vectorlen = vlen;
+ hctx->rndvector = rv;
+
+ if (entropy != NULL)
+ isc_entropy_attach(entropy, &hctx->entropy);
+
+ *hctxp = hctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup_lock:
+ DESTROYLOCK(&hctx->lock);
+ errout:
+ isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
+ if (rv != NULL)
+ isc_mem_put(mctx, rv, vlen);
+
+ return (result);
+}
+
+static void
+initialize_lock(void) {
+ RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(mctx != NULL);
+ INSIST(hash == NULL);
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize_lock) == ISC_R_SUCCESS);
+
+ LOCK(&createlock);
+
+ if (hash == NULL)
+ result = isc_hash_ctxcreate(mctx, entropy, limit, &hash);
+
+ UNLOCK(&createlock);
+
+ return (result);
+}
+
+void
+isc_hash_ctxinit(isc_hash_t *hctx) {
+ isc_result_t result;
+
+ LOCK(&hctx->lock);
+
+ if (hctx->initialized == ISC_TRUE)
+ goto out;
+
+ if (hctx->entropy) {
+ result = isc_entropy_getdata(hctx->entropy,
+ hctx->rndvector, hctx->vectorlen,
+ NULL, 0);
+ INSIST(result == ISC_R_SUCCESS);
+ } else {
+ isc_uint32_t pr;
+ unsigned int i, copylen;
+ unsigned char *p;
+
+ p = (unsigned char *)hctx->rndvector;
+ for (i = 0; i < hctx->vectorlen; i += copylen, p += copylen) {
+ isc_random_get(&pr);
+ if (i + sizeof(pr) <= hctx->vectorlen)
+ copylen = sizeof(pr);
+ else
+ copylen = hctx->vectorlen - i;
+
+ memcpy(p, &pr, copylen);
+ }
+ INSIST(p == (unsigned char *)hctx->rndvector +
+ hctx->vectorlen);
+ }
+
+ hctx->initialized = ISC_TRUE;
+
+ out:
+ UNLOCK(&hctx->lock);
+}
+
+void
+isc_hash_init() {
+ INSIST(hash != NULL && VALID_HASH(hash));
+
+ isc_hash_ctxinit(hash);
+}
+
+void
+isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp) {
+ REQUIRE(VALID_HASH(hctx));
+ REQUIRE(hctxp != NULL && *hctxp == NULL);
+
+ isc_refcount_increment(&hctx->refcnt, NULL);
+ *hctxp = hctx;
+}
+
+static void
+destroy(isc_hash_t **hctxp) {
+ isc_hash_t *hctx;
+ isc_mem_t *mctx;
+
+ REQUIRE(hctxp != NULL && *hctxp != NULL);
+ hctx = *hctxp;
+ *hctxp = NULL;
+
+ LOCK(&hctx->lock);
+
+ isc_refcount_destroy(&hctx->refcnt);
+
+ mctx = hctx->mctx;
+ if (hctx->entropy != NULL)
+ isc_entropy_detach(&hctx->entropy);
+ if (hctx->rndvector != NULL)
+ isc_mem_put(mctx, hctx->rndvector, hctx->vectorlen);
+
+ UNLOCK(&hctx->lock);
+
+ DESTROYLOCK(&hctx->lock);
+
+ memset(hctx, 0, sizeof(isc_hash_t));
+ isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
+ isc_mem_detach(&mctx);
+}
+
+void
+isc_hash_ctxdetach(isc_hash_t **hctxp) {
+ isc_hash_t *hctx;
+ unsigned int refs;
+
+ REQUIRE(hctxp != NULL && VALID_HASH(*hctxp));
+ hctx = *hctxp;
+
+ isc_refcount_decrement(&hctx->refcnt, &refs);
+ if (refs == 0)
+ destroy(&hctx);
+
+ *hctxp = NULL;
+}
+
+void
+isc_hash_destroy() {
+ unsigned int refs;
+
+ INSIST(hash != NULL && VALID_HASH(hash));
+
+ isc_refcount_decrement(&hash->refcnt, &refs);
+ INSIST(refs == 0);
+
+ destroy(&hash);
+}
+
+static inline unsigned int
+hash_calc(isc_hash_t *hctx, const unsigned char *key, unsigned int keylen,
+ isc_boolean_t case_sensitive)
+{
+ hash_accum_t partial_sum = 0;
+ hash_random_t *p = hctx->rndvector;
+ unsigned int i = 0;
+
+ /* Make it sure that the hash context is initialized. */
+ if (hctx->initialized == ISC_FALSE)
+ isc_hash_ctxinit(hctx);
+
+ if (case_sensitive) {
+ for (i = 0; i < keylen; i++)
+ partial_sum += key[i] * (hash_accum_t)p[i];
+ } else {
+ for (i = 0; i < keylen; i++)
+ partial_sum += maptolower[key[i]] * (hash_accum_t)p[i];
+ }
+
+ partial_sum += p[i];
+
+ return ((unsigned int)(partial_sum % PRIME32));
+}
+
+unsigned int
+isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key,
+ unsigned int keylen, isc_boolean_t case_sensitive)
+{
+ REQUIRE(hctx != NULL && VALID_HASH(hctx));
+ REQUIRE(keylen <= hctx->limit);
+
+ return (hash_calc(hctx, key, keylen, case_sensitive));
+}
+
+unsigned int
+isc_hash_calc(const unsigned char *key, unsigned int keylen,
+ isc_boolean_t case_sensitive)
+{
+ INSIST(hash != NULL && VALID_HASH(hash));
+ REQUIRE(keylen <= hash->limit);
+
+ return (hash_calc(hash, key, keylen, case_sensitive));
+}
diff --git a/lib/isc/heap.c b/lib/isc/heap.c
new file mode 100644
index 0000000..9c495a7
--- /dev/null
+++ b/lib/isc/heap.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-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: heap.c,v 1.30.18.3 2006/04/17 18:27:33 explorer Exp $ */
+
+/*! \file
+ * Heap implementation of priority queues adapted from the following:
+ *
+ * \li "Introduction to Algorithms," Cormen, Leiserson, and Rivest,
+ * MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7.
+ *
+ * \li "Algorithms," Second Edition, Sedgewick, Addison-Wesley, 1988,
+ * ISBN 0-201-06673-4, chapter 11.
+ */
+
+#include <config.h>
+
+#include <isc/heap.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/string.h> /* Required for memcpy. */
+#include <isc/util.h>
+
+/*@{*/
+/*%
+ * 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. The parent is index/2, and the left-child is index*2.
+ * The right child is index*2+1.
+ */
+#define heap_parent(i) ((i) >> 1)
+#define heap_left(i) ((i) << 1)
+/*@}*/
+
+#define SIZE_INCREMENT 1024
+
+#define HEAP_MAGIC ISC_MAGIC('H', 'E', 'A', 'P')
+#define VALID_HEAP(h) ISC_MAGIC_VALID(h, HEAP_MAGIC)
+
+/*%
+ * When the heap is in a consistent state, the following invariant
+ * holds true: for every element i > 1, heap_parent(i) has a priority
+ * higher than or equal to that of i.
+ */
+#define HEAPCONDITION(i) ((i) == 1 || \
+ ! heap->compare(heap->array[(i)], \
+ heap->array[heap_parent(i)]))
+
+/*% ISC heap structure. */
+struct isc_heap {
+ unsigned int magic;
+ isc_mem_t * mctx;
+ unsigned int size;
+ unsigned int size_increment;
+ unsigned int last;
+ void **array;
+ isc_heapcompare_t compare;
+ isc_heapindex_t index;
+};
+
+isc_result_t
+isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare,
+ isc_heapindex_t index, unsigned int size_increment,
+ isc_heap_t **heapp)
+{
+ isc_heap_t *heap;
+
+ REQUIRE(heapp != NULL && *heapp == NULL);
+ REQUIRE(compare != NULL);
+
+ heap = isc_mem_get(mctx, sizeof(*heap));
+ if (heap == NULL)
+ return (ISC_R_NOMEMORY);
+ heap->magic = HEAP_MAGIC;
+ heap->mctx = mctx;
+ heap->size = 0;
+ if (size_increment == 0)
+ heap->size_increment = SIZE_INCREMENT;
+ else
+ heap->size_increment = size_increment;
+ heap->last = 0;
+ heap->array = NULL;
+ heap->compare = compare;
+ heap->index = index;
+
+ *heapp = heap;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_heap_destroy(isc_heap_t **heapp) {
+ isc_heap_t *heap;
+
+ REQUIRE(heapp != NULL);
+ heap = *heapp;
+ REQUIRE(VALID_HEAP(heap));
+
+ if (heap->array != NULL)
+ isc_mem_put(heap->mctx, heap->array,
+ heap->size * sizeof(void *));
+ heap->magic = 0;
+ isc_mem_put(heap->mctx, heap, sizeof(*heap));
+
+ *heapp = NULL;
+}
+
+static isc_boolean_t
+resize(isc_heap_t *heap) {
+ void **new_array;
+ size_t new_size;
+
+ REQUIRE(VALID_HEAP(heap));
+
+ new_size = heap->size + heap->size_increment;
+ new_array = isc_mem_get(heap->mctx, new_size * sizeof(void *));
+ if (new_array == NULL)
+ return (ISC_FALSE);
+ if (heap->array != NULL) {
+ memcpy(new_array, heap->array, heap->size * sizeof(void *));
+ isc_mem_put(heap->mctx, heap->array,
+ heap->size * sizeof(void *));
+ }
+ heap->size = new_size;
+ heap->array = new_array;
+
+ return (ISC_TRUE);
+}
+
+static void
+float_up(isc_heap_t *heap, unsigned int i, void *elt) {
+ unsigned int p;
+
+ for (p = heap_parent(i) ;
+ i > 1 && heap->compare(elt, heap->array[p]) ;
+ i = p, p = heap_parent(i)) {
+ heap->array[i] = heap->array[p];
+ if (heap->index != NULL)
+ (heap->index)(heap->array[i], i);
+ }
+ heap->array[i] = elt;
+ if (heap->index != NULL)
+ (heap->index)(heap->array[i], i);
+
+ INSIST(HEAPCONDITION(i));
+}
+
+static void
+sink_down(isc_heap_t *heap, unsigned int i, void *elt) {
+ unsigned int j, size, half_size;
+ size = heap->last;
+ half_size = size / 2;
+ while (i <= half_size) {
+ /* Find the smallest of the (at most) two children. */
+ j = heap_left(i);
+ if (j < size && heap->compare(heap->array[j+1],
+ heap->array[j]))
+ j++;
+ if (heap->compare(elt, heap->array[j]))
+ break;
+ heap->array[i] = heap->array[j];
+ if (heap->index != NULL)
+ (heap->index)(heap->array[i], i);
+ i = j;
+ }
+ heap->array[i] = elt;
+ if (heap->index != NULL)
+ (heap->index)(heap->array[i], i);
+
+ INSIST(HEAPCONDITION(i));
+}
+
+isc_result_t
+isc_heap_insert(isc_heap_t *heap, void *elt) {
+ unsigned int i;
+
+ REQUIRE(VALID_HEAP(heap));
+
+ i = ++heap->last;
+ if (heap->last >= heap->size && !resize(heap))
+ return (ISC_R_NOMEMORY);
+
+ float_up(heap, i, elt);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_heap_delete(isc_heap_t *heap, unsigned int index) {
+ void *elt;
+ isc_boolean_t less;
+
+ REQUIRE(VALID_HEAP(heap));
+ REQUIRE(index >= 1 && index <= heap->last);
+
+ if (index == heap->last) {
+ heap->last--;
+ } else {
+ elt = heap->array[heap->last--];
+ less = heap->compare(elt, heap->array[index]);
+ heap->array[index] = elt;
+ if (less)
+ float_up(heap, index, heap->array[index]);
+ else
+ sink_down(heap, index, heap->array[index]);
+ }
+}
+
+void
+isc_heap_increased(isc_heap_t *heap, unsigned int index) {
+ REQUIRE(VALID_HEAP(heap));
+ REQUIRE(index >= 1 && index <= heap->last);
+
+ float_up(heap, index, heap->array[index]);
+}
+
+void
+isc_heap_decreased(isc_heap_t *heap, unsigned int index) {
+ REQUIRE(VALID_HEAP(heap));
+ REQUIRE(index >= 1 && index <= heap->last);
+
+ sink_down(heap, index, heap->array[index]);
+}
+
+void *
+isc_heap_element(isc_heap_t *heap, unsigned int index) {
+ REQUIRE(VALID_HEAP(heap));
+ REQUIRE(index >= 1 && index <= heap->last);
+
+ return (heap->array[index]);
+}
+
+void
+isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap) {
+ unsigned int i;
+
+ REQUIRE(VALID_HEAP(heap));
+ REQUIRE(action != NULL);
+
+ for (i = 1 ; i <= heap->last ; i++)
+ (action)(heap->array[i], uap);
+}
diff --git a/lib/isc/hex.c b/lib/isc/hex.c
new file mode 100644
index 0000000..8dfec02
--- /dev/null
+++ b/lib/isc/hex.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2004, 2005 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: hex.c,v 1.14.18.2 2005/04/29 00:16:46 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+
+#include <isc/buffer.h>
+#include <isc/hex.h>
+#include <isc/lex.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define RETERR(x) do { \
+ isc_result_t _r = (x); \
+ if (_r != ISC_R_SUCCESS) \
+ return (_r); \
+ } while (0)
+
+
+/*
+ * BEW: These static functions are copied from lib/dns/rdata.c.
+ */
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target);
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
+
+static const char hex[] = "0123456789ABCDEF";
+
+isc_result_t
+isc_hex_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target)
+{
+ char buf[3];
+ unsigned int loops = 0;
+
+ if (wordlength < 2)
+ wordlength = 2;
+
+ memset(buf, 0, sizeof(buf));
+ while (source->length > 0) {
+ buf[0] = hex[(source->base[0] >> 4) & 0xf];
+ buf[1] = hex[(source->base[0]) & 0xf];
+ RETERR(str_totext(buf, target));
+ isc_region_consume(source, 1);
+
+ loops++;
+ if (source->length != 0 &&
+ (int)((loops + 1) * 2) >= wordlength)
+ {
+ loops = 0;
+ RETERR(str_totext(wordbreak, target));
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * State of a hex decoding process in progress.
+ */
+typedef struct {
+ int length; /*%< Desired length of binary data or -1 */
+ isc_buffer_t *target; /*%< Buffer for resulting binary data */
+ int digits; /*%< Number of buffered hex digits */
+ int val[2];
+} hex_decode_ctx_t;
+
+static inline void
+hex_decode_init(hex_decode_ctx_t *ctx, int length, isc_buffer_t *target)
+{
+ ctx->digits = 0;
+ ctx->length = length;
+ ctx->target = target;
+}
+
+static inline isc_result_t
+hex_decode_char(hex_decode_ctx_t *ctx, int c) {
+ char *s;
+
+ if ((s = strchr(hex, toupper(c))) == NULL)
+ return (ISC_R_BADHEX);
+ ctx->val[ctx->digits++] = s - hex;
+ if (ctx->digits == 2) {
+ unsigned char num;
+
+ num = (ctx->val[0] << 4) + (ctx->val[1]);
+ RETERR(mem_tobuffer(ctx->target, &num, 1));
+ if (ctx->length >= 0) {
+ if (ctx->length == 0)
+ return (ISC_R_BADHEX);
+ else
+ ctx->length -= 1;
+ }
+ ctx->digits = 0;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+hex_decode_finish(hex_decode_ctx_t *ctx) {
+ if (ctx->length > 0)
+ return (ISC_R_UNEXPECTEDEND);
+ if (ctx->digits != 0)
+ return (ISC_R_BADHEX);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+ hex_decode_ctx_t ctx;
+ isc_textregion_t *tr;
+ isc_token_t token;
+ isc_boolean_t eol;
+
+ hex_decode_init(&ctx, length, target);
+
+ while (ctx.length != 0) {
+ unsigned int i;
+
+ if (length > 0)
+ eol = ISC_FALSE;
+ else
+ eol = ISC_TRUE;
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string, eol));
+ if (token.type != isc_tokentype_string)
+ break;
+ tr = &token.value.as_textregion;
+ for (i = 0; i < tr->length; i++)
+ RETERR(hex_decode_char(&ctx, tr->base[i]));
+ }
+ if (ctx.length < 0)
+ isc_lex_ungettoken(lexer, &token);
+ RETERR(hex_decode_finish(&ctx));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_hex_decodestring(char *cstr, isc_buffer_t *target) {
+ hex_decode_ctx_t ctx;
+
+ hex_decode_init(&ctx, -1, target);
+ for (;;) {
+ int c = *cstr++;
+ if (c == '\0')
+ break;
+ if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
+ continue;
+ RETERR(hex_decode_char(&ctx, c));
+ }
+ RETERR(hex_decode_finish(&ctx));
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target) {
+ unsigned int l;
+ isc_region_t region;
+
+ isc_buffer_availableregion(target, &region);
+ l = strlen(source);
+
+ if (l > region.length)
+ return (ISC_R_NOSPACE);
+
+ memcpy(region.base, source, l);
+ isc_buffer_add(target, l);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
+ isc_region_t tr;
+
+ isc_buffer_availableregion(target, &tr);
+ if (length > tr.length)
+ return (ISC_R_NOSPACE);
+ memcpy(tr.base, base, length);
+ isc_buffer_add(target, length);
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/hmacmd5.c b/lib/isc/hmacmd5.c
new file mode 100644
index 0000000..f832146
--- /dev/null
+++ b/lib/isc/hmacmd5.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2004-2006 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: hmacmd5.c,v 1.7.18.5 2006/02/26 22:30:56 marka Exp $ */
+
+/*! \file
+ * This code implements the HMAC-MD5 keyed hash algorithm
+ * described in RFC2104.
+ */
+
+#include "config.h"
+
+#include <isc/assertions.h>
+#include <isc/hmacmd5.h>
+#include <isc/md5.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#define PADLEN 64
+#define IPAD 0x36
+#define OPAD 0x5C
+
+/*!
+ * Start HMAC-MD5 process. Initialize an md5 context and digest the key.
+ */
+void
+isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[PADLEN];
+ int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_md5_t md5ctx;
+ isc_md5_init(&md5ctx);
+ isc_md5_update(&md5ctx, key, len);
+ isc_md5_final(&md5ctx, ctx->key);
+ } else
+ memcpy(ctx->key, key, len);
+
+ isc_md5_init(&ctx->md5ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < PADLEN; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_md5_update(&ctx->md5ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
+ isc_md5_invalidate(&ctx->md5ctx);
+ memset(ctx->key, 0, sizeof(ctx->key));
+}
+
+/*!
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_md5_update(&ctx->md5ctx, buf, len);
+}
+
+/*!
+ * Compute signature - finalize MD5 operation and reapply MD5.
+ */
+void
+isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
+ unsigned char opad[PADLEN];
+ int i;
+
+ isc_md5_final(&ctx->md5ctx, digest);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < PADLEN; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_md5_init(&ctx->md5ctx);
+ isc_md5_update(&ctx->md5ctx, opad, sizeof(opad));
+ isc_md5_update(&ctx->md5ctx, digest, ISC_MD5_DIGESTLENGTH);
+ isc_md5_final(&ctx->md5ctx, digest);
+ isc_hmacmd5_invalidate(ctx);
+}
+
+/*!
+ * Verify signature - finalize MD5 operation and reapply MD5, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest) {
+ return (isc_hmacmd5_verify2(ctx, digest, ISC_MD5_DIGESTLENGTH));
+}
+
+isc_boolean_t
+isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_MD5_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_MD5_DIGESTLENGTH);
+ isc_hmacmd5_sign(ctx, newdigest);
+ return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
diff --git a/lib/isc/hmacsha.c b/lib/isc/hmacsha.c
new file mode 100644
index 0000000..7ee13f7
--- /dev/null
+++ b/lib/isc/hmacsha.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2005-2007 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: hmacsha.c,v 1.2.2.7 2007/08/28 07:20:06 tbox Exp $ */
+
+/*
+ * This code implements the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256, HMAC-SHA384
+ * and HMAC-SHA512 keyed hash algorithm described in RFC 2104 and
+ * draft-ietf-dnsext-tsig-sha-01.txt.
+ */
+
+#include "config.h"
+
+#include <isc/assertions.h>
+#include <isc/hmacsha.h>
+#include <isc/sha1.h>
+#include <isc/sha2.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#define IPAD 0x36
+#define OPAD 0x5C
+
+/*
+ * Start HMAC-SHA1 process. Initialize an sha1 context and digest the key.
+ */
+void
+isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[ISC_SHA1_BLOCK_LENGTH];
+ unsigned int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_sha1_t sha1ctx;
+ isc_sha1_init(&sha1ctx);
+ isc_sha1_update(&sha1ctx, key, len);
+ isc_sha1_final(&sha1ctx, ctx->key);
+ } else
+ memcpy(ctx->key, key, len);
+
+ isc_sha1_init(&ctx->sha1ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < ISC_SHA1_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_sha1_update(&ctx->sha1ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) {
+ isc_sha1_invalidate(&ctx->sha1ctx);
+ memset(ctx->key, 0, sizeof(ctx->key));
+ memset(ctx, 0, sizeof(ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_sha1_update(&ctx->sha1ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA1 operation and reapply SHA1.
+ */
+void
+isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char opad[ISC_SHA1_BLOCK_LENGTH];
+ unsigned char newdigest[ISC_SHA1_DIGESTLENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA1_DIGESTLENGTH);
+ isc_sha1_final(&ctx->sha1ctx, newdigest);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < ISC_SHA1_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_sha1_init(&ctx->sha1ctx);
+ isc_sha1_update(&ctx->sha1ctx, opad, sizeof(opad));
+ isc_sha1_update(&ctx->sha1ctx, newdigest, ISC_SHA1_DIGESTLENGTH);
+ isc_sha1_final(&ctx->sha1ctx, newdigest);
+ isc_hmacsha1_invalidate(ctx);
+ memcpy(digest, newdigest, len);
+ memset(newdigest, 0, sizeof(newdigest));
+}
+
+/*
+ * Verify signature - finalize SHA1 operation and reapply SHA1, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA1_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA1_DIGESTLENGTH);
+ isc_hmacsha1_sign(ctx, newdigest, ISC_SHA1_DIGESTLENGTH);
+ return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
+
+/*
+ * Start HMAC-SHA224 process. Initialize an sha224 context and digest the key.
+ */
+void
+isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[ISC_SHA224_BLOCK_LENGTH];
+ unsigned int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_sha224_t sha224ctx;
+ isc_sha224_init(&sha224ctx);
+ isc_sha224_update(&sha224ctx, key, len);
+ isc_sha224_final(ctx->key, &sha224ctx);
+ } else
+ memcpy(ctx->key, key, len);
+
+ isc_sha224_init(&ctx->sha224ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < ISC_SHA224_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_sha224_update(&ctx->sha224ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) {
+ memset(ctx->key, 0, sizeof(ctx->key));
+ memset(ctx, 0, sizeof(ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_sha224_update(&ctx->sha224ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA224 operation and reapply SHA224.
+ */
+void
+isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char opad[ISC_SHA224_BLOCK_LENGTH];
+ unsigned char newdigest[ISC_SHA224_DIGESTLENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA224_DIGESTLENGTH);
+ isc_sha224_final(newdigest, &ctx->sha224ctx);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < ISC_SHA224_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_sha224_init(&ctx->sha224ctx);
+ isc_sha224_update(&ctx->sha224ctx, opad, sizeof(opad));
+ isc_sha224_update(&ctx->sha224ctx, newdigest, ISC_SHA224_DIGESTLENGTH);
+ isc_sha224_final(newdigest, &ctx->sha224ctx);
+ memcpy(digest, newdigest, len);
+ memset(newdigest, 0, sizeof(newdigest));
+}
+
+/*
+ * Verify signature - finalize SHA224 operation and reapply SHA224, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA224_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA224_DIGESTLENGTH);
+ isc_hmacsha224_sign(ctx, newdigest, ISC_SHA224_DIGESTLENGTH);
+ return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
+
+/*
+ * Start HMAC-SHA256 process. Initialize an sha256 context and digest the key.
+ */
+void
+isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[ISC_SHA256_BLOCK_LENGTH];
+ unsigned int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_sha256_t sha256ctx;
+ isc_sha256_init(&sha256ctx);
+ isc_sha256_update(&sha256ctx, key, len);
+ isc_sha256_final(ctx->key, &sha256ctx);
+ } else
+ memcpy(ctx->key, key, len);
+
+ isc_sha256_init(&ctx->sha256ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < ISC_SHA256_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_sha256_update(&ctx->sha256ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) {
+ memset(ctx->key, 0, sizeof(ctx->key));
+ memset(ctx, 0, sizeof(ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_sha256_update(&ctx->sha256ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA256 operation and reapply SHA256.
+ */
+void
+isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char opad[ISC_SHA256_BLOCK_LENGTH];
+ unsigned char newdigest[ISC_SHA256_DIGESTLENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA256_DIGESTLENGTH);
+ isc_sha256_final(newdigest, &ctx->sha256ctx);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < ISC_SHA256_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_sha256_init(&ctx->sha256ctx);
+ isc_sha256_update(&ctx->sha256ctx, opad, sizeof(opad));
+ isc_sha256_update(&ctx->sha256ctx, newdigest, ISC_SHA256_DIGESTLENGTH);
+ isc_sha256_final(newdigest, &ctx->sha256ctx);
+ memcpy(digest, newdigest, len);
+ memset(newdigest, 0, sizeof(newdigest));
+}
+
+/*
+ * Verify signature - finalize SHA256 operation and reapply SHA256, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA256_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA256_DIGESTLENGTH);
+ isc_hmacsha256_sign(ctx, newdigest, ISC_SHA256_DIGESTLENGTH);
+ return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
+
+/*
+ * Start HMAC-SHA384 process. Initialize an sha384 context and digest the key.
+ */
+void
+isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[ISC_SHA384_BLOCK_LENGTH];
+ unsigned int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_sha384_t sha384ctx;
+ isc_sha384_init(&sha384ctx);
+ isc_sha384_update(&sha384ctx, key, len);
+ isc_sha384_final(ctx->key, &sha384ctx);
+ } else
+ memcpy(ctx->key, key, len);
+
+ isc_sha384_init(&ctx->sha384ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < ISC_SHA384_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_sha384_update(&ctx->sha384ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) {
+ memset(ctx->key, 0, sizeof(ctx->key));
+ memset(ctx, 0, sizeof(ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_sha384_update(&ctx->sha384ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA384 operation and reapply SHA384.
+ */
+void
+isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char opad[ISC_SHA384_BLOCK_LENGTH];
+ unsigned char newdigest[ISC_SHA384_DIGESTLENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA384_DIGESTLENGTH);
+ isc_sha384_final(newdigest, &ctx->sha384ctx);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < ISC_SHA384_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_sha384_init(&ctx->sha384ctx);
+ isc_sha384_update(&ctx->sha384ctx, opad, sizeof(opad));
+ isc_sha384_update(&ctx->sha384ctx, newdigest, ISC_SHA384_DIGESTLENGTH);
+ isc_sha384_final(newdigest, &ctx->sha384ctx);
+ memcpy(digest, newdigest, len);
+ memset(newdigest, 0, sizeof(newdigest));
+}
+
+/*
+ * Verify signature - finalize SHA384 operation and reapply SHA384, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA384_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA384_DIGESTLENGTH);
+ isc_hmacsha384_sign(ctx, newdigest, ISC_SHA384_DIGESTLENGTH);
+ return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
+
+/*
+ * Start HMAC-SHA512 process. Initialize an sha512 context and digest the key.
+ */
+void
+isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key,
+ unsigned int len)
+{
+ unsigned char ipad[ISC_SHA512_BLOCK_LENGTH];
+ unsigned int i;
+
+ memset(ctx->key, 0, sizeof(ctx->key));
+ if (len > sizeof(ctx->key)) {
+ isc_sha512_t sha512ctx;
+ isc_sha512_init(&sha512ctx);
+ isc_sha512_update(&sha512ctx, key, len);
+ isc_sha512_final(ctx->key, &sha512ctx);
+ } else
+ memcpy(ctx->key, key, len);
+
+ isc_sha512_init(&ctx->sha512ctx);
+ memset(ipad, IPAD, sizeof(ipad));
+ for (i = 0; i < ISC_SHA512_BLOCK_LENGTH; i++)
+ ipad[i] ^= ctx->key[i];
+ isc_sha512_update(&ctx->sha512ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) {
+ memset(ctx->key, 0, sizeof(ctx->key));
+ memset(ctx, 0, sizeof(ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf,
+ unsigned int len)
+{
+ isc_sha512_update(&ctx->sha512ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA512 operation and reapply SHA512.
+ */
+void
+isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char opad[ISC_SHA512_BLOCK_LENGTH];
+ unsigned char newdigest[ISC_SHA512_DIGESTLENGTH];
+ unsigned int i;
+
+ REQUIRE(len <= ISC_SHA512_DIGESTLENGTH);
+ isc_sha512_final(newdigest, &ctx->sha512ctx);
+
+ memset(opad, OPAD, sizeof(opad));
+ for (i = 0; i < ISC_SHA512_BLOCK_LENGTH; i++)
+ opad[i] ^= ctx->key[i];
+
+ isc_sha512_init(&ctx->sha512ctx);
+ isc_sha512_update(&ctx->sha512ctx, opad, sizeof(opad));
+ isc_sha512_update(&ctx->sha512ctx, newdigest, ISC_SHA512_DIGESTLENGTH);
+ isc_sha512_final(newdigest, &ctx->sha512ctx);
+ memcpy(digest, newdigest, len);
+ memset(newdigest, 0, sizeof(newdigest));
+}
+
+/*
+ * Verify signature - finalize SHA512 operation and reapply SHA512, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacsha512_verify(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) {
+ unsigned char newdigest[ISC_SHA512_DIGESTLENGTH];
+
+ REQUIRE(len <= ISC_SHA512_DIGESTLENGTH);
+ isc_hmacsha512_sign(ctx, newdigest, ISC_SHA512_DIGESTLENGTH);
+ return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
diff --git a/lib/isc/ia64/Makefile.in b/lib/isc/ia64/Makefile.in
new file mode 100644
index 0000000..c8e77e4
--- /dev/null
+++ b/lib/isc/ia64/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/ia64/include/Makefile.in b/lib/isc/ia64/include/Makefile.in
new file mode 100644
index 0000000..f4dd2f6
--- /dev/null
+++ b/lib/isc/ia64/include/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/ia64/include/isc/Makefile.in b/lib/isc/ia64/include/isc/Makefile.in
new file mode 100644
index 0000000..6760ce6
--- /dev/null
+++ b/lib/isc/ia64/include/isc/Makefile.in
@@ -0,0 +1,36 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc ; \
+ done
diff --git a/lib/isc/ia64/include/isc/atomic.h b/lib/isc/ia64/include/isc/atomic.h
new file mode 100644
index 0000000..20cbabd
--- /dev/null
+++ b/lib/isc/ia64/include/isc/atomic.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.2.2.1 2006/06/21 03:38:32 marka Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ *
+ * Open issue: can 'fetchadd' make the code faster for some particular values
+ * (e.g., 1 and -1)?
+ */
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+ isc_int32_t prev, swapped;
+
+ for (prev = *(volatile isc_int32_t *)p; ; prev = swapped) {
+ swapped = prev + val;
+ __asm__ volatile(
+ "mov ar.ccv=%2;"
+ "cmpxchg4.acq %0=%4,%3,ar.ccv"
+ : "=r" (swapped), "=m" (*p)
+ : "r" (prev), "r" (swapped), "m" (*p)
+ : "memory");
+ if (swapped == prev)
+ break;
+ }
+
+ return (prev);
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+ __asm__ volatile(
+ "st4.rel %0=%1"
+ : "=m" (*p)
+ : "r" (val)
+ : "memory"
+ );
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+ isc_int32_t ret;
+
+ __asm__ volatile(
+ "mov ar.ccv=%2;"
+ "cmpxchg4.acq %0=%4,%3,ar.ccv"
+ : "=r" (ret), "=m" (*p)
+ : "r" (cmpval), "r" (val), "m" (*p)
+ : "memory");
+
+ return (ret);
+}
+#else /* !ISC_PLATFORM_USEGCCASM */
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/include/Makefile.in b/lib/isc/include/Makefile.in
new file mode 100644
index 0000000..ceb8eb6
--- /dev/null
+++ b/lib/isc/include/Makefile.in
@@ -0,0 +1,25 @@
+# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-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: Makefile.in,v 1.11 2004/03/05 05:10:53 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/include/isc/Makefile.in b/lib/isc/include/isc/Makefile.in
new file mode 100644
index 0000000..0f0e936
--- /dev/null
+++ b/lib/isc/include/isc/Makefile.in
@@ -0,0 +1,57 @@
+# Copyright (C) 2004-2006 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.54.18.4 2006/01/27 23:57:45 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+#
+# Only list headers that are to be installed and are not
+# machine generated. The latter are handled specially in the
+# install target below.
+#
+HEADERS = app.h assertions.h base64.h bitstring.h boolean.h buffer.h \
+ bufferlist.h commandline.h entropy.h error.h event.h \
+ eventclass.h file.h formatcheck.h fsaccess.h \
+ hash.h heap.h hex.h hmacmd5.h \
+ interfaceiter.h @ISC_IPV6_H@ lang.h lex.h \
+ lfsr.h lib.h list.h log.h magic.h md5.h mem.h msgcat.h msgs.h \
+ mutexblock.h netaddr.h ondestroy.h os.h parseint.h \
+ print.h quota.h random.h ratelimiter.h \
+ refcount.h region.h resource.h \
+ result.h resultclass.h rwlock.h serial.h sha1.h sha2.h \
+ sockaddr.h socket.h stdio.h stdlib.h string.h symtab.h \
+ task.h taskpool.h timer.h types.h util.h version.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/isc ; \
+ done
+ ${INSTALL_DATA} platform.h ${DESTDIR}${includedir}/isc
+
+distclean::
+ rm -f platform.h
diff --git a/lib/isc/include/isc/app.h b/lib/isc/include/isc/app.h
new file mode 100644
index 0000000..f51aff7
--- /dev/null
+++ b/lib/isc/include/isc/app.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2004, 2005 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: app.h,v 1.2.18.2 2005/04/29 00:16:52 marka Exp $ */
+
+#ifndef ISC_APP_H
+#define ISC_APP_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief ISC Application Support
+ *
+ * Dealing with program termination can be difficult, especially in a
+ * multithreaded program. The routines in this module help coordinate
+ * the shutdown process. They are used as follows by the initial (main)
+ * thread of the application:
+ *
+ *\li isc_app_start(); Call very early in main(), before
+ * any other threads have been created.
+ *
+ *\li isc_app_run(); This will post any on-run events,
+ * and then block until application
+ * shutdown is requested. A shutdown
+ * request is made by calling
+ * isc_app_shutdown(), or by sending
+ * SIGINT or SIGTERM to the process.
+ * After isc_app_run() returns, the
+ * application should shutdown itself.
+ *
+ *\li isc_app_finish(); Call very late in main().
+ *
+ * Applications that want to use SIGHUP/isc_app_reload() to trigger reloading
+ * should check the result of isc_app_run() and call the reload routine if
+ * the result is ISC_R_RELOAD. They should then call isc_app_run() again
+ * to resume waiting for reload or termination.
+ *
+ * Use of this module is not required. In particular, isc_app_start() is
+ * NOT an ISC library initialization routine.
+ *
+ * \li MP:
+ * Clients must ensure that isc_app_start(), isc_app_run(), and
+ * isc_app_finish() are called at most once. isc_app_shutdown()
+ * is safe to use by any thread (provided isc_app_start() has been
+ * called previously).
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * None.
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+#include <isc/eventclass.h>
+#include <isc/lang.h>
+#include <isc/result.h>
+
+typedef isc_event_t isc_appevent_t;
+
+#define ISC_APPEVENT_FIRSTEVENT (ISC_EVENTCLASS_APP + 0)
+#define ISC_APPEVENT_SHUTDOWN (ISC_EVENTCLASS_APP + 1)
+#define ISC_APPEVENT_LASTEVENT (ISC_EVENTCLASS_APP + 65535)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_app_start(void);
+/*!<
+ * \brief Start an ISC library application.
+ *
+ * Notes:
+ * This call should be made before any other ISC library call, and as
+ * close to the beginning of the application as possible.
+ */
+
+isc_result_t
+isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
+ void *arg);
+/*!<
+ * \brief Request delivery of an event when the application is run.
+ *
+ * Requires:
+ * isc_app_start() has been called.
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_NOMEMORY
+ */
+
+isc_result_t
+isc_app_run(void);
+/*!<
+ * \brief Run an ISC library application.
+ *
+ * Notes:
+ *\li The caller (typically the initial thread of an application) will
+ * block until shutdown is requested. When the call returns, the
+ * caller should start shutting down the application.
+ *
+ * Requires:
+ *\li isc_app_start() has been called.
+ *
+ * Ensures:
+ *\li Any events requested via isc_app_onrun() will have been posted (in
+ * FIFO order) before isc_app_run() blocks.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS Shutdown has been requested.
+ *\li ISC_R_RELOAD Reload has been requested.
+ */
+
+isc_result_t
+isc_app_shutdown(void);
+/*!<
+ * \brief Request application shutdown.
+ *
+ * Notes:
+ *\li It is safe to call isc_app_shutdown() multiple times. Shutdown will
+ * only be triggered once.
+ *
+ * Requires:
+ *\li isc_app_run() has been called.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_app_reload(void);
+/*!<
+ * \brief Request application reload.
+ *
+ * Requires:
+ *\li isc_app_run() has been called.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_UNEXPECTED
+ */
+
+void
+isc_app_finish(void);
+/*!<
+ * \brief Finish an ISC library application.
+ *
+ * Notes:
+ *\li This call should be made at or near the end of main().
+ *
+ * Requires:
+ *\li isc_app_start() has been called.
+ *
+ * Ensures:
+ *\li Any resources allocated by isc_app_start() have been released.
+ */
+
+void
+isc_app_block(void);
+/*!<
+ * \brief Indicate that a blocking operation will be performed.
+ *
+ * Notes:
+ *\li If a blocking operation is in process, a call to isc_app_shutdown()
+ * or an external signal will abort the program, rather than allowing
+ * clean shutdown. This is primarily useful for reading user input.
+ *
+ * Requires:
+ * \li isc_app_start() has been called.
+ * \li No other blocking operations are in progress.
+ */
+
+void
+isc_app_unblock(void);
+/*!<
+ * \brief Indicate that a blocking operation is complete.
+ *
+ * Notes:
+ * \li When a blocking operation has completed, return the program to a
+ * state where a call to isc_app_shutdown() or an external signal will
+ * shutdown normally.
+ *
+ * Requires:
+ * \li isc_app_start() has been called.
+ * \li isc_app_block() has been called by the same thread.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_APP_H */
diff --git a/lib/isc/include/isc/assertions.h b/lib/isc/include/isc/assertions.h
new file mode 100644
index 0000000..c1e68a1
--- /dev/null
+++ b/lib/isc/include/isc/assertions.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-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: assertions.h,v 1.18.18.2 2005/04/29 00:16:52 marka Exp $
+ */
+/*! \file assertions.h
+ */
+
+#ifndef ISC_ASSERTIONS_H
+#define ISC_ASSERTIONS_H 1
+
+#include <isc/lang.h>
+#include <isc/platform.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% isc assertion type */
+typedef enum {
+ isc_assertiontype_require,
+ isc_assertiontype_ensure,
+ isc_assertiontype_insist,
+ isc_assertiontype_invariant
+} isc_assertiontype_t;
+
+typedef void (*isc_assertioncallback_t)(const char *, int, isc_assertiontype_t,
+ const char *);
+
+LIBISC_EXTERNAL_DATA extern isc_assertioncallback_t isc_assertion_failed;
+
+void
+isc_assertion_setcallback(isc_assertioncallback_t);
+
+const char *
+isc_assertion_typetotext(isc_assertiontype_t type);
+
+#ifdef ISC_CHECK_ALL
+#define ISC_CHECK_REQUIRE 1
+#define ISC_CHECK_ENSURE 1
+#define ISC_CHECK_INSIST 1
+#define ISC_CHECK_INVARIANT 1
+#endif
+
+#ifdef ISC_CHECK_NONE
+#define ISC_CHECK_REQUIRE 0
+#define ISC_CHECK_ENSURE 0
+#define ISC_CHECK_INSIST 0
+#define ISC_CHECK_INVARIANT 0
+#endif
+
+#ifndef ISC_CHECK_REQUIRE
+#define ISC_CHECK_REQUIRE 1
+#endif
+
+#ifndef ISC_CHECK_ENSURE
+#define ISC_CHECK_ENSURE 1
+#endif
+
+#ifndef ISC_CHECK_INSIST
+#define ISC_CHECK_INSIST 1
+#endif
+
+#ifndef ISC_CHECK_INVARIANT
+#define ISC_CHECK_INVARIANT 1
+#endif
+
+#if ISC_CHECK_REQUIRE != 0
+#define ISC_REQUIRE(cond) \
+ ((void) ((cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_require, \
+ #cond), 0)))
+#else
+#define ISC_REQUIRE(cond) ((void) 0)
+#endif /* ISC_CHECK_REQUIRE */
+
+#if ISC_CHECK_ENSURE != 0
+#define ISC_ENSURE(cond) \
+ ((void) ((cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_ensure, \
+ #cond), 0)))
+#else
+#define ISC_ENSURE(cond) ((void) 0)
+#endif /* ISC_CHECK_ENSURE */
+
+#if ISC_CHECK_INSIST != 0
+#define ISC_INSIST(cond) \
+ ((void) ((cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_insist, \
+ #cond), 0)))
+#else
+#define ISC_INSIST(cond) ((void) 0)
+#endif /* ISC_CHECK_INSIST */
+
+#if ISC_CHECK_INVARIANT != 0
+#define ISC_INVARIANT(cond) \
+ ((void) ((cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_invariant, \
+ #cond), 0)))
+#else
+#define ISC_INVARIANT(cond) ((void) 0)
+#endif /* ISC_CHECK_INVARIANT */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ASSERTIONS_H */
diff --git a/lib/isc/include/isc/base64.h b/lib/isc/include/isc/base64.h
new file mode 100644
index 0000000..26ffa48
--- /dev/null
+++ b/lib/isc/include/isc/base64.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2004, 2005 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: base64.h,v 1.16.18.2 2005/04/29 00:16:53 marka Exp $ */
+
+#ifndef ISC_BASE64_H
+#define ISC_BASE64_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_base64_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
+/*!<
+ * \brief Convert data into base64 encoded text.
+ *
+ * Notes:
+ *\li The base64 encoded text in 'target' will be divided into
+ * words of at most 'wordlength' characters, separated by
+ * the 'wordbreak' string. No parentheses will surround
+ * the text.
+ *
+ * Requires:
+ *\li 'source' is a region containing binary data
+ *\li 'target' is a text buffer containing available space
+ *\li 'wordbreak' points to a null-terminated string of
+ * zero or more whitespace characters
+ *
+ * Ensures:
+ *\li target will contain the base64 encoded version of the data
+ * in source. The 'used' pointer in target will be advanced as
+ * necessary.
+ */
+
+isc_result_t
+isc_base64_decodestring(const char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated base64 string.
+ *
+ * Requires:
+ *\li 'cstr' is non-null.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADBASE64 -- 'cstr' is not a valid base64 encoding.
+ *
+ * Other error returns are any possible error code from:
+ *\li isc_lex_create(),
+ *\li isc_lex_openbuffer(),
+ *\li isc_base64_tobuffer().
+ */
+
+isc_result_t
+isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert base64 encoded text from a lexer context into data.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer context
+ *\li 'target' is a buffer containing binary data
+ *\li 'length' is an integer
+ *
+ * Ensures:
+ *\li target will contain the data represented by the base64 encoded
+ * string parsed by the lexer. No more than length bytes will be read,
+ * if length is positive. The 'used' pointer in target will be
+ * advanced as necessary.
+ */
+
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BASE64_H */
diff --git a/lib/isc/include/isc/bitstring.h b/lib/isc/include/isc/bitstring.h
new file mode 100644
index 0000000..3e626b8
--- /dev/null
+++ b/lib/isc/include/isc/bitstring.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2004, 2005 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: bitstring.h,v 1.8.18.2 2005/04/29 00:16:53 marka Exp $ */
+
+#ifndef ISC_BITSTRING_H
+#define ISC_BITSTRING_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file bitstring.h
+ *
+ * \brief Bitstring manipulation functions.
+ *
+ * A bitstring is a packed array of bits, stored in a contiguous
+ * sequence of octets. The "most significant bit" (msb) of a bitstring
+ * is the high bit of the first octet. The "least significant bit" of a
+ * bitstring is the low bit of the last octet.
+ *
+ * Two bit numbering schemes are supported, "msb0" and "lsb0".
+ *
+ * In the "msb0" scheme, bit number 0 designates the most significant bit,
+ * and any padding bits required to make the bitstring a multiple of 8 bits
+ * long are added to the least significant end of the last octet.
+ *
+ * In the "lsb0" scheme, bit number 0 designates the least significant bit,
+ * and any padding bits required to make the bitstring a multiple of 8 bits
+ * long are added to the most significant end of the first octet.
+ *
+ * E.g., consider the bitstring "11010001111". This bitstring is 11 bits
+ * long and will take two octets. Let "p" denote a pad bit. In the msb0
+ * encoding, it would be
+ *
+ * \verbatim
+ * Octet 0 Octet 1
+ * |
+ * 1 1 0 1 0 0 0 1 | 1 1 1 p p p p p
+ * ^ | ^
+ * | |
+ * bit 0 bit 15
+ * \endverbatim
+ *
+ * In the lsb0 encoding, it would be
+ *
+ * \verbatim
+ * Octet 0 Octet 1
+ * |
+ * p p p p p 1 1 0 | 1 0 0 0 1 1 1 1
+ * ^ | ^
+ * | |
+ * bit 15 bit 0
+ * \endverbatim
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+struct isc_bitstring {
+ unsigned int magic;
+ unsigned char * data;
+ unsigned int length;
+ unsigned int size;
+ isc_boolean_t lsb0;
+};
+
+/***
+ *** Functions
+ ***/
+
+void
+isc_bitstring_init(isc_bitstring_t *bitstring, unsigned char *data,
+ unsigned int length, unsigned int size, isc_boolean_t lsb0);
+/*!<
+ * \brief Make 'bitstring' refer to the bitstring of 'size' bits starting
+ * at 'data'. 'length' bits of the bitstring are valid. If 'lsb0'
+ * is set then, bit 0 refers to the least significant bit of the
+ * bitstring. Otherwise bit 0 is the most significant bit.
+ *
+ * Requires:
+ *
+ *\li 'bitstring' points to a isc_bitstring_t.
+ *
+ *\li 'data' points to an array of unsigned char large enough to hold
+ * 'size' bits.
+ *
+ *\li 'length' <= 'size'.
+ *
+ * Ensures:
+ *
+ *\li 'bitstring' is a valid bitstring.
+ */
+
+void
+isc_bitstring_invalidate(isc_bitstring_t *bitstring);
+/*!<
+ * \brief Invalidate 'bitstring'.
+ *
+ * Requires:
+ *
+ *\li 'bitstring' is a valid bitstring.
+ *
+ * Ensures:
+ *
+ *\li 'bitstring' is not a valid bitstring.
+ */
+
+void
+isc_bitstring_copy(isc_bitstring_t *source, unsigned int sbitpos,
+ isc_bitstring_t *target, unsigned int tbitpos,
+ unsigned int n);
+/*!<
+ * \brief Starting at bit 'sbitpos', copy 'n' bits from 'source' to
+ * the 'n' bits of 'target' starting at 'tbitpos'.
+ *
+ * Requires:
+ *
+ *\li 'source' and target are valid bitstrings with the same lsb0 setting.
+ *
+ *\li 'sbitpos' + 'n' is less than or equal to the length of 'source'.
+ *
+ *\li 'tbitpos' + 'n' is less than or equal to the size of 'target'.
+ *
+ * Ensures:
+ *
+ *\li The specified bits have been copied, and the length of 'target'
+ * adjusted (if required).
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BITSTRING_H */
diff --git a/lib/isc/include/isc/boolean.h b/lib/isc/include/isc/boolean.h
new file mode 100644
index 0000000..ad736fe
--- /dev/null
+++ b/lib/isc/include/isc/boolean.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: boolean.h,v 1.13.18.2 2005/04/29 00:16:53 marka Exp $ */
+
+#ifndef ISC_BOOLEAN_H
+#define ISC_BOOLEAN_H 1
+
+/*! \file */
+
+typedef enum { isc_boolean_false = 0, isc_boolean_true = 1 } isc_boolean_t;
+
+#define ISC_FALSE isc_boolean_false
+#define ISC_TRUE isc_boolean_true
+#define ISC_TF(x) ((x) ? ISC_TRUE : ISC_FALSE)
+
+#endif /* ISC_BOOLEAN_H */
diff --git a/lib/isc/include/isc/buffer.h b/lib/isc/include/isc/buffer.h
new file mode 100644
index 0000000..a285e27
--- /dev/null
+++ b/lib/isc/include/isc/buffer.h
@@ -0,0 +1,811 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: buffer.h,v 1.43.18.2 2005/04/29 00:16:53 marka Exp $ */
+
+#ifndef ISC_BUFFER_H
+#define ISC_BUFFER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file buffer.h
+ *
+ * \brief A buffer is a region of memory, together with a set of related subregions.
+ * Buffers are used for parsing and I/O operations.
+ *
+ * The 'used region' and the 'available' region are disjoint, and their
+ * union is the buffer's region. The used region extends from the beginning
+ * of the buffer region to the last used byte. The available region
+ * extends from one byte greater than the last used byte to the end of the
+ * buffer's region. The size of the used region can be changed using various
+ * buffer commands. Initially, the used region is empty.
+ *
+ * The used region is further subdivided into two disjoint regions: the
+ * 'consumed region' and the 'remaining region'. The union of these two
+ * regions is the used region. The consumed region extends from the beginning
+ * of the used region to the byte before the 'current' offset (if any). The
+ * 'remaining' region the current pointer to the end of the used
+ * region. The size of the consumed region can be changed using various
+ * buffer commands. Initially, the consumed region is empty.
+ *
+ * The 'active region' is an (optional) subregion of the remaining region.
+ * It extends from the current offset to an offset in the remaining region
+ * that is selected with isc_buffer_setactive(). Initially, the active region
+ * is empty. If the current offset advances beyond the chosen offset, the
+ * active region will also be empty.
+ *
+ * \verbatim
+ * /------------entire length---------------\
+ * /----- used region -----\/-- available --\
+ * +----------------------------------------+
+ * | consumed | remaining | |
+ * +----------------------------------------+
+ * a b c d e
+ *
+ * a == base of buffer.
+ * b == current pointer. Can be anywhere between a and d.
+ * c == active pointer. Meaningful between b and d.
+ * d == used pointer.
+ * e == length of buffer.
+ *
+ * a-e == entire length of buffer.
+ * a-d == used region.
+ * a-b == consumed region.
+ * b-d == remaining region.
+ * b-c == optional active region.
+ *\endverbatim
+ *
+ * The following invariants are maintained by all routines:
+ *
+ *\code
+ * length > 0
+ *
+ * base is a valid pointer to length bytes of memory
+ *
+ * 0 <= used <= length
+ *
+ * 0 <= current <= used
+ *
+ * 0 <= active <= used
+ * (although active < current implies empty active region)
+ *\endcode
+ *
+ * \li MP:
+ * Buffers have no synchronization. Clients must ensure exclusive
+ * access.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * Memory: 1 pointer + 6 unsigned integers per buffer.
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/types.h>
+
+/*!
+ * To make many functions be inline macros (via #define) define this.
+ * If it is undefined, a function will be used.
+ */
+/* #define ISC_BUFFER_USEINLINE */
+
+ISC_LANG_BEGINDECLS
+
+/*@{*/
+/*!
+ *** Magic numbers
+ ***/
+#define ISC_BUFFER_MAGIC 0x42756621U /* Buf!. */
+#define ISC_BUFFER_VALID(b) ISC_MAGIC_VALID(b, ISC_BUFFER_MAGIC)
+/*@}*/
+
+/*
+ * The following macros MUST be used only on valid buffers. It is the
+ * caller's responsibility to ensure this by using the ISC_BUFFER_VALID
+ * check above, or by calling another isc_buffer_*() function (rather than
+ * another macro.)
+ */
+
+/*@{*/
+/*!
+ * Fundamental buffer elements. (A through E in the introductory comment.)
+ */
+#define isc_buffer_base(b) ((void *)(b)->base) /*a*/
+#define isc_buffer_current(b) \
+ ((void *)((unsigned char *)(b)->base + (b)->current)) /*b*/
+#define isc_buffer_active(b) \
+ ((void *)((unsigned char *)(b)->base + (b)->active)) /*c*/
+#define isc_buffer_used(b) \
+ ((void *)((unsigned char *)(b)->base + (b)->used)) /*d*/
+#define isc_buffer_length(b) ((b)->length) /*e*/
+/*@}*/
+
+/*@{*/
+/*!
+ * Derived lengths. (Described in the introductory comment.)
+ */
+#define isc_buffer_usedlength(b) ((b)->used) /* d-a */
+#define isc_buffer_consumedlength(b) ((b)->current) /* b-a */
+#define isc_buffer_remaininglength(b) ((b)->used - (b)->current) /* d-b */
+#define isc_buffer_activelength(b) ((b)->active - (b)->current) /* c-b */
+#define isc_buffer_availablelength(b) ((b)->length - (b)->used) /* e-d */
+/*@}*/
+
+/*!
+ * Note that the buffer structure is public. This is principally so buffer
+ * operations can be implemented using macros. Applications are strongly
+ * discouraged from directly manipulating the structure.
+ */
+
+struct isc_buffer {
+ unsigned int magic;
+ void *base;
+ /*@{*/
+ /*! The following integers are byte offsets from 'base'. */
+ unsigned int length;
+ unsigned int used;
+ unsigned int current;
+ unsigned int active;
+ /*@}*/
+ /*! linkable */
+ ISC_LINK(isc_buffer_t) link;
+ /*! private internal elements */
+ isc_mem_t *mctx;
+};
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
+ unsigned int length);
+/*!<
+ * \brief Allocate a dynamic linkable buffer which has "length" bytes in the
+ * data region.
+ *
+ * Requires:
+ *\li "mctx" is valid.
+ *
+ *\li "dynbuffer" is non-NULL, and "*dynbuffer" is NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS - success
+ *\li ISC_R_NOMEMORY - no memory available
+ *
+ * Note:
+ *\li Changing the buffer's length field is not permitted.
+ */
+
+void
+isc_buffer_free(isc_buffer_t **dynbuffer);
+/*!<
+ * \brief Release resources allocated for a dynamic buffer.
+ *
+ * Requires:
+ *\li "dynbuffer" is not NULL.
+ *
+ *\li "*dynbuffer" is a valid dynamic buffer.
+ *
+ * Ensures:
+ *\li "*dynbuffer" will be NULL on return, and all memory associated with
+ * the dynamic buffer is returned to the memory context used in
+ * isc_buffer_allocate().
+ */
+
+void
+isc__buffer_init(isc_buffer_t *b, const void *base, unsigned int length);
+/*!<
+ * \brief Make 'b' refer to the 'length'-byte region starting at base.
+ *
+ * Requires:
+ *
+ *\li 'length' > 0
+ *
+ *\li 'base' is a pointer to a sequence of 'length' bytes.
+ *
+ */
+
+void
+isc__buffer_invalidate(isc_buffer_t *b);
+/*!<
+ * \brief Make 'b' an invalid buffer.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ * Ensures:
+ *\li If assertion checking is enabled, future attempts to use 'b' without
+ * calling isc_buffer_init() on it will cause an assertion failure.
+ */
+
+void
+isc__buffer_region(isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the used region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the available region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_add(isc_buffer_t *b, unsigned int n);
+/*!<
+ * \brief Increase the 'used' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li used + n <= length
+ *
+ */
+
+void
+isc__buffer_subtract(isc_buffer_t *b, unsigned int n);
+/*!<
+ * \brief Decrease the 'used' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li used >= n
+ *
+ */
+
+void
+isc__buffer_clear(isc_buffer_t *b);
+/*!<
+ * \brief Make the used region empty.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ *\li used = 0
+ *
+ */
+
+void
+isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the consumed region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the remaining region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r);
+/*!<
+ * \brief Make 'r' refer to the active region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+
+void
+isc__buffer_setactive(isc_buffer_t *b, unsigned int n);
+/*!<
+ * \brief Sets the end of the active region 'n' bytes after current.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li current + n <= used
+ */
+
+void
+isc__buffer_first(isc_buffer_t *b);
+/*!<
+ * \brief Make the consumed region empty.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ *\li current == 0
+ *
+ */
+
+void
+isc__buffer_forward(isc_buffer_t *b, unsigned int n);
+/*!<
+ * \brief Increase the 'consumed' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li current + n <= used
+ *
+ */
+
+void
+isc__buffer_back(isc_buffer_t *b, unsigned int n);
+/*!<
+ * \brief Decrease the 'consumed' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li n <= current
+ *
+ */
+
+void
+isc_buffer_compact(isc_buffer_t *b);
+/*!<
+ * \brief Compact the used region by moving the remaining region so it occurs
+ * at the start of the buffer. The used region is shrunk by the size of
+ * the consumed region, and the consumed region is then made empty.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ *\li current == 0
+ *
+ *\li The size of the used region is now equal to the size of the remaining
+ * region (as it was before the call). The contents of the used region
+ * are those of the remaining region (as it was before the call).
+ */
+
+isc_uint8_t
+isc_buffer_getuint8(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 8-bit integer from 'b' and return it.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 1.
+ *
+ * Ensures:
+ *
+ *\li The current pointer in 'b' is advanced by 1.
+ *
+ * Returns:
+ *
+ *\li A 8-bit unsigned integer.
+ */
+
+void
+isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val);
+/*!<
+ * \brief Store an unsigned 8-bit integer from 'val' into 'b'.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the unused region of 'b' is at least 1.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 1.
+ */
+
+isc_uint16_t
+isc_buffer_getuint16(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 16-bit integer in network byte order from 'b', convert
+ * it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 2.
+ *
+ * Ensures:
+ *
+ *\li The current pointer in 'b' is advanced by 2.
+ *
+ * Returns:
+ *
+ *\li A 16-bit unsigned integer.
+ */
+
+void
+isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val);
+/*!<
+ * \brief Store an unsigned 16-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the unused region of 'b' is at least 2.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 2.
+ */
+
+isc_uint32_t
+isc_buffer_getuint32(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 32-bit integer in network byte order from 'b', convert
+ * it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 4.
+ *
+ * Ensures:
+ *
+ *\li The current pointer in 'b' is advanced by 4.
+ *
+ * Returns:
+ *
+ *\li A 32-bit unsigned integer.
+ */
+
+void
+isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val);
+/*!<
+ * \brief Store an unsigned 32-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the unused region of 'b' is at least 4.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 4.
+ */
+
+void
+isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
+ unsigned int length);
+/*!<
+ * \brief Copy 'length' bytes of memory at 'base' into 'b'.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'base' points to 'length' bytes of valid memory.
+ *
+ */
+
+void
+isc__buffer_putstr(isc_buffer_t *b, const char *source);
+/*!<
+ * \brief Copy 'source' into 'b', not including terminating NUL.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'source' to be a valid NULL terminated string.
+ *
+ *\li strlen(source) <= isc_buffer_available(b)
+ */
+
+isc_result_t
+isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r);
+/*!<
+ * \brief Copy the contents of 'r' into 'b'.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' is a valid region.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOSPACE The available region of 'b' is not
+ * big enough.
+ */
+
+ISC_LANG_ENDDECLS
+
+/*
+ * Inline macro versions of the functions. These should never be called
+ * directly by an application, but will be used by the functions within
+ * buffer.c. The callers should always use "isc_buffer_*()" names, never
+ * ones beginning with "isc__"
+ */
+
+/*! \note
+ * XXXDCL Something more could be done with initializing buffers that
+ * point to const data. For example, a new function, isc_buffer_initconst,
+ * could be used, and a new boolean flag in the buffer structure could
+ * indicate whether the buffer was initialized with that function.
+ * (isc_bufer_init itself would be reprototyped to *not* have its "base"
+ * parameter be const.) Then if the boolean were true, the isc_buffer_put*
+ * functions could assert a contractual requirement for a non-const buffer.
+ * One drawback is that the isc_buffer_* functions (macros) that return
+ * pointers would still need to return non-const pointers to avoid compiler
+ * warnings, so it would be up to code that uses them to have to deal
+ * with the possibility that the buffer was initialized as const --
+ * a problem that they *already* have to deal with but have absolutely
+ * no ability to. With a new isc_buffer_isconst() function returning
+ * true/false, they could at least assert a contractual requirement for
+ * non-const buffers when needed.
+ */
+#define ISC__BUFFER_INIT(_b, _base, _length) \
+ do { \
+ union { \
+ const void * konst; \
+ void * var; \
+ } _u; \
+ _u.konst = (_base); \
+ (_b)->base = _u.var; \
+ (_b)->length = (_length); \
+ (_b)->used = 0; \
+ (_b)->current = 0; \
+ (_b)->active = 0; \
+ (_b)->mctx = NULL; \
+ ISC_LINK_INIT(_b, link); \
+ (_b)->magic = ISC_BUFFER_MAGIC; \
+ } while (0)
+
+#define ISC__BUFFER_INVALIDATE(_b) \
+ do { \
+ (_b)->magic = 0; \
+ (_b)->base = NULL; \
+ (_b)->length = 0; \
+ (_b)->used = 0; \
+ (_b)->current = 0; \
+ (_b)->active = 0; \
+ } while (0)
+
+#define ISC__BUFFER_REGION(_b, _r) \
+ do { \
+ (_r)->base = (_b)->base; \
+ (_r)->length = (_b)->length; \
+ } while (0)
+
+#define ISC__BUFFER_USEDREGION(_b, _r) \
+ do { \
+ (_r)->base = (_b)->base; \
+ (_r)->length = (_b)->used; \
+ } while (0)
+
+#define ISC__BUFFER_AVAILABLEREGION(_b, _r) \
+ do { \
+ (_r)->base = isc_buffer_used(_b); \
+ (_r)->length = isc_buffer_availablelength(_b); \
+ } while (0)
+
+#define ISC__BUFFER_ADD(_b, _n) \
+ do { \
+ (_b)->used += (_n); \
+ } while (0)
+
+#define ISC__BUFFER_SUBTRACT(_b, _n) \
+ do { \
+ (_b)->used -= (_n); \
+ if ((_b)->current > (_b)->used) \
+ (_b)->current = (_b)->used; \
+ if ((_b)->active > (_b)->used) \
+ (_b)->active = (_b)->used; \
+ } while (0)
+
+#define ISC__BUFFER_CLEAR(_b) \
+ do { \
+ (_b)->used = 0; \
+ (_b)->current = 0; \
+ (_b)->active = 0; \
+ } while (0)
+
+#define ISC__BUFFER_CONSUMEDREGION(_b, _r) \
+ do { \
+ (_r)->base = (_b)->base; \
+ (_r)->length = (_b)->current; \
+ } while (0)
+
+#define ISC__BUFFER_REMAININGREGION(_b, _r) \
+ do { \
+ (_r)->base = isc_buffer_current(_b); \
+ (_r)->length = isc_buffer_remaininglength(_b); \
+ } while (0)
+
+#define ISC__BUFFER_ACTIVEREGION(_b, _r) \
+ do { \
+ if ((_b)->current < (_b)->active) { \
+ (_r)->base = isc_buffer_current(_b); \
+ (_r)->length = isc_buffer_activelength(_b); \
+ } else { \
+ (_r)->base = NULL; \
+ (_r)->length = 0; \
+ } \
+ } while (0)
+
+#define ISC__BUFFER_SETACTIVE(_b, _n) \
+ do { \
+ (_b)->active = (_b)->current + (_n); \
+ } while (0)
+
+#define ISC__BUFFER_FIRST(_b) \
+ do { \
+ (_b)->current = 0; \
+ } while (0)
+
+#define ISC__BUFFER_FORWARD(_b, _n) \
+ do { \
+ (_b)->current += (_n); \
+ } while (0)
+
+#define ISC__BUFFER_BACK(_b, _n) \
+ do { \
+ (_b)->current -= (_n); \
+ } while (0)
+
+#define ISC__BUFFER_PUTMEM(_b, _base, _length) \
+ do { \
+ memcpy(isc_buffer_used(_b), (_base), (_length)); \
+ (_b)->used += (_length); \
+ } while (0)
+
+#define ISC__BUFFER_PUTSTR(_b, _source) \
+ do { \
+ unsigned int _length; \
+ unsigned char *_cp; \
+ _length = strlen(_source); \
+ _cp = isc_buffer_used(_b); \
+ memcpy(_cp, (_source), _length); \
+ (_b)->used += (_length); \
+ } while (0)
+
+#define ISC__BUFFER_PUTUINT8(_b, _val) \
+ do { \
+ unsigned char *_cp; \
+ isc_uint8_t _val2 = (_val); \
+ _cp = isc_buffer_used(_b); \
+ (_b)->used++; \
+ _cp[0] = _val2 & 0x00ff; \
+ } while (0)
+
+#define ISC__BUFFER_PUTUINT16(_b, _val) \
+ do { \
+ unsigned char *_cp; \
+ isc_uint16_t _val2 = (_val); \
+ _cp = isc_buffer_used(_b); \
+ (_b)->used += 2; \
+ _cp[0] = (unsigned char)((_val2 & 0xff00U) >> 8); \
+ _cp[1] = (unsigned char)(_val2 & 0x00ffU); \
+ } while (0)
+
+#define ISC__BUFFER_PUTUINT32(_b, _val) \
+ do { \
+ unsigned char *_cp; \
+ isc_uint32_t _val2 = (_val); \
+ _cp = isc_buffer_used(_b); \
+ (_b)->used += 4; \
+ _cp[0] = (unsigned char)((_val2 & 0xff000000) >> 24); \
+ _cp[1] = (unsigned char)((_val2 & 0x00ff0000) >> 16); \
+ _cp[2] = (unsigned char)((_val2 & 0x0000ff00) >> 8); \
+ _cp[3] = (unsigned char)((_val2 & 0x000000ff)); \
+ } while (0)
+
+#if defined(ISC_BUFFER_USEINLINE)
+#define isc_buffer_init ISC__BUFFER_INIT
+#define isc_buffer_invalidate ISC__BUFFER_INVALIDATE
+#define isc_buffer_region ISC__BUFFER_REGION
+#define isc_buffer_usedregion ISC__BUFFER_USEDREGION
+#define isc_buffer_availableregion ISC__BUFFER_AVAILABLEREGION
+#define isc_buffer_add ISC__BUFFER_ADD
+#define isc_buffer_subtract ISC__BUFFER_SUBTRACT
+#define isc_buffer_clear ISC__BUFFER_CLEAR
+#define isc_buffer_consumedregion ISC__BUFFER_CONSUMEDREGION
+#define isc_buffer_remainingregion ISC__BUFFER_REMAININGREGION
+#define isc_buffer_activeregion ISC__BUFFER_ACTIVEREGION
+#define isc_buffer_setactive ISC__BUFFER_SETACTIVE
+#define isc_buffer_first ISC__BUFFER_FIRST
+#define isc_buffer_forward ISC__BUFFER_FORWARD
+#define isc_buffer_back ISC__BUFFER_BACK
+#define isc_buffer_putmem ISC__BUFFER_PUTMEM
+#define isc_buffer_putstr ISC__BUFFER_PUTSTR
+#define isc_buffer_putuint8 ISC__BUFFER_PUTUINT8
+#define isc_buffer_putuint16 ISC__BUFFER_PUTUINT16
+#define isc_buffer_putuint32 ISC__BUFFER_PUTUINT32
+#else
+#define isc_buffer_init isc__buffer_init
+#define isc_buffer_invalidate isc__buffer_invalidate
+#define isc_buffer_region isc__buffer_region
+#define isc_buffer_usedregion isc__buffer_usedregion
+#define isc_buffer_availableregion isc__buffer_availableregion
+#define isc_buffer_add isc__buffer_add
+#define isc_buffer_subtract isc__buffer_subtract
+#define isc_buffer_clear isc__buffer_clear
+#define isc_buffer_consumedregion isc__buffer_consumedregion
+#define isc_buffer_remainingregion isc__buffer_remainingregion
+#define isc_buffer_activeregion isc__buffer_activeregion
+#define isc_buffer_setactive isc__buffer_setactive
+#define isc_buffer_first isc__buffer_first
+#define isc_buffer_forward isc__buffer_forward
+#define isc_buffer_back isc__buffer_back
+#define isc_buffer_putmem isc__buffer_putmem
+#define isc_buffer_putstr isc__buffer_putstr
+#define isc_buffer_putuint8 isc__buffer_putuint8
+#define isc_buffer_putuint16 isc__buffer_putuint16
+#define isc_buffer_putuint32 isc__buffer_putuint32
+#endif
+
+#endif /* ISC_BUFFER_H */
diff --git a/lib/isc/include/isc/bufferlist.h b/lib/isc/include/isc/bufferlist.h
new file mode 100644
index 0000000..7fc2ecc
--- /dev/null
+++ b/lib/isc/include/isc/bufferlist.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2004, 2005 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: bufferlist.h,v 1.11.18.2 2005/04/29 00:16:53 marka Exp $ */
+
+#ifndef ISC_BUFFERLIST_H
+#define ISC_BUFFERLIST_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file bufferlist.h
+ *
+ *
+ *\brief Buffer lists have no synchronization. Clients must ensure exclusive
+ * access.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+unsigned int
+isc_bufferlist_usedcount(isc_bufferlist_t *bl);
+/*!<
+ * \brief Return the length of the sum of all used regions of all buffers in
+ * the buffer list 'bl'
+ *
+ * Requires:
+ *
+ *\li 'bl' is not NULL.
+ *
+ * Returns:
+ *\li sum of all used regions' lengths.
+ */
+
+unsigned int
+isc_bufferlist_availablecount(isc_bufferlist_t *bl);
+/*!<
+ * \brief Return the length of the sum of all available regions of all buffers in
+ * the buffer list 'bl'
+ *
+ * Requires:
+ *
+ *\li 'bl' is not NULL.
+ *
+ * Returns:
+ *\li sum of all available regions' lengths.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BUFFERLIST_H */
diff --git a/lib/isc/include/isc/commandline.h b/lib/isc/include/isc/commandline.h
new file mode 100644
index 0000000..5ece26f
--- /dev/null
+++ b/lib/isc/include/isc/commandline.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2004, 2005 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: commandline.h,v 1.10.18.2 2005/04/29 00:16:53 marka Exp $ */
+
+#ifndef ISC_COMMANDLINE_H
+#define ISC_COMMANDLINE_H 1
+
+/*! \file */
+
+#include <isc/boolean.h>
+#include <isc/lang.h>
+#include <isc/platform.h>
+
+/*% Index into parent argv vector. */
+LIBISC_EXTERNAL_DATA extern int isc_commandline_index;
+/*% Character checked for validity. */
+LIBISC_EXTERNAL_DATA extern int isc_commandline_option;
+/*% Argument associated with option. */
+LIBISC_EXTERNAL_DATA extern char *isc_commandline_argument;
+/*% For printing error messages. */
+LIBISC_EXTERNAL_DATA extern char *isc_commandline_progname;
+/*% Print error message. */
+LIBISC_EXTERNAL_DATA extern isc_boolean_t isc_commandline_errprint;
+/*% Reset getopt. */
+LIBISC_EXTERNAL_DATA extern isc_boolean_t isc_commandline_reset;
+
+ISC_LANG_BEGINDECLS
+
+/*% parse command line */
+int
+isc_commandline_parse(int argc, char * const *argv, const char *options);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_COMMANDLINE_H */
diff --git a/lib/isc/include/isc/entropy.h b/lib/isc/include/isc/entropy.h
new file mode 100644
index 0000000..2890f6c
--- /dev/null
+++ b/lib/isc/include/isc/entropy.h
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2004, 2005 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: entropy.h,v 1.25.18.2 2005/04/29 00:16:54 marka Exp $ */
+
+#ifndef ISC_ENTROPY_H
+#define ISC_ENTROPY_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file entropy.h
+ * \brief The entropy API
+ *
+ * \li MP:
+ * The entropy object is locked internally. All callbacks into
+ * application-provided functions (for setup, gathering, and
+ * shutdown of sources) are guaranteed to be called with the
+ * entropy API lock held. This means these functions are
+ * not permitted to call back into the entropy API.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * A buffer, used as an entropy pool.
+ *
+ * \li Security:
+ * While this code is believed to implement good entropy gathering
+ * and distribution, it has not been reviewed by a cryptographic
+ * expert.
+ * Since the added entropy is only as good as the sources used,
+ * this module could hand out bad data and never know it.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*@{*/
+/*% Entropy callback function. */
+typedef isc_result_t (*isc_entropystart_t)(isc_entropysource_t *source,
+ void *arg, isc_boolean_t blocking);
+typedef isc_result_t (*isc_entropyget_t)(isc_entropysource_t *source,
+ void *arg, isc_boolean_t blocking);
+typedef void (*isc_entropystop_t)(isc_entropysource_t *source, void *arg);
+/*@}*/
+
+/***
+ *** Flags.
+ ***/
+
+/*!
+ * \brief
+ * Extract only "good" data; return failure if there is not enough
+ * data available and there are no sources which we can poll to get
+ * data, or those sources are empty.
+ *
+ *
+ */
+#define ISC_ENTROPY_GOODONLY 0x00000001U
+/*!
+ * \brief
+ * Extract as much good data as possible, but if there isn't enough
+ * at hand, return what is available. This flag only makes sense
+ * when used with _GOODONLY.
+ */
+#define ISC_ENTROPY_PARTIAL 0x00000002U
+/*!
+ * \brief
+ * Block the task until data is available. This is contrary to the
+ * ISC task system, where tasks should never block. However, if
+ * this is a special purpose application where blocking a task is
+ * acceptable (say, an offline zone signer) this flag may be set.
+ * This flag only makes sense when used with _GOODONLY, and will
+ * block regardless of the setting for _PARTIAL.
+ */
+#define ISC_ENTROPY_BLOCKING 0x00000004U
+
+/*!
+ * \brief
+ * Estimate the amount of entropy contained in the sample pool.
+ * If this is not set, the source will be gathered and perodically
+ * mixed into the entropy pool, but no increment in contained entropy
+ * will be assumed. This flag only makes sense on sample sources.
+ */
+#define ISC_ENTROPYSOURCE_ESTIMATE 0x00000001U
+
+/*
+ * For use with isc_entropy_usebestsource().
+ */
+/*!
+ * \brief
+ * Use the keyboard as the only entropy source.
+ */
+#define ISC_ENTROPY_KEYBOARDYES 1
+/*!
+ * \brief
+ * Never use the keyboard as an entropy source.
+ */
+#define ISC_ENTROPY_KEYBOARDNO 2
+/*!
+ * \brief
+ * Use the keyboard as an entropy source only if opening the
+ * random device fails.
+ */
+#define ISC_ENTROPY_KEYBOARDMAYBE 3
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp);
+/*!<
+ * \brief Create a new entropy object.
+ */
+
+void
+isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp);
+/*!<
+ * Attaches to an entropy object.
+ */
+
+void
+isc_entropy_detach(isc_entropy_t **entp);
+/*!<
+ * \brief Detaches from an entropy object.
+ */
+
+isc_result_t
+isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname);
+/*!<
+ * \brief Create a new entropy source from a file.
+ *
+ * The file is assumed to contain good randomness, and will be mixed directly
+ * into the pool with every byte adding 8 bits of entropy.
+ *
+ * The file will be put into non-blocking mode, so it may be a device file,
+ * such as /dev/random. /dev/urandom should not be used here if it can
+ * be avoided, since it will always provide data even if it isn't good.
+ * We will make as much pseudorandom data as we need internally if our
+ * caller asks for it.
+ *
+ * If we hit end-of-file, we will stop reading from this source. Callers
+ * who require strong random data will get failure when our pool drains.
+ * The file will never be opened/read again once EOF is reached.
+ */
+
+void
+isc_entropy_destroysource(isc_entropysource_t **sourcep);
+/*!<
+ * \brief Removes an entropy source from the entropy system.
+ */
+
+isc_result_t
+isc_entropy_createsamplesource(isc_entropy_t *ent,
+ isc_entropysource_t **sourcep);
+/*!<
+ * \brief Create an entropy source that consists of samples. Each sample is added
+ * to the source via isc_entropy_addsamples(), below.
+ */
+
+isc_result_t
+isc_entropy_createcallbacksource(isc_entropy_t *ent,
+ isc_entropystart_t start,
+ isc_entropyget_t get,
+ isc_entropystop_t stop,
+ void *arg,
+ isc_entropysource_t **sourcep);
+/*!<
+ * \brief Create an entropy source that is polled via a callback.
+ *
+ * This would
+ * be used when keyboard input is used, or a GUI input method. It can
+ * also be used to hook in any external entropy source.
+ *
+ * Samples are added via isc_entropy_addcallbacksample(), below.
+ * _addcallbacksample() is the only function which may be called from
+ * within an entropy API callback function.
+ */
+
+void
+isc_entropy_stopcallbacksources(isc_entropy_t *ent);
+/*!<
+ * \brief Call the stop functions for callback sources that have had their
+ * start functions called.
+ */
+
+/*@{*/
+isc_result_t
+isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
+ isc_uint32_t extra);
+isc_result_t
+isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
+ isc_uint32_t extra);
+/*!<
+ * \brief Add a sample to the sample source.
+ *
+ * The sample MUST be a timestamp
+ * that increases over time, with the exception of wrap-around for
+ * extremely high resolution timers which will quickly wrap-around
+ * a 32-bit integer.
+ *
+ * The "extra" parameter is used only to add a bit more unpredictable
+ * data. It is not used other than included in the hash of samples.
+ *
+ * When in an entropy API callback function, _addcallbacksource() must be
+ * used. At all other times, _addsample() must be used.
+ */
+/*@}*/
+
+isc_result_t
+isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
+ unsigned int *returned, unsigned int flags);
+/*!<
+ * \brief Extract data from the entropy pool. This may load the pool from various
+ * sources.
+ *
+ * Do this by stiring the pool and returning a part of hash as randomness.
+ * Note that no secrets are given away here since parts of the hash are
+ * xored together before returned.
+ *
+ * Honor the request from the caller to only return good data, any data,
+ * etc.
+ */
+
+void
+isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
+ isc_uint32_t entropy);
+/*!<
+ * \brief Add "length" bytes in "data" to the entropy pool, incrementing the pool's
+ * entropy count by "entropy."
+ *
+ * These bytes will prime the pseudorandom portion even no entropy is actually
+ * added.
+ */
+
+void
+isc_entropy_stats(isc_entropy_t *ent, FILE *out);
+/*!<
+ * \brief Dump some (trivial) stats to the stdio stream "out".
+ */
+
+isc_result_t
+isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
+ const char *randomfile, int use_keyboard);
+/*!<
+ * \brief Use whatever source of entropy is best.
+ *
+ * Notes:
+ *\li If "randomfile" is not NULL, open it with
+ * isc_entropy_createfilesource().
+ *
+ *\li If "randomfile" is NULL and the system's random device was detected
+ * when the program was configured and built, open that device with
+ * isc_entropy_createfilesource().
+ *
+ *\li If "use_keyboard" is #ISC_ENTROPY_KEYBOARDYES, then always open
+ * the keyboard as an entropy source (possibly in addition to
+ * "randomfile" or the random device).
+ *
+ *\li If "use_keyboard" is #ISC_ENTROPY_KEYBOARDMAYBE, open the keyboard only
+ * if opening the random file/device fails. A message will be
+ * printed describing the need for keyboard input.
+ *
+ *\li If "use_keyboard" is #ISC_ENTROPY_KEYBOARDNO, the keyboard will
+ * never be opened.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS if at least one source of entropy could be started.
+ *
+ *\li #ISC_R_NOENTROPY if use_keyboard is #ISC_ENTROPY_KEYBOARDNO and
+ * there is no random device pathname compiled into the program.
+ *
+ *\li A return code from isc_entropy_createfilesource() or
+ * isc_entropy_createcallbacksource().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ENTROPY_H */
diff --git a/lib/isc/include/isc/error.h b/lib/isc/include/isc/error.h
new file mode 100644
index 0000000..3320ae9
--- /dev/null
+++ b/lib/isc/include/isc/error.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: error.h,v 1.14.18.2 2005/04/29 00:16:54 marka Exp $ */
+
+#ifndef ISC_ERROR_H
+#define ISC_ERROR_H 1
+
+/*! \file */
+
+#include <stdarg.h>
+
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef void (*isc_errorcallback_t)(const char *, int, const char *, va_list);
+
+/*% set unexpected error */
+void
+isc_error_setunexpected(isc_errorcallback_t);
+
+/*% set fatal error */
+void
+isc_error_setfatal(isc_errorcallback_t);
+
+/*% unexpected error */
+void
+isc_error_unexpected(const char *, int, const char *, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+
+/*% fatal error */
+void
+isc_error_fatal(const char *, int, const char *, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+
+/*% runtimecheck error */
+void
+isc_error_runtimecheck(const char *, int, const char *);
+
+#define ISC_ERROR_RUNTIMECHECK(cond) \
+ ((void) ((cond) || \
+ ((isc_error_runtimecheck)(__FILE__, __LINE__, #cond), 0)))
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ERROR_H */
diff --git a/lib/isc/include/isc/event.h b/lib/isc/include/isc/event.h
new file mode 100644
index 0000000..f1b1d61
--- /dev/null
+++ b/lib/isc/include/isc/event.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: event.h,v 1.27.18.3 2005/04/29 00:16:54 marka Exp $ */
+
+#ifndef ISC_EVENT_H
+#define ISC_EVENT_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*****
+ ***** Events.
+ *****/
+
+typedef void (*isc_eventdestructor_t)(isc_event_t *);
+
+#define ISC_EVENT_COMMON(ltype) \
+ size_t ev_size; \
+ unsigned int ev_attributes; \
+ void * ev_tag; \
+ isc_eventtype_t ev_type; \
+ isc_taskaction_t ev_action; \
+ void * ev_arg; \
+ void * ev_sender; \
+ isc_eventdestructor_t ev_destroy; \
+ void * ev_destroy_arg; \
+ ISC_LINK(ltype) ev_link
+
+/*%
+ * Attributes matching a mask of 0x000000ff are reserved for the task library's
+ * definition. Attributes of 0xffffff00 may be used by the application
+ * or non-ISC libraries.
+ */
+#define ISC_EVENTATTR_NOPURGE 0x00000001
+
+/*%
+ * The ISC_EVENTATTR_CANCELED attribute is intended to indicate
+ * that an event is delivered as a result of a canceled operation
+ * rather than successful completion, by mutual agreement
+ * between the sender and receiver. It is not set or used by
+ * the task system.
+ */
+#define ISC_EVENTATTR_CANCELED 0x00000002
+
+#define ISC_EVENT_INIT(event, sz, at, ta, ty, ac, ar, sn, df, da) \
+do { \
+ (event)->ev_size = (sz); \
+ (event)->ev_attributes = (at); \
+ (event)->ev_tag = (ta); \
+ (event)->ev_type = (ty); \
+ (event)->ev_action = (ac); \
+ (event)->ev_arg = (ar); \
+ (event)->ev_sender = (sn); \
+ (event)->ev_destroy = (df); \
+ (event)->ev_destroy_arg = (da); \
+ ISC_LINK_INIT((event), ev_link); \
+} while (0)
+
+/*%
+ * This structure is public because "subclassing" it may be useful when
+ * defining new event types.
+ */
+struct isc_event {
+ ISC_EVENT_COMMON(struct isc_event);
+};
+
+#define ISC_EVENTTYPE_FIRSTEVENT 0x00000000
+#define ISC_EVENTTYPE_LASTEVENT 0xffffffff
+
+#define ISC_EVENT_PTR(p) ((isc_event_t **)(void *)(p))
+
+ISC_LANG_BEGINDECLS
+
+isc_event_t *
+isc_event_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
+ isc_taskaction_t action, const void *arg, size_t size);
+/*%<
+ * Allocate an event structure.
+ *
+ * Allocate and initialize in a structure with initial elements
+ * defined by:
+ *
+ * \code
+ * struct {
+ * ISC_EVENT_COMMON(struct isc_event);
+ * ...
+ * };
+ * \endcode
+ *
+ * Requires:
+ *\li 'size' >= sizeof(struct isc_event)
+ *\li 'action' to be non NULL
+ *
+ * Returns:
+ *\li a pointer to a initialized structure of the requested size.
+ *\li NULL if unable to allocate memory.
+ */
+
+void
+isc_event_free(isc_event_t **);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_EVENT_H */
diff --git a/lib/isc/include/isc/eventclass.h b/lib/isc/include/isc/eventclass.h
new file mode 100644
index 0000000..71de715
--- /dev/null
+++ b/lib/isc/include/isc/eventclass.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: eventclass.h,v 1.14.18.2 2005/04/29 00:16:54 marka Exp $ */
+
+#ifndef ISC_EVENTCLASS_H
+#define ISC_EVENTCLASS_H 1
+
+/*! \file isc/eventclass.h
+ ***** Registry of Predefined Event Type Classes
+ *****/
+
+/*%
+ * An event class is an unsigned 16 bit number. Each class may contain up
+ * to 65536 events. An event type is formed by adding the event number
+ * within the class to the class number.
+ *
+ */
+
+#define ISC_EVENTCLASS(eclass) ((eclass) << 16)
+
+/*@{*/
+/*!
+ * Classes < 1024 are reserved for ISC use.
+ * Event classes >= 1024 and <= 65535 are reserved for application use.
+ */
+
+#define ISC_EVENTCLASS_TASK ISC_EVENTCLASS(0)
+#define ISC_EVENTCLASS_TIMER ISC_EVENTCLASS(1)
+#define ISC_EVENTCLASS_SOCKET ISC_EVENTCLASS(2)
+#define ISC_EVENTCLASS_FILE ISC_EVENTCLASS(3)
+#define ISC_EVENTCLASS_DNS ISC_EVENTCLASS(4)
+#define ISC_EVENTCLASS_APP ISC_EVENTCLASS(5)
+#define ISC_EVENTCLASS_OMAPI ISC_EVENTCLASS(6)
+#define ISC_EVENTCLASS_RATELIMITER ISC_EVENTCLASS(7)
+#define ISC_EVENTCLASS_ISCCC ISC_EVENTCLASS(8)
+/*@}*/
+
+#endif /* ISC_EVENTCLASS_H */
diff --git a/lib/isc/include/isc/file.h b/lib/isc/include/isc/file.h
new file mode 100644
index 0000000..16b0075
--- /dev/null
+++ b/lib/isc/include/isc/file.h
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2004, 2005 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: file.h,v 1.27.18.2 2005/04/29 00:16:54 marka Exp $ */
+
+#ifndef ISC_FILE_H
+#define ISC_FILE_H 1
+
+/*! \file */
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_file_settime(const char *file, isc_time_t *time);
+
+isc_result_t
+isc_file_getmodtime(const char *file, isc_time_t *time);
+/*!<
+ * \brief Get the time of last modication of a file.
+ *
+ * Notes:
+ *\li The time that is set is relative to the (OS-specific) epoch, as are
+ * all isc_time_t structures.
+ *
+ * Requires:
+ *\li file != NULL.
+ *\li time != NULL.
+ *
+ * Ensures:
+ *\li If the file could not be accessed, 'time' is unchanged.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * Success.
+ *\li #ISC_R_NOTFOUND
+ * No such file exists.
+ *\li #ISC_R_INVALIDFILE
+ * The path specified was not usable by the operating system.
+ *\li #ISC_R_NOPERM
+ * The file's metainformation could not be retrieved because
+ * permission was denied to some part of the file's path.
+ *\li #ISC_R_EIO
+ * Hardware error interacting with the filesystem.
+ *\li #ISC_R_UNEXPECTED
+ * Something totally unexpected happened.
+ *
+ */
+
+isc_result_t
+isc_file_mktemplate(const char *path, char *buf, size_t buflen);
+/*!<
+ * \brief Generate a template string suitable for use with isc_file_openunique().
+ *
+ * Notes:
+ *\li This function is intended to make creating temporary files
+ * portable between different operating systems.
+ *
+ *\li The path is prepended to an implementation-defined string and
+ * placed into buf. The string has no path characters in it,
+ * and its maximum length is 14 characters plus a NUL. Thus
+ * buflen should be at least strlen(path) + 15 characters or
+ * an error will be returned.
+ *
+ * Requires:
+ *\li buf != NULL.
+ *
+ * Ensures:
+ *\li If result == #ISC_R_SUCCESS:
+ * buf contains a string suitable for use as the template argument
+ * to isc_file_openunique().
+ *
+ *\li If result != #ISC_R_SUCCESS:
+ * buf is unchanged.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOSPACE buflen indicates buf is too small for the catenation
+ * of the path with the internal template string.
+ */
+
+
+isc_result_t
+isc_file_openunique(char *templet, FILE **fp);
+/*!<
+ * \brief Create and open a file with a unique name based on 'templet'.
+ *
+ * Notes:
+ *\li 'template' is a reserved work in C++. If you want to complain
+ * about the spelling of 'templet', first look it up in the
+ * Merriam-Webster English dictionary. (http://www.m-w.com/)
+ *
+ *\li This function works by using the template to generate file names.
+ * The template must be a writable string, as it is modified in place.
+ * Trailing X characters in the file name (full file name on Unix,
+ * basename on Win32 -- eg, tmp-XXXXXX vs XXXXXX.tmp, respectively)
+ * are replaced with ASCII characters until a non-existent filename
+ * is found. If the template does not include pathname information,
+ * the files in the working directory of the program are searched.
+ *
+ *\li isc_file_mktemplate is a good, portable way to get a template.
+ *
+ * Requires:
+ *\li 'fp' is non-NULL and '*fp' is NULL.
+ *
+ *\li 'template' is non-NULL, and of a form suitable for use by
+ * the system as described above.
+ *
+ * Ensures:
+ *\li If result is #ISC_R_SUCCESS:
+ * *fp points to an stream opening in stdio's "w+" mode.
+ *
+ *\li If result is not #ISC_R_SUCCESS:
+ * *fp is NULL.
+ *
+ * No file is open. Even if one was created (but unable
+ * to be reopened as a stdio FILE pointer) then it has been
+ * removed.
+ *
+ *\li This function does *not* ensure that the template string has not been
+ * modified, even if the operation was unsuccessful.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * Success.
+ *\li #ISC_R_EXISTS
+ * No file with a unique name could be created based on the
+ * template.
+ *\li #ISC_R_INVALIDFILE
+ * The path specified was not usable by the operating system.
+ *\li #ISC_R_NOPERM
+ * The file could not be created because permission was denied
+ * to some part of the file's path.
+ *\li #ISC_R_IOERROR
+ * Hardware error interacting with the filesystem.
+ *\li #ISC_R_UNEXPECTED
+ * Something totally unexpected happened.
+ */
+
+isc_result_t
+isc_file_remove(const char *filename);
+/*!<
+ * \brief Remove the file named by 'filename'.
+ */
+
+isc_result_t
+isc_file_rename(const char *oldname, const char *newname);
+/*!<
+ * \brief Rename the file 'oldname' to 'newname'.
+ */
+
+isc_boolean_t
+isc_file_exists(const char *pathname);
+/*!<
+ * \brief Return #ISC_TRUE if the calling process can tell that the given file exists.
+ * Will not return true if the calling process has insufficient privileges
+ * to search the entire path.
+ */
+
+isc_boolean_t
+isc_file_isabsolute(const char *filename);
+/*!<
+ * \brief Return #ISC_TRUE if the given file name is absolute.
+ */
+
+isc_boolean_t
+isc_file_iscurrentdir(const char *filename);
+/*!<
+ * \brief Return #ISC_TRUE if the given file name is the current directory (".").
+ */
+
+isc_boolean_t
+isc_file_ischdiridempotent(const char *filename);
+/*%<
+ * Return #ISC_TRUE if calling chdir(filename) multiple times will give
+ * the same result as calling it once.
+ */
+
+const char *
+isc_file_basename(const char *filename);
+/*%<
+ * Return the final component of the path in the file name.
+ */
+
+isc_result_t
+isc_file_progname(const char *filename, char *buf, size_t buflen);
+/*!<
+ * \brief Given an operating system specific file name "filename"
+ * referring to a program, return the canonical program name.
+ *
+ *
+ * Any directory prefix or executable file name extension (if
+ * used on the OS in case) is stripped. On systems where program
+ * names are case insensitive, the name is canonicalized to all
+ * lower case. The name is written to 'buf', an array of 'buflen'
+ * chars, and null terminated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE The name did not fit in 'buf'.
+ */
+
+isc_result_t
+isc_file_template(const char *path, const char *templet, char *buf,
+ size_t buflen);
+/*%<
+ * Create an OS specific template using 'path' to define the directory
+ * 'templet' to describe the filename and store the result in 'buf'
+ * such that path can be renamed to buf atomically.
+ */
+
+isc_result_t
+isc_file_renameunique(const char *file, char *templet);
+/*%<
+ * Rename 'file' using 'templet' as a template for the new file name.
+ */
+
+isc_result_t
+isc_file_absolutepath(const char *filename, char *path, size_t pathlen);
+/*%<
+ * Given a file name, return the fully qualified path to the file.
+ */
+
+/*
+ * XXX We should also have a isc_file_writeeopen() function
+ * for safely open a file in a publicly writable directory
+ * (see write_open() in BIND 8's ns_config.c).
+ */
+
+isc_result_t
+isc_file_truncate(const char *filename, isc_offset_t size);
+/*%<
+ * Truncate/extend the file specified to 'size' bytes.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_FILE_H */
diff --git a/lib/isc/include/isc/formatcheck.h b/lib/isc/include/isc/formatcheck.h
new file mode 100644
index 0000000..93c6232
--- /dev/null
+++ b/lib/isc/include/isc/formatcheck.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2004, 2005 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: formatcheck.h,v 1.7.18.2 2005/04/29 00:16:54 marka Exp $ */
+
+#ifndef ISC_FORMATCHECK_H
+#define ISC_FORMATCHECK_H 1
+
+/*! \file */
+
+/*%
+ * ISC_FORMAT_PRINTF().
+ *
+ * \li fmt is the location of the format string parameter.
+ * \li args is the location of the first argument (or 0 for no argument checking).
+ *
+ * Note:
+ * \li The first parameter is 1, not 0.
+ */
+#ifdef __GNUC__
+#define ISC_FORMAT_PRINTF(fmt, args) __attribute__((__format__(__printf__, fmt, args)))
+#else
+#define ISC_FORMAT_PRINTF(fmt, args)
+#endif
+
+#endif /* ISC_FORMATCHECK_H */
diff --git a/lib/isc/include/isc/fsaccess.h b/lib/isc/include/isc/fsaccess.h
new file mode 100644
index 0000000..70c4d7c
--- /dev/null
+++ b/lib/isc/include/isc/fsaccess.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2004, 2005 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: fsaccess.h,v 1.8.18.2 2005/04/29 00:16:55 marka Exp $ */
+
+#ifndef ISC_FSACCESS_H
+#define ISC_FSACCESS_H 1
+
+/*! \file
+ * \brief The ISC filesystem access module encapsulates the setting of file
+ * and directory access permissions into one API that is meant to be
+ * portable to multiple operating systems.
+ *
+ * The two primary operating system flavors that are initially accomodated are
+ * POSIX and Windows NT 4.0 and later. The Windows NT access model is
+ * considerable more flexible than POSIX's model (as much as I am loathe to
+ * admit it), and so the ISC API has a higher degree of complexity than would
+ * be needed to simply address POSIX's needs.
+ *
+ * The full breadth of NT's flexibility is not available either, for the
+ * present time. Much of it is to provide compatibility with what Unix
+ * programmers are expecting. This is also due to not yet really needing all
+ * of the functionality of an NT system (or, for that matter, a POSIX system)
+ * in BIND9, and so resolving how to handle the various incompatibilities has
+ * been a purely theoretical exercise with no operational experience to
+ * indicate how flawed the thinking may be.
+ *
+ * Some of the more notable dumbing down of NT for this API includes:
+ *
+ *\li Each of FILE_READ_DATA and FILE_READ_EA are set with #ISC_FSACCESS_READ.
+ *
+ * \li All of FILE_WRITE_DATA, FILE_WRITE_EA and FILE_APPEND_DATA are
+ * set with #ISC_FSACCESS_WRITE. FILE_WRITE_ATTRIBUTES is not set
+ * so as to be consistent with Unix, where only the owner of the file
+ * or the superuser can change the attributes/mode of a file.
+ *
+ * \li Both of FILE_ADD_FILE and FILE_ADD_SUBDIRECTORY are set with
+ * #ISC_FSACCESS_CREATECHILD. This is similar to setting the WRITE
+ * permission on a Unix directory.
+ *
+ * \li SYNCHRONIZE is always set for files and directories, unless someone
+ * can give me a reason why this is a bad idea.
+ *
+ * \li READ_CONTROL and FILE_READ_ATTRIBUTES are always set; this is
+ * consistent with Unix, where any file or directory can be stat()'d
+ * unless the directory path disallows complete access somewhere along
+ * the way.
+ *
+ * \li WRITE_DAC is only set for the owner. This too is consistent with
+ * Unix, and is tighter security than allowing anyone else to be
+ * able to set permissions.
+ *
+ * \li DELETE is only set for the owner. On Unix the ability to delete
+ * a file is controlled by the directory permissions, but it isn't
+ * currently clear to me what happens on NT if the directory has
+ * FILE_DELETE_CHILD set but a file within it does not have DELETE
+ * set. Always setting DELETE on the file/directory for the owner
+ * gives maximum flexibility to the owner without exposing the
+ * file to deletion by others.
+ *
+ * \li WRITE_OWNER is never set. This too is consistent with Unix,
+ * and is also tighter security than allowing anyone to change the
+ * ownership of the file apart from the superu..ahem, Administrator.
+ *
+ * \li Inheritance is set to NO_INHERITANCE.
+ *
+ * Unix's dumbing down includes:
+ *
+ * \li The sticky bit cannot be set.
+ *
+ * \li setuid and setgid cannot be set.
+ *
+ * \li Only regular files and directories can be set.
+ *
+ * The rest of this comment discusses a few of the incompatibilities
+ * between the two systems that need more thought if this API is to
+ * be extended to accomodate them.
+ *
+ * The Windows standard access right "DELETE" doesn't have a direct
+ * equivalent in the Unix world, so it isn't clear what should be done
+ * with it.
+ *
+ * The Unix sticky bit is not supported. While NT does have a concept
+ * of allowing users to create files in a directory but not delete or
+ * rename them, it does not have a concept of allowing them to be deleted
+ * if they are owned by the user trying to delete/rename. While it is
+ * probable that something could be cobbled together in NT 5 with inheritence,
+ * it can't really be done in NT 4 as a single property that you could
+ * set on a directory. You'd need to coordinate something with file creation
+ * so that every file created had DELETE set for the owner but noone else.
+ *
+ * On Unix systems, setting #ISC_FSACCESS_LISTDIRECTORY sets READ.
+ * ... setting either of #ISC_FSACCESS_(CREATE|DELETE)CHILD sets WRITE.
+ * ... setting #ISC_FSACCESS_ACCESSCHILD sets EXECUTE.
+ *
+ * On NT systems, setting #ISC_FSACCESS_LISTDIRECTORY sets FILE_LIST_DIRECTORY.
+ * ... setting ISC_FSACCESS_(CREATE|DELETE)CHILD sets
+ * FILE_(CREATE|DELETE)_CHILD independently.
+ * ... setting #ISC_FSACCESS_ACCESSCHILD sets FILE_TRAVERSE.
+ *
+ * Unresolved: XXXDCL
+ * \li What NT access right controls the ability to rename a file?
+ * \li How does DELETE work? If a directory has FILE_DELETE_CHILD but a
+ * file or directory within it does not have DELETE, is that file
+ * or directory deletable?
+ * \li To implement isc_fsaccess_get(), mapping an existing Unix permission
+ * mode_t back to an isc_fsaccess_t is pretty trivial; however, mapping
+ * an NT DACL could be impossible to do in a responsible way.
+ * \li Similarly, trying to implement the functionality of being able to
+ * say "add group writability to whatever permissions already exist"
+ * could be tricky on NT because of the order-of-entry issue combined
+ * with possibly having one or more matching ACEs already explicitly
+ * granting or denying access. Because this functionality is
+ * not yet needed by the ISC, no code has been written to try to
+ * solve this problem.
+ */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*
+ * Trustees.
+ */
+#define ISC_FSACCESS_OWNER 0x1 /*%< User account. */
+#define ISC_FSACCESS_GROUP 0x2 /*%< Primary group owner. */
+#define ISC_FSACCESS_OTHER 0x4 /*%< Not the owner or the group owner. */
+#define ISC_FSACCESS_WORLD 0x7 /*%< User, Group, Other. */
+
+/*
+ * Types of permission.
+ */
+#define ISC_FSACCESS_READ 0x00000001 /*%< File only. */
+#define ISC_FSACCESS_WRITE 0x00000002 /*%< File only. */
+#define ISC_FSACCESS_EXECUTE 0x00000004 /*%< File only. */
+#define ISC_FSACCESS_CREATECHILD 0x00000008 /*%< Dir only. */
+#define ISC_FSACCESS_DELETECHILD 0x00000010 /*%< Dir only. */
+#define ISC_FSACCESS_LISTDIRECTORY 0x00000020 /*%< Dir only. */
+#define ISC_FSACCESS_ACCESSCHILD 0x00000040 /*%< Dir only. */
+
+/*%
+ * Adding any permission bits beyond 0x200 would mean typedef'ing
+ * isc_fsaccess_t as isc_uint64_t, and redefining this value to
+ * reflect the new range of permission types, Probably to 21 for
+ * maximum flexibility. The number of bits has to accomodate all of
+ * the permission types, and three full sets of them have to fit
+ * within an isc_fsaccess_t.
+ */
+#define ISC__FSACCESS_PERMISSIONBITS 10
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_fsaccess_add(int trustee, int permission, isc_fsaccess_t *access);
+
+void
+isc_fsaccess_remove(int trustee, int permission, isc_fsaccess_t *access);
+
+isc_result_t
+isc_fsaccess_set(const char *path, isc_fsaccess_t access);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_FSACCESS_H */
diff --git a/lib/isc/include/isc/hash.h b/lib/isc/include/isc/hash.h
new file mode 100644
index 0000000..cd29cdf
--- /dev/null
+++ b/lib/isc/include/isc/hash.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: hash.h,v 1.4.18.2 2005/04/29 00:16:55 marka Exp $ */
+
+#ifndef ISC_HASH_H
+#define ISC_HASH_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ *
+ * \brief The hash API
+ * provides an unpredictable hash value for variable length data.
+ * A hash object contains a random vector (which is hidden from clients
+ * of this API) to make the actual hash value unpredictable.
+ *
+ * The algorithm used in the API guarantees the probability of hash
+ * collision; in the current implementation, as long as the values stored
+ * in the random vector are unpredictable, the probability of hash
+ * collision between arbitrary two different values is at most 1/2^16.
+ *
+ * Altough the API is generic about the hash keys, it mainly expects
+ * DNS names (and sometimes IPv4/v6 addresses) as inputs. It has an
+ * upper limit of the input length, and may run slow to calculate the
+ * hash values for large inputs.
+ *
+ * This API is designed to be general so that it can provide multiple
+ * different hash contexts that have different random vectors. However,
+ * it should be typical to have a single context for an entire system.
+ * To support such cases, the API also provides a single-context mode.
+ *
+ * \li MP:
+ * The hash object is almost read-only. Once the internal random vector
+ * is initialized, no write operation will occur, and there will be no
+ * need to lock the object to calculate actual hash values.
+ *
+ * \li Reliability:
+ * In some cases this module uses low-level data copy to initialize the
+ * random vector. Errors in this part are likely to crash the server or
+ * corrupt memory.
+ *
+ * \li Resources:
+ * A buffer, used as a random vector for calculating hash values.
+ *
+ * \li Security:
+ * This module intends to provide unpredictable hash values in
+ * adversarial environments in order to avoid denial of service attacks
+ * to hash buckets.
+ * Its unpredictability relies on the quality of entropy to build the
+ * random vector.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/types.h>
+
+/***
+ *** Functions
+ ***/
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy, unsigned int limit,
+ isc_hash_t **hctx);
+isc_result_t
+isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit);
+/*!<
+ * \brief Create a new hash object.
+ *
+ * isc_hash_ctxcreate() creates a different object.
+ *
+ * isc_hash_create() creates a module-internal object to support the
+ * single-context mode. It should be called only once.
+ *
+ * 'entropy' must be NULL or a valid entropy object. If 'entropy' is NULL,
+ * pseudo random values will be used to build the random vector, which may
+ * weaken security.
+ *
+ * 'limit' specifies the maximum number of hash keys. If it is too large,
+ * these functions may fail.
+ */
+
+void
+isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp);
+/*!<
+ * \brief Attach to a hash object.
+ *
+ * This function is only necessary for the multiple-context mode.
+ */
+
+void
+isc_hash_ctxdetach(isc_hash_t **hctxp);
+/*!<
+ * \brief Detach from a hash object.
+ *
+ * This function is for the multiple-context mode, and takes a valid
+ * hash object as an argument.
+ */
+
+void
+isc_hash_destroy(void);
+/*!<
+ * \brief This function is for the single-context mode, and is expected to be used
+ * as a counterpart of isc_hash_create().
+ *
+ * A valid module-internal hash object must have been created, and this
+ * function should be called only once.
+ */
+
+/*@{*/
+void
+isc_hash_ctxinit(isc_hash_t *hctx);
+void
+isc_hash_init(void);
+/*!<
+ * \brief Initialize a hash object.
+ *
+ * It fills in the random vector with a proper
+ * source of entropy, which is typically from the entropy object specified
+ * at the creation. Thus, it is desirable to call these functions after
+ * initializing the entropy object with some good entropy sources.
+ *
+ * These functions should be called before the first hash calculation.
+ *
+ * isc_hash_ctxinit() is for the multiple-context mode, and takes a valid hash
+ * object as an argument.
+ *
+ * isc_hash_init() is for the single-context mode. A valid module-internal
+ * hash object must have been created, and this function should be called only
+ * once.
+ */
+/*@}*/
+
+/*@{*/
+unsigned int
+isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key,
+ unsigned int keylen, isc_boolean_t case_sensitive);
+unsigned int
+isc_hash_calc(const unsigned char *key, unsigned int keylen,
+ isc_boolean_t case_sensitive);
+/*!<
+ * \brief Calculate a hash value.
+ *
+ * isc_hash_ctxinit() is for the multiple-context mode, and takes a valid hash
+ * object as an argument.
+ *
+ * isc_hash_init() is for the single-context mode. A valid module-internal
+ * hash object must have been created.
+ *
+ * 'key' is the hash key, which is a variable length buffer.
+ *
+ * 'keylen' specifies the key length, which must not be larger than the limit
+ * specified for the corresponding hash object.
+ *
+ * 'case_sensitive' specifies whether the hash key should be treated as
+ * case_sensitive values. It should typically be ISC_FALSE if the hash key
+ * is a DNS name.
+ */
+/*@}*/
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HASH_H */
diff --git a/lib/isc/include/isc/heap.h b/lib/isc/include/isc/heap.h
new file mode 100644
index 0000000..d54a8d5
--- /dev/null
+++ b/lib/isc/include/isc/heap.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-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: heap.h,v 1.17.18.3 2006/04/17 18:27:33 explorer Exp $ */
+
+#ifndef ISC_HEAP_H
+#define ISC_HEAP_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * The comparision function returns ISC_TRUE if the first argument has
+ * higher priority than the second argument, and ISC_FALSE otherwise.
+ */
+typedef isc_boolean_t (*isc_heapcompare_t)(void *, void *);
+
+/*%
+ * The index function allows the client of the heap to receive a callback
+ * when an item's index number changes. This allows it to maintain
+ * sync with its external state, but still delete itself, since deletions
+ * from the heap require the index be provided.
+ */
+typedef void (*isc_heapindex_t)(void *, unsigned int);
+
+/*%
+ * The heapaction function is used when iterating over the heap.
+ *
+ * NOTE: The heap structure CANNOT BE MODIFIED during the call to
+ * isc_heap_foreach().
+ */
+typedef void (*isc_heapaction_t)(void *, void *);
+
+typedef struct isc_heap isc_heap_t;
+
+isc_result_t
+isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare,
+ isc_heapindex_t index, unsigned int size_increment,
+ isc_heap_t **heapp);
+/*!<
+ * \brief Create a new heap. The heap is implemented using a space-efficient
+ * storage method. When the heap elements are deleted space is not freed
+ * but will be reused when new elements are inserted.
+ *
+ * Requires:
+ *\li "mctx" is valid.
+ *\li "compare" is a function which takes two void * arguments and
+ * returns ISC_TRUE if the first argument has a higher priority than
+ * the second, and ISC_FALSE otherwise.
+ *\li "index" is a function which takes a void *, and an unsigned int
+ * argument. This function will be called whenever an element's
+ * index value changes, so it may continue to delete itself from the
+ * heap. This option may be NULL if this functionality is unneeded.
+ *\li "size_increment" is a hint about how large the heap should grow
+ * when resizing is needed. If this is 0, a default size will be
+ * used, which is currently 1024, allowing space for an additional 1024
+ * heap elements to be inserted before adding more space.
+ *\li "heapp" is not NULL, and "*heap" is NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS - success
+ *\li ISC_R_NOMEMORY - insufficient memory
+ */
+
+void
+isc_heap_destroy(isc_heap_t **heapp);
+/*!<
+ * \brief Destroys a heap.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ */
+
+isc_result_t
+isc_heap_insert(isc_heap_t *heap, void *elt);
+/*!<
+ * \brief Inserts a new element into a heap.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ */
+
+void
+isc_heap_delete(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Deletes an element from a heap, by element index.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ */
+
+void
+isc_heap_increased(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Indicates to the heap that an element's priority has increased.
+ * This function MUST be called whenever an element has increased in priority.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ */
+
+void
+isc_heap_decreased(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Indicates to the heap that an element's priority has decreased.
+ * This function MUST be called whenever an element has decreased in priority.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ */
+
+void *
+isc_heap_element(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Returns the element for a specific element index.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ *
+ * Returns:
+ *\li A pointer to the element for the element index.
+ */
+
+void
+isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap);
+/*!<
+ * \brief Iterate over the heap, calling an action for each element. The
+ * order of iteration is not sorted.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "action" is not NULL, and is a function which takes two arguments.
+ * The first is a void *, representing the element, and the second is
+ * "uap" as provided to isc_heap_foreach.
+ *\li "uap" is a caller-provided argument, and may be NULL.
+ *
+ * Note:
+ *\li The heap structure CANNOT be modified during this iteration. The only
+ * safe function to call while iterating the heap is isc_heap_element().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HEAP_H */
diff --git a/lib/isc/include/isc/hex.h b/lib/isc/include/isc/hex.h
new file mode 100644
index 0000000..9124a9b
--- /dev/null
+++ b/lib/isc/include/isc/hex.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2004, 2005 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: hex.h,v 1.5.18.2 2005/04/29 00:16:55 marka Exp $ */
+
+#ifndef ISC_HEX_H
+#define ISC_HEX_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_hex_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
+/*!<
+ * \brief Convert data into hex encoded text.
+ *
+ * Notes:
+ *\li The hex encoded text in 'target' will be divided into
+ * words of at most 'wordlength' characters, separated by
+ * the 'wordbreak' string. No parentheses will surround
+ * the text.
+ *
+ * Requires:
+ *\li 'source' is a region containing binary data
+ *\li 'target' is a text buffer containing available space
+ *\li 'wordbreak' points to a null-terminated string of
+ * zero or more whitespace characters
+ *
+ * Ensures:
+ *\li target will contain the hex encoded version of the data
+ * in source. The 'used' pointer in target will be advanced as
+ * necessary.
+ */
+
+isc_result_t
+isc_hex_decodestring(char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated hex string.
+ *
+ * Requires:
+ *\li 'cstr' is non-null.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADHEX -- 'cstr' is not a valid hex encoding.
+ *
+ * Other error returns are any possible error code from:
+ * isc_lex_create(),
+ * isc_lex_openbuffer(),
+ * isc_hex_tobuffer().
+ */
+
+isc_result_t
+isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert hex encoded text from a lexer context into data.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer context
+ *\li 'target' is a buffer containing binary data
+ *\li 'length' is an integer
+ *
+ * Ensures:
+ *\li target will contain the data represented by the hex encoded
+ * string parsed by the lexer. No more than length bytes will be read,
+ * if length is positive. The 'used' pointer in target will be
+ * advanced as necessary.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HEX_H */
diff --git a/lib/isc/include/isc/hmacmd5.h b/lib/isc/include/isc/hmacmd5.h
new file mode 100644
index 0000000..5c05675
--- /dev/null
+++ b/lib/isc/include/isc/hmacmd5.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2004-2006 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: hmacmd5.h,v 1.5.18.4 2006/01/27 23:57:45 marka Exp $ */
+
+/*! \file
+ * \brief This is the header file for the HMAC-MD5 keyed hash algorithm
+ * described in RFC2104.
+ */
+
+#ifndef ISC_HMACMD5_H
+#define ISC_HMACMD5_H 1
+
+#include <isc/lang.h>
+#include <isc/md5.h>
+#include <isc/types.h>
+
+#define ISC_HMACMD5_KEYLENGTH 64
+
+typedef struct {
+ isc_md5_t md5ctx;
+ unsigned char key[ISC_HMACMD5_KEYLENGTH];
+} isc_hmacmd5_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx);
+
+void
+isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest);
+
+isc_boolean_t
+isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest);
+
+isc_boolean_t
+isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HMACMD5_H */
diff --git a/lib/isc/include/isc/hmacsha.h b/lib/isc/include/isc/hmacsha.h
new file mode 100644
index 0000000..fce645c5
--- /dev/null
+++ b/lib/isc/include/isc/hmacsha.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2005, 2006 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: hmacsha.h,v 1.2.2.3 2006/08/16 03:18:14 marka Exp $ */
+
+/*
+ * This is the header file for the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256,
+ * HMAC-SHA334 and HMAC-SHA512 hash algorithm described in RFC 2104.
+ */
+
+#ifndef ISC_HMACSHA_H
+#define ISC_HMACSHA_H 1
+
+#include <isc/lang.h>
+#include <isc/sha1.h>
+#include <isc/sha2.h>
+#include <isc/types.h>
+
+#define ISC_HMACSHA1_KEYLENGTH ISC_SHA1_BLOCK_LENGTH
+#define ISC_HMACSHA224_KEYLENGTH ISC_SHA224_BLOCK_LENGTH
+#define ISC_HMACSHA256_KEYLENGTH ISC_SHA256_BLOCK_LENGTH
+#define ISC_HMACSHA384_KEYLENGTH ISC_SHA384_BLOCK_LENGTH
+#define ISC_HMACSHA512_KEYLENGTH ISC_SHA512_BLOCK_LENGTH
+
+typedef struct {
+ isc_sha1_t sha1ctx;
+ unsigned char key[ISC_HMACSHA1_KEYLENGTH];
+} isc_hmacsha1_t;
+
+typedef struct {
+ isc_sha224_t sha224ctx;
+ unsigned char key[ISC_HMACSHA224_KEYLENGTH];
+} isc_hmacsha224_t;
+
+typedef struct {
+ isc_sha256_t sha256ctx;
+ unsigned char key[ISC_HMACSHA256_KEYLENGTH];
+} isc_hmacsha256_t;
+
+typedef struct {
+ isc_sha384_t sha384ctx;
+ unsigned char key[ISC_HMACSHA384_KEYLENGTH];
+} isc_hmacsha384_t;
+
+typedef struct {
+ isc_sha512_t sha512ctx;
+ unsigned char key[ISC_HMACSHA512_KEYLENGTH];
+} isc_hmacsha512_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx);
+
+void
+isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len);
+
+isc_boolean_t
+isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len);
+
+
+void
+isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx);
+
+void
+isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len);
+
+isc_boolean_t
+isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len);
+
+
+void
+isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx);
+
+void
+isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len);
+
+isc_boolean_t
+isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len);
+
+
+void
+isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx);
+
+void
+isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len);
+
+isc_boolean_t
+isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len);
+
+
+void
+isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key,
+ unsigned int len);
+
+void
+isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx);
+
+void
+isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf,
+ unsigned int len);
+
+void
+isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len);
+
+isc_boolean_t
+isc_hmacsha512_verify(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HMACSHA_H */
diff --git a/lib/isc/include/isc/interfaceiter.h b/lib/isc/include/isc/interfaceiter.h
new file mode 100644
index 0000000..12ec188
--- /dev/null
+++ b/lib/isc/include/isc/interfaceiter.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2004, 2005 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: interfaceiter.h,v 1.11.18.2 2005/04/29 00:16:55 marka Exp $ */
+
+#ifndef ISC_INTERFACEITER_H
+#define ISC_INTERFACEITER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief Iterates over the list of network interfaces.
+ *
+ * Interfaces whose address family is not supported are ignored and never
+ * returned by the iterator. Interfaces whose netmask, interface flags,
+ * or similar cannot be obtained are also ignored, and the failure is logged.
+ *
+ * Standards:
+ * The API for scanning varies greatly among operating systems.
+ * This module attempts to hide the differences.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/netaddr.h>
+#include <isc/types.h>
+
+/*!
+ * \brief Public structure describing a network interface.
+ */
+
+struct isc_interface {
+ char name[32]; /*%< Interface name, null-terminated. */
+ unsigned int af; /*%< Address family. */
+ isc_netaddr_t address; /*%< Local address. */
+ isc_netaddr_t netmask; /*%< Network mask. */
+ isc_netaddr_t dstaddress; /*%< Destination address (point-to-point only). */
+ isc_uint32_t flags; /*%< Flags; see INTERFACE flags. */
+};
+
+/*@{*/
+/*! Interface flags. */
+
+#define INTERFACE_F_UP 0x00000001U
+#define INTERFACE_F_POINTTOPOINT 0x00000002U
+#define INTERFACE_F_LOOPBACK 0x00000004U
+/*@}*/
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp);
+/*!<
+ * \brief Create an iterator for traversing the operating system's list
+ * of network interfaces.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ *\li Various network-related errors
+ */
+
+isc_result_t
+isc_interfaceiter_first(isc_interfaceiter_t *iter);
+/*!<
+ * \brief Position the iterator on the first interface.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOMORE There are no interfaces.
+ */
+
+isc_result_t
+isc_interfaceiter_current(isc_interfaceiter_t *iter,
+ isc_interface_t *ifdata);
+/*!<
+ * \brief Get information about the interface the iterator is currently
+ * positioned at and store it at *ifdata.
+ *
+ * Requires:
+ *\li The iterator has been successfully positioned using
+ * isc_interface_iter_first() / isc_interface_iter_next().
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ */
+
+isc_result_t
+isc_interfaceiter_next(isc_interfaceiter_t *iter);
+/*!<
+ * \brief Position the iterator on the next interface.
+ *
+ * Requires:
+ * \li The iterator has been successfully positioned using
+ * isc_interface_iter_first() / isc_interface_iter_next().
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOMORE There are no more interfaces.
+ */
+
+void
+isc_interfaceiter_destroy(isc_interfaceiter_t **iterp);
+/*!<
+ * \brief Destroy the iterator.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_INTERFACEITER_H */
diff --git a/lib/isc/include/isc/ipv6.h b/lib/isc/include/isc/ipv6.h
new file mode 100644
index 0000000..7c88f2b
--- /dev/null
+++ b/lib/isc/include/isc/ipv6.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2004, 2005 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: ipv6.h,v 1.20.18.2 2005/04/29 00:16:56 marka Exp $ */
+
+#ifndef ISC_IPV6_H
+#define ISC_IPV6_H 1
+
+/*!
+ * Also define LWRES_IPV6_H to keep it from being included if liblwres is
+ * being used, or redefinition errors will occur.
+ */
+#define LWRES_IPV6_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/ipv6.h
+ * \brief IPv6 definitions for systems which do not support IPv6.
+ *
+ * \li MP:
+ * No impact.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * N/A.
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * RFC2553.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/int.h>
+#include <isc/platform.h>
+
+/***
+ *** Types.
+ ***/
+
+struct in6_addr {
+ union {
+ isc_uint8_t _S6_u8[16];
+ isc_uint16_t _S6_u16[8];
+ isc_uint32_t _S6_u32[4];
+ } _S6_un;
+};
+#define s6_addr _S6_un._S6_u8
+#define s6_addr8 _S6_un._S6_u8
+#define s6_addr16 _S6_un._S6_u16
+#define s6_addr32 _S6_un._S6_u32
+
+#define IN6ADDR_ANY_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}}
+#define IN6ADDR_LOOPBACK_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}}
+
+LIBISC_EXTERNAL_DATA extern const struct in6_addr in6addr_any;
+LIBISC_EXTERNAL_DATA extern const struct in6_addr in6addr_loopback;
+
+struct sockaddr_in6 {
+#ifdef ISC_PLATFORM_HAVESALEN
+ isc_uint8_t sin6_len;
+ isc_uint8_t sin6_family;
+#else
+ isc_uint16_t sin6_family;
+#endif
+ isc_uint16_t sin6_port;
+ isc_uint32_t sin6_flowinfo;
+ struct in6_addr sin6_addr;
+ isc_uint32_t sin6_scope_id;
+};
+
+#ifdef ISC_PLATFORM_HAVESALEN
+#define SIN6_LEN 1
+#endif
+
+/*%
+ * Unspecified
+ */
+#define IN6_IS_ADDR_UNSPECIFIED(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] == 0))
+
+/*%
+ * Loopback
+ */
+#define IN6_IS_ADDR_LOOPBACK(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] == htonl(1)))
+
+/*%
+ * IPv4 compatible
+ */
+#define IN6_IS_ADDR_V4COMPAT(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] != 0) && \
+ ((a)->s6_addr32[3] != htonl(1)))
+
+/*%
+ * Mapped
+ */
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == htonl(0x0000ffff)))
+
+/*%
+ * Multicast
+ */
+#define IN6_IS_ADDR_MULTICAST(a) \
+ ((a)->s6_addr8[0] == 0xffU)
+
+/*%
+ * Unicast link / site local.
+ */
+#define IN6_IS_ADDR_LINKLOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
+#define IN6_IS_ADDR_SITELOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
+
+#endif /* ISC_IPV6_H */
diff --git a/lib/isc/include/isc/lang.h b/lib/isc/include/isc/lang.h
new file mode 100644
index 0000000..abe16f5
--- /dev/null
+++ b/lib/isc/include/isc/lang.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2004, 2005 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: lang.h,v 1.7.18.2 2005/04/29 00:16:56 marka Exp $ */
+
+#ifndef ISC_LANG_H
+#define ISC_LANG_H 1
+
+/*! \file */
+
+#ifdef __cplusplus
+#define ISC_LANG_BEGINDECLS extern "C" {
+#define ISC_LANG_ENDDECLS }
+#else
+#define ISC_LANG_BEGINDECLS
+#define ISC_LANG_ENDDECLS
+#endif
+
+#endif /* ISC_LANG_H */
diff --git a/lib/isc/include/isc/lex.h b/lib/isc/include/isc/lex.h
new file mode 100644
index 0000000..8c6624a
--- /dev/null
+++ b/lib/isc/include/isc/lex.h
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: lex.h,v 1.30.18.3 2005/06/04 00:39:05 marka Exp $ */
+
+#ifndef ISC_LEX_H
+#define ISC_LEX_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/lex.h
+ * \brief The "lex" module provides a lightweight tokenizer. It can operate
+ * on files or buffers, and can handle "include". It is designed for
+ * parsing of DNS master files and the BIND configuration file, but
+ * should be general enough to tokenize other things, e.g. HTTP.
+ *
+ * \li MP:
+ * No synchronization is provided. Clients must ensure exclusive
+ * access.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/region.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Options
+ ***/
+
+/*@{*/
+/*!
+ * Various options for isc_lex_gettoken().
+ */
+
+#define ISC_LEXOPT_EOL 0x01 /*%< Want end-of-line token. */
+#define ISC_LEXOPT_EOF 0x02 /*%< Want end-of-file token. */
+#define ISC_LEXOPT_INITIALWS 0x04 /*%< Want initial whitespace. */
+#define ISC_LEXOPT_NUMBER 0x08 /*%< Recognize numbers. */
+#define ISC_LEXOPT_QSTRING 0x10 /*%< Recognize qstrings. */
+/*@}*/
+
+/*@{*/
+/*!
+ * The ISC_LEXOPT_DNSMULTILINE option handles the processing of '(' and ')' in
+ * the DNS master file format. If this option is set, then the
+ * ISC_LEXOPT_INITIALWS and ISC_LEXOPT_EOL options will be ignored when
+ * the paren count is > 0. To use this option, '(' and ')' must be special
+ * characters.
+ */
+#define ISC_LEXOPT_DNSMULTILINE 0x20 /*%< Handle '(' and ')'. */
+#define ISC_LEXOPT_NOMORE 0x40 /*%< Want "no more" token. */
+
+#define ISC_LEXOPT_CNUMBER 0x80 /*%< Regognize octal and hex. */
+#define ISC_LEXOPT_ESCAPE 0x100 /*%< Recognize escapes. */
+#define ISC_LEXOPT_QSTRINGMULTILINE 0x200 /*%< Allow multiline "" strings */
+#define ISC_LEXOPT_OCTAL 0x400 /*%< Expect a octal number. */
+/*@}*/
+/*@{*/
+/*!
+ * Various commenting styles, which may be changed at any time with
+ * isc_lex_setcomments().
+ */
+
+#define ISC_LEXCOMMENT_C 0x01
+#define ISC_LEXCOMMENT_CPLUSPLUS 0x02
+#define ISC_LEXCOMMENT_SHELL 0x04
+#define ISC_LEXCOMMENT_DNSMASTERFILE 0x08
+/*@}*/
+
+/***
+ *** Types
+ ***/
+
+/*! Lex */
+
+typedef char isc_lexspecials_t[256];
+
+/* Tokens */
+
+typedef enum {
+ isc_tokentype_unknown = 0,
+ isc_tokentype_string = 1,
+ isc_tokentype_number = 2,
+ isc_tokentype_qstring = 3,
+ isc_tokentype_eol = 4,
+ isc_tokentype_eof = 5,
+ isc_tokentype_initialws = 6,
+ isc_tokentype_special = 7,
+ isc_tokentype_nomore = 8
+} isc_tokentype_t;
+
+typedef union {
+ char as_char;
+ unsigned long as_ulong;
+ isc_region_t as_region;
+ isc_textregion_t as_textregion;
+ void * as_pointer;
+} isc_tokenvalue_t;
+
+typedef struct isc_token {
+ isc_tokentype_t type;
+ isc_tokenvalue_t value;
+} isc_token_t;
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp);
+/*%<
+ * Create a lexer.
+ *
+ * 'max_token' is a hint of the number of bytes in the largest token.
+ *
+ * Requires:
+ *\li '*lexp' is a valid lexer.
+ *
+ *\li max_token > 0.
+ *
+ * Ensures:
+ *\li On success, *lexp is attached to the newly created lexer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+void
+isc_lex_destroy(isc_lex_t **lexp);
+/*%<
+ * Destroy the lexer.
+ *
+ * Requires:
+ *\li '*lexp' is a valid lexer.
+ *
+ * Ensures:
+ *\li *lexp == NULL
+ */
+
+unsigned int
+isc_lex_getcomments(isc_lex_t *lex);
+/*%<
+ * Return the current lexer commenting styles.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ *\li The commenting sytles which are currently allowed.
+ */
+
+void
+isc_lex_setcomments(isc_lex_t *lex, unsigned int comments);
+/*%<
+ * Set allowed lexer commenting styles.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'comments' has meaningful values.
+ */
+
+void
+isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials);
+/*%<
+ * Put the current list of specials into 'specials'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ */
+
+void
+isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials);
+/*!<
+ * The characters in 'specials' are returned as tokens. Along with
+ * whitespace, they delimit strings and numbers.
+ *
+ * Note:
+ *\li Comment processing takes precedence over special character
+ * recognition.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ */
+
+isc_result_t
+isc_lex_openfile(isc_lex_t *lex, const char *filename);
+/*%<
+ * Open 'filename' and make it the current input source for 'lex'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li filename is a valid C string.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY Out of memory
+ *\li #ISC_R_NOTFOUND File not found
+ *\li #ISC_R_NOPERM No permission to open file
+ *\li #ISC_R_FAILURE Couldn't open file, not sure why
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_lex_openstream(isc_lex_t *lex, FILE *stream);
+/*%<
+ * Make 'stream' the current input source for 'lex'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'stream' is a valid C stream.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY Out of memory
+ */
+
+isc_result_t
+isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer);
+/*%<
+ * Make 'buffer' the current input source for 'lex'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'buffer' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY Out of memory
+ */
+
+isc_result_t
+isc_lex_close(isc_lex_t *lex);
+/*%<
+ * Close the most recently opened object (i.e. file or buffer).
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMORE No more input sources
+ */
+
+isc_result_t
+isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp);
+/*%<
+ * Get the next token.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'lex' has an input source.
+ *
+ *\li 'options' contains valid options.
+ *
+ *\li '*tokenp' is a valid pointer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_UNEXPECTEDEND
+ *\li #ISC_R_NOMEMORY
+ *
+ * These two results are returned only if their corresponding lexer
+ * options are not set.
+ *
+ *\li #ISC_R_EOF End of input source
+ *\li #ISC_R_NOMORE No more input sources
+ */
+
+isc_result_t
+isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
+ isc_tokentype_t expect, isc_boolean_t eol);
+/*%<
+ * Get the next token from a DNS master file type stream. This is a
+ * convenience function that sets appropriate options and handles quoted
+ * strings and end of line correctly for master files. It also ungets
+ * unexpected tokens.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'token' is a valid pointer
+ *
+ * Returns:
+ *
+ * \li any return code from isc_lex_gettoken().
+ */
+
+isc_result_t
+isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol);
+/*%<
+ * Get the next token from a DNS master file type stream. This is a
+ * convenience function that sets appropriate options and handles end
+ * of line correctly for master files. It also ungets unexpected tokens.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'token' is a valid pointer
+ *
+ * Returns:
+ *
+ * \li any return code from isc_lex_gettoken().
+ */
+
+void
+isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp);
+/*%<
+ * Unget the current token.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'lex' has an input source.
+ *
+ *\li 'tokenp' points to a valid token.
+ *
+ *\li There is no ungotten token already.
+ */
+
+void
+isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r);
+/*%<
+ * Returns a region containing the text of the last token returned.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'lex' has an input source.
+ *
+ *\li 'tokenp' points to a valid token.
+ *
+ *\li A token has been gotten and not ungotten.
+ */
+
+char *
+isc_lex_getsourcename(isc_lex_t *lex);
+/*%<
+ * Return the input source name.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li source name or NULL if no current source.
+ *\li result valid while current input source exists.
+ */
+
+
+unsigned long
+isc_lex_getsourceline(isc_lex_t *lex);
+/*%<
+ * Return the input source line number.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ *\li Current line number or 0 if no current source.
+ */
+
+isc_result_t
+isc_lex_setsourcename(isc_lex_t *lex, const char *name);
+/*%<
+ * Assigns a new name to the input source.
+ *
+ * Requires:
+ *
+ * \li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ * \li #ISC_R_NOTFOUND - there are no sources.
+ */
+
+isc_boolean_t
+isc_lex_isfile(isc_lex_t *lex);
+/*%<
+ * Return whether the current input source is a file.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li #ISC_TRUE if the current input is a file,
+ *\li #ISC_FALSE otherwise.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_LEX_H */
diff --git a/lib/isc/include/isc/lfsr.h b/lib/isc/include/isc/lfsr.h
new file mode 100644
index 0000000..0c2e845
--- /dev/null
+++ b/lib/isc/include/isc/lfsr.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2004, 2005 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: lfsr.h,v 1.11.18.2 2005/04/29 00:16:56 marka Exp $ */
+
+#ifndef ISC_LFSR_H
+#define ISC_LFSR_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+typedef struct isc_lfsr isc_lfsr_t;
+
+/*%
+ * This function is called when reseeding is needed. It is allowed to
+ * modify any state in the LFSR in any way it sees fit OTHER THAN "bits".
+ *
+ * It MUST set "count" to a new value or the lfsr will never reseed again.
+ *
+ * Also, a reseed will never occur in the middle of an extraction. This
+ * is purely an optimization, and is probably what one would want.
+ */
+typedef void (*isc_lfsrreseed_t)(isc_lfsr_t *, void *);
+
+/*%
+ * The members of this structure can be used by the application, but care
+ * needs to be taken to not change state once the lfsr is in operation.
+ */
+struct isc_lfsr {
+ isc_uint32_t state; /*%< previous state */
+ unsigned int bits; /*%< length */
+ isc_uint32_t tap; /*%< bit taps */
+ unsigned int count; /*%< reseed count (in BITS!) */
+ isc_lfsrreseed_t reseed; /*%< reseed function */
+ void *arg; /*%< reseed function argument */
+};
+
+ISC_LANG_BEGINDECLS
+
+
+void
+isc_lfsr_init(isc_lfsr_t *lfsr, isc_uint32_t state, unsigned int bits,
+ isc_uint32_t tap, unsigned int count,
+ isc_lfsrreseed_t reseed, void *arg);
+/*%<
+ * Initialize an LFSR.
+ *
+ * Note:
+ *
+ *\li Putting untrusted values into this function will cause the LFSR to
+ * generate (perhaps) non-maximal length sequences.
+ *
+ * Requires:
+ *
+ *\li lfsr != NULL
+ *
+ *\li 8 <= bits <= 32
+ *
+ *\li tap != 0
+ */
+
+void
+isc_lfsr_generate(isc_lfsr_t *lfsr, void *data, unsigned int count);
+/*%<
+ * Returns "count" bytes of data from the LFSR.
+ *
+ * Requires:
+ *
+ *\li lfsr be valid.
+ *
+ *\li data != NULL.
+ *
+ *\li count > 0.
+ */
+
+void
+isc_lfsr_skip(isc_lfsr_t *lfsr, unsigned int skip);
+/*%<
+ * Skip "skip" states.
+ *
+ * Requires:
+ *
+ *\li lfsr be valid.
+ */
+
+isc_uint32_t
+isc_lfsr_generate32(isc_lfsr_t *lfsr1, isc_lfsr_t *lfsr2);
+/*%<
+ * Given two LFSRs, use the current state from each to skip entries in the
+ * other. The next states are then xor'd together and returned.
+ *
+ * WARNING:
+ *
+ *\li This function is used only for very, very low security data, such
+ * as DNS message IDs where it is desired to have an unpredictable
+ * stream of bytes that are harder to predict than a simple flooding
+ * attack.
+ *
+ * Notes:
+ *
+ *\li Since the current state from each of the LFSRs is used to skip
+ * state in the other, it is important that no state be leaked
+ * from either LFSR.
+ *
+ * Requires:
+ *
+ *\li lfsr1 and lfsr2 be valid.
+ *
+ *\li 1 <= skipbits <= 31
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_LFSR_H */
diff --git a/lib/isc/include/isc/lib.h b/lib/isc/include/isc/lib.h
new file mode 100644
index 0000000..45c547c
--- /dev/null
+++ b/lib/isc/include/isc/lib.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2004, 2005 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: lib.h,v 1.8.18.2 2005/04/29 00:16:58 marka Exp $ */
+
+#ifndef ISC_LIB_H
+#define ISC_LIB_H 1
+
+/*! \file */
+
+#include <isc/types.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+LIBISC_EXTERNAL_DATA extern isc_msgcat_t *isc_msgcat;
+
+void
+isc_lib_initmsgcat(void);
+/*!<
+ * \brief Initialize the ISC library's message catalog, isc_msgcat, if it
+ * has not already been initialized.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_LIB_H */
diff --git a/lib/isc/include/isc/list.h b/lib/isc/include/isc/list.h
new file mode 100644
index 0000000..2adc33f
--- /dev/null
+++ b/lib/isc/include/isc/list.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-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: list.h,v 1.20.18.2 2006/06/06 00:11:41 marka Exp $ */
+
+#ifndef ISC_LIST_H
+#define ISC_LIST_H 1
+#include <isc/boolean.h>
+#include <isc/assertions.h>
+
+#ifdef ISC_LIST_CHECKINIT
+#define ISC_LINK_INSIST(x) ISC_INSIST(x)
+#else
+#define ISC_LINK_INSIST(x)
+#endif
+
+#define ISC_LIST(type) struct { type *head, *tail; }
+#define ISC_LIST_INIT(list) \
+ do { (list).head = NULL; (list).tail = NULL; } while (0)
+
+#define ISC_LINK(type) struct { type *prev, *next; }
+#define ISC_LINK_INIT_TYPE(elt, link, type) \
+ do { \
+ (elt)->link.prev = (type *)(-1); \
+ (elt)->link.next = (type *)(-1); \
+ } while (0)
+#define ISC_LINK_INIT(elt, link) \
+ ISC_LINK_INIT_TYPE(elt, link, void)
+#define ISC_LINK_LINKED(elt, link) ((void *)((elt)->link.prev) != (void *)(-1))
+
+#define ISC_LIST_HEAD(list) ((list).head)
+#define ISC_LIST_TAIL(list) ((list).tail)
+#define ISC_LIST_EMPTY(list) ISC_TF((list).head == NULL)
+
+#define __ISC_LIST_PREPENDUNSAFE(list, elt, link) \
+ do { \
+ 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 ISC_LIST_PREPEND(list, elt, link) \
+ do { \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_PREPENDUNSAFE(list, elt, link); \
+ } while (0)
+
+#define ISC_LIST_INITANDPREPEND(list, elt, link) \
+ __ISC_LIST_PREPENDUNSAFE(list, elt, link)
+
+#define __ISC_LIST_APPENDUNSAFE(list, elt, link) \
+ do { \
+ 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 ISC_LIST_APPEND(list, elt, link) \
+ do { \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_APPENDUNSAFE(list, elt, link); \
+ } while (0)
+
+#define ISC_LIST_INITANDAPPEND(list, elt, link) \
+ __ISC_LIST_APPENDUNSAFE(list, elt, link)
+
+#define __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type) \
+ do { \
+ if ((elt)->link.next != NULL) \
+ (elt)->link.next->link.prev = (elt)->link.prev; \
+ else { \
+ ISC_INSIST((list).tail == (elt)); \
+ (list).tail = (elt)->link.prev; \
+ } \
+ if ((elt)->link.prev != NULL) \
+ (elt)->link.prev->link.next = (elt)->link.next; \
+ else { \
+ ISC_INSIST((list).head == (elt)); \
+ (list).head = (elt)->link.next; \
+ } \
+ (elt)->link.prev = (type *)(-1); \
+ (elt)->link.next = (type *)(-1); \
+ } while (0)
+
+#define __ISC_LIST_UNLINKUNSAFE(list, elt, link) \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, void)
+
+#define ISC_LIST_UNLINK_TYPE(list, elt, link, type) \
+ do { \
+ ISC_LINK_INSIST(ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type); \
+ } while (0)
+#define ISC_LIST_UNLINK(list, elt, link) \
+ ISC_LIST_UNLINK_TYPE(list, elt, link, void)
+
+#define ISC_LIST_PREV(elt, link) ((elt)->link.prev)
+#define ISC_LIST_NEXT(elt, link) ((elt)->link.next)
+
+#define __ISC_LIST_INSERTBEFOREUNSAFE(list, before, elt, link) \
+ do { \
+ if ((before)->link.prev == NULL) \
+ ISC_LIST_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 ISC_LIST_INSERTBEFORE(list, before, elt, link) \
+ do { \
+ ISC_LINK_INSIST(ISC_LINK_LINKED(before, link)); \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_INSERTBEFOREUNSAFE(list, before, elt, link); \
+ } while (0)
+
+#define __ISC_LIST_INSERTAFTERUNSAFE(list, after, elt, link) \
+ do { \
+ if ((after)->link.next == NULL) \
+ ISC_LIST_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 ISC_LIST_INSERTAFTER(list, after, elt, link) \
+ do { \
+ ISC_LINK_INSIST(ISC_LINK_LINKED(after, link)); \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_INSERTAFTERUNSAFE(list, after, elt, link); \
+ } while (0)
+
+#define ISC_LIST_APPENDLIST(list1, list2, link) \
+ do { \
+ if (ISC_LIST_EMPTY(list1)) \
+ (list1) = (list2); \
+ else if (!ISC_LIST_EMPTY(list2)) { \
+ (list1).tail->link.next = (list2).head; \
+ (list2).head->link.prev = (list1).tail; \
+ (list1).tail = (list2).tail; \
+ } \
+ (list2).head = NULL; \
+ (list2).tail = NULL; \
+ } while (0)
+
+#define ISC_LIST_ENQUEUE(list, elt, link) ISC_LIST_APPEND(list, elt, link)
+#define __ISC_LIST_ENQUEUEUNSAFE(list, elt, link) \
+ __ISC_LIST_APPENDUNSAFE(list, elt, link)
+#define ISC_LIST_DEQUEUE(list, elt, link) \
+ ISC_LIST_UNLINK_TYPE(list, elt, link, void)
+#define ISC_LIST_DEQUEUE_TYPE(list, elt, link, type) \
+ ISC_LIST_UNLINK_TYPE(list, elt, link, type)
+#define __ISC_LIST_DEQUEUEUNSAFE(list, elt, link) \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, void)
+#define __ISC_LIST_DEQUEUEUNSAFE_TYPE(list, elt, link, type) \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type)
+
+#endif /* ISC_LIST_H */
diff --git a/lib/isc/include/isc/log.h b/lib/isc/include/isc/log.h
new file mode 100644
index 0000000..c381775
--- /dev/null
+++ b/lib/isc/include/isc/log.h
@@ -0,0 +1,913 @@
+/*
+ * Copyright (C) 2004, 2005 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: log.h,v 1.47.18.3 2005/04/29 00:16:58 marka Exp $ */
+
+#ifndef ISC_LOG_H
+#define ISC_LOG_H 1
+
+/*! \file */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h> /* XXXDCL NT */
+
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+/*@{*/
+/*!
+ * \brief Severity levels, patterned after Unix's syslog levels.
+ *
+ */
+#define ISC_LOG_DEBUG(level) (level)
+/*!
+ * #ISC_LOG_DYNAMIC can only be used for defining channels with
+ * isc_log_createchannel(), not to specify a level in isc_log_write().
+ */
+#define ISC_LOG_DYNAMIC 0
+#define ISC_LOG_INFO (-1)
+#define ISC_LOG_NOTICE (-2)
+#define ISC_LOG_WARNING (-3)
+#define ISC_LOG_ERROR (-4)
+#define ISC_LOG_CRITICAL (-5)
+/*@}*/
+
+/*@{*/
+/*!
+ * \brief Destinations.
+ */
+#define ISC_LOG_TONULL 1
+#define ISC_LOG_TOSYSLOG 2
+#define ISC_LOG_TOFILE 3
+#define ISC_LOG_TOFILEDESC 4
+/*@}*/
+
+/*@{*/
+/*%
+ * Channel flags.
+ */
+#define ISC_LOG_PRINTTIME 0x0001
+#define ISC_LOG_PRINTLEVEL 0x0002
+#define ISC_LOG_PRINTCATEGORY 0x0004
+#define ISC_LOG_PRINTMODULE 0x0008
+#define ISC_LOG_PRINTTAG 0x0010
+#define ISC_LOG_PRINTALL 0x001F
+#define ISC_LOG_DEBUGONLY 0x1000
+#define ISC_LOG_OPENERR 0x8000 /* internal */
+/*@}*/
+
+/*@{*/
+/*!
+ * \brief Other options.
+ *
+ * XXXDCL INFINITE doesn't yet work. Arguably it isn't needed, but
+ * since I am intend to make large number of versions work efficiently,
+ * INFINITE is going to be trivial to add to that.
+ */
+#define ISC_LOG_ROLLINFINITE (-1)
+#define ISC_LOG_ROLLNEVER (-2)
+/*@}*/
+
+/*!
+ * \brief Used to name the categories used by a library.
+ *
+ * An array of isc_logcategory
+ * structures names each category, and the id value is initialized by calling
+ * isc_log_registercategories.
+ */
+struct isc_logcategory {
+ const char *name;
+ unsigned int id;
+};
+
+/*%
+ * Similar to isc_logcategory, but for all the modules a library defines.
+ */
+struct isc_logmodule {
+ const char *name;
+ unsigned int id;
+};
+
+/*%
+ * The isc_logfile structure is initialized as part of an isc_logdestination
+ * before calling isc_log_createchannel().
+ *
+ * When defining an #ISC_LOG_TOFILE
+ * channel the name, versions and maximum_size should be set before calling
+ * isc_log_createchannel(). To define an #ISC_LOG_TOFILEDESC channel set only
+ * the stream before the call.
+ *
+ * Setting maximum_size to zero implies no maximum.
+ */
+typedef struct isc_logfile {
+ FILE *stream; /*%< Initialized to NULL for #ISC_LOG_TOFILE. */
+ const char *name; /*%< NULL for #ISC_LOG_TOFILEDESC. */
+ int versions; /* >= 0, #ISC_LOG_ROLLNEVER, #ISC_LOG_ROLLINFINITE. */
+ /*%
+ * stdio's ftell is standardized to return a long, which may well not
+ * be big enough for the largest file supportable by the operating
+ * system (though it is _probably_ big enough for the largest log
+ * anyone would want). st_size returned by fstat should be typedef'd
+ * to a size large enough for the largest possible file on a system.
+ */
+ isc_offset_t maximum_size;
+ isc_boolean_t maximum_reached; /*%< Private. */
+} isc_logfile_t;
+
+/*%
+ * Passed to isc_log_createchannel to define the attributes of either
+ * a stdio or a syslog log.
+ */
+typedef union isc_logdestination {
+ isc_logfile_t file;
+ int facility; /* XXXDCL NT */
+} isc_logdestination_t;
+
+/*@{*/
+/*%
+ * The built-in categories of libisc.
+ *
+ * Each library registering categories should provide library_LOGCATEGORY_name
+ * definitions with indexes into its isc_logcategory structure corresponding to
+ * the order of the names.
+ */
+LIBISC_EXTERNAL_DATA extern isc_logcategory_t isc_categories[];
+LIBISC_EXTERNAL_DATA extern isc_log_t *isc_lctx;
+LIBISC_EXTERNAL_DATA extern isc_logmodule_t isc_modules[];
+/*@}*/
+
+/*@{*/
+/*%
+ * Do not log directly to DEFAULT. Use another category. When in doubt,
+ * use GENERAL.
+ */
+#define ISC_LOGCATEGORY_DEFAULT (&isc_categories[0])
+#define ISC_LOGCATEGORY_GENERAL (&isc_categories[1])
+/*@}*/
+
+#define ISC_LOGMODULE_SOCKET (&isc_modules[0])
+#define ISC_LOGMODULE_TIME (&isc_modules[1])
+#define ISC_LOGMODULE_INTERFACE (&isc_modules[2])
+#define ISC_LOGMODULE_TIMER (&isc_modules[3])
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp);
+/*%<
+ * Establish a new logging context, with default channels.
+ *
+ * Notes:
+ *\li isc_log_create() calls isc_logconfig_create(), so see its comment
+ * below for more information.
+ *
+ * Requires:
+ *\li mctx is a valid memory context.
+ *\li lctxp is not null and *lctxp is null.
+ *\li lcfgp is null or lcfgp is not null and *lcfgp is null.
+ *
+ * Ensures:
+ *\li *lctxp will point to a valid logging context if all of the necessary
+ * memory was allocated, or NULL otherwise.
+ *\li *lcfgp will point to a valid logging configuration if all of the
+ * necessary memory was allocated, or NULL otherwise.
+ *\li On failure, no additional memory is allocated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of memory
+ */
+
+isc_result_t
+isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp);
+/*%<
+ * Create the data structure that holds all of the configurable information
+ * about where messages are actually supposed to be sent -- the information
+ * that could changed based on some configuration file, as opposed to the
+ * the category/module specification of isc_log_[v]write[1] that is compiled
+ * into a program, or the debug_level which is dynamic state information.
+ *
+ * Notes:
+ *\li It is necessary to specify the logging context the configuration
+ * will be used with because the number of categories and modules
+ * needs to be known in order to set the configuration. However,
+ * the configuration is not used by the logging context until the
+ * isc_logconfig_use function is called.
+ *
+ *\li The memory context used for operations that allocate memory for
+ * the configuration is that of the logging context, as specified
+ * in the isc_log_create call.
+ *
+ *\li Four default channels are established:
+ *\verbatim
+ * default_syslog
+ * - log to syslog's daemon facility #ISC_LOG_INFO or higher
+ * default_stderr
+ * - log to stderr #ISC_LOG_INFO or higher
+ * default_debug
+ * - log to stderr #ISC_LOG_DEBUG dynamically
+ * null
+ * - log nothing
+ *\endverbatim
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li lcftp is not null and *lcfgp is null.
+ *
+ * Ensures:
+ *\li *lcfgp will point to a valid logging context if all of the necessary
+ * memory was allocated, or NULL otherwise.
+ *\li On failure, no additional memory is allocated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of memory
+ */
+
+isc_logconfig_t *
+isc_logconfig_get(isc_log_t *lctx);
+/*%<
+ * Returns a pointer to the configuration currently in use by the log context.
+ *
+ * Requires:
+ *\li lctx is a valid context.
+ *
+ * Ensures:
+ *\li The configuration pointer is non-null.
+ *
+ * Returns:
+ *\li The configuration pointer.
+ */
+
+isc_result_t
+isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg);
+/*%<
+ * Associate a new configuration with a logging context.
+ *
+ * Notes:
+ *\li This is thread safe. The logging context will lock a mutex
+ * before attempting to swap in the new configuration, and isc_log_doit
+ * (the internal function used by all of isc_log_[v]write[1]) locks
+ * the same lock for the duration of its use of the configuration.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li lcfg is a valid logging configuration.
+ *\li lctx is the same configuration given to isc_logconfig_create
+ * when the configuration was created.
+ *
+ * Ensures:
+ *\li Future calls to isc_log_write will use the new configuration.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of memory
+ */
+
+void
+isc_log_destroy(isc_log_t **lctxp);
+/*%<
+ * Deallocate the memory associated with a logging context.
+ *
+ * Requires:
+ *\li *lctx is a valid logging context.
+ *
+ * Ensures:
+ *\li All of the memory associated with the logging context is returned
+ * to the free memory pool.
+ *
+ *\li Any open files are closed.
+ *
+ *\li The logging context is marked as invalid.
+ */
+
+void
+isc_logconfig_destroy(isc_logconfig_t **lcfgp);
+/*%<
+ * Destroy a logging configuration.
+ *
+ * Notes:
+ *\li This function cannot be used directly with the return value of
+ * isc_logconfig_get, because a logging context must always have
+ * a valid configuration associated with it.
+ *
+ * Requires:
+ *\li lcfgp is not null and *lcfgp is a valid logging configuration.
+ *\li The logging configuration is not in use by an existing logging context.
+ *
+ * Ensures:
+ *\li All memory allocated for the configuration is freed.
+ *
+ *\li The configuration is marked as invalid.
+ */
+
+void
+isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]);
+/*%<
+ * Identify logging categories a library will use.
+ *
+ * Notes:
+ *\li A category should only be registered once, but no mechanism enforces
+ * this rule.
+ *
+ *\li The end of the categories array is identified by a NULL name.
+ *
+ *\li Because the name is used by #ISC_LOG_PRINTCATEGORY, it should not
+ * be altered or destroyed after isc_log_registercategories().
+ *
+ *\li Because each element of the categories array is used by
+ * isc_log_categorybyname, it should not be altered or destroyed
+ * after registration.
+ *
+ *\li The value of the id integer in each structure is overwritten
+ * by this function, and so id need not be initialized to any particular
+ * value prior to the function call.
+ *
+ *\li A subsequent call to isc_log_registercategories with the same
+ * logging context (but new categories) will cause the last
+ * element of the categories array from the prior call to have
+ * its "name" member changed from NULL to point to the new
+ * categories array, and its "id" member set to UINT_MAX.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li categories != NULL.
+ *\li categories[0].name != NULL.
+ *
+ * Ensures:
+ * \li There are references to each category in the logging context,
+ * so they can be used with isc_log_usechannel() and isc_log_write().
+ */
+
+void
+isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]);
+/*%<
+ * Identify logging categories a library will use.
+ *
+ * Notes:
+ *\li A module should only be registered once, but no mechanism enforces
+ * this rule.
+ *
+ *\li The end of the modules array is identified by a NULL name.
+ *
+ *\li Because the name is used by #ISC_LOG_PRINTMODULE, it should not
+ * be altered or destroyed after isc_log_registermodules().
+ *
+ *\li Because each element of the modules array is used by
+ * isc_log_modulebyname, it should not be altered or destroyed
+ * after registration.
+ *
+ *\li The value of the id integer in each structure is overwritten
+ * by this function, and so id need not be initialized to any particular
+ * value prior to the function call.
+ *
+ *\li A subsequent call to isc_log_registermodules with the same
+ * logging context (but new modules) will cause the last
+ * element of the modules array from the prior call to have
+ * its "name" member changed from NULL to point to the new
+ * modules array, and its "id" member set to UINT_MAX.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li modules != NULL.
+ *\li modules[0].name != NULL;
+ *
+ * Ensures:
+ *\li Each module has a reference in the logging context, so they can be
+ * used with isc_log_usechannel() and isc_log_write().
+ */
+
+isc_result_t
+isc_log_createchannel(isc_logconfig_t *lcfg, const char *name,
+ unsigned int type, int level,
+ const isc_logdestination_t *destination,
+ unsigned int flags);
+/*%<
+ * Specify the parameters of a logging channel.
+ *
+ * Notes:
+ *\li The name argument is copied to memory in the logging context, so
+ * it can be altered or destroyed after isc_log_createchannel().
+ *
+ *\li Defining a very large number of channels will have a performance
+ * impact on isc_log_usechannel(), since the names are searched
+ * linearly until a match is made. This same issue does not affect
+ * isc_log_write, however.
+ *
+ *\li Channel names can be redefined; this is primarily useful for programs
+ * that want their own definition of default_syslog, default_debug
+ * and default_stderr.
+ *
+ *\li Any channel that is redefined will not affect logging that was
+ * already directed to its original definition, _except_ for the
+ * default_stderr channel. This case is handled specially so that
+ * the default logging category can be changed by redefining
+ * default_stderr. (XXXDCL Though now that I think of it, the default
+ * logging category can be changed with only one additional function
+ * call by defining a new channel and then calling isc_log_usechannel()
+ * for #ISC_LOGCATEGORY_DEFAULT.)
+ *
+ *\li Specifying #ISC_LOG_PRINTTIME or #ISC_LOG_PRINTTAG for syslog is allowed,
+ * but probably not what you wanted to do.
+ *
+ * #ISC_LOG_DEBUGONLY will mark the channel as usable only when the
+ * debug level of the logging context (see isc_log_setdebuglevel)
+ * is non-zero.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ *\li name is not NULL.
+ *
+ *\li type is #ISC_LOG_TOSYSLOG, #ISC_LOG_TOFILE, #ISC_LOG_TOFILEDESC or
+ * #ISC_LOG_TONULL.
+ *
+ *\li destination is not NULL unless type is #ISC_LOG_TONULL.
+ *
+ *\li level is >= #ISC_LOG_CRITICAL (the most negative logging level).
+ *
+ *\li flags does not include any bits aside from the ISC_LOG_PRINT* bits
+ * or #ISC_LOG_DEBUGONLY.
+ *
+ * Ensures:
+ *\li #ISC_R_SUCCESS
+ * A channel with the given name is usable with
+ * isc_log_usechannel().
+ *
+ *\li #ISC_R_NOMEMORY or #ISC_R_UNEXPECTED
+ * No additional memory is being used by the logging context.
+ * Any channel that previously existed with the given name
+ * is not redefined.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of memory
+ *\li #ISC_R_UNEXPECTED type was out of range and REQUIRE()
+ * was disabled.
+ */
+
+isc_result_t
+isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
+ const isc_logcategory_t *category,
+ const isc_logmodule_t *module);
+/*%<
+ * Associate a named logging channel with a category and module that
+ * will use it.
+ *
+ * Notes:
+ *\li The name is searched for linearly in the set of known channel names
+ * until a match is found. (Note the performance impact of a very large
+ * number of named channels.) When multiple channels of the same
+ * name are defined, the most recent definition is found.
+ *
+ *\li Specifing a very large number of channels for a category will have
+ * a moderate impact on performance in isc_log_write(), as each
+ * call looks up the category for the start of a linked list, which
+ * it follows all the way to the end to find matching modules. The
+ * test for matching modules is integral, though.
+ *
+ *\li If category is NULL, then the channel is associated with the indicated
+ * module for all known categories (including the "default" category).
+ *
+ *\li If module is NULL, then the channel is associated with every module
+ * that uses that category.
+ *
+ *\li Passing both category and module as NULL would make every log message
+ * use the indicated channel.
+ *
+ * \li Specifying a channel that is #ISC_LOG_TONULL for a category/module pair
+ * has no effect on any other channels associated with that pair,
+ * regardless of ordering. Thus you cannot use it to "mask out" one
+ * category/module pair when you have specified some other channel that
+ * is also used by that category/module pair.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ *\li category is NULL or has an id that is in the range of known ids.
+ *
+ * module is NULL or has an id that is in the range of known ids.
+ *
+ * Ensures:
+ *\li #ISC_R_SUCCESS
+ * The channel will be used by the indicated category/module
+ * arguments.
+ *
+ *\li #ISC_R_NOMEMORY
+ * If assignment for a specific category has been requested,
+ * the channel has not been associated with the indicated
+ * category/module arguments and no additional memory is
+ * used by the logging context.
+ * If assignment for all categories has been requested
+ * then _some_ may have succeeded (starting with category
+ * "default" and progressing through the order of categories
+ * passed to isc_log_registercategories()) and additional memory
+ * is being used by whatever assignments succeeded.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of memory
+ */
+
+/* Attention: next four comments PRECEED code */
+/*!
+ * \brief
+ * Write a message to the log channels.
+ *
+ * Notes:
+ *\li Log messages containing natural language text should be logged with
+ * isc_log_iwrite() to allow for localization.
+ *
+ *\li lctx can be NULL; this is allowed so that programs which use
+ * libraries that use the ISC logging system are not required to
+ * also use it.
+ *
+ *\li The format argument is a printf(3) string, with additional arguments
+ * as necessary.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ *\li The category and module arguments must have ids that are in the
+ * range of known ids, as estabished by isc_log_registercategories()
+ * and isc_log_registermodules().
+ *
+ *\li level != #ISC_LOG_DYNAMIC. ISC_LOG_DYNAMIC is used only to define
+ * channels, and explicit debugging level must be identified for
+ * isc_log_write() via ISC_LOG_DEBUG(level).
+ *
+ *\li format != NULL.
+ *
+ * Ensures:
+ *\li The log message is written to every channel associated with the
+ * indicated category/module pair.
+ *
+ * Returns:
+ *\li Nothing. Failure to log a message is not construed as a
+ * meaningful error.
+ */
+void
+isc_log_write(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ const char *format, ...)
+
+ISC_FORMAT_PRINTF(5, 6);
+
+/*%
+ * Write a message to the log channels.
+ *
+ * Notes:
+ *\li lctx can be NULL; this is allowed so that programs which use
+ * libraries that use the ISC logging system are not required to
+ * also use it.
+ *
+ *\li The format argument is a printf(3) string, with additional arguments
+ * as necessary.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ *\li The category and module arguments must have ids that are in the
+ * range of known ids, as estabished by isc_log_registercategories()
+ * and isc_log_registermodules().
+ *
+ *\li level != #ISC_LOG_DYNAMIC. ISC_LOG_DYNAMIC is used only to define
+ * channels, and explicit debugging level must be identified for
+ * isc_log_write() via ISC_LOG_DEBUG(level).
+ *
+ *\li format != NULL.
+ *
+ * Ensures:
+ *\li The log message is written to every channel associated with the
+ * indicated category/module pair.
+ *
+ * Returns:
+ *\li Nothing. Failure to log a message is not construed as a
+ * meaningful error.
+ */
+void
+isc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ const char *format, va_list args)
+
+ISC_FORMAT_PRINTF(5, 0);
+
+/*%
+ * Write a message to the log channels, pruning duplicates that occur within
+ * a configurable amount of seconds (see isc_log_[sg]etduplicateinterval).
+ * This function is otherwise identical to isc_log_write().
+ */
+void
+isc_log_write1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format, ...)
+
+ISC_FORMAT_PRINTF(5, 6);
+
+/*%
+ * Write a message to the log channels, pruning duplicates that occur within
+ * a configurable amount of seconds (see isc_log_[sg]etduplicateinterval).
+ * This function is otherwise identical to isc_log_vwrite().
+ */
+void
+isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format,
+ va_list args)
+
+ISC_FORMAT_PRINTF(5, 0);
+
+/*%
+ * These are four internationalized versions of the the isc_log_[v]write[1]
+ * functions.
+ *
+ * The only difference is that they take arguments for a message
+ * catalog, message set, and message number, all immediately preceding the
+ * format argument. The format argument becomes the default text, a la
+ * isc_msgcat_get. If the message catalog is NULL, no lookup is attempted
+ * for a message -- which makes the message set and message number irrelevant,
+ * and the non-internationalized call should have probably been used instead.
+ *
+ * Yes, that means there are now *eight* interfaces to logging a message.
+ * Sheesh. Make the madness stop!
+ */
+/*@{*/
+void
+isc_log_iwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *format, ...)
+ISC_FORMAT_PRINTF(8, 9);
+
+void
+isc_log_ivwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *format, va_list args)
+ISC_FORMAT_PRINTF(8, 0);
+
+void
+isc_log_iwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *format, ...)
+ISC_FORMAT_PRINTF(8, 9);
+
+void
+isc_log_ivwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *format, va_list args)
+ISC_FORMAT_PRINTF(8, 0);
+/*@}*/
+
+void
+isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level);
+/*%<
+ * Set the debugging level used for logging.
+ *
+ * Notes:
+ *\li Setting the debugging level to 0 disables debugging log messages.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ * Ensures:
+ *\li The debugging level is set to the requested value.
+ */
+
+unsigned int
+isc_log_getdebuglevel(isc_log_t *lctx);
+/*%<
+ * Get the current debugging level.
+ *
+ * Notes:
+ *\li This is provided so that a program can have a notion of
+ * "increment debugging level" or "decrement debugging level"
+ * without needing to keep track of what the current level is.
+ *
+ *\li A return value of 0 indicates that debugging messages are disabled.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ * Ensures:
+ *\li The current logging debugging level is returned.
+ */
+
+isc_boolean_t
+isc_log_wouldlog(isc_log_t *lctx, int level);
+/*%<
+ * Determine whether logging something to 'lctx' at 'level' would
+ * actually cause something to be logged somewhere.
+ *
+ * If #ISC_FALSE is returned, it is guaranteed that nothing would
+ * be logged, allowing the caller to omit unnecessary
+ * isc_log_write() calls and possible message preformatting.
+ */
+
+void
+isc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval);
+/*%<
+ * Set the interval over which duplicate log messages will be ignored
+ * by isc_log_[v]write1(), in seconds.
+ *
+ * Notes:
+ *\li Increasing the duplicate interval from X to Y will not necessarily
+ * filter out duplicates of messages logged in Y - X seconds since the
+ * increase. (Example: Message1 is logged at midnight. Message2
+ * is logged at 00:01:00, when the interval is only 30 seconds, causing
+ * Message1 to be expired from the log message history. Then the interval
+ * is increased to 3000 (five minutes) and at 00:04:00 Message1 is logged
+ * again. It will appear the second time even though less than five
+ * passed since the first occurrence.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ */
+
+unsigned int
+isc_log_getduplicateinterval(isc_logconfig_t *lcfg);
+/*%<
+ * Get the current duplicate filtering interval.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ * Returns:
+ *\li The current duplicate filtering interval.
+ */
+
+isc_result_t
+isc_log_settag(isc_logconfig_t *lcfg, const char *tag);
+/*%<
+ * Set the program name or other identifier for #ISC_LOG_PRINTTAG.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ * Notes:
+ *\li If this function has not set the tag to a non-NULL, non-empty value,
+ * then the #ISC_LOG_PRINTTAG channel flag will not print anything.
+ * Unlike some implementations of syslog on Unix systems, you *must* set
+ * the tag in order to get it logged. It is not implicitly derived from
+ * the program name (which is pretty impossible to infer portably).
+ *
+ *\li Setting the tag to NULL or the empty string will also cause the
+ * #ISC_LOG_PRINTTAG channel flag to not print anything. If tag equals the
+ * empty string, calls to isc_log_gettag will return NULL.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource Limit: Out of memory
+ *
+ * XXXDCL when creating a new isc_logconfig_t, it might be nice if the tag
+ * of the currently active isc_logconfig_t was inherited. this does not
+ * currently happen.
+ */
+
+char *
+isc_log_gettag(isc_logconfig_t *lcfg);
+/*%<
+ * Get the current identifier printed with #ISC_LOG_PRINTTAG.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ * Notes:
+ *\li Since isc_log_settag() will not associate a zero-length string
+ * with the logging configuration, attempts to do so will cause
+ * this function to return NULL. However, a determined programmer
+ * will observe that (currently) a tag of length greater than zero
+ * could be set, and then modified to be zero length.
+ *
+ * Returns:
+ *\li A pointer to the current identifier, or NULL if none has been set.
+ */
+
+void
+isc_log_opensyslog(const char *tag, int options, int facility);
+/*%<
+ * Initialize syslog logging.
+ *
+ * Notes:
+ *\li XXXDCL NT
+ * This is currently equivalent to openlog(), but is not going to remain
+ * that way. In the meantime, the arguments are all identical to
+ * those used by openlog(3), as follows:
+ *
+ * \code
+ * tag: The string to use in the position of the program
+ * name in syslog messages. Most (all?) syslogs
+ * will use basename(argv[0]) if tag is NULL.
+ *
+ * options: LOG_CONS, LOG_PID, LOG_NDELAY ... whatever your
+ * syslog supports.
+ *
+ * facility: The default syslog facility. This is irrelevant
+ * since isc_log_write will ALWAYS use the channel's
+ * declared facility.
+ * \endcode
+ *
+ *\li Zero effort has been made (yet) to accomodate systems with openlog()
+ * that only takes two arguments, or to identify valid syslog
+ * facilities or options for any given architecture.
+ *
+ *\li It is necessary to call isc_log_opensyslog() to initialize
+ * syslogging on machines which do not support network connections to
+ * syslogd because they require a Unix domain socket to be used. Since
+ * this is a chore to determine at run-time, it is suggested that it
+ * always be called by programs using the ISC logging system.
+ *
+ * Requires:
+ *\li Nothing.
+ *
+ * Ensures:
+ *\li openlog() is called to initialize the syslog system.
+ */
+
+void
+isc_log_closefilelogs(isc_log_t *lctx);
+/*%<
+ * Close all open files used by #ISC_LOG_TOFILE channels.
+ *
+ * Notes:
+ *\li This function is provided for programs that want to use their own
+ * log rolling mechanism rather than the one provided internally.
+ * For example, a program that wanted to keep daily logs would define
+ * a channel which used #ISC_LOG_ROLLNEVER, then once a day would
+ * rename the log file and call isc_log_closefilelogs().
+ *
+ *\li #ISC_LOG_TOFILEDESC channels are unaffected.
+ *
+ * Requires:
+ *\li lctx is a valid context.
+ *
+ * Ensures:
+ *\li The open files are closed and will be reopened when they are
+ * next needed.
+ */
+
+isc_logcategory_t *
+isc_log_categorybyname(isc_log_t *lctx, const char *name);
+/*%<
+ * Find a category by its name.
+ *
+ * Notes:
+ *\li The string name of a category is not required to be unique.
+ *
+ * Requires:
+ *\li lctx is a valid context.
+ *\li name is not NULL.
+ *
+ * Returns:
+ *\li A pointer to the _first_ isc_logcategory_t structure used by "name".
+ *
+ *\li NULL if no category exists by that name.
+ */
+
+isc_logmodule_t *
+isc_log_modulebyname(isc_log_t *lctx, const char *name);
+/*%<
+ * Find a module by its name.
+ *
+ * Notes:
+ *\li The string name of a module is not required to be unique.
+ *
+ * Requires:
+ *\li lctx is a valid context.
+ *\li name is not NULL.
+ *
+ * Returns:
+ *\li A pointer to the _first_ isc_logmodule_t structure used by "name".
+ *
+ *\li NULL if no module exists by that name.
+ */
+
+void
+isc_log_setcontext(isc_log_t *lctx);
+/*%<
+ * Sets the context used by the libisc for logging.
+ *
+ * Requires:
+ *\li lctx be a valid context.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_LOG_H */
diff --git a/lib/isc/include/isc/magic.h b/lib/isc/include/isc/magic.h
new file mode 100644
index 0000000..045b54f
--- /dev/null
+++ b/lib/isc/include/isc/magic.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2004, 2005 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: magic.h,v 1.12.18.2 2005/04/29 00:16:59 marka Exp $ */
+
+#ifndef ISC_MAGIC_H
+#define ISC_MAGIC_H 1
+
+/*! \file */
+
+typedef struct {
+ unsigned int magic;
+} isc__magic_t;
+
+
+/*%
+ * To use this macro the magic number MUST be the first thing in the
+ * structure, and MUST be of type "unsigned int".
+ * The intent of this is to allow magic numbers to be checked even though
+ * the object is otherwise opaque.
+ */
+#define ISC_MAGIC_VALID(a,b) (((a) != NULL) && \
+ (((const isc__magic_t *)(a))->magic == (b)))
+
+#define ISC_MAGIC(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
+
+#endif /* ISC_MAGIC_H */
diff --git a/lib/isc/include/isc/md5.h b/lib/isc/include/isc/md5.h
new file mode 100644
index 0000000..3f9667e
--- /dev/null
+++ b/lib/isc/include/isc/md5.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2004-2006 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: md5.h,v 1.9.18.4 2006/02/01 00:10:34 marka Exp $ */
+
+/*! \file
+ * \brief This is the header file for the MD5 message-digest algorithm.
+ *
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ * - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ */
+
+#ifndef ISC_MD5_H
+#define ISC_MD5_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#define ISC_MD5_DIGESTLENGTH 16U
+
+typedef struct {
+ isc_uint32_t buf[4];
+ isc_uint32_t bytes[2];
+ isc_uint32_t in[16];
+} isc_md5_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_md5_init(isc_md5_t *ctx);
+
+void
+isc_md5_invalidate(isc_md5_t *ctx);
+
+void
+isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len);
+
+void
+isc_md5_final(isc_md5_t *ctx, unsigned char *digest);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_MD5_H */
diff --git a/lib/isc/include/isc/mem.h b/lib/isc/include/isc/mem.h
new file mode 100644
index 0000000..dc68bcb
--- /dev/null
+++ b/lib/isc/include/isc/mem.h
@@ -0,0 +1,543 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-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: mem.h,v 1.59.18.9 2006/01/04 23:50:23 marka Exp $ */
+
+#ifndef ISC_MEM_H
+#define ISC_MEM_H 1
+
+/*! \file */
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+#define ISC_MEM_LOWATER 0
+#define ISC_MEM_HIWATER 1
+typedef void (*isc_mem_water_t)(void *, int);
+
+typedef void * (*isc_memalloc_t)(void *, size_t);
+typedef void (*isc_memfree_t)(void *, void *);
+
+/*%
+ * Define ISC_MEM_DEBUG=1 to make all functions that free memory
+ * set the pointer being freed to NULL after being freed.
+ * This is the default; set ISC_MEM_DEBUG=0 to disable it.
+ */
+#ifndef ISC_MEM_DEBUG
+#define ISC_MEM_DEBUG 1
+#endif
+
+/*%
+ * Define ISC_MEM_TRACKLINES=1 to turn on detailed tracing of memory
+ * allocation and freeing by file and line number.
+ */
+#ifndef ISC_MEM_TRACKLINES
+#define ISC_MEM_TRACKLINES 1
+#endif
+
+/*%
+ * Define ISC_MEM_CHECKOVERRUN=1 to turn on checks for using memory outside
+ * the requested space. This will increase the size of each allocation.
+ */
+#ifndef ISC_MEM_CHECKOVERRUN
+#define ISC_MEM_CHECKOVERRUN 1
+#endif
+
+/*%
+ * Define ISC_MEM_FILL=1 to fill each block of memory returned to the system
+ * with the byte string '0xbe'. This helps track down uninitialized pointers
+ * and the like. On freeing memory, the space is filled with '0xde' for
+ * the same reasons.
+ */
+#ifndef ISC_MEM_FILL
+#define ISC_MEM_FILL 1
+#endif
+
+/*%
+ * Define ISC_MEMPOOL_NAMES=1 to make memory pools store a symbolic
+ * name so that the leaking pool can be more readily identified in
+ * case of a memory leak.
+ */
+#ifndef ISC_MEMPOOL_NAMES
+#define ISC_MEMPOOL_NAMES 1
+#endif
+
+LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_debugging;
+/*@{*/
+#define ISC_MEM_DEBUGTRACE 0x00000001U
+#define ISC_MEM_DEBUGRECORD 0x00000002U
+#define ISC_MEM_DEBUGUSAGE 0x00000004U
+#define ISC_MEM_DEBUGSIZE 0x00000008U
+#define ISC_MEM_DEBUGCTX 0x00000010U
+#define ISC_MEM_DEBUGALL 0x0000001FU
+/*!<
+ * The variable isc_mem_debugging holds a set of flags for
+ * turning certain memory debugging options on or off at
+ * runtime. Its is intialized to the value ISC_MEM_DEGBUGGING,
+ * which is 0 by default but may be overridden at compile time.
+ * The following flags can be specified:
+ *
+ * \li #ISC_MEM_DEBUGTRACE
+ * Log each allocation and free to isc_lctx.
+ *
+ * \li #ISC_MEM_DEBUGRECORD
+ * Remember each allocation, and match them up on free.
+ * Crash if a free doesn't match an allocation.
+ *
+ * \li #ISC_MEM_DEBUGUSAGE
+ * If a hi_water mark is set, print the maximium inuse memory
+ * every time it is raised once it exceeds the hi_water mark.
+ *
+ * \li #ISC_MEM_DEBUGSIZE
+ * Check the size argument being passed to isc_mem_put() matches
+ * that passed to isc_mem_get().
+ *
+ * \li #ISC_MEM_DEBUGCTX
+ * Check the mctx argument being passed to isc_mem_put() matches
+ * that passed to isc_mem_get().
+ */
+/*@}*/
+
+#if ISC_MEM_TRACKLINES
+#define _ISC_MEM_FILELINE , __FILE__, __LINE__
+#define _ISC_MEM_FLARG , const char *, int
+#else
+#define _ISC_MEM_FILELINE
+#define _ISC_MEM_FLARG
+#endif
+
+/*!
+ * Define ISC_MEM_USE_INTERNAL_MALLOC=1 to use the internal malloc()
+ * implementation in preference to the system one. The internal malloc()
+ * is very space-efficient, and quite fast on uniprocessor systems. It
+ * performs poorly on multiprocessor machines.
+ * JT: we can overcome the performance issue on multiprocessor machines
+ * by carefully separating memory contexts.
+ */
+
+#ifndef ISC_MEM_USE_INTERNAL_MALLOC
+#define ISC_MEM_USE_INTERNAL_MALLOC 1
+#endif
+
+/*
+ * Flags for isc_mem_create2()calls.
+ */
+#define ISC_MEMFLAG_NOLOCK 0x00000001 /* no lock is necessary */
+#define ISC_MEMFLAG_INTERNAL 0x00000002 /* use internal malloc */
+#if ISC_MEM_USE_INTERNAL_MALLOC
+#define ISC_MEMFLAG_DEFAULT ISC_MEMFLAG_INTERNAL
+#else
+#define ISC_MEMFLAG_DEFAULT 0
+#endif
+
+
+#define isc_mem_get(c, s) isc__mem_get((c), (s) _ISC_MEM_FILELINE)
+#define isc_mem_allocate(c, s) isc__mem_allocate((c), (s) _ISC_MEM_FILELINE)
+#define isc_mem_strdup(c, p) isc__mem_strdup((c), (p) _ISC_MEM_FILELINE)
+#define isc_mempool_get(c) isc__mempool_get((c) _ISC_MEM_FILELINE)
+
+/*%
+ * isc_mem_putanddetach() is a convienence function for use where you
+ * have a structure with an attached memory context.
+ *
+ * Given:
+ *
+ * \code
+ * struct {
+ * ...
+ * isc_mem_t *mctx;
+ * ...
+ * } *ptr;
+ *
+ * isc_mem_t *mctx;
+ *
+ * isc_mem_putanddetach(&ptr->mctx, ptr, sizeof(*ptr));
+ * \endcode
+ *
+ * is the equivalent of:
+ *
+ * \code
+ * mctx = NULL;
+ * isc_mem_attach(ptr->mctx, &mctx);
+ * isc_mem_detach(&ptr->mctx);
+ * isc_mem_put(mctx, ptr, sizeof(*ptr));
+ * isc_mem_detach(&mctx);
+ * \endcode
+ */
+
+#if ISC_MEM_DEBUG
+#define isc_mem_put(c, p, s) \
+ do { \
+ isc__mem_put((c), (p), (s) _ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#define isc_mem_putanddetach(c, p, s) \
+ do { \
+ isc__mem_putanddetach((c), (p), (s) _ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#define isc_mem_free(c, p) \
+ do { \
+ isc__mem_free((c), (p) _ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#define isc_mempool_put(c, p) \
+ do { \
+ isc__mempool_put((c), (p) _ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#else
+#define isc_mem_put(c, p, s) isc__mem_put((c), (p), (s) _ISC_MEM_FILELINE)
+#define isc_mem_putanddetach(c, p, s) \
+ isc__mem_putanddetach((c), (p), (s) _ISC_MEM_FILELINE)
+#define isc_mem_free(c, p) isc__mem_free((c), (p) _ISC_MEM_FILELINE)
+#define isc_mempool_put(c, p) isc__mempool_put((c), (p) _ISC_MEM_FILELINE)
+#endif
+
+/*@{*/
+isc_result_t
+isc_mem_create(size_t max_size, size_t target_size,
+ isc_mem_t **mctxp);
+
+isc_result_t
+isc_mem_create2(size_t max_size, size_t target_size,
+ isc_mem_t **mctxp, unsigned int flags);
+
+isc_result_t
+isc_mem_createx(size_t max_size, size_t target_size,
+ isc_memalloc_t memalloc, isc_memfree_t memfree,
+ void *arg, isc_mem_t **mctxp);
+
+isc_result_t
+isc_mem_createx2(size_t max_size, size_t target_size,
+ isc_memalloc_t memalloc, isc_memfree_t memfree,
+ void *arg, isc_mem_t **mctxp, unsigned int flags);
+
+/*!<
+ * \brief Create a memory context.
+ *
+ * 'max_size' and 'target_size' are tuning parameters. When
+ * ISC_MEMFLAG_INTERNAL is set, allocations smaller than 'max_size'
+ * will be satisfied by getting blocks of size 'target_size' from the
+ * system allocator and breaking them up into pieces; larger allocations
+ * will use the system allocator directly. If 'max_size' and/or
+ * 'target_size' are zero, default values will be * used. When
+ * ISC_MEMFLAG_INTERNAL is not set, 'target_size' is ignored.
+ *
+ * 'max_size' is also used to size the statistics arrays and the array
+ * used to record active memory when ISC_MEM_DEBUGRECORD is set. Settin
+ * 'max_size' too low can have detrimental effects on performance.
+ *
+ * A memory context created using isc_mem_createx() will obtain
+ * memory from the system by calling 'memalloc' and 'memfree',
+ * passing them the argument 'arg'. A memory context created
+ * using isc_mem_create() will use the standard library malloc()
+ * and free().
+ *
+ * If ISC_MEMFLAG_NOLOCK is set in 'flags', the corresponding memory context
+ * will be accessed without locking. The user who creates the context must
+ * ensure there be no race. Since this can be a source of bug, it is generally
+ * inadvisable to use this flag unless the user is very sure about the race
+ * condition and the access to the object is highly performance sensitive.
+ *
+ * Requires:
+ * mctxp != NULL && *mctxp == NULL */
+/*@}*/
+
+/*@{*/
+void
+isc_mem_attach(isc_mem_t *, isc_mem_t **);
+void
+isc_mem_detach(isc_mem_t **);
+/*!<
+ * \brief Attach to / detach from a memory context.
+ *
+ * This is intended for applications that use multiple memory contexts
+ * in such a way that it is not obvious when the last allocations from
+ * a given context has been freed and destroying the context is safe.
+ *
+ * Most applications do not need to call these functions as they can
+ * simply create a single memory context at the beginning of main()
+ * and destroy it at the end of main(), thereby guaranteeing that it
+ * is not destroyed while there are outstanding allocations.
+ */
+/*@}*/
+
+void
+isc_mem_destroy(isc_mem_t **);
+/*%<
+ * Destroy a memory context.
+ */
+
+isc_result_t
+isc_mem_ondestroy(isc_mem_t *ctx,
+ isc_task_t *task,
+ isc_event_t **event);
+/*%<
+ * Request to be notified with an event when a memory context has
+ * been successfully destroyed.
+ */
+
+void
+isc_mem_stats(isc_mem_t *mctx, FILE *out);
+/*%<
+ * Print memory usage statistics for 'mctx' on the stream 'out'.
+ */
+
+void
+isc_mem_setdestroycheck(isc_mem_t *mctx,
+ isc_boolean_t on);
+/*%<
+ * If 'on' is ISC_TRUE, 'mctx' will check for memory leaks when
+ * destroyed and abort the program if any are present.
+ */
+
+/*@{*/
+void
+isc_mem_setquota(isc_mem_t *, size_t);
+size_t
+isc_mem_getquota(isc_mem_t *);
+/*%<
+ * Set/get the memory quota of 'mctx'. This is a hard limit
+ * on the amount of memory that may be allocated from mctx;
+ * if it is exceeded, allocations will fail.
+ */
+/*@}*/
+
+size_t
+isc_mem_inuse(isc_mem_t *mctx);
+/*%<
+ * Get an estimate of the number of memory in use in 'mctx', in bytes.
+ * This includes quantization overhead, but does not include memory
+ * allocated from the system but not yet used.
+ */
+
+void
+isc_mem_setwater(isc_mem_t *mctx, isc_mem_water_t water, void *water_arg,
+ size_t hiwater, size_t lowater);
+/*%<
+ * Set high and low water marks for this memory context.
+ *
+ * When the memory
+ * usage of 'mctx' exceeds 'hiwater', '(water)(water_arg, #ISC_MEM_HIWATER)'
+ * will be called. When the usage drops below 'lowater', 'water' will
+ * again be called, this time with #ISC_MEM_LOWATER.
+ *
+ * If 'water' is NULL then 'water_arg', 'hi_water' and 'lo_water' are
+ * ignored and the state is reset.
+ *
+ * Requires:
+ *
+ * 'water' is not NULL.
+ * hi_water >= lo_water
+ */
+
+void
+isc_mem_printactive(isc_mem_t *mctx, FILE *file);
+/*%<
+ * Print to 'file' all active memory in 'mctx'.
+ *
+ * Requires ISC_MEM_DEBUGRECORD to have been set.
+ */
+
+void
+isc_mem_printallactive(FILE *file);
+/*%<
+ * Print to 'file' all active memory in all contexts.
+ *
+ * Requires ISC_MEM_DEBUGRECORD to have been set.
+ */
+
+void
+isc_mem_checkdestroyed(FILE *file);
+/*%<
+ * Check that all memory contexts have been destroyed.
+ * Prints out those that have not been.
+ * Fatally fails if there are still active contexts.
+ */
+
+/*
+ * Memory pools
+ */
+
+isc_result_t
+isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
+/*%<
+ * Create a memory pool.
+ *
+ * Requires:
+ *\li mctx is a valid memory context.
+ *\li size > 0
+ *\li mpctxp != NULL and *mpctxp == NULL
+ *
+ * Defaults:
+ *\li maxalloc = UINT_MAX
+ *\li freemax = 1
+ *\li fillcount = 1
+ *
+ * Returns:
+ *\li #ISC_R_NOMEMORY -- not enough memory to create pool
+ *\li #ISC_R_SUCCESS -- all is well.
+ */
+
+void
+isc_mempool_destroy(isc_mempool_t **mpctxp);
+/*%<
+ * Destroy a memory pool.
+ *
+ * Requires:
+ *\li mpctxp != NULL && *mpctxp is a valid pool.
+ *\li The pool has no un"put" allocations outstanding
+ */
+
+void
+isc_mempool_setname(isc_mempool_t *mpctx, const char *name);
+/*%<
+ * Associate a name with a memory pool. At most 15 characters may be used.
+ *
+ * Requires:
+ *\li mpctx is a valid pool.
+ *\li name != NULL;
+ */
+
+void
+isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
+/*%<
+ * Associate a lock with this memory pool.
+ *
+ * This lock is used when getting or putting items using this memory pool,
+ * and it is also used to set or get internal state via the isc_mempool_get*()
+ * and isc_mempool_set*() set of functions.
+ *
+ * Mutiple pools can each share a single lock. For instance, if "manager"
+ * type object contained pools for various sizes of events, and each of
+ * these pools used a common lock. Note that this lock must NEVER be used
+ * by other than mempool routines once it is given to a pool, since that can
+ * easily cause double locking.
+ *
+ * Requires:
+ *
+ *\li mpctpx is a valid pool.
+ *
+ *\li lock != NULL.
+ *
+ *\li No previous lock is assigned to this pool.
+ *
+ *\li The lock is initialized before calling this function via the normal
+ * means of doing that.
+ */
+
+/*
+ * The following functions get/set various parameters. Note that due to
+ * the unlocked nature of pools these are potentially random values unless
+ * the imposed externally provided locking protocols are followed.
+ *
+ * Also note that the quota limits will not always take immediate effect.
+ * For instance, setting "maxalloc" to a number smaller than the currently
+ * allocated count is permitted. New allocations will be refused until
+ * the count drops below this threshold.
+ *
+ * All functions require (in addition to other requirements):
+ * mpctx is a valid memory pool
+ */
+
+unsigned int
+isc_mempool_getfreemax(isc_mempool_t *mpctx);
+/*%<
+ * Returns the maximum allowed size of the free list.
+ */
+
+void
+isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
+/*%<
+ * Sets the maximum allowed size of the free list.
+ */
+
+unsigned int
+isc_mempool_getfreecount(isc_mempool_t *mpctx);
+/*%<
+ * Returns current size of the free list.
+ */
+
+unsigned int
+isc_mempool_getmaxalloc(isc_mempool_t *mpctx);
+/*!<
+ * Returns the maximum allowed number of allocations.
+ */
+
+void
+isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
+/*%<
+ * Sets the maximum allowed number of allocations.
+ *
+ * Additional requirements:
+ *\li limit > 0
+ */
+
+unsigned int
+isc_mempool_getallocated(isc_mempool_t *mpctx);
+/*%<
+ * Returns the number of items allocated from this pool.
+ */
+
+unsigned int
+isc_mempool_getfillcount(isc_mempool_t *mpctx);
+/*%<
+ * Returns the number of items allocated as a block from the parent memory
+ * context when the free list is empty.
+ */
+
+void
+isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
+/*%<
+ * Sets the fillcount.
+ *
+ * Additional requirements:
+ *\li limit > 0
+ */
+
+
+/*
+ * Pseudo-private functions for use via macros. Do not call directly.
+ */
+void *
+isc__mem_get(isc_mem_t *, size_t _ISC_MEM_FLARG);
+void
+isc__mem_putanddetach(isc_mem_t **, void *,
+ size_t _ISC_MEM_FLARG);
+void
+isc__mem_put(isc_mem_t *, void *, size_t _ISC_MEM_FLARG);
+void *
+isc__mem_allocate(isc_mem_t *, size_t _ISC_MEM_FLARG);
+void
+isc__mem_free(isc_mem_t *, void * _ISC_MEM_FLARG);
+char *
+isc__mem_strdup(isc_mem_t *, const char *_ISC_MEM_FLARG);
+void *
+isc__mempool_get(isc_mempool_t * _ISC_MEM_FLARG);
+void
+isc__mempool_put(isc_mempool_t *, void * _ISC_MEM_FLARG);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_MEM_H */
diff --git a/lib/isc/include/isc/msgcat.h b/lib/isc/include/isc/msgcat.h
new file mode 100644
index 0000000..813b57c
--- /dev/null
+++ b/lib/isc/include/isc/msgcat.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2004, 2005 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: msgcat.h,v 1.9.18.2 2005/04/29 00:16:59 marka Exp $ */
+
+#ifndef ISC_MSGCAT_H
+#define ISC_MSGCAT_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/msgcat.h
+ * \brief The ISC Message Catalog
+ * aids internationalization of applications by allowing
+ * messages to be retrieved from locale-specific files instead of
+ * hardwiring them into the application. This allows translations of
+ * messages appropriate to the locale to be supplied without recompiling
+ * the application.
+ *
+ * Notes:
+ *\li It's very important that message catalogs work, even if only the
+ * default_text can be used.
+ *
+ * MP:
+ *\li The caller must ensure appropriate synchronization of
+ * isc_msgcat_open() and isc_msgcat_close(). isc_msgcat_get()
+ * ensures appropriate synchronization.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/*****
+ ***** Imports
+ *****/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Methods
+ *****/
+
+void
+isc_msgcat_open(const char *name, isc_msgcat_t **msgcatp);
+/*%<
+ * Open a message catalog.
+ *
+ * Notes:
+ *
+ *\li If memory cannot be allocated or other failures occur, *msgcatp
+ * will be set to NULL. If a NULL msgcat is given to isc_msgcat_get(),
+ * the default_text will be returned, ensuring that some message text
+ * will be available, no matter what's going wrong.
+ *
+ * Requires:
+ *
+ *\li 'name' is a valid string.
+ *
+ *\li msgcatp != NULL && *msgcatp == NULL
+ */
+
+void
+isc_msgcat_close(isc_msgcat_t **msgcatp);
+/*%<
+ * Close a message catalog.
+ *
+ * Notes:
+ *
+ *\li Any string pointers returned by prior calls to isc_msgcat_get() are
+ * invalid after isc_msgcat_close() has been called and must not be
+ * used.
+ *
+ * Requires:
+ *
+ *\li *msgcatp is a valid message catalog or is NULL.
+ *
+ * Ensures:
+ *
+ *\li All resources associated with the message catalog are released.
+ *
+ *\li *msgcatp == NULL
+ */
+
+const char *
+isc_msgcat_get(isc_msgcat_t *msgcat, int set, int message,
+ const char *default_text);
+/*%<
+ * Get message 'message' from message set 'set' in 'msgcat'. If it
+ * is not available, use 'default_text'.
+ *
+ * Requires:
+ *
+ *\li 'msgcat' is a valid message catalog or is NULL.
+ *
+ *\li set > 0
+ *
+ *\li message > 0
+ *
+ *\li 'default_text' is a valid string.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_MSGCAT_H */
diff --git a/lib/isc/include/isc/msgs.h b/lib/isc/include/isc/msgs.h
new file mode 100644
index 0000000..97b2108
--- /dev/null
+++ b/lib/isc/include/isc/msgs.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2004, 2005 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: msgs.h,v 1.9.18.2 2005/04/29 00:16:59 marka Exp $ */
+
+#ifndef ISC_MSGS_H
+#define ISC_MSGS_H 1
+
+/*! \file */
+
+#include <isc/lib.h> /* Provide isc_msgcat global variable. */
+#include <isc/msgcat.h> /* Provide isc_msgcat_*() functions. */
+
+/*@{*/
+/*!
+ * \brief Message sets, named per source file, excepting "GENERAL".
+ *
+ * IMPORTANT: The original list is alphabetical, but any new sets must
+ * be added to the end.
+ */
+#define ISC_MSGSET_GENERAL 1
+/* ISC_RESULT_RESULTSET 2 */ /* XXX */
+/* ISC_RESULT_UNAVAILABLESET 3 */ /* XXX */
+#define ISC_MSGSET_APP 4
+#define ISC_MSGSET_COMMANDLINE 5
+#define ISC_MSGSET_ENTROPY 6
+#define ISC_MSGSET_IFITERIOCTL 7
+#define ISC_MSGSET_IFITERSYSCTL 8
+#define ISC_MSGSET_LEX 9
+#define ISC_MSGSET_LOG 10
+#define ISC_MSGSET_MEM 11
+#define ISC_MSGSET_NETADDR 12
+#define ISC_MSGSET_PRINT 13
+#define ISC_MSGSET_RESULT 14
+#define ISC_MSGSET_RWLOCK 15
+#define ISC_MSGSET_SOCKADDR 16
+#define ISC_MSGSET_SOCKET 17
+#define ISC_MSGSET_TASK 18
+#define ISC_MSGSET_TIMER 19
+#define ISC_MSGSET_UTIL 20
+#define ISC_MSGSET_IFITERGETIFADDRS 21
+/*@}*/
+
+/*@{*/
+/*!
+ * Message numbers
+ * are only required to be unique per message set,
+ * but are unique throughout the entire catalog to not be as confusing when
+ * debugging.
+ *
+ * The initial numbering was done by multiply by 100 the set number the
+ * message appears in then adding the incremental message number.
+ */
+#define ISC_MSG_FAILED 101 /*%< "failed" */
+#define ISC_MSG_SUCCEEDED 102 /*%< Compatible with "failed" */
+#define ISC_MSG_SUCCESS 103 /*%< More usual way to say "success" */
+#define ISC_MSG_STARTING 104 /*%< As in "daemon: starting" */
+#define ISC_MSG_STOPING 105 /*%< As in "daemon: stopping" */
+#define ISC_MSG_ENTERING 106 /*%< As in "some_subr: entering" */
+#define ISC_MSG_EXITING 107 /*%< As in "some_subr: exiting" */
+#define ISC_MSG_CALLING 108 /*%< As in "calling some_subr()" */
+#define ISC_MSG_RETURNED 109 /*%< As in "some_subr: returned <foo>" */
+#define ISC_MSG_FATALERROR 110 /*%< "fatal error" */
+#define ISC_MSG_SHUTTINGDOWN 111 /*%< "shutting down" */
+#define ISC_MSG_RUNNING 112 /*%< "running" */
+#define ISC_MSG_WAIT 113 /*%< "wait" */
+#define ISC_MSG_WAITUNTIL 114 /*%< "waituntil" */
+
+#define ISC_MSG_SIGNALSETUP 201 /*%< "handle_signal() %d setup: %s" */
+
+#define ISC_MSG_ILLEGALOPT 301 /*%< "illegal option" */
+#define ISC_MSG_OPTNEEDARG 302 /*%< "option requires an argument" */
+
+#define ISC_MSG_ENTROPYSTATS 401 /*%< "Entropy pool %p: refcnt %u ..." */
+
+#define ISC_MSG_MAKESCANSOCKET 501 /*%< "making interface scan socket: %s" */
+#define ISC_MSG_GETIFCONFIG 502 /*%< "get interface configuration: %s" */
+#define ISC_MSG_BUFFERMAX 503 /*%< "... maximum buffer size exceeded" */
+#define ISC_MSG_GETDESTADDR 504 /*%< "%s: getting destination address: %s" */
+#define ISC_MSG_GETNETMASK 505 /*%< "%s: getting netmask: %s" */
+
+#define ISC_MSG_GETIFLISTSIZE 601 /*%< "getting interface list size: ..." */
+#define ISC_MSG_GETIFLIST 602 /*%< "getting interface list: ..." */
+#define ISC_MSG_UNEXPECTEDTYPE 603 /*%< "... unexpected ... message type" */
+
+#define ISC_MSG_UNEXPECTEDSTATE 701 /*%< "Unexpected state %d" */
+
+#define ISC_MSG_BADTIME 801 /*%< "Bad 00 99:99:99.999 " */
+#define ISC_MSG_LEVEL 802 /*%< "level %d: " */
+
+#define ISC_MSG_ADDTRACE 901 /*%< "add %p size %u " */
+#define ISC_MSG_DELTRACE 902 /*%< "del %p size %u " */
+#define ISC_MSG_POOLSTATS 903 /*%< "[Pool statistics]\n" */
+#define ISC_MSG_POOLNAME 904 /*%< "name" */
+#define ISC_MSG_POOLSIZE 905 /*%< "size" */
+#define ISC_MSG_POOLMAXALLOC 906 /*%< "maxalloc" */
+#define ISC_MSG_POOLALLOCATED 907 /*%< "allocated" */
+#define ISC_MSG_POOLFREECOUNT 908 /*%< "freecount" */
+#define ISC_MSG_POOLFREEMAX 909 /*%< "freemax" */
+#define ISC_MSG_POOLFILLCOUNT 910 /*%< "fillcount" */
+#define ISC_MSG_POOLGETS 911 /*%< "gets" */
+#define ISC_MSG_DUMPALLOC 912 /*%< "DUMP OF ALL OUTSTANDING MEMORY ..." */
+#define ISC_MSG_NONE 913 /*%< "\tNone.\n" */
+#define ISC_MSG_PTRFILELINE 914 /*%< "\tptr %p file %s line %u\n" */
+
+#define ISC_MSG_UNKNOWNADDR 1001 /*%< "<unknown address, family %u>" */
+
+#define ISC_MSG_NOLONGDBL 1104 /*%< "long doubles are not supported" */
+
+#define ISC_MSG_PRINTLOCK 1201 /*%< "rwlock %p thread %lu ..." */
+#define ISC_MSG_READ 1202 /*%< "read" */
+#define ISC_MSG_WRITE 1203 /*%< "write" */
+#define ISC_MSG_READING 1204 /*%< "reading" */
+#define ISC_MSG_WRITING 1205 /*%< "writing" */
+#define ISC_MSG_PRELOCK 1206 /*%< "prelock" */
+#define ISC_MSG_POSTLOCK 1207 /*%< "postlock" */
+#define ISC_MSG_PREUNLOCK 1208 /*%< "preunlock" */
+#define ISC_MSG_POSTUNLOCK 1209 /*%< "postunlock" */
+
+#define ISC_MSG_UNKNOWNFAMILY 1301 /*%< "unknown address family: %d" */
+
+#define ISC_MSG_WRITEFAILED 1401 /*%< "write() failed during watcher ..." */
+#define ISC_MSG_READFAILED 1402 /*%< "read() failed during watcher ... " */
+#define ISC_MSG_PROCESSCMSG 1403 /*%< "processing cmsg %p" */
+#define ISC_MSG_IFRECEIVED 1404 /*%< "interface received on ifindex %u" */
+#define ISC_MSG_SENDTODATA 1405 /*%< "sendto pktinfo data, ifindex %u" */
+#define ISC_MSG_DOIORECV 1406 /*%< "doio_recv: recvmsg(%d) %d bytes ..." */
+#define ISC_MSG_PKTRECV 1407 /*%< "packet received correctly" */
+#define ISC_MSG_DESTROYING 1408 /*%< "destroying" */
+#define ISC_MSG_CREATED 1409 /*%< "created" */
+#define ISC_MSG_ACCEPTLOCK 1410 /*%< "internal_accept called, locked ..." */
+#define ISC_MSG_ACCEPTEDCXN 1411 /*%< "accepted connection, new socket %p" */
+#define ISC_MSG_INTERNALRECV 1412 /*%< "internal_recv: task %p got event %p" */
+#define ISC_MSG_INTERNALSEND 1413 /*%< "internal_send: task %p got event %p" */
+#define ISC_MSG_WATCHERMSG 1414 /*%< "watcher got message %d" */
+#define ISC_MSG_SOCKETSREMAIN 1415 /*%< "sockets exist" */
+#define ISC_MSG_PKTINFOPROVIDED 1416 /*%< "pktinfo structure provided, ..." */
+#define ISC_MSG_BOUND 1417 /*%< "bound" */
+#define ISC_MSG_ACCEPTRETURNED 1418 /*%< accept() returned %d/%s */
+#define ISC_MSG_TOOMANYFDS 1419 /*%< %s: too many open file descriptors */
+#define ISC_MSG_ZEROPORT 1420 /*%< dropping source port zero packet */
+#define ISC_MSG_FILTER 1420 /*%< setsockopt(SO_ACCEPTFILTER): %s */
+
+#define ISC_MSG_AWAKE 1502 /*%< "awake" */
+#define ISC_MSG_WORKING 1503 /*%< "working" */
+#define ISC_MSG_EXECUTE 1504 /*%< "execute action" */
+#define ISC_MSG_EMPTY 1505 /*%< "empty" */
+#define ISC_MSG_DONE 1506 /*%< "done" */
+#define ISC_MSG_QUANTUM 1507 /*%< "quantum" */
+
+#define ISC_MSG_SCHEDULE 1601 /*%< "schedule" */
+#define ISC_MSG_SIGNALSCHED 1602 /*%< "signal (schedule)" */
+#define ISC_MSG_SIGNALDESCHED 1603 /*%< "signal (deschedule)" */
+#define ISC_MSG_SIGNALDESTROY 1604 /*%< "signal (destroy)" */
+#define ISC_MSG_IDLERESCHED 1605 /*%< "idle reschedule" */
+#define ISC_MSG_EVENTNOTALLOC 1606 /*%< "couldn't allocate event" */
+#define ISC_MSG_SCHEDFAIL 1607 /*%< "couldn't schedule timer: %u" */
+#define ISC_MSG_POSTING 1608 /*%< "posting" */
+#define ISC_MSG_WAKEUP 1609 /*%< "wakeup" */
+
+#define ISC_MSG_LOCK 1701 /*%< "LOCK" */
+#define ISC_MSG_LOCKING 1702 /*%< "LOCKING" */
+#define ISC_MSG_LOCKED 1703 /*%< "LOCKED" */
+#define ISC_MSG_UNLOCKED 1704 /*%< "UNLOCKED" */
+#define ISC_MSG_RWLOCK 1705 /*%< "RWLOCK" */
+#define ISC_MSG_RWLOCKED 1706 /*%< "RWLOCKED" */
+#define ISC_MSG_RWUNLOCK 1707 /*%< "RWUNLOCK" */
+#define ISC_MSG_BROADCAST 1708 /*%< "BROADCAST" */
+#define ISC_MSG_SIGNAL 1709 /*%< "SIGNAL" */
+#define ISC_MSG_UTILWAIT 1710 /*%< "WAIT" */
+#define ISC_MSG_WAITED 1711 /*%< "WAITED" */
+
+#define ISC_MSG_GETIFADDRS 1801 /*%< "getting interface addresses: ..." */
+
+/*@}*/
+
+#endif /* ISC_MSGS_H */
diff --git a/lib/isc/include/isc/mutexblock.h b/lib/isc/include/isc/mutexblock.h
new file mode 100644
index 0000000..fa244c9
--- /dev/null
+++ b/lib/isc/include/isc/mutexblock.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2004, 2005 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: mutexblock.h,v 1.11.18.2 2005/04/29 00:17:00 marka Exp $ */
+
+#ifndef ISC_MUTEXBLOCK_H
+#define ISC_MUTEXBLOCK_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_mutexblock_init(isc_mutex_t *block, unsigned int count);
+/*%<
+ * Initialize a block of locks. If an error occurs all initialized locks
+ * will be destroyed, if possible.
+ *
+ * Requires:
+ *
+ *\li block != NULL
+ *
+ *\li count > 0
+ *
+ * Returns:
+ *
+ *\li Any code isc_mutex_init() can return is a valid return for this
+ * function.
+ */
+
+isc_result_t
+isc_mutexblock_destroy(isc_mutex_t *block, unsigned int count);
+/*%<
+ * Destroy a block of locks.
+ *
+ * Requires:
+ *
+ *\li block != NULL
+ *
+ *\li count > 0
+ *
+ *\li Each lock in the block be initialized via isc_mutex_init() or
+ * the whole block was initialized via isc_mutex_initblock().
+ *
+ * Returns:
+ *
+ *\li Any code isc_mutex_init() can return is a valid return for this
+ * function.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_MUTEXBLOCK_H */
diff --git a/lib/isc/include/isc/netaddr.h b/lib/isc/include/isc/netaddr.h
new file mode 100644
index 0000000..06d063e
--- /dev/null
+++ b/lib/isc/include/isc/netaddr.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: netaddr.h,v 1.25.18.5 2005/07/28 04:58:47 marka Exp $ */
+
+#ifndef ISC_NETADDR_H
+#define ISC_NETADDR_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/net.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_HAVESYSUNH
+#include <sys/types.h>
+#include <sys/un.h>
+#endif
+
+ISC_LANG_BEGINDECLS
+
+struct isc_netaddr {
+ unsigned int family;
+ union {
+ struct in_addr in;
+ struct in6_addr in6;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ char un[sizeof(((struct sockaddr_un *)0)->sun_path)];
+#endif
+ } type;
+ isc_uint32_t zone;
+};
+
+isc_boolean_t
+isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b);
+
+isc_boolean_t
+isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
+ unsigned int prefixlen);
+/*%<
+ * Compare the 'prefixlen' most significant bits of the network
+ * addresses 'a' and 'b'. Return #ISC_TRUE if they are equal,
+ * #ISC_FALSE if not.
+ */
+
+isc_result_t
+isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp);
+/*%<
+ * Convert a netmask in 's' into a prefix length in '*lenp'.
+ * The mask should consist of zero or more '1' bits in the most
+ * most significant part of the address, followed by '0' bits.
+ * If this is not the case, #ISC_R_MASKNONCONTIG is returned.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_MASKNONCONTIG
+ */
+
+isc_result_t
+isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target);
+/*%<
+ * Append a text representation of 'sockaddr' to the buffer 'target'.
+ * The text is NOT null terminated. Handles IPv4 and IPv6 addresses.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE The text or the null termination did not fit.
+ *\li #ISC_R_FAILURE Unspecified failure
+ */
+
+void
+isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size);
+/*%<
+ * Format a human-readable representation of the network address '*na'
+ * into the character array 'array', which is of size 'size'.
+ * The resulting string is guaranteed to be null-terminated.
+ */
+
+#define ISC_NETADDR_FORMATSIZE \
+ sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX%SSSSSSSSSS")
+/*%<
+ * Minimum size of array to pass to isc_netaddr_format().
+ */
+
+void
+isc_netaddr_fromsockaddr(isc_netaddr_t *netaddr, const isc_sockaddr_t *source);
+
+void
+isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina);
+
+void
+isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6);
+
+isc_result_t
+isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path);
+
+void
+isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone);
+
+isc_uint32_t
+isc_netaddr_getzone(const isc_netaddr_t *netaddr);
+
+void
+isc_netaddr_any(isc_netaddr_t *netaddr);
+/*%<
+ * Return the IPv4 wildcard address.
+ */
+
+void
+isc_netaddr_any6(isc_netaddr_t *netaddr);
+/*%<
+ * Return the IPv6 wildcard address.
+ */
+
+isc_boolean_t
+isc_netaddr_ismulticast(isc_netaddr_t *na);
+/*%<
+ * Returns ISC_TRUE if the address is a multicast address.
+ */
+
+isc_boolean_t
+isc_netaddr_isexperimental(isc_netaddr_t *na);
+/*%<
+ * Returns ISC_TRUE if the address is a experimental (CLASS E) address.
+ */
+
+isc_boolean_t
+isc_netaddr_islinklocal(isc_netaddr_t *na);
+/*%<
+ * Returns #ISC_TRUE if the address is a link local address.
+ */
+
+isc_boolean_t
+isc_netaddr_issitelocal(isc_netaddr_t *na);
+/*%<
+ * Returns #ISC_TRUE if the address is a site local address.
+ */
+
+void
+isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s);
+/*%<
+ * Convert an IPv6 v4mapped address into an IPv4 address.
+ */
+
+isc_result_t
+isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen);
+/*
+ * Test whether the netaddr 'na' and 'prefixlen' are consistant.
+ * e.g. prefixlen within range.
+ * na does not have bits set which are not covered by the prefixlen.
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_RANGE prefixlen out of range
+ * ISC_R_NOTIMPLENTED unsupported family
+ * ISC_R_FAILURE extra bits.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NETADDR_H */
diff --git a/lib/isc/include/isc/netscope.h b/lib/isc/include/isc/netscope.h
new file mode 100644
index 0000000..d9bea54
--- /dev/null
+++ b/lib/isc/include/isc/netscope.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: netscope.h,v 1.5.18.2 2005/04/29 00:17:00 marka Exp $ */
+
+#ifndef ISC_NETSCOPE_H
+#define ISC_NETSCOPE_H 1
+
+/*! \file */
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * Convert a string of an IPv6 scope zone to zone index. If the conversion
+ * succeeds, 'zoneid' will store the index value.
+ *
+ * XXXJT: when a standard interface for this purpose is defined,
+ * we should use it.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS: conversion succeeds
+ * \li ISC_R_FAILURE: conversion fails
+ */
+isc_result_t
+isc_netscope_pton(int af, char *scopename, void *addr, isc_uint32_t *zoneid);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NETADDR_H */
diff --git a/lib/isc/include/isc/ondestroy.h b/lib/isc/include/isc/ondestroy.h
new file mode 100644
index 0000000..035873c
--- /dev/null
+++ b/lib/isc/include/isc/ondestroy.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2004, 2005 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: ondestroy.h,v 1.8.18.2 2005/04/29 00:17:00 marka Exp $ */
+
+#ifndef ISC_ONDESTROY_H
+#define ISC_ONDESTROY_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*! \file
+ * ondestroy handling.
+ *
+ * Any class ``X'' of objects that wants to send out notifications
+ * on its destruction should declare a field of type isc_ondestroy_t
+ * (call it 'ondest').
+ *
+ * \code
+ * typedef struct {
+ * ...
+ * isc_ondestroy_t ondest;
+ * ...
+ * } X;
+ * \endcode
+ *
+ * When an object ``A'' of type X is created
+ * it must initialize the field ondest with a call to
+ *
+ * \code
+ * isc_ondestroy_init(&A->ondest).
+ * \endcode
+ *
+ * X should also provide a registration function for third-party
+ * objects to call to register their interest in being told about
+ * the destruction of a particular instance of X.
+ *
+ * \code
+ * isc_result_t
+ * X_ondestroy(X *instance, isc_task_t *task,
+ * isc_event_t **eventp) {
+ * return(isc_ondestroy_register(&instance->ondest, task,eventp));
+ * }
+ * \endcode
+ *
+ * Note: locking of the ondestory structure embedded inside of X, is
+ * X's responsibility.
+ *
+ * When an instance of X is destroyed, a call to isc_ondestroy_notify()
+ * sends the notifications:
+ *
+ * \code
+ * X *instance;
+ * isc_ondestroy_t ondest = instance->ondest;
+ *
+ * ... completely cleanup 'instance' here...
+ *
+ * isc_ondestroy_notify(&ondest, instance);
+ * \endcode
+ *
+ *
+ * see lib/dns/zone.c for an ifdef'd-out example.
+ */
+
+struct isc_ondestroy {
+ unsigned int magic;
+ isc_eventlist_t events;
+};
+
+void
+isc_ondestroy_init(isc_ondestroy_t *ondest);
+/*%<
+ * Initialize the on ondest structure. *must* be called before first call
+ * to isc_ondestroy_register().
+ */
+
+isc_result_t
+isc_ondestroy_register(isc_ondestroy_t *ondest, isc_task_t *task,
+ isc_event_t **eventp);
+
+/*%<
+ * Stores task and *eventp away inside *ondest. Ownership of **event is
+ * taken from the caller (and *eventp is set to NULL). The task is attached
+ * to.
+ */
+
+void
+isc_ondestroy_notify(isc_ondestroy_t *ondest, void *sender);
+/*%<
+ * Dispatches the event(s) to the task(s) that were given in
+ * isc_ondestroy_register call(s) (done via calls to
+ * isc_task_sendanddetach()). Before dispatch, the sender value of each
+ * event structure is set to the value of the sender paramater. The
+ * internal structures of the ondest parameter are cleaned out, so no other
+ * cleanup is needed.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ONDESTROY_H */
diff --git a/lib/isc/include/isc/os.h b/lib/isc/include/isc/os.h
new file mode 100644
index 0000000..b2b76d5
--- /dev/null
+++ b/lib/isc/include/isc/os.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2004, 2005 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: os.h,v 1.6.18.2 2005/04/29 00:17:00 marka Exp $ */
+
+#ifndef ISC_OS_H
+#define ISC_OS_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+unsigned int
+isc_os_ncpus(void);
+/*%<
+ * Return the number of CPUs available on the system, or 1 if this cannot
+ * be determined.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_OS_H */
diff --git a/lib/isc/include/isc/parseint.h b/lib/isc/include/isc/parseint.h
new file mode 100644
index 0000000..6940add
--- /dev/null
+++ b/lib/isc/include/isc/parseint.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2004, 2005 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: parseint.h,v 1.3.18.2 2005/04/29 00:17:00 marka Exp $ */
+
+#ifndef ISC_PARSEINT_H
+#define ISC_PARSEINT_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*! \file
+ * \brief Parse integers, in a saner way than atoi() or strtoul() do.
+ */
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_parse_uint32(isc_uint32_t *uip, const char *string, int base);
+
+isc_result_t
+isc_parse_uint16(isc_uint16_t *uip, const char *string, int base);
+
+isc_result_t
+isc_parse_uint8(isc_uint8_t *uip, const char *string, int base);
+/*%<
+ * Parse the null-terminated string 'string' containing a base 'base'
+ * integer, storing the result in '*uip'.
+ * The base is interpreted
+ * as in strtoul(). Unlike strtoul(), leading whitespace, minus or
+ * plus signs are not accepted, and all errors (including overflow)
+ * are reported uniformly through the return value.
+ *
+ * Requires:
+ *\li 'string' points to a null-terminated string
+ *\li 0 <= 'base' <= 36
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_BADNUMBER The string is not numeric (in the given base)
+ *\li #ISC_R_RANGE The number is not representable as the requested type.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_PARSEINT_H */
diff --git a/lib/isc/include/isc/platform.h.in b/lib/isc/include/isc/platform.h.in
new file mode 100644
index 0000000..0531edf
--- /dev/null
+++ b/lib/isc/include/isc/platform.h.in
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: platform.h.in,v 1.34.18.9 2007/09/13 05:04:01 each Exp $ */
+
+#ifndef ISC_PLATFORM_H
+#define ISC_PLATFORM_H 1
+
+/*! \file */
+
+/*****
+ ***** Platform-dependent defines.
+ *****/
+
+/*
+ * Define if the platform has <strings.h>.
+ */
+@ISC_PLATFORM_HAVESTRINGSH@
+
+/***
+ *** Network.
+ ***/
+
+/*! \brief
+ * Define if this system needs the <netinet/in6.h> header file included
+ * for full IPv6 support (pretty much only UnixWare).
+ */
+@ISC_PLATFORM_NEEDNETINETIN6H@
+
+/*! \brief
+ * Define if this system needs the <netinet6/in6.h> header file included
+ * to support in6_pkinfo (pretty much only BSD/OS).
+ */
+@ISC_PLATFORM_NEEDNETINET6IN6H@
+
+/*! \brief
+ * If sockaddrs on this system have an sa_len field, ISC_PLATFORM_HAVESALEN
+ * will be defined.
+ */
+@ISC_PLATFORM_HAVESALEN@
+
+/*! \brief
+ * If this system has the IPv6 structure definitions, ISC_PLATFORM_HAVEIPV6
+ * will be defined.
+ */
+@ISC_PLATFORM_HAVEIPV6@
+
+/*! \brief
+ * If this system is missing in6addr_any, ISC_PLATFORM_NEEDIN6ADDRANY will
+ * be defined.
+ */
+@ISC_PLATFORM_NEEDIN6ADDRANY@
+
+/*! \brief
+ * If this system is missing in6addr_loopback, ISC_PLATFORM_NEEDIN6ADDRLOOPBACK
+ * will be defined.
+ */
+@ISC_PLATFORM_NEEDIN6ADDRLOOPBACK@
+
+/*! \brief
+ * If this system has in6_pktinfo, ISC_PLATFORM_HAVEIN6PKTINFO will be
+ * defined.
+ */
+@ISC_PLATFORM_HAVEIN6PKTINFO@
+
+/*! \brief
+ * If this system has in_addr6, rather than in6_addr, ISC_PLATFORM_HAVEINADDR6
+ * will be defined.
+ */
+@ISC_PLATFORM_HAVEINADDR6@
+
+/*! \brief
+ * If this system has sin6_scope_id, ISC_PLATFORM_HAVESCOPEID will be defined.
+ */
+@ISC_PLATFORM_HAVESCOPEID@
+
+/*! \brief
+ * If this system needs inet_ntop(), ISC_PLATFORM_NEEDNTOP will be defined.
+ */
+@ISC_PLATFORM_NEEDNTOP@
+
+/*! \brief
+ * If this system needs inet_pton(), ISC_PLATFORM_NEEDPTON will be defined.
+ */
+@ISC_PLATFORM_NEEDPTON@
+
+/*! \brief
+ * If this system needs inet_aton(), ISC_PLATFORM_NEEDATON will be defined.
+ */
+@ISC_PLATFORM_NEEDATON@
+
+/*! \brief
+ * If this system needs in_port_t, ISC_PLATFORM_NEEDPORTT will be defined.
+ */
+@ISC_PLATFORM_NEEDPORTT@
+
+/*! \brief
+ * If the system needs strsep(), ISC_PLATFORM_NEEDSTRSEP will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRSEP@
+
+/*! \brief
+ * If the system needs strlcpy(), ISC_PLATFORM_NEEDSTRLCPY will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRLCPY@
+
+/*! \brief
+ * If the system needs strlcat(), ISC_PLATFORM_NEEDSTRLCAT will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRLCAT@
+
+/*! \brief
+ * Define either ISC_PLATFORM_BSD44MSGHDR or ISC_PLATFORM_BSD43MSGHDR.
+ */
+@ISC_PLATFORM_MSGHDRFLAVOR@
+
+/*! \brief
+ * Define if PTHREAD_ONCE_INIT should be surrounded by braces to
+ * prevent compiler warnings (such as with gcc on Solaris 2.8).
+ */
+@ISC_PLATFORM_BRACEPTHREADONCEINIT@
+
+/*! \brief
+ * Define on some UnixWare systems to fix erroneous definitions of various
+ * IN6_IS_ADDR_* macros.
+ */
+@ISC_PLATFORM_FIXIN6ISADDR@
+
+/*
+ *** Printing.
+ ***/
+
+/*! \brief
+ * If this system needs vsnprintf() and snprintf(), ISC_PLATFORM_NEEDVSNPRINTF
+ * will be defined.
+ */
+@ISC_PLATFORM_NEEDVSNPRINTF@
+
+/*! \brief
+ * If this system need a modern sprintf() that returns (int) not (char*).
+ */
+@ISC_PLATFORM_NEEDSPRINTF@
+
+/*! \brief
+ * The printf format string modifier to use with isc_uint64_t values.
+ */
+@ISC_PLATFORM_QUADFORMAT@
+
+/*! \brief
+ * Defined if we are using threads.
+ */
+@ISC_PLATFORM_USETHREADS@
+
+/*! \brief
+ * Defined if unistd.h does not cause fd_set to be delared.
+ */
+@ISC_PLATFORM_NEEDSYSSELECTH@
+
+/*! \brief
+ * Type used for resource limits.
+ */
+@ISC_PLATFORM_RLIMITTYPE@
+
+/*! \brief
+ * Define if your compiler supports "long long int".
+ */
+@ISC_PLATFORM_HAVELONGLONG@
+
+/*! \brief
+ * Define if the system has struct lifconf which is a extended struct ifconf
+ * for IPv6.
+ */
+@ISC_PLATFORM_HAVELIFCONF@
+
+/*! \brief
+ * Define if the system has struct if_laddrconf which is a extended struct
+ * ifconf for IPv6.
+ */
+@ISC_PLATFORM_HAVEIF_LADDRCONF@
+
+/*! \brief
+ * Define if the system has struct if_laddrreq.
+ */
+@ISC_PLATFORM_HAVEIF_LADDRREQ@
+
+/*! \brief
+ * Used to control how extern data is linked; needed for Win32 platforms.
+ */
+@ISC_PLATFORM_USEDECLSPEC@
+
+/*! \brief
+ * Define if the system supports if_nametoindex.
+ */
+@ISC_PLATFORM_HAVEIFNAMETOINDEX@
+
+/*! \brief
+ * Define if this system needs strtoul.
+ */
+@ISC_PLATFORM_NEEDSTRTOUL@
+
+/*! \brief
+ * Define if this system needs memmove.
+ */
+@ISC_PLATFORM_NEEDMEMMOVE@
+
+/*
+ * Define if the platform has <sys/un.h>.
+ */
+@ISC_PLATFORM_HAVESYSUNH@
+
+/*
+ * If the "xadd" operation is available on this architecture,
+ * ISC_PLATFORM_HAVEXADD will be defined.
+ */
+@ISC_PLATFORM_HAVEXADD@
+
+/*
+ * If the "atomic swap" operation is available on this architecture,
+ * ISC_PLATFORM_HAVEATOMICSTORE" will be defined.
+ */
+@ISC_PLATFORM_HAVEATOMICSTORE@
+
+/*
+ * If the "compare-and-exchange" operation is available on this architecture,
+ * ISC_PLATFORM_HAVECMPXCHG will be defined.
+ */
+@ISC_PLATFORM_HAVECMPXCHG@
+
+/*
+ * Define if gcc ASM extension is available
+ */
+@ISC_PLATFORM_USEGCCASM@
+
+/*
+ * Define if Tru64 style ASM syntax must be used.
+ */
+@ISC_PLATFORM_USEOSFASM@
+
+/*
+ * Define if the standard __asm function must be used.
+ */
+@ISC_PLATFORM_USESTDASM@
+
+/*
+ * Define if MacOS style of PPC assembly must be used.
+ * e.g. "r6", not "6", for register six.
+ */
+@ISC_PLATFORM_USEMACASM@
+
+#ifndef ISC_PLATFORM_USEDECLSPEC
+#define LIBISC_EXTERNAL_DATA
+#define LIBDNS_EXTERNAL_DATA
+#define LIBISCCC_EXTERNAL_DATA
+#define LIBISCCFG_EXTERNAL_DATA
+#define LIBBIND9_EXTERNAL_DATA
+#else /*! \brief ISC_PLATFORM_USEDECLSPEC */
+#ifdef LIBISC_EXPORTS
+#define LIBISC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBDNS_EXPORTS
+#define LIBDNS_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBDNS_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBISCCC_EXPORTS
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBISCCFG_EXPORTS
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBBIND9_EXPORTS
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#endif /*! \brief ISC_PLATFORM_USEDECLSPEC */
+
+/*
+ * Tell emacs to use C mode for this file.
+ *
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
+#endif /* ISC_PLATFORM_H */
diff --git a/lib/isc/include/isc/print.h b/lib/isc/include/isc/print.h
new file mode 100644
index 0000000..95c6b1c
--- /dev/null
+++ b/lib/isc/include/isc/print.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2004, 2005 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: print.h,v 1.19.18.3 2005/06/08 02:07:56 marka Exp $ */
+
+#ifndef ISC_PRINT_H
+#define ISC_PRINT_H 1
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/formatcheck.h> /* Required for ISC_FORMAT_PRINTF() macro. */
+#include <isc/lang.h>
+#include <isc/platform.h>
+
+/*!
+ * This block allows lib/isc/print.c to be cleanly compiled even if
+ * the platform does not need it. The standard Makefile will still
+ * not compile print.c or archive print.o, so this is just to make test
+ * compilation ("make print.o") easier.
+ */
+#if !defined(ISC_PLATFORM_NEEDVSNPRINTF) && defined(ISC__PRINT_SOURCE)
+#define ISC_PLATFORM_NEEDVSNPRINTF
+#endif
+
+#if !defined(ISC_PLATFORM_NEEDSPRINTF) && defined(ISC__PRINT_SOURCE)
+#define ISC_PLATFORM_NEEDSPRINTF
+#endif
+
+/***
+ *** Macros
+ ***/
+#define ISC_PRINT_QUADFORMAT ISC_PLATFORM_QUADFORMAT
+
+/***
+ *** Functions
+ ***/
+
+#ifdef ISC_PLATFORM_NEEDVSNPRINTF
+#include <stdarg.h>
+#include <stddef.h>
+#endif
+#ifdef ISC_PLATFORM_NEEDSPRINTF
+#include <stdio.h>
+#endif
+
+
+ISC_LANG_BEGINDECLS
+
+#ifdef ISC_PLATFORM_NEEDVSNPRINTF
+int
+isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap)
+ ISC_FORMAT_PRINTF(3, 0);
+#define vsnprintf isc_print_vsnprintf
+
+int
+isc_print_snprintf(char *str, size_t size, const char *format, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+#define snprintf isc_print_snprintf
+#endif /* ISC_PLATFORM_NEEDVSNPRINTF */
+
+#ifdef ISC_PLATFORM_NEEDSPRINTF
+int
+isc_print_sprintf(char *str, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
+#define sprintf isc_print_sprintf
+#endif
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_PRINT_H */
diff --git a/lib/isc/include/isc/quota.h b/lib/isc/include/isc/quota.h
new file mode 100644
index 0000000..6f95cd5
--- /dev/null
+++ b/lib/isc/include/isc/quota.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2004, 2005 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: quota.h,v 1.10.18.4 2005/08/11 15:01:54 marka Exp $ */
+
+#ifndef ISC_QUOTA_H
+#define ISC_QUOTA_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/quota.h
+ *
+ * \brief The isc_quota_t object is a simple helper object for implementing
+ * quotas on things like the number of simultaneous connections to
+ * a server. It keeps track of the amount of quota in use, and
+ * encapsulates the locking necessary to allow multiple tasks to
+ * share a quota.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+/*****
+ ***** Types.
+ *****/
+
+ISC_LANG_BEGINDECLS
+
+/*% isc_quota structure */
+struct isc_quota {
+ isc_mutex_t lock; /*%< Locked by lock. */
+ int max;
+ int used;
+ int soft;
+};
+
+isc_result_t
+isc_quota_init(isc_quota_t *quota, int max);
+/*%<
+ * Initialize a quota object.
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * Other error Lock creation failed.
+ */
+
+void
+isc_quota_destroy(isc_quota_t *quota);
+/*%<
+ * Destroy a quota object.
+ */
+
+void
+isc_quota_soft(isc_quota_t *quota, int soft);
+/*%<
+ * Set a soft quota.
+ */
+
+void
+isc_quota_max(isc_quota_t *quota, int max);
+/*%<
+ * Re-set a maximum quota.
+ */
+
+isc_result_t
+isc_quota_reserve(isc_quota_t *quota);
+/*%<
+ * Attempt to reserve one unit of 'quota'.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS Success
+ * \li #ISC_R_SOFTQUOTA Success soft quota reached
+ * \li #ISC_R_QUOTA Quota is full
+ */
+
+void
+isc_quota_release(isc_quota_t *quota);
+/*%<
+ * Release one unit of quota.
+ */
+
+isc_result_t
+isc_quota_attach(isc_quota_t *quota, isc_quota_t **p);
+/*%<
+ * Like isc_quota_reserve, and also attaches '*p' to the
+ * quota if successful (ISC_R_SUCCESS or ISC_R_SOFTQUOTA).
+ */
+
+void
+isc_quota_detach(isc_quota_t **p);
+/*%<
+ * Like isc_quota_release, and also detaches '*p' from the
+ * quota.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_QUOTA_H */
diff --git a/lib/isc/include/isc/random.h b/lib/isc/include/isc/random.h
new file mode 100644
index 0000000..c5cef8b
--- /dev/null
+++ b/lib/isc/include/isc/random.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2004, 2005 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: random.h,v 1.12.18.2 2005/04/29 00:17:01 marka Exp $ */
+
+#ifndef ISC_RANDOM_H
+#define ISC_RANDOM_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*! \file
+ * \brief Implements a random state pool which will let the caller return a
+ * series of possibly non-reproducable random values.
+ *
+ * Note that the
+ * strength of these numbers is not all that high, and should not be
+ * used in cryptography functions. It is useful for jittering values
+ * a bit here and there, such as timeouts, etc.
+ */
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_random_seed(isc_uint32_t seed);
+/*%<
+ * Set the initial seed of the random state.
+ */
+
+void
+isc_random_get(isc_uint32_t *val);
+/*%<
+ * Get a random value.
+ *
+ * Requires:
+ * val != NULL.
+ */
+
+isc_uint32_t
+isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter);
+/*%<
+ * Get a random value between (max - jitter) and (max).
+ * This is useful for jittering timer values.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RANDOM_H */
diff --git a/lib/isc/include/isc/ratelimiter.h b/lib/isc/include/isc/ratelimiter.h
new file mode 100644
index 0000000..1944754
--- /dev/null
+++ b/lib/isc/include/isc/ratelimiter.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2004, 2005 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: ratelimiter.h,v 1.15.18.2 2005/04/29 00:17:01 marka Exp $ */
+
+#ifndef ISC_RATELIMITER_H
+#define ISC_RATELIMITER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief A rate limiter is a mechanism for dispatching events at a limited
+ * rate. This is intended to be used when sending zone maintenance
+ * SOA queries, NOTIFY messages, etc.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Functions.
+ *****/
+
+isc_result_t
+isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
+ isc_task_t *task, isc_ratelimiter_t **ratelimiterp);
+/*%<
+ * Create a rate limiter. The execution interval is initially undefined.
+ */
+
+isc_result_t
+isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval);
+/*!<
+ * Set the mininum interval between event executions.
+ * The interval value is copied, so the caller need not preserve it.
+ *
+ * Requires:
+ * '*interval' is a nonzero interval.
+ */
+
+void
+isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, isc_uint32_t perint);
+/*%<
+ * Set the number of events processed per interval timer tick.
+ * If 'perint' is zero it is treated as 1.
+ */
+
+isc_result_t
+isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
+ isc_event_t **eventp);
+/*%<
+ * Queue an event for rate-limited execution.
+ *
+ * This is similar
+ * to doing an isc_task_send() to the 'task', except that the
+ * execution may be delayed to achieve the desired rate of
+ * execution.
+ *
+ * '(*eventp)->ev_sender' is used to hold the task. The caller
+ * must ensure that the task exists until the event is delivered.
+ *
+ * Requires:
+ *\li An interval has been set by calling
+ * isc_ratelimiter_setinterval().
+ *
+ *\li 'task' to be non NULL.
+ *\li '(*eventp)->ev_sender' to be NULL.
+ */
+
+void
+isc_ratelimiter_shutdown(isc_ratelimiter_t *ratelimiter);
+/*%<
+ * Shut down a rate limiter.
+ *
+ * Ensures:
+ *\li All events that have not yet been
+ * dispatched to the task are dispatched immediately with
+ * the #ISC_EVENTATTR_CANCELED bit set in ev_attributes.
+ *
+ *\li Further attempts to enqueue events will fail with
+ * #ISC_R_SHUTTINGDOWN.
+ *
+ *\li The reatelimiter is no longer attached to its task.
+ */
+
+void
+isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target);
+/*%<
+ * Attach to a rate limiter.
+ */
+
+void
+isc_ratelimiter_detach(isc_ratelimiter_t **ratelimiterp);
+/*%<
+ * Detach from a rate limiter.
+ */
+
+isc_result_t
+isc_ratelimiter_stall(isc_ratelimiter_t *rl);
+/*%<
+ * Stall event processing.
+ */
+
+isc_result_t
+isc_ratelimiter_release(isc_ratelimiter_t *rl);
+/*%<
+ * Release a stalled rate limiter.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RATELIMITER_H */
diff --git a/lib/isc/include/isc/refcount.h b/lib/isc/include/isc/refcount.h
new file mode 100644
index 0000000..b930465
--- /dev/null
+++ b/lib/isc/include/isc/refcount.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2004, 2005 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: refcount.h,v 1.6.18.5 2005/07/12 01:22:31 marka Exp $ */
+
+#ifndef ISC_REFCOUNT_H
+#define ISC_REFCOUNT_H 1
+
+#include <isc/atomic.h>
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+/*! \file
+ * \brief Implements a locked reference counter.
+ *
+ * These functions may actually be
+ * implemented using macros, and implementations of these macros are below.
+ * The isc_refcount_t type should not be accessed directly, as its contents
+ * depend on the implementation.
+ */
+
+ISC_LANG_BEGINDECLS
+
+/*
+ * Function prototypes
+ */
+
+/*
+ * isc_result_t
+ * isc_refcount_init(isc_refcount_t *ref, unsigned int n);
+ *
+ * Initialize the reference counter. There will be 'n' initial references.
+ *
+ * Requires:
+ * ref != NULL
+ */
+
+/*
+ * void
+ * isc_refcount_destroy(isc_refcount_t *ref);
+ *
+ * Destroys a reference counter.
+ *
+ * Requires:
+ * ref != NULL
+ * The number of references is 0.
+ */
+
+/*
+ * void
+ * isc_refcount_increment(isc_refcount_t *ref, unsigned int *targetp);
+ * isc_refcount_increment0(isc_refcount_t *ref, unsigned int *targetp);
+ *
+ * Increments the reference count, returning the new value in targetp if it's
+ * not NULL. The reference counter typically begins with the initial counter
+ * of 1, and will be destroyed once the counter reaches 0. Thus,
+ * isc_refcount_increment() additionally requires the previous counter be
+ * larger than 0 so that an error which violates the usage can be easily
+ * caught. isc_refcount_increment0() does not have this restriction.
+ *
+ * Requires:
+ * ref != NULL.
+ */
+
+/*
+ * void
+ * isc_refcount_decrement(isc_refcount_t *ref, unsigned int *targetp);
+ *
+ * Decrements the reference count, returning the new value in targetp if it's
+ * not NULL.
+ *
+ * Requires:
+ * ref != NULL.
+ */
+
+
+/*
+ * Sample implementations
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+#ifdef ISC_PLATFORM_HAVEXADD
+
+#define ISC_REFCOUNT_HAVEATOMIC 1
+
+typedef struct isc_refcount {
+ isc_int32_t refs;
+} isc_refcount_t;
+
+#define isc_refcount_destroy(rp) (REQUIRE((rp)->refs == 0))
+#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
+
+#define isc_refcount_increment0(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ isc_int32_t prev; \
+ prev = isc_atomic_xadd(&(rp)->refs, 1); \
+ if (_tmp != NULL) \
+ *_tmp = prev + 1; \
+ } while (0)
+
+#define isc_refcount_increment(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ isc_int32_t prev; \
+ prev = isc_atomic_xadd(&(rp)->refs, 1); \
+ REQUIRE(prev > 0); \
+ if (_tmp != NULL) \
+ *_tmp = prev + 1; \
+ } while (0)
+
+#define isc_refcount_decrement(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ isc_int32_t prev; \
+ prev = isc_atomic_xadd(&(rp)->refs, -1); \
+ REQUIRE(prev > 0); \
+ if (_tmp != NULL) \
+ *_tmp = prev - 1; \
+ } while (0)
+
+#else /* ISC_PLATFORM_HAVEXADD */
+
+typedef struct isc_refcount {
+ int refs;
+ isc_mutex_t lock;
+} isc_refcount_t;
+
+/*% Destroys a reference counter. */
+#define isc_refcount_destroy(rp) \
+ do { \
+ REQUIRE((rp)->refs == 0); \
+ DESTROYLOCK(&(rp)->lock); \
+ } while (0)
+
+#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
+
+/*% Increments the reference count, returning the new value in targetp if it's not NULL. */
+#define isc_refcount_increment0(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ LOCK(&(rp)->lock); \
+ ++((rp)->refs); \
+ if (_tmp != NULL) \
+ *_tmp = ((rp)->refs); \
+ UNLOCK(&(rp)->lock); \
+ } while (0)
+
+#define isc_refcount_increment(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ LOCK(&(rp)->lock); \
+ REQUIRE((rp)->refs > 0); \
+ ++((rp)->refs); \
+ if (_tmp != NULL) \
+ *_tmp = ((rp)->refs); \
+ UNLOCK(&(rp)->lock); \
+ } while (0)
+
+/*% Decrements the reference count, returning the new value in targetp if it's not NULL. */
+#define isc_refcount_decrement(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ LOCK(&(rp)->lock); \
+ REQUIRE((rp)->refs > 0); \
+ --((rp)->refs); \
+ if (_tmp != NULL) \
+ *_tmp = ((rp)->refs); \
+ UNLOCK(&(rp)->lock); \
+ } while (0)
+
+#endif /* ISC_PLATFORM_HAVEXADD */
+#else /* ISC_PLATFORM_USETHREADS */
+
+typedef struct isc_refcount {
+ int refs;
+} isc_refcount_t;
+
+#define isc_refcount_destroy(rp) (REQUIRE((rp)->refs == 0))
+#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
+
+#define isc_refcount_increment0(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int _n = ++(rp)->refs; \
+ if (_tmp != NULL) \
+ *_tmp = _n; \
+ } while (0)
+
+#define isc_refcount_increment(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int _n; \
+ REQUIRE((rp)->refs > 0); \
+ _n = ++(rp)->refs; \
+ if (_tmp != NULL) \
+ *_tmp = _n; \
+ } while (0)
+
+#define isc_refcount_decrement(rp, tp) \
+ do { \
+ unsigned int *_tmp = (unsigned int *)(tp); \
+ int _n; \
+ REQUIRE((rp)->refs > 0); \
+ _n = --(rp)->refs; \
+ if (_tmp != NULL) \
+ *_tmp = _n; \
+ } while (0)
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+isc_result_t
+isc_refcount_init(isc_refcount_t *ref, unsigned int n);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_REFCOUNT_H */
diff --git a/lib/isc/include/isc/region.h b/lib/isc/include/isc/region.h
new file mode 100644
index 0000000..9b651fe
--- /dev/null
+++ b/lib/isc/include/isc/region.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: region.h,v 1.19.18.2 2005/04/29 00:17:01 marka Exp $ */
+
+#ifndef ISC_REGION_H
+#define ISC_REGION_H 1
+
+/*! \file */
+
+#include <isc/types.h>
+
+struct isc_region {
+ unsigned char * base;
+ unsigned int length;
+};
+
+struct isc_textregion {
+ char * base;
+ unsigned int length;
+};
+
+/* XXXDCL questionable ... bears discussion. we have been putting off
+ * discussing the region api.
+ */
+struct isc_constregion {
+ const void * base;
+ unsigned int length;
+};
+
+struct isc_consttextregion {
+ const char * base;
+ unsigned int length;
+};
+
+/*@{*/
+/*!
+ * The region structure is not opaque, and is usually directly manipulated.
+ * Some macros are defined below for convenience.
+ */
+
+#define isc_region_consume(r,l) \
+ do { \
+ isc_region_t *_r = (r); \
+ unsigned int _l = (l); \
+ INSIST(_r->length >= _l); \
+ _r->base += _l; \
+ _r->length -= _l; \
+ } while (0)
+
+#define isc_textregion_consume(r,l) \
+ do { \
+ isc_textregion_t *_r = (r); \
+ unsigned int _l = (l); \
+ INSIST(_r->length >= _l); \
+ _r->base += _l; \
+ _r->length -= _l; \
+ } while (0)
+
+#define isc_constregion_consume(r,l) \
+ do { \
+ isc_constregion_t *_r = (r); \
+ unsigned int _l = (l); \
+ INSIST(_r->length >= _l); \
+ _r->base += _l; \
+ _r->length -= _l; \
+ } while (0)
+/*@}*/
+
+int
+isc_region_compare(isc_region_t *r1, isc_region_t *r2);
+/*%<
+ * Compares the contents of two regions
+ *
+ * Requires:
+ *\li 'r1' is a valid region
+ *\li 'r2' is a valid region
+ *
+ * Returns:
+ *\li < 0 if r1 is lexicographically less than r2
+ *\li = 0 if r1 is lexicographically identical to r2
+ *\li > 0 if r1 is lexicographically greater than r2
+ */
+
+#endif /* ISC_REGION_H */
diff --git a/lib/isc/include/isc/resource.h b/lib/isc/include/isc/resource.h
new file mode 100644
index 0000000..53b2a4e
--- /dev/null
+++ b/lib/isc/include/isc/resource.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2004, 2005 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: resource.h,v 1.5.18.2 2005/04/29 00:17:02 marka Exp $ */
+
+#ifndef ISC_RESOURCE_H
+#define ISC_RESOURCE_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#define ISC_RESOURCE_UNLIMITED ((isc_resourcevalue_t)ISC_UINT64_MAX)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value);
+/*%<
+ * Set the maximum limit for a system resource.
+ *
+ * Notes:
+ *\li If 'value' exceeds the maximum possible on the operating system,
+ * it is silently limited to that maximum -- or to "infinity", if
+ * the operating system has that concept. #ISC_RESOURCE_UNLIMITED
+ * can be used to explicitly ask for the maximum.
+ *
+ * Requires:
+ *\li 'resource' is a valid member of the isc_resource_t enumeration.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOTIMPLEMENTED 'resource' is not a type known by the OS.
+ *\li #ISC_R_NOPERM The calling process did not have adequate permission
+ * to change the resource limit.
+ */
+
+isc_result_t
+isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value);
+/*%<
+ * Get the maximum limit for a system resource.
+ *
+ * Notes:
+ *\li 'value' is set to the maximum limit.
+ *
+ *\li #ISC_RESOURCE_UNLIMITED is the maximum value of isc_resourcevalue_t.
+ *
+ *\li On many (all?) Unix systems, RLIM_INFINITY is a valid value that is
+ * significantly less than #ISC_RESOURCE_UNLIMITED, but which in practice
+ * behaves the same.
+ *
+ *\li The current ISC libdns configuration file parser assigns a value
+ * of ISC_UINT32_MAX for a size_spec of "unlimited" and ISC_UNIT32_MAX - 1
+ * for "default", the latter of which is supposed to represent "the
+ * limit that was in force when the server started". Since these are
+ * valid values in the middle of the range of isc_resourcevalue_t,
+ * there is the possibility for confusion over what exactly those
+ * particular values are supposed to represent in a particular context --
+ * discrete integral values or generalized concepts.
+ *
+ * Requires:
+ *\li 'resource' is a valid member of the isc_resource_t enumeration.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOTIMPLEMENTED 'resource' is not a type known by the OS.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RESOURCE_H */
+
diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h
new file mode 100644
index 0000000..0de3493
--- /dev/null
+++ b/lib/isc/include/isc/result.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2004, 2005 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: result.h,v 1.62.18.4 2005/06/22 22:05:49 marka Exp $ */
+
+#ifndef ISC_RESULT_H
+#define ISC_RESULT_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#define ISC_R_SUCCESS 0 /*%< success */
+#define ISC_R_NOMEMORY 1 /*%< out of memory */
+#define ISC_R_TIMEDOUT 2 /*%< timed out */
+#define ISC_R_NOTHREADS 3 /*%< no available threads */
+#define ISC_R_ADDRNOTAVAIL 4 /*%< address not available */
+#define ISC_R_ADDRINUSE 5 /*%< address in use */
+#define ISC_R_NOPERM 6 /*%< permission denied */
+#define ISC_R_NOCONN 7 /*%< no pending connections */
+#define ISC_R_NETUNREACH 8 /*%< network unreachable */
+#define ISC_R_HOSTUNREACH 9 /*%< host unreachable */
+#define ISC_R_NETDOWN 10 /*%< network down */
+#define ISC_R_HOSTDOWN 11 /*%< host down */
+#define ISC_R_CONNREFUSED 12 /*%< connection refused */
+#define ISC_R_NORESOURCES 13 /*%< not enough free resources */
+#define ISC_R_EOF 14 /*%< end of file */
+#define ISC_R_BOUND 15 /*%< socket already bound */
+#define ISC_R_RELOAD 16 /*%< reload */
+#define ISC_R_LOCKBUSY 17 /*%< lock busy */
+#define ISC_R_EXISTS 18 /*%< already exists */
+#define ISC_R_NOSPACE 19 /*%< ran out of space */
+#define ISC_R_CANCELED 20 /*%< operation canceled */
+#define ISC_R_NOTBOUND 21 /*%< socket is not bound */
+#define ISC_R_SHUTTINGDOWN 22 /*%< shutting down */
+#define ISC_R_NOTFOUND 23 /*%< not found */
+#define ISC_R_UNEXPECTEDEND 24 /*%< unexpected end of input */
+#define ISC_R_FAILURE 25 /*%< generic failure */
+#define ISC_R_IOERROR 26 /*%< I/O error */
+#define ISC_R_NOTIMPLEMENTED 27 /*%< not implemented */
+#define ISC_R_UNBALANCED 28 /*%< unbalanced parentheses */
+#define ISC_R_NOMORE 29 /*%< no more */
+#define ISC_R_INVALIDFILE 30 /*%< invalid file */
+#define ISC_R_BADBASE64 31 /*%< bad base64 encoding */
+#define ISC_R_UNEXPECTEDTOKEN 32 /*%< unexpected token */
+#define ISC_R_QUOTA 33 /*%< quota reached */
+#define ISC_R_UNEXPECTED 34 /*%< unexpected error */
+#define ISC_R_ALREADYRUNNING 35 /*%< already running */
+#define ISC_R_IGNORE 36 /*%< ignore */
+#define ISC_R_MASKNONCONTIG 37 /*%< addr mask not contiguous */
+#define ISC_R_FILENOTFOUND 38 /*%< file not found */
+#define ISC_R_FILEEXISTS 39 /*%< file already exists */
+#define ISC_R_NOTCONNECTED 40 /*%< socket is not connected */
+#define ISC_R_RANGE 41 /*%< out of range */
+#define ISC_R_NOENTROPY 42 /*%< out of entropy */
+#define ISC_R_MULTICAST 43 /*%< invalid use of multicast */
+#define ISC_R_NOTFILE 44 /*%< not a file */
+#define ISC_R_NOTDIRECTORY 45 /*%< not a directory */
+#define ISC_R_QUEUEFULL 46 /*%< queue is full */
+#define ISC_R_FAMILYMISMATCH 47 /*%< address family mismatch */
+#define ISC_R_FAMILYNOSUPPORT 48 /*%< AF not supported */
+#define ISC_R_BADHEX 49 /*%< bad hex encoding */
+#define ISC_R_TOOMANYOPENFILES 50 /*%< too many open files */
+#define ISC_R_NOTBLOCKING 51 /*%< not blocking */
+#define ISC_R_UNBALANCEDQUOTES 52 /*%< unbalanced quotes */
+#define ISC_R_INPROGRESS 53 /*%< operation in progress */
+#define ISC_R_CONNECTIONRESET 54 /*%< connection reset */
+#define ISC_R_SOFTQUOTA 55 /*%< soft quota reached */
+#define ISC_R_BADNUMBER 56 /*%< not a valid number */
+#define ISC_R_DISABLED 57 /*%< disabled */
+#define ISC_R_MAXSIZE 58 /*%< max size */
+#define ISC_R_BADADDRESSFORM 59 /*%< invalid address format */
+
+/*% Not a result code: the number of results. */
+#define ISC_R_NRESULTS 60
+
+ISC_LANG_BEGINDECLS
+
+const char *
+isc_result_totext(isc_result_t);
+/*%<
+ * Convert an isc_result_t into a string message describing the result.
+ */
+
+isc_result_t
+isc_result_register(unsigned int base, unsigned int nresults,
+ const char **text, isc_msgcat_t *msgcat, int set);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RESULT_H */
diff --git a/lib/isc/include/isc/resultclass.h b/lib/isc/include/isc/resultclass.h
new file mode 100644
index 0000000..5e20800
--- /dev/null
+++ b/lib/isc/include/isc/resultclass.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2004, 2005 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: resultclass.h,v 1.12.18.2 2005/04/29 00:17:02 marka Exp $ */
+
+#ifndef ISC_RESULTCLASS_H
+#define ISC_RESULTCLASS_H 1
+
+
+/*! \file
+ * \brief Registry of Predefined Result Type Classes
+ *
+ * A result class number is an unsigned 16 bit number. Each class may
+ * contain up to 65536 results. A result code is formed by adding the
+ * result number within the class to the class number multiplied by 65536.
+ *
+ * Classes < 1024 are reserved for ISC use.
+ * Result classes >= 1024 and <= 65535 are reserved for application use.
+ */
+
+#define ISC_RESULTCLASS_FROMNUM(num) ((num) << 16)
+#define ISC_RESULTCLASS_TONUM(rclass) ((rclass) >> 16)
+#define ISC_RESULTCLASS_SIZE 65536
+#define ISC_RESULTCLASS_INCLASS(rclass, result) \
+ ((rclass) == ((result) & 0xFFFF0000))
+
+
+#define ISC_RESULTCLASS_ISC ISC_RESULTCLASS_FROMNUM(0)
+#define ISC_RESULTCLASS_DNS ISC_RESULTCLASS_FROMNUM(1)
+#define ISC_RESULTCLASS_DST ISC_RESULTCLASS_FROMNUM(2)
+#define ISC_RESULTCLASS_DNSRCODE ISC_RESULTCLASS_FROMNUM(3)
+#define ISC_RESULTCLASS_OMAPI ISC_RESULTCLASS_FROMNUM(4)
+#define ISC_RESULTCLASS_ISCCC ISC_RESULTCLASS_FROMNUM(5)
+
+
+#endif /* ISC_RESULTCLASS_H */
diff --git a/lib/isc/include/isc/rwlock.h b/lib/isc/include/isc/rwlock.h
new file mode 100644
index 0000000..404f93c
--- /dev/null
+++ b/lib/isc/include/isc/rwlock.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2004, 2005 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: rwlock.h,v 1.21.18.3 2005/06/04 06:23:44 jinmei Exp $ */
+
+#ifndef ISC_RWLOCK_H
+#define ISC_RWLOCK_H 1
+
+/*! \file */
+
+#include <isc/condition.h>
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef enum {
+ isc_rwlocktype_none = 0,
+ isc_rwlocktype_read,
+ isc_rwlocktype_write
+} isc_rwlocktype_t;
+
+#ifdef ISC_PLATFORM_USETHREADS
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+#define ISC_RWLOCK_USEATOMIC 1
+#endif
+
+struct isc_rwlock {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mutex_t lock;
+
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+ /*
+ * When some atomic instructions with hardware assistance are
+ * available, rwlock will use those so that concurrent readers do not
+ * interfere with each other through mutex as long as no writers
+ * appear, massively reducing the lock overhead in the typical case.
+ *
+ * The basic algorithm of this approach is the "simple
+ * writer-preference lock" shown in the following URL:
+ * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html
+ * but our implementation does not rely on the spin lock unlike the
+ * original algorithm to be more portable as a user space application.
+ */
+
+ /* Read or modified atomically. */
+ isc_int32_t write_requests;
+ isc_int32_t write_completions;
+ isc_int32_t cnt_and_flag;
+
+ /* Locked by lock. */
+ isc_condition_t readable;
+ isc_condition_t writeable;
+ unsigned int readers_waiting;
+
+ /* Locked by rwlock itself. */
+ unsigned int write_granted;
+
+ /* Unlocked. */
+ unsigned int write_quota;
+
+#else /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+
+ /*%< Locked by lock. */
+ isc_condition_t readable;
+ isc_condition_t writeable;
+ isc_rwlocktype_t type;
+
+ /*% The number of threads that have the lock. */
+ unsigned int active;
+
+ /*%
+ * The number of lock grants made since the lock was last switched
+ * from reading to writing or vice versa; used in determining
+ * when the quota is reached and it is time to switch.
+ */
+ unsigned int granted;
+
+ unsigned int readers_waiting;
+ unsigned int writers_waiting;
+ unsigned int read_quota;
+ unsigned int write_quota;
+ isc_rwlocktype_t original;
+#endif /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+};
+#else /* ISC_PLATFORM_USETHREADS */
+struct isc_rwlock {
+ unsigned int magic;
+ isc_rwlocktype_t type;
+ unsigned int active;
+};
+#endif /* ISC_PLATFORM_USETHREADS */
+
+
+isc_result_t
+isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
+ unsigned int write_quota);
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl);
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl);
+
+void
+isc_rwlock_destroy(isc_rwlock_t *rwl);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RWLOCK_H */
diff --git a/lib/isc/include/isc/serial.h b/lib/isc/include/isc/serial.h
new file mode 100644
index 0000000..86d9b2f
--- /dev/null
+++ b/lib/isc/include/isc/serial.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2004, 2005 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: serial.h,v 1.10.18.2 2005/04/29 00:17:02 marka Exp $ */
+
+#ifndef ISC_SERIAL_H
+#define ISC_SERIAL_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*! \file
+ * \brief Implement 32 bit serial space arithmetic comparision functions.
+ * Note: Undefined results are returned as ISC_FALSE.
+ */
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_boolean_t
+isc_serial_lt(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ * Return true if 'a' < 'b' otherwise false.
+ */
+
+isc_boolean_t
+isc_serial_gt(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ * Return true if 'a' > 'b' otherwise false.
+ */
+
+isc_boolean_t
+isc_serial_le(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ * Return true if 'a' <= 'b' otherwise false.
+ */
+
+isc_boolean_t
+isc_serial_ge(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ * Return true if 'a' >= 'b' otherwise false.
+ */
+
+isc_boolean_t
+isc_serial_eq(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ * Return true if 'a' == 'b' otherwise false.
+ */
+
+isc_boolean_t
+isc_serial_ne(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ * Return true if 'a' != 'b' otherwise false.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SERIAL_H */
diff --git a/lib/isc/include/isc/sha1.h b/lib/isc/include/isc/sha1.h
new file mode 100644
index 0000000..bb22f06
--- /dev/null
+++ b/lib/isc/include/isc/sha1.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004-2006 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.
+ */
+
+#ifndef ISC_SHA1_H
+#define ISC_SHA1_H 1
+
+/* $Id: sha1.h,v 1.9.18.5 2006/08/16 03:18:14 marka Exp $ */
+
+/* $NetBSD: sha1.h,v 1.2 1998/05/29 22:55:44 thorpej Exp $ */
+
+/*! \file
+ * \brief SHA-1 in C
+ * \author By Steve Reid <steve@edmweb.com>
+ * \note 100% Public Domain
+ */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#define ISC_SHA1_DIGESTLENGTH 20U
+#define ISC_SHA1_BLOCK_LENGTH 64U
+
+typedef struct {
+ isc_uint32_t state[5];
+ isc_uint32_t count[2];
+ unsigned char buffer[ISC_SHA1_BLOCK_LENGTH];
+} isc_sha1_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_sha1_init(isc_sha1_t *ctx);
+
+void
+isc_sha1_invalidate(isc_sha1_t *ctx);
+
+void
+isc_sha1_update(isc_sha1_t *ctx, const unsigned char *data, unsigned int len);
+
+void
+isc_sha1_final(isc_sha1_t *ctx, unsigned char *digest);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SHA1_H */
diff --git a/lib/isc/include/isc/sha2.h b/lib/isc/include/isc/sha2.h
new file mode 100644
index 0000000..e54c620
--- /dev/null
+++ b/lib/isc/include/isc/sha2.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2005, 2006 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: sha2.h,v 1.2.2.6 2006/08/16 03:18:14 marka Exp $ */
+
+/* $FreeBSD$ */
+/* $KAME: sha2.h,v 1.3 2001/03/12 08:27:48 itojun Exp $ */
+
+/*
+ * sha2.h
+ *
+ * Version 1.0.0beta1
+ *
+ * Written by Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright 2000 Aaron D. Gifford. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef ISC_SHA2_H
+#define ISC_SHA2_H
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*** SHA-224/256/384/512 Various Length Definitions ***********************/
+
+#define ISC_SHA224_BLOCK_LENGTH 64U
+#define ISC_SHA224_DIGESTLENGTH 28U
+#define ISC_SHA224_DIGESTSTRINGLENGTH (ISC_SHA224_DIGESTLENGTH * 2 + 1)
+#define ISC_SHA256_BLOCK_LENGTH 64U
+#define ISC_SHA256_DIGESTLENGTH 32U
+#define ISC_SHA256_DIGESTSTRINGLENGTH (ISC_SHA256_DIGESTLENGTH * 2 + 1)
+#define ISC_SHA384_BLOCK_LENGTH 128
+#define ISC_SHA384_DIGESTLENGTH 48U
+#define ISC_SHA384_DIGESTSTRINGLENGTH (ISC_SHA384_DIGESTLENGTH * 2 + 1)
+#define ISC_SHA512_BLOCK_LENGTH 128U
+#define ISC_SHA512_DIGESTLENGTH 64U
+#define ISC_SHA512_DIGESTSTRINGLENGTH (ISC_SHA512_DIGESTLENGTH * 2 + 1)
+
+
+ISC_LANG_BEGINDECLS
+
+/*** SHA-256/384/512 Context Structures *******************************/
+
+/*
+ * Keep buffer immediately after bitcount to preserve alignment.
+ */
+typedef struct {
+ isc_uint32_t state[8];
+ isc_uint64_t bitcount;
+ isc_uint8_t buffer[ISC_SHA256_BLOCK_LENGTH];
+} isc_sha256_t;
+
+/*
+ * Keep buffer immediately after bitcount to preserve alignment.
+ */
+typedef struct {
+ isc_uint64_t state[8];
+ isc_uint64_t bitcount[2];
+ isc_uint8_t buffer[ISC_SHA512_BLOCK_LENGTH];
+} isc_sha512_t;
+
+typedef isc_sha256_t isc_sha224_t;
+typedef isc_sha512_t isc_sha384_t;
+
+/*** SHA-224/256/384/512 Function Prototypes ******************************/
+
+void isc_sha224_init (isc_sha224_t *);
+void isc_sha224_update (isc_sha224_t *, const isc_uint8_t *, size_t);
+void isc_sha224_final (isc_uint8_t[ISC_SHA224_DIGESTLENGTH], isc_sha224_t *);
+char *isc_sha224_end (isc_sha224_t *, char[ISC_SHA224_DIGESTSTRINGLENGTH]);
+char *isc_sha224_data (const isc_uint8_t *, size_t, char[ISC_SHA224_DIGESTSTRINGLENGTH]);
+
+void isc_sha256_init (isc_sha256_t *);
+void isc_sha256_update (isc_sha256_t *, const isc_uint8_t *, size_t);
+void isc_sha256_final (isc_uint8_t[ISC_SHA256_DIGESTLENGTH], isc_sha256_t *);
+char *isc_sha256_end (isc_sha256_t *, char[ISC_SHA256_DIGESTSTRINGLENGTH]);
+char *isc_sha256_data (const isc_uint8_t *, size_t, char[ISC_SHA256_DIGESTSTRINGLENGTH]);
+
+void isc_sha384_init (isc_sha384_t *);
+void isc_sha384_update (isc_sha384_t *, const isc_uint8_t *, size_t);
+void isc_sha384_final (isc_uint8_t[ISC_SHA384_DIGESTLENGTH], isc_sha384_t *);
+char *isc_sha384_end (isc_sha384_t *, char[ISC_SHA384_DIGESTSTRINGLENGTH]);
+char *isc_sha384_data (const isc_uint8_t *, size_t, char[ISC_SHA384_DIGESTSTRINGLENGTH]);
+
+void isc_sha512_init (isc_sha512_t *);
+void isc_sha512_update (isc_sha512_t *, const isc_uint8_t *, size_t);
+void isc_sha512_final (isc_uint8_t[ISC_SHA512_DIGESTLENGTH], isc_sha512_t *);
+char *isc_sha512_end (isc_sha512_t *, char[ISC_SHA512_DIGESTSTRINGLENGTH]);
+char *isc_sha512_data (const isc_uint8_t *, size_t, char[ISC_SHA512_DIGESTSTRINGLENGTH]);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SHA2_H */
diff --git a/lib/isc/include/isc/sockaddr.h b/lib/isc/include/isc/sockaddr.h
new file mode 100644
index 0000000..83412d2
--- /dev/null
+++ b/lib/isc/include/isc/sockaddr.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: sockaddr.h,v 1.42.18.8 2006/03/02 00:37:22 marka Exp $ */
+
+#ifndef ISC_SOCKADDR_H
+#define ISC_SOCKADDR_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/net.h>
+#include <isc/types.h>
+#ifdef ISC_PLATFORM_HAVESYSUNH
+#include <sys/un.h>
+#endif
+
+struct isc_sockaddr {
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ struct sockaddr_un sunix;
+#endif
+ } type;
+ unsigned int length; /* XXXRTH beginning? */
+ ISC_LINK(struct isc_sockaddr) link;
+};
+
+typedef ISC_LIST(struct isc_sockaddr) isc_sockaddrlist_t;
+
+#define ISC_SOCKADDR_CMPADDR 0x0001 /*%< compare the address
+ * sin_addr/sin6_addr */
+#define ISC_SOCKADDR_CMPPORT 0x0002 /*%< compare the port
+ * sin_port/sin6_port */
+#define ISC_SOCKADDR_CMPSCOPE 0x0004 /*%< compare the scope
+ * sin6_scope */
+#define ISC_SOCKADDR_CMPSCOPEZERO 0x0008 /*%< when comparing scopes
+ * zero scopes always match */
+
+ISC_LANG_BEGINDECLS
+
+isc_boolean_t
+isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+ unsigned int flags);
+/*%<
+ * Compare the elements of the two address ('a' and 'b') as specified
+ * by 'flags' and report if they are equal or not.
+ *
+ * 'flags' is set from ISC_SOCKADDR_CMP*.
+ */
+
+isc_boolean_t
+isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b);
+/*%<
+ * Return ISC_TRUE iff the socket addresses 'a' and 'b' are equal.
+ */
+
+isc_boolean_t
+isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b);
+/*%<
+ * Return ISC_TRUE iff the address parts of the socket addresses
+ * 'a' and 'b' are equal, ignoring the ports.
+ */
+
+isc_boolean_t
+isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+ unsigned int prefixlen);
+/*%<
+ * Return ISC_TRUE iff the most significant 'prefixlen' bits of the
+ * socket addresses 'a' and 'b' are equal, ignoring the ports.
+ */
+
+unsigned int
+isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only);
+/*%<
+ * Return a hash value for the socket address 'sockaddr'. If 'address_only'
+ * is ISC_TRUE, the hash value will not depend on the port.
+ *
+ * IPv6 addresses containing mapped IPv4 addresses generate the same hash
+ * value as the equivalent IPv4 address.
+ */
+
+void
+isc_sockaddr_any(isc_sockaddr_t *sockaddr);
+/*%<
+ * Return the IPv4 wildcard address.
+ */
+
+void
+isc_sockaddr_any6(isc_sockaddr_t *sockaddr);
+/*%<
+ * Return the IPv6 wildcard address.
+ */
+
+void
+isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int family);
+/*%<
+ * Set '*sockaddr' to the wildcard address of protocol family
+ * 'family'.
+ *
+ * Requires:
+ * \li 'family' is AF_INET or AF_INET6.
+ */
+
+void
+isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
+ in_port_t port);
+/*%<
+ * Construct an isc_sockaddr_t from an IPv4 address and port.
+ */
+
+void
+isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
+ in_port_t port);
+/*%<
+ * Construct an isc_sockaddr_t from an IPv6 address and port.
+ */
+
+void
+isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
+ in_port_t port);
+/*%<
+ * Construct an IPv6 isc_sockaddr_t representing a mapped IPv4 address.
+ */
+
+void
+isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
+ in_port_t port);
+/*%<
+ * Construct an isc_sockaddr_t from an isc_netaddr_t and port.
+ */
+
+int
+isc_sockaddr_pf(const isc_sockaddr_t *sockaddr);
+/*%<
+ * Get the protocol family of 'sockaddr'.
+ *
+ * Requires:
+ *
+ *\li 'sockaddr' is a valid sockaddr with an address family of AF_INET
+ * or AF_INET6.
+ *
+ * Returns:
+ *
+ *\li The protocol family of 'sockaddr', e.g. PF_INET or PF_INET6.
+ */
+
+void
+isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port);
+/*%<
+ * Set the port of 'sockaddr' to 'port'.
+ */
+
+in_port_t
+isc_sockaddr_getport(const isc_sockaddr_t *sockaddr);
+/*%<
+ * Get the port stored in 'sockaddr'.
+ */
+
+isc_result_t
+isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target);
+/*%<
+ * Append a text representation of 'sockaddr' to the buffer 'target'.
+ * The text will include both the IP address (v4 or v6) and the port.
+ * The text is null terminated, but the terminating null is not
+ * part of the buffer's used region.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOSPACE The text or the null termination did not fit.
+ */
+
+void
+isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size);
+/*%<
+ * Format a human-readable representation of the socket address '*sa'
+ * into the character array 'array', which is of size 'size'.
+ * The resulting string is guaranteed to be null-terminated.
+ */
+
+isc_boolean_t
+isc_sockaddr_ismulticast(const isc_sockaddr_t *sa);
+/*%<
+ * Returns #ISC_TRUE if the address is a multicast address.
+ */
+
+isc_boolean_t
+isc_sockaddr_isexperimental(const isc_sockaddr_t *sa);
+/*
+ * Returns ISC_TRUE if the address is a experimental (CLASS E) address.
+ */
+
+isc_boolean_t
+isc_sockaddr_islinklocal(const isc_sockaddr_t *sa);
+/*%<
+ * Returns ISC_TRUE if the address is a link local addresss.
+ */
+
+isc_boolean_t
+isc_sockaddr_issitelocal(const isc_sockaddr_t *sa);
+/*%<
+ * Returns ISC_TRUE if the address is a sitelocal address.
+ */
+
+isc_result_t
+isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path);
+/*
+ * Create a UNIX domain sockaddr that refers to path.
+ *
+ * Returns:
+ * \li ISC_R_NOSPACE
+ * \li ISC_R_NOTIMPLEMENTED
+ * \li ISC_R_SUCCESS
+ */
+
+#define ISC_SOCKADDR_FORMATSIZE \
+ sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX%SSSSSSSSSS#YYYYY")
+/*%<
+ * Minimum size of array to pass to isc_sockaddr_format().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SOCKADDR_H */
diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h
new file mode 100644
index 0000000..ccc49f5
--- /dev/null
+++ b/lib/isc/include/isc/socket.h
@@ -0,0 +1,752 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: socket.h,v 1.57.18.6 2006/06/07 00:29:45 marka Exp $ */
+
+#ifndef ISC_SOCKET_H
+#define ISC_SOCKET_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief Provides TCP and UDP sockets for network I/O. The sockets are event
+ * sources in the task system.
+ *
+ * When I/O completes, a completion event for the socket is posted to the
+ * event queue of the task which requested the I/O.
+ *
+ * \li MP:
+ * The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ * Clients of this module must not be holding a socket's task's lock when
+ * making a call that affects that socket. Failure to follow this rule
+ * can result in deadlock.
+ * The caller must ensure that isc_socketmgr_destroy() is called only
+ * once for a given manager.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+#include <isc/event.h>
+#include <isc/eventclass.h>
+#include <isc/time.h>
+#include <isc/region.h>
+#include <isc/sockaddr.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Constants
+ ***/
+
+/*%
+ * Maximum number of buffers in a scatter/gather read/write. The operating
+ * system in use must support at least this number (plus one on some.)
+ */
+#define ISC_SOCKET_MAXSCATTERGATHER 8
+
+/***
+ *** Types
+ ***/
+
+struct isc_socketevent {
+ ISC_EVENT_COMMON(isc_socketevent_t);
+ isc_result_t result; /*%< OK, EOF, whatever else */
+ unsigned int minimum; /*%< minimum i/o for event */
+ unsigned int n; /*%< bytes read or written */
+ unsigned int offset; /*%< offset into buffer list */
+ isc_region_t region; /*%< for single-buffer i/o */
+ isc_bufferlist_t bufferlist; /*%< list of buffers */
+ isc_sockaddr_t address; /*%< source address */
+ isc_time_t timestamp; /*%< timestamp of packet recv */
+ struct in6_pktinfo pktinfo; /*%< ipv6 pktinfo */
+ isc_uint32_t attributes; /*%< see below */
+ isc_eventdestructor_t destroy; /*%< original destructor */
+};
+
+typedef struct isc_socket_newconnev isc_socket_newconnev_t;
+struct isc_socket_newconnev {
+ ISC_EVENT_COMMON(isc_socket_newconnev_t);
+ isc_socket_t * newsocket;
+ isc_result_t result; /*%< OK, EOF, whatever else */
+ isc_sockaddr_t address; /*%< source address */
+};
+
+typedef struct isc_socket_connev isc_socket_connev_t;
+struct isc_socket_connev {
+ ISC_EVENT_COMMON(isc_socket_connev_t);
+ isc_result_t result; /*%< OK, EOF, whatever else */
+};
+
+/*@{*/
+/*!
+ * _ATTACHED: Internal use only.
+ * _TRUNC: Packet was truncated on receive.
+ * _CTRUNC: Packet control information was truncated. This can
+ * indicate that the packet is not complete, even though
+ * all the data is valid.
+ * _TIMESTAMP: The timestamp member is valid.
+ * _PKTINFO: The pktinfo member is valid.
+ * _MULTICAST: The UDP packet was received via a multicast transmission.
+ */
+#define ISC_SOCKEVENTATTR_ATTACHED 0x80000000U /* internal */
+#define ISC_SOCKEVENTATTR_TRUNC 0x00800000U /* public */
+#define ISC_SOCKEVENTATTR_CTRUNC 0x00400000U /* public */
+#define ISC_SOCKEVENTATTR_TIMESTAMP 0x00200000U /* public */
+#define ISC_SOCKEVENTATTR_PKTINFO 0x00100000U /* public */
+#define ISC_SOCKEVENTATTR_MULTICAST 0x00080000U /* public */
+/*@}*/
+
+#define ISC_SOCKEVENT_ANYEVENT (0)
+#define ISC_SOCKEVENT_RECVDONE (ISC_EVENTCLASS_SOCKET + 1)
+#define ISC_SOCKEVENT_SENDDONE (ISC_EVENTCLASS_SOCKET + 2)
+#define ISC_SOCKEVENT_NEWCONN (ISC_EVENTCLASS_SOCKET + 3)
+#define ISC_SOCKEVENT_CONNECT (ISC_EVENTCLASS_SOCKET + 4)
+
+/*
+ * Internal events.
+ */
+#define ISC_SOCKEVENT_INTR (ISC_EVENTCLASS_SOCKET + 256)
+#define ISC_SOCKEVENT_INTW (ISC_EVENTCLASS_SOCKET + 257)
+
+typedef enum {
+ isc_sockettype_udp = 1,
+ isc_sockettype_tcp = 2,
+ isc_sockettype_unix = 3
+} isc_sockettype_t;
+
+/*@{*/
+/*!
+ * How a socket should be shutdown in isc_socket_shutdown() calls.
+ */
+#define ISC_SOCKSHUT_RECV 0x00000001 /*%< close read side */
+#define ISC_SOCKSHUT_SEND 0x00000002 /*%< close write side */
+#define ISC_SOCKSHUT_ALL 0x00000003 /*%< close them all */
+/*@}*/
+
+/*@{*/
+/*!
+ * What I/O events to cancel in isc_socket_cancel() calls.
+ */
+#define ISC_SOCKCANCEL_RECV 0x00000001 /*%< cancel recv */
+#define ISC_SOCKCANCEL_SEND 0x00000002 /*%< cancel send */
+#define ISC_SOCKCANCEL_ACCEPT 0x00000004 /*%< cancel accept */
+#define ISC_SOCKCANCEL_CONNECT 0x00000008 /*%< cancel connect */
+#define ISC_SOCKCANCEL_ALL 0x0000000f /*%< cancel everything */
+/*@}*/
+
+/*@{*/
+/*!
+ * Flags for isc_socket_send() and isc_socket_recv() calls.
+ */
+#define ISC_SOCKFLAG_IMMEDIATE 0x00000001 /*%< send event only if needed */
+#define ISC_SOCKFLAG_NORETRY 0x00000002 /*%< drop failed UDP sends */
+/*@}*/
+
+/***
+ *** Socket and Socket Manager Functions
+ ***
+ *** Note: all Ensures conditions apply only if the result is success for
+ *** those functions which return an isc_result.
+ ***/
+
+isc_result_t
+isc_socket_create(isc_socketmgr_t *manager,
+ int pf,
+ isc_sockettype_t type,
+ isc_socket_t **socketp);
+/*%<
+ * Create a new 'type' socket managed by 'manager'.
+ *
+ * Note:
+ *
+ *\li 'pf' is the desired protocol family, e.g. PF_INET or PF_INET6.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid manager
+ *
+ *\li 'socketp' is a valid pointer, and *socketp == NULL
+ *
+ * Ensures:
+ *
+ * '*socketp' is attached to the newly created socket
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_NORESOURCES
+ *\li #ISC_R_UNEXPECTED
+ */
+
+void
+isc_socket_cancel(isc_socket_t *sock, isc_task_t *task,
+ unsigned int how);
+/*%<
+ * Cancel pending I/O of the type specified by "how".
+ *
+ * Note: if "task" is NULL, then the cancel applies to all tasks using the
+ * socket.
+ *
+ * Requires:
+ *
+ * \li "socket" is a valid socket
+ *
+ * \li "task" is NULL or a valid task
+ *
+ * "how" is a bitmask describing the type of cancelation to perform.
+ * The type ISC_SOCKCANCEL_ALL will cancel all pending I/O on this
+ * socket.
+ *
+ * \li ISC_SOCKCANCEL_RECV:
+ * Cancel pending isc_socket_recv() calls.
+ *
+ * \li ISC_SOCKCANCEL_SEND:
+ * Cancel pending isc_socket_send() and isc_socket_sendto() calls.
+ *
+ * \li ISC_SOCKCANCEL_ACCEPT:
+ * Cancel pending isc_socket_accept() calls.
+ *
+ * \li ISC_SOCKCANCEL_CONNECT:
+ * Cancel pending isc_socket_connect() call.
+ */
+
+void
+isc_socket_shutdown(isc_socket_t *sock, unsigned int how);
+/*%<
+ * Shutdown 'socket' according to 'how'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket.
+ *
+ * \li 'task' is NULL or is a valid task.
+ *
+ * \li If 'how' is 'ISC_SOCKSHUT_RECV' or 'ISC_SOCKSHUT_ALL' then
+ *
+ * The read queue must be empty.
+ *
+ * No further read requests may be made.
+ *
+ * \li If 'how' is 'ISC_SOCKSHUT_SEND' or 'ISC_SOCKSHUT_ALL' then
+ *
+ * The write queue must be empty.
+ *
+ * No further write requests may be made.
+ */
+
+void
+isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp);
+/*%<
+ * Attach *socketp to socket.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket.
+ *
+ * \li 'socketp' points to a NULL socket.
+ *
+ * Ensures:
+ *
+ * \li *socketp is attached to socket.
+ */
+
+void
+isc_socket_detach(isc_socket_t **socketp);
+/*%<
+ * Detach *socketp from its socket.
+ *
+ * Requires:
+ *
+ * \li 'socketp' points to a valid socket.
+ *
+ * \li If '*socketp' is the last reference to the socket,
+ * then:
+ *
+ * There must be no pending I/O requests.
+ *
+ * Ensures:
+ *
+ * \li *socketp is NULL.
+ *
+ * \li If '*socketp' is the last reference to the socket,
+ * then:
+ *
+ * The socket will be shutdown (both reading and writing)
+ * for all tasks.
+ *
+ * All resources used by the socket have been freed
+ */
+
+isc_result_t
+isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *addressp);
+/*%<
+ * Bind 'socket' to '*addressp'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket
+ *
+ * \li 'addressp' points to a valid isc_sockaddr.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOPERM
+ * \li ISC_R_ADDRNOTAVAIL
+ * \li ISC_R_ADDRINUSE
+ * \li ISC_R_BOUND
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_filter(isc_socket_t *sock, const char *filter);
+/*%<
+ * Inform the kernel that it should perform accept filtering.
+ * If filter is NULL the current filter will be removed.:w
+ */
+
+isc_result_t
+isc_socket_listen(isc_socket_t *sock, unsigned int backlog);
+/*%<
+ * Set listen mode on the socket. After this call, the only function that
+ * can be used (other than attach and detach) is isc_socket_accept().
+ *
+ * Notes:
+ *
+ * \li 'backlog' is as in the UNIX system call listen() and may be
+ * ignored by non-UNIX implementations.
+ *
+ * \li If 'backlog' is zero, a reasonable system default is used, usually
+ * SOMAXCONN.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid, bound TCP socket or a valid, bound UNIX socket.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_accept(isc_socket_t *sock,
+ isc_task_t *task, isc_taskaction_t action, const void *arg);
+/*%<
+ * Queue accept event. When a new connection is received, the task will
+ * get an ISC_SOCKEVENT_NEWCONN event with the sender set to the listen
+ * socket. The new socket structure is sent inside the isc_socket_newconnev_t
+ * event type, and is attached to the task 'task'.
+ *
+ * REQUIRES:
+ * \li 'socket' is a valid TCP socket that isc_socket_listen() was called
+ * on.
+ *
+ * \li 'task' is a valid task
+ *
+ * \li 'action' is a valid action
+ *
+ * RETURNS:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addressp,
+ isc_task_t *task, isc_taskaction_t action,
+ const void *arg);
+/*%<
+ * Connect 'socket' to peer with address *saddr. When the connection
+ * succeeds, or when an error occurs, a CONNECT event with action 'action'
+ * and arg 'arg' will be posted to the event queue for 'task'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid TCP socket
+ *
+ * \li 'addressp' points to a valid isc_sockaddr
+ *
+ * \li 'task' is a valid task
+ *
+ * \li 'action' is a valid action
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_UNEXPECTED
+ *
+ * Posted event's result code:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_TIMEDOUT
+ * \li ISC_R_CONNREFUSED
+ * \li ISC_R_NETUNREACH
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp);
+/*%<
+ * Get the name of the peer connected to 'socket'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid TCP socket.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_TOOSMALL
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp);
+/*%<
+ * Get the name of 'socket'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_TOOSMALL
+ * \li ISC_R_UNEXPECTED
+ */
+
+/*@{*/
+isc_result_t
+isc_socket_recv(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum,
+ isc_task_t *task, isc_taskaction_t action, const void *arg);
+isc_result_t
+isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ unsigned int minimum,
+ isc_task_t *task, isc_taskaction_t action, const void *arg);
+
+isc_result_t
+isc_socket_recv2(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_socketevent_t *event, unsigned int flags);
+
+/*!
+ * Receive from 'socket', storing the results in region.
+ *
+ * Notes:
+ *
+ *\li Let 'length' refer to the length of 'region' or to the sum of all
+ * available regions in the list of buffers '*buflist'.
+ *
+ *\li If 'minimum' is non-zero and at least that many bytes are read,
+ * the completion event will be posted to the task 'task.' If minimum
+ * is zero, the exact number of bytes requested in the region must
+ * be read for an event to be posted. This only makes sense for TCP
+ * connections, and is always set to 1 byte for UDP.
+ *
+ *\li The read will complete when the desired number of bytes have been
+ * read, if end-of-input occurs, or if an error occurs. A read done
+ * event with the given 'action' and 'arg' will be posted to the
+ * event queue of 'task'.
+ *
+ *\li The caller may not modify 'region', the buffers which are passed
+ * into this function, or any data they refer to until the completion
+ * event is received.
+ *
+ *\li For isc_socket_recvv():
+ * On successful completion, '*buflist' will be empty, and the list of
+ * all buffers will be returned in the done event's 'bufferlist'
+ * member. On error return, '*buflist' will be unchanged.
+ *
+ *\li For isc_socket_recv2():
+ * 'event' is not NULL, and the non-socket specific fields are
+ * expected to be initialized.
+ *
+ *\li For isc_socket_recv2():
+ * The only defined value for 'flags' is ISC_SOCKFLAG_IMMEDIATE. If
+ * set and the operation completes, the return value will be
+ * ISC_R_SUCCESS and the event will be filled in and not sent. If the
+ * operation does not complete, the return value will be
+ * ISC_R_INPROGRESS and the event will be sent when the operation
+ * completes.
+ *
+ * Requires:
+ *
+ *\li 'socket' is a valid, bound socket.
+ *
+ *\li For isc_socket_recv():
+ * 'region' is a valid region
+ *
+ *\li For isc_socket_recvv():
+ * 'buflist' is non-NULL, and '*buflist' contain at least one buffer.
+ *
+ *\li 'task' is a valid task
+ *
+ *\li For isc_socket_recv() and isc_socket_recvv():
+ * action != NULL and is a valid action
+ *
+ *\li For isc_socket_recv2():
+ * event != NULL
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_INPROGRESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ *
+ * Event results:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_UNEXPECTED
+ *\li XXX needs other net-type errors
+ */
+/*@}*/
+
+/*@{*/
+isc_result_t
+isc_socket_send(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, const void *arg);
+isc_result_t
+isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, const void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo);
+isc_result_t
+isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, const void *arg);
+isc_result_t
+isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, const void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo);
+isc_result_t
+isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ isc_socketevent_t *event, unsigned int flags);
+
+/*!
+ * Send the contents of 'region' to the socket's peer.
+ *
+ * Notes:
+ *
+ *\li Shutting down the requestor's task *may* result in any
+ * still pending writes being dropped or completed, depending on the
+ * underlying OS implementation.
+ *
+ *\li If 'action' is NULL, then no completion event will be posted.
+ *
+ *\li The caller may not modify 'region', the buffers which are passed
+ * into this function, or any data they refer to until the completion
+ * event is received.
+ *
+ *\li For isc_socket_sendv() and isc_socket_sendtov():
+ * On successful completion, '*buflist' will be empty, and the list of
+ * all buffers will be returned in the done event's 'bufferlist'
+ * member. On error return, '*buflist' will be unchanged.
+ *
+ *\li For isc_socket_sendto2():
+ * 'event' is not NULL, and the non-socket specific fields are
+ * expected to be initialized.
+ *
+ *\li For isc_socket_sendto2():
+ * The only defined values for 'flags' are ISC_SOCKFLAG_IMMEDIATE
+ * and ISC_SOCKFLAG_NORETRY.
+ *
+ *\li If ISC_SOCKFLAG_IMMEDIATE is set and the operation completes, the
+ * return value will be ISC_R_SUCCESS and the event will be filled
+ * in and not sent. If the operation does not complete, the return
+ * value will be ISC_R_INPROGRESS and the event will be sent when
+ * the operation completes.
+ *
+ *\li ISC_SOCKFLAG_NORETRY can only be set for UDP sockets. If set
+ * and the send operation fails due to a transient error, the send
+ * will not be retried and the error will be indicated in the event.
+ * Using this option along with ISC_SOCKFLAG_IMMEDIATE allows the caller
+ * to specify a region that is allocated on the stack.
+ *
+ * Requires:
+ *
+ *\li 'socket' is a valid, bound socket.
+ *
+ *\li For isc_socket_send():
+ * 'region' is a valid region
+ *
+ *\li For isc_socket_sendv() and isc_socket_sendtov():
+ * 'buflist' is non-NULL, and '*buflist' contain at least one buffer.
+ *
+ *\li 'task' is a valid task
+ *
+ *\li For isc_socket_sendv(), isc_socket_sendtov(), isc_socket_send(), and
+ * isc_socket_sendto():
+ * action == NULL or is a valid action
+ *
+ *\li For isc_socket_sendto2():
+ * event != NULL
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_INPROGRESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ *
+ * Event results:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_UNEXPECTED
+ *\li XXX needs other net-type errors
+ */
+/*@}*/
+
+isc_result_t
+isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp);
+/*%<
+ * Create a socket manager.
+ *
+ * Notes:
+ *
+ *\li All memory will be allocated in memory context 'mctx'.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li 'managerp' points to a NULL isc_socketmgr_t.
+ *
+ * Ensures:
+ *
+ *\li '*managerp' is a valid isc_socketmgr_t.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ */
+
+void
+isc_socketmgr_destroy(isc_socketmgr_t **managerp);
+/*%<
+ * Destroy a socket manager.
+ *
+ * Notes:
+ *
+ *\li This routine blocks until there are no sockets left in the manager,
+ * so if the caller holds any socket references using the manager, it
+ * must detach them before calling isc_socketmgr_destroy() or it will
+ * block forever.
+ *
+ * Requires:
+ *
+ *\li '*managerp' is a valid isc_socketmgr_t.
+ *
+ *\li All sockets managed by this manager are fully detached.
+ *
+ * Ensures:
+ *
+ *\li *managerp == NULL
+ *
+ *\li All resources used by the manager have been freed.
+ */
+
+isc_sockettype_t
+isc_socket_gettype(isc_socket_t *sock);
+/*%<
+ * Returns the socket type for "sock."
+ *
+ * Requires:
+ *
+ *\li "sock" is a valid socket.
+ */
+
+/*@{*/
+isc_boolean_t
+isc_socket_isbound(isc_socket_t *sock);
+
+void
+isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes);
+/*%<
+ * If the socket is an IPv6 socket set/clear the IPV6_IPV6ONLY socket
+ * option if the host OS supports this option.
+ *
+ * Requires:
+ *\li 'sock' is a valid socket.
+ */
+/*@}*/
+
+void
+isc_socket_cleanunix(isc_sockaddr_t *addr, isc_boolean_t active);
+
+/*%<
+ * Cleanup UNIX domain sockets in the file-system. If 'active' is true
+ * then just unlink the socket. If 'active' is false try to determine
+ * if there is a listener of the socket or not. If no listener is found
+ * then unlink socket.
+ *
+ * Prior to unlinking the path is tested to see if it a socket.
+ *
+ * Note: there are a number of race conditions which cannot be avoided
+ * both in the filesystem and any application using UNIX domain
+ * sockets (e.g. socket is tested between bind() and listen(),
+ * the socket is deleted and replaced in the file-system between
+ * stat() and unlink()).
+ */
+
+isc_result_t
+isc_socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm,
+ isc_uint32_t owner, isc_uint32_t group);
+/*%<
+ * Set ownership and file permissions on the UNIX domain socket.
+ *
+ * Note: On Solaris and SunOS this secures the directory containing
+ * the socket as Solaris and SunOS do not honour the filesytem
+ * permissions on the socket.
+ *
+ * Requires:
+ * \li 'sockaddr' to be a valid UNIX domain sockaddr.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_FAILURE
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SOCKET_H */
diff --git a/lib/isc/include/isc/stdio.h b/lib/isc/include/isc/stdio.h
new file mode 100644
index 0000000..e3bf0cd
--- /dev/null
+++ b/lib/isc/include/isc/stdio.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2004, 2005 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: stdio.h,v 1.7.18.2 2005/04/29 00:17:03 marka Exp $ */
+
+#ifndef ISC_STDIO_H
+#define ISC_STDIO_H 1
+
+/*! \file */
+
+/*%
+ * These functions are wrappers around the corresponding stdio functions.
+ *
+ * They return a detailed error code in the form of an an isc_result_t. ANSI C
+ * does not guarantee that stdio functions set errno, hence these functions
+ * must use platform dependent methods (e.g., the POSIX errno) to construct the
+ * error code.
+ */
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% Open */
+isc_result_t
+isc_stdio_open(const char *filename, const char *mode, FILE **fp);
+
+/*% Close */
+isc_result_t
+isc_stdio_close(FILE *f);
+
+/*% Seek */
+isc_result_t
+isc_stdio_seek(FILE *f, long offset, int whence);
+
+/*% Read */
+isc_result_t
+isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f,
+ size_t *nret);
+
+/*% Write */
+isc_result_t
+isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f,
+ size_t *nret);
+
+/*% Flush */
+isc_result_t
+isc_stdio_flush(FILE *f);
+
+isc_result_t
+isc_stdio_sync(FILE *f);
+/*%<
+ * Invoke fsync() on the file descriptor underlying an stdio stream, or an
+ * equivalent system-dependent operation. Note that this function has no
+ * direct counterpart in the stdio library.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STDIO_H */
diff --git a/lib/isc/include/isc/stdlib.h b/lib/isc/include/isc/stdlib.h
new file mode 100644
index 0000000..0e2c697
--- /dev/null
+++ b/lib/isc/include/isc/stdlib.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: stdlib.h,v 1.2.18.2 2005/04/29 00:17:03 marka Exp $ */
+
+#ifndef ISC_STDLIB_H
+#define ISC_STDLIB_H 1
+
+/*! \file */
+
+#include <stdlib.h>
+
+#include <isc/lang.h>
+#include <isc/platform.h>
+
+#ifdef ISC_PLATFORM_NEEDSTRTOUL
+#define strtoul isc_strtoul
+#endif
+
+ISC_LANG_BEGINDECLS
+
+unsigned long isc_strtoul(const char *, char **, int);
+
+ISC_LANG_ENDDECLS
+
+#endif
diff --git a/lib/isc/include/isc/string.h b/lib/isc/include/isc/string.h
new file mode 100644
index 0000000..bda71f4
--- /dev/null
+++ b/lib/isc/include/isc/string.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: string.h,v 1.12.18.6 2007/09/13 05:04:01 each Exp $ */
+
+#ifndef ISC_STRING_H
+#define ISC_STRING_H 1
+
+/*! \file */
+
+#include <isc/formatcheck.h>
+#include <isc/int.h>
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#include <string.h>
+
+#ifdef ISC_PLATFORM_HAVESTRINGSH
+#include <strings.h>
+#endif
+
+#define ISC_STRING_MAGIC 0x5e
+
+ISC_LANG_BEGINDECLS
+
+isc_uint64_t
+isc_string_touint64(char *source, char **endp, int base);
+/*%<
+ * Convert the string pointed to by 'source' to isc_uint64_t.
+ *
+ * On successful conversion 'endp' points to the first character
+ * after conversion is complete.
+ *
+ * 'base': 0 or 2..36
+ *
+ * If base is 0 the base is computed from the string type.
+ *
+ * On error 'endp' points to 'source'.
+ */
+
+isc_result_t
+isc_string_copy(char *target, size_t size, const char *source);
+/*
+ * Copy the string pointed to by 'source' to 'target' which is a
+ * pointer to a string of at least 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a char[] of at least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * If result == ISC_R_SUCCESS
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ *
+ * If result == ISC_R_NOSPACE
+ * 'target' is undefined.
+ *
+ * Returns:
+ * ISC_R_SUCCESS -- 'source' was successfully copied to 'target'.
+ * ISC_R_NOSPACE -- 'source' could not be copied since 'target'
+ * is too small.
+ */
+
+void
+isc_string_copy_truncate(char *target, size_t size, const char *source);
+/*
+ * Copy the string pointed to by 'source' to 'target' which is a
+ * pointer to a string of at least 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a char[] of at least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ */
+
+isc_result_t
+isc_string_append(char *target, size_t size, const char *source);
+/*
+ * Append the string pointed to by 'source' to 'target' which is a
+ * pointer to a NUL terminated string of at least 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a NUL terminated char[] of at
+ * least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * If result == ISC_R_SUCCESS
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ *
+ * If result == ISC_R_NOSPACE
+ * 'target' is undefined.
+ *
+ * Returns:
+ * ISC_R_SUCCESS -- 'source' was successfully appended to 'target'.
+ * ISC_R_NOSPACE -- 'source' could not be appended since 'target'
+ * is too small.
+ */
+
+void
+isc_string_append_truncate(char *target, size_t size, const char *source);
+/*
+ * Append the string pointed to by 'source' to 'target' which is a
+ * pointer to a NUL terminated string of at least 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a NUL terminated char[] of at
+ * least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ */
+
+isc_result_t
+isc_string_printf(char *target, size_t size, const char *format, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+/*
+ * Print 'format' to 'target' which is a pointer to a string of at least
+ * 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a char[] of at least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'format' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * If result == ISC_R_SUCCESS
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ *
+ * If result == ISC_R_NOSPACE
+ * 'target' is undefined.
+ *
+ * Returns:
+ * ISC_R_SUCCESS -- 'format' was successfully printed to 'target'.
+ * ISC_R_NOSPACE -- 'format' could not be printed to 'target' since it
+ * is too small.
+ */
+
+void
+isc_string_printf_truncate(char *target, size_t size, const char *format, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+/*
+ * Print 'format' to 'target' which is a pointer to a string of at least
+ * 'size' bytes.
+ *
+ * Requires:
+ * 'target' is a pointer to a char[] of at least 'size' bytes.
+ * 'size' an integer > 0.
+ * 'format' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ * 'target' will be a NUL terminated string of no more
+ * than 'size' bytes (including NUL).
+ */
+
+
+char *
+isc_string_regiondup(isc_mem_t *mctx, const isc_region_t *source);
+/*
+ * Copy the region pointed to by r to a NUL terminated string
+ * allocated from the memory context pointed to by mctx.
+ *
+ * The result should be deallocated using isc_mem_free()
+ *
+ * Requires:
+ * 'mctx' is a point to a valid memory context.
+ * 'source' is a pointer to a valid region.
+ *
+ * Returns:
+ * a pointer to a NUL terminated string or
+ * NULL if memory for the copy could not be allocated
+ *
+ */
+
+char *
+isc_string_separate(char **stringp, const char *delim);
+
+#ifdef ISC_PLATFORM_NEEDSTRSEP
+#define strsep isc_string_separate
+#endif
+
+#ifdef ISC_PLATFORM_NEEDMEMMOVE
+#define memmove(a,b,c) bcopy(b,a,c)
+#endif
+
+size_t
+isc_string_strlcpy(char *dst, const char *src, size_t size);
+
+
+#ifdef ISC_PLATFORM_NEEDSTRLCPY
+#define strlcpy isc_string_strlcpy
+#endif
+
+
+size_t
+isc_string_strlcat(char *dst, const char *src, size_t size);
+
+#ifdef ISC_PLATFORM_NEEDSTRLCAT
+#define strlcat isc_string_strlcat
+#endif
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STRING_H */
diff --git a/lib/isc/include/isc/symtab.h b/lib/isc/include/isc/symtab.h
new file mode 100644
index 0000000..94ea173
--- /dev/null
+++ b/lib/isc/include/isc/symtab.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-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: symtab.h,v 1.17.18.4 2006/03/02 00:37:22 marka Exp $ */
+
+#ifndef ISC_SYMTAB_H
+#define ISC_SYMTAB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief Provides a simple memory-based symbol table.
+ *
+ * Keys are C strings, and key comparisons are case-insenstive. A type may
+ * be specified when looking up, defining, or undefining. A type value of
+ * 0 means "match any type"; any other value will only match the given
+ * type.
+ *
+ * It's possible that a client will attempt to define a <key, type, value>
+ * tuple when a tuple with the given key and type already exists in the table.
+ * What to do in this case is specified by the client. Possible policies are:
+ *
+ *\li #isc_symexists_reject Disallow the define, returning #ISC_R_EXISTS
+ *\li #isc_symexists_replace Replace the old value with the new. The
+ * undefine action (if provided) will be called
+ * with the old <key, type, value> tuple.
+ *\li #isc_symexists_add Add the new tuple, leaving the old tuple in
+ * the table. Subsequent lookups will retrieve
+ * the most-recently-defined tuple.
+ *
+ * A lookup of a key using type 0 will return the most-recently defined
+ * symbol with that key. An undefine of a key using type 0 will undefine the
+ * most-recently defined symbol with that key. Trying to define a key with
+ * type 0 is illegal.
+ *
+ * The symbol table library does not make a copy the key field, so the
+ * caller must ensure that any key it passes to isc_symtab_define() will not
+ * change until it calls isc_symtab_undefine() or isc_symtab_destroy().
+ *
+ * A user-specified action will be called (if provided) when a symbol is
+ * undefined. It can be used to free memory associated with keys and/or
+ * values.
+ *
+ * \li MP:
+ * The callers of this module must ensure any required synchronization.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*
+ *** Symbol Tables.
+ ***/
+/*% Symbol table value. */
+typedef union isc_symvalue {
+ void * as_pointer;
+ const void * as_cpointer;
+ int as_integer;
+ unsigned int as_uinteger;
+} isc_symvalue_t;
+
+typedef void (*isc_symtabaction_t)(char *key, unsigned int type,
+ isc_symvalue_t value, void *userarg);
+/*% Symbol table exists. */
+typedef enum {
+ isc_symexists_reject = 0, /*%< Disallow the define */
+ isc_symexists_replace = 1, /*%< Replace the old value with the new */
+ isc_symexists_add = 2 /*%< Add the new tuple */
+} isc_symexists_t;
+
+ISC_LANG_BEGINDECLS
+
+/*% Create a symbol table. */
+isc_result_t
+isc_symtab_create(isc_mem_t *mctx, unsigned int size,
+ isc_symtabaction_t undefine_action, void *undefine_arg,
+ isc_boolean_t case_sensitive, isc_symtab_t **symtabp);
+
+/*% Destroy a symbol table. */
+void
+isc_symtab_destroy(isc_symtab_t **symtabp);
+
+/*% Lookup a symbol table. */
+isc_result_t
+isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type,
+ isc_symvalue_t *value);
+
+/*% Define a symbol table. */
+isc_result_t
+isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type,
+ isc_symvalue_t value, isc_symexists_t exists_policy);
+
+/*% Undefine a symbol table. */
+isc_result_t
+isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SYMTAB_H */
diff --git a/lib/isc/include/isc/task.h b/lib/isc/include/isc/task.h
new file mode 100644
index 0000000..f7d237c
--- /dev/null
+++ b/lib/isc/include/isc/task.h
@@ -0,0 +1,616 @@
+/*
+ * Copyright (C) 2004, 2005 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: task.h,v 1.51.18.2 2005/04/29 00:17:03 marka Exp $ */
+
+#ifndef ISC_TASK_H
+#define ISC_TASK_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief The task system provides a lightweight execution context, which is
+ * basically an event queue.
+
+ * When a task's event queue is non-empty, the
+ * task is runnable. A small work crew of threads, typically one per CPU,
+ * execute runnable tasks by dispatching the events on the tasks' event
+ * queues. Context switching between tasks is fast.
+ *
+ * \li MP:
+ * The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ * The caller must ensure that isc_taskmgr_destroy() is called only
+ * once for a given manager.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ *
+ * \section purge Purging and Unsending
+ *
+ * Events which have been queued for a task but not delivered may be removed
+ * from the task's event queue by purging or unsending.
+ *
+ * With both types, the caller specifies a matching pattern that selects
+ * events based upon their sender, type, and tag.
+ *
+ * Purging calls isc_event_free() on the matching events.
+ *
+ * Unsending returns a list of events that matched the pattern.
+ * The caller is then responsible for them.
+ *
+ * Consumers of events should purge, not unsend.
+ *
+ * Producers of events often want to remove events when the caller indicates
+ * it is no longer interested in the object, e.g. by cancelling a timer.
+ * Sometimes this can be done by purging, but for some event types, the
+ * calls to isc_event_free() cause deadlock because the event free routine
+ * wants to acquire a lock the caller is already holding. Unsending instead
+ * of purging solves this problem. As a general rule, producers should only
+ * unsend events which they have sent.
+ */
+
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/eventclass.h>
+#include <isc/lang.h>
+#include <isc/stdtime.h>
+#include <isc/types.h>
+
+#define ISC_TASKEVENT_FIRSTEVENT (ISC_EVENTCLASS_TASK + 0)
+#define ISC_TASKEVENT_SHUTDOWN (ISC_EVENTCLASS_TASK + 1)
+#define ISC_TASKEVENT_LASTEVENT (ISC_EVENTCLASS_TASK + 65535)
+
+/*****
+ ***** Tasks.
+ *****/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
+ isc_task_t **taskp);
+/*%<
+ * Create a task.
+ *
+ * Notes:
+ *
+ *\li If 'quantum' is non-zero, then only that many events can be dispatched
+ * before the task must yield to other tasks waiting to execute. If
+ * quantum is zero, then the default quantum of the task manager will
+ * be used.
+ *
+ *\li The 'quantum' option may be removed from isc_task_create() in the
+ * future. If this happens, isc_task_getquantum() and
+ * isc_task_setquantum() will be provided.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid task manager.
+ *
+ *\li taskp != NULL && *taskp == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, '*taskp' is bound to the new task.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ *\li #ISC_R_SHUTTINGDOWN
+ */
+
+void
+isc_task_attach(isc_task_t *source, isc_task_t **targetp);
+/*%<
+ * Attach *targetp to source.
+ *
+ * Requires:
+ *
+ *\li 'source' is a valid task.
+ *
+ *\li 'targetp' points to a NULL isc_task_t *.
+ *
+ * Ensures:
+ *
+ *\li *targetp is attached to source.
+ */
+
+void
+isc_task_detach(isc_task_t **taskp);
+/*%<
+ * Detach *taskp from its task.
+ *
+ * Requires:
+ *
+ *\li '*taskp' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li *taskp is NULL.
+ *
+ *\li If '*taskp' is the last reference to the task, the task is idle (has
+ * an empty event queue), and has not been shutdown, the task will be
+ * shutdown.
+ *
+ *\li If '*taskp' is the last reference to the task and
+ * the task has been shutdown,
+ * all resources used by the task will be freed.
+ */
+
+void
+isc_task_send(isc_task_t *task, isc_event_t **eventp);
+/*%<
+ * Send '*event' to 'task'.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *\li eventp != NULL && *eventp != NULL.
+ *
+ * Ensures:
+ *
+ *\li *eventp == NULL.
+ */
+
+void
+isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp);
+/*%<
+ * Send '*event' to '*taskp' and then detach '*taskp' from its
+ * task.
+ *
+ * Requires:
+ *
+ *\li '*taskp' is a valid task.
+ *\li eventp != NULL && *eventp != NULL.
+ *
+ * Ensures:
+ *
+ *\li *eventp == NULL.
+ *
+ *\li *taskp == NULL.
+ *
+ *\li If '*taskp' is the last reference to the task, the task is
+ * idle (has an empty event queue), and has not been shutdown,
+ * the task will be shutdown.
+ *
+ *\li If '*taskp' is the last reference to the task and
+ * the task has been shutdown,
+ * all resources used by the task will be freed.
+ */
+
+
+unsigned int
+isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag);
+/*%<
+ * Purge events from a task's event queue.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li last >= first
+ *
+ * Ensures:
+ *
+ *\li Events in the event queue of 'task' whose sender is 'sender', whose
+ * type is >= first and <= last, and whose tag is 'tag' will be purged,
+ * unless they are marked as unpurgable.
+ *
+ *\li A sender of NULL will match any sender. A NULL tag matches any
+ * tag.
+ *
+ * Returns:
+ *
+ *\li The number of events purged.
+ */
+
+unsigned int
+isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag);
+/*%<
+ * Purge events from a task's event queue.
+ *
+ * Notes:
+ *
+ *\li This function is equivalent to
+ *
+ *\code
+ * isc_task_purgerange(task, sender, type, type, tag);
+ *\endcode
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li Events in the event queue of 'task' whose sender is 'sender', whose
+ * type is 'type', and whose tag is 'tag' will be purged, unless they
+ * are marked as unpurgable.
+ *
+ *\li A sender of NULL will match any sender. A NULL tag matches any
+ * tag.
+ *
+ * Returns:
+ *
+ *\li The number of events purged.
+ */
+
+isc_boolean_t
+isc_task_purgeevent(isc_task_t *task, isc_event_t *event);
+/*%<
+ * Purge 'event' from a task's event queue.
+ *
+ * XXXRTH: WARNING: This method may be removed before beta.
+ *
+ * Notes:
+ *
+ *\li If 'event' is on the task's event queue, it will be purged,
+ * unless it is marked as unpurgeable. 'event' does not have to be
+ * on the task's event queue; in fact, it can even be an invalid
+ * pointer. Purging only occurs if the event is actually on the task's
+ * event queue.
+ *
+ * \li Purging never changes the state of the task.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li 'event' is not in the event queue for 'task'.
+ *
+ * Returns:
+ *
+ *\li #ISC_TRUE The event was purged.
+ *\li #ISC_FALSE The event was not in the event queue,
+ * or was marked unpurgeable.
+ */
+
+unsigned int
+isc_task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag, isc_eventlist_t *events);
+/*%<
+ * Remove events from a task's event queue.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li last >= first.
+ *
+ *\li *events is a valid list.
+ *
+ * Ensures:
+ *
+ *\li Events in the event queue of 'task' whose sender is 'sender', whose
+ * type is >= first and <= last, and whose tag is 'tag' will be dequeued
+ * and appended to *events.
+ *
+ *\li A sender of NULL will match any sender. A NULL tag matches any
+ * tag.
+ *
+ * Returns:
+ *
+ *\li The number of events unsent.
+ */
+
+unsigned int
+isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag, isc_eventlist_t *events);
+/*%<
+ * Remove events from a task's event queue.
+ *
+ * Notes:
+ *
+ *\li This function is equivalent to
+ *
+ *\code
+ * isc_task_unsendrange(task, sender, type, type, tag, events);
+ *\endcode
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li *events is a valid list.
+ *
+ * Ensures:
+ *
+ *\li Events in the event queue of 'task' whose sender is 'sender', whose
+ * type is 'type', and whose tag is 'tag' will be dequeued and appended
+ * to *events.
+ *
+ * Returns:
+ *
+ *\li The number of events unsent.
+ */
+
+isc_result_t
+isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action,
+ const void *arg);
+/*%<
+ * Send a shutdown event with action 'action' and argument 'arg' when
+ * 'task' is shutdown.
+ *
+ * Notes:
+ *
+ *\li Shutdown events are posted in LIFO order.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li 'action' is a valid task action.
+ *
+ * Ensures:
+ *
+ *\li When the task is shutdown, shutdown events requested with
+ * isc_task_onshutdown() will be appended to the task's event queue.
+ *
+
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_TASKSHUTTINGDOWN Task is shutting down.
+ */
+
+void
+isc_task_shutdown(isc_task_t *task);
+/*%<
+ * Shutdown 'task'.
+ *
+ * Notes:
+ *
+ *\li Shutting down a task causes any shutdown events requested with
+ * isc_task_onshutdown() to be posted (in LIFO order). The task
+ * moves into a "shutting down" mode which prevents further calls
+ * to isc_task_onshutdown().
+ *
+ *\li Trying to shutdown a task that has already been shutdown has no
+ * effect.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li Any shutdown events requested with isc_task_onshutdown() have been
+ * posted (in LIFO order).
+ */
+
+void
+isc_task_destroy(isc_task_t **taskp);
+/*%<
+ * Destroy '*taskp'.
+ *
+ * Notes:
+ *
+ *\li This call is equivalent to:
+ *
+ *\code
+ * isc_task_shutdown(*taskp);
+ * isc_task_detach(taskp);
+ *\endcode
+ *
+ * Requires:
+ *
+ * '*taskp' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li Any shutdown events requested with isc_task_onshutdown() have been
+ * posted (in LIFO order).
+ *
+ *\li *taskp == NULL
+ *
+ *\li If '*taskp' is the last reference to the task,
+ * all resources used by the task will be freed.
+ */
+
+void
+isc_task_setname(isc_task_t *task, const char *name, void *tag);
+/*%<
+ * Name 'task'.
+ *
+ * Notes:
+ *
+ *\li Only the first 15 characters of 'name' will be copied.
+ *
+ *\li Naming a task is currently only useful for debugging purposes.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ */
+
+const char *
+isc_task_getname(isc_task_t *task);
+/*%<
+ * Get the name of 'task', as previously set using isc_task_setname().
+ *
+ * Notes:
+ *\li This function is for debugging purposes only.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ *
+ * Returns:
+ *\li A non-NULL pointer to a null-terminated string.
+ * If the task has not been named, the string is
+ * empty.
+ *
+ */
+
+void *
+isc_task_gettag(isc_task_t *task);
+/*%<
+ * Get the tag value for 'task', as previously set using isc_task_settag().
+ *
+ * Notes:
+ *\li This function is for debugging purposes only.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
+isc_result_t
+isc_task_beginexclusive(isc_task_t *task);
+/*%<
+ * Request exclusive access for 'task', which must be the calling
+ * task. Waits for any other concurrently executing tasks to finish their
+ * current event, and prevents any new events from executing in any of the
+ * tasks sharing a task manager with 'task'.
+ *
+ * The exclusive access must be relinquished by calling
+ * isc_task_endexclusive() before returning from the current event handler.
+ *
+ * Requires:
+ *\li 'task' is the calling task.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS The current task now has exclusive access.
+ *\li #ISC_R_LOCKBUSY Another task has already requested exclusive
+ * access.
+ */
+
+void
+isc_task_endexclusive(isc_task_t *task);
+/*%<
+ * Relinquish the exclusive access obtained by isc_task_beginexclusive(),
+ * allowing other tasks to execute.
+ *
+ * Requires:
+ *\li 'task' is the calling task, and has obtained
+ * exclusive access by calling isc_task_spl().
+ */
+
+void
+isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t);
+/*%<
+ * Provide the most recent timestamp on the task. The timestamp is considered
+ * as the "current time" in the second-order granularity.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ *\li 't' is a valid non NULL pointer.
+ *
+ * Ensures:
+ *\li '*t' has the "current time".
+ */
+
+/*****
+ ***** Task Manager.
+ *****/
+
+isc_result_t
+isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
+ unsigned int default_quantum, isc_taskmgr_t **managerp);
+/*%<
+ * Create a new task manager.
+ *
+ * Notes:
+ *
+ *\li 'workers' in the number of worker threads to create. In general,
+ * the value should be close to the number of processors in the system.
+ * The 'workers' value is advisory only. An attempt will be made to
+ * create 'workers' threads, but if at least one thread creation
+ * succeeds, isc_taskmgr_create() may return ISC_R_SUCCESS.
+ *
+ *\li If 'default_quantum' is non-zero, then it will be used as the default
+ * quantum value when tasks are created. If zero, then an implementation
+ * defined default quantum will be used.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li workers > 0
+ *
+ *\li managerp != NULL && *managerp == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, '*managerp' will be attached to the newly created task
+ * manager.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_NOTHREADS No threads could be created.
+ *\li #ISC_R_UNEXPECTED An unexpected error occurred.
+ */
+
+void
+isc_taskmgr_destroy(isc_taskmgr_t **managerp);
+/*%<
+ * Destroy '*managerp'.
+ *
+ * Notes:
+ *
+ *\li Calling isc_taskmgr_destroy() will shutdown all tasks managed by
+ * *managerp that haven't already been shutdown. The call will block
+ * until all tasks have entered the done state.
+ *
+ *\li isc_taskmgr_destroy() must not be called by a task event action,
+ * because it would block forever waiting for the event action to
+ * complete. An event action that wants to cause task manager shutdown
+ * should request some non-event action thread of execution to do the
+ * shutdown, e.g. by signalling a condition variable or using
+ * isc_app_shutdown().
+ *
+ *\li Task manager references are not reference counted, so the caller
+ * must ensure that no attempt will be made to use the manager after
+ * isc_taskmgr_destroy() returns.
+ *
+ * Requires:
+ *
+ *\li '*managerp' is a valid task manager.
+ *
+ *\li isc_taskmgr_destroy() has not be called previously on '*managerp'.
+ *
+ * Ensures:
+ *
+ *\li All resources used by the task manager, and any tasks it managed,
+ * have been freed.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TASK_H */
diff --git a/lib/isc/include/isc/taskpool.h b/lib/isc/include/isc/taskpool.h
new file mode 100644
index 0000000..6c97605
--- /dev/null
+++ b/lib/isc/include/isc/taskpool.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2004, 2005 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: taskpool.h,v 1.9.18.2 2005/04/29 00:17:04 marka Exp $ */
+
+#ifndef ISC_TASKPOOL_H
+#define ISC_TASKPOOL_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief A task pool is a mechanism for sharing a small number of tasks
+ * among a large number of objects such that each object is
+ * assigned a unique task, but each task may be shared by several
+ * objects.
+ *
+ * Task pools are used to let objects that can exist in large
+ * numbers (e.g., zones) use tasks for synchronization without
+ * the memory overhead and unfair scheduling competition that
+ * could result from creating a separate task for each object.
+ */
+
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/task.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Types.
+ *****/
+
+typedef struct isc_taskpool isc_taskpool_t;
+
+/*****
+ ***** Functions.
+ *****/
+
+isc_result_t
+isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx,
+ unsigned int ntasks, unsigned int quantum,
+ isc_taskpool_t **poolp);
+/*%<
+ * Create a task pool of "ntasks" tasks, each with quantum
+ * "quantum".
+ *
+ * Requires:
+ *
+ *\li 'tmgr' is a valid task manager.
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li poolp != NULL && *poolp == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, '*taskp' points to the new task pool.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ */
+
+void
+isc_taskpool_gettask(isc_taskpool_t *pool, unsigned int hash,
+ isc_task_t **targetp);
+/*%<
+ * Attach to the task corresponding to the hash value "hash".
+ */
+
+void
+isc_taskpool_destroy(isc_taskpool_t **poolp);
+/*%<
+ * Destroy a task pool. The tasks in the pool are detached but not
+ * shut down.
+ *
+ * Requires:
+ * \li '*poolp' is a valid task pool.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TASKPOOL_H */
diff --git a/lib/isc/include/isc/timer.h b/lib/isc/include/isc/timer.h
new file mode 100644
index 0000000..1e139dd
--- /dev/null
+++ b/lib/isc/include/isc/timer.h
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: timer.h,v 1.31.18.3 2005/10/26 06:50:50 marka Exp $ */
+
+#ifndef ISC_TIMER_H
+#define ISC_TIMER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief Provides timers which are event sources in the task system.
+ *
+ * Three types of timers are supported:
+ *
+ *\li 'ticker' timers generate a periodic tick event.
+ *
+ *\li 'once' timers generate an idle timeout event if they are idle for too
+ * long, and generate a life timeout event if their lifetime expires.
+ * They are used to implement both (possibly expiring) idle timers and
+ * 'one-shot' timers.
+ *
+ *\li 'limited' timers generate a periodic tick event until they reach
+ * their lifetime when they generate a life timeout event.
+ *
+ *\li 'inactive' timers generate no events.
+ *
+ * Timers can change type. It is typical to create a timer as
+ * an 'inactive' timer and then change it into a 'ticker' or
+ * 'once' timer.
+ *
+ *\li MP:
+ * The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ * Clients of this module must not be holding a timer's task's lock when
+ * making a call that affects that timer. Failure to follow this rule
+ * can result in deadlock.
+ * The caller must ensure that isc_timermgr_destroy() is called only
+ * once for a given manager.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/types.h>
+#include <isc/event.h>
+#include <isc/eventclass.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+/*% Timer Type */
+typedef enum {
+ isc_timertype_ticker = 0, /*%< Ticker */
+ isc_timertype_once = 1, /*%< Once */
+ isc_timertype_limited = 2, /*%< Limited */
+ isc_timertype_inactive = 3 /*%< Inactive */
+} isc_timertype_t;
+
+typedef struct isc_timerevent {
+ struct isc_event common;
+} isc_timerevent_t;
+
+#define ISC_TIMEREVENT_FIRSTEVENT (ISC_EVENTCLASS_TIMER + 0)
+#define ISC_TIMEREVENT_TICK (ISC_EVENTCLASS_TIMER + 1)
+#define ISC_TIMEREVENT_IDLE (ISC_EVENTCLASS_TIMER + 2)
+#define ISC_TIMEREVENT_LIFE (ISC_EVENTCLASS_TIMER + 3)
+#define ISC_TIMEREVENT_LASTEVENT (ISC_EVENTCLASS_TIMER + 65535)
+
+/***
+ *** Timer and Timer Manager Functions
+ ***
+ *** Note: all Ensures conditions apply only if the result is success for
+ *** those functions which return an isc_result_t.
+ ***/
+
+isc_result_t
+isc_timer_create(isc_timermgr_t *manager,
+ isc_timertype_t type,
+ isc_time_t *expires,
+ isc_interval_t *interval,
+ isc_task_t *task,
+ isc_taskaction_t action,
+ const void *arg,
+ isc_timer_t **timerp);
+/*%<
+ * Create a new 'type' timer managed by 'manager'. The timers parameters
+ * are specified by 'expires' and 'interval'. Events will be posted to
+ * 'task' and when dispatched 'action' will be called with 'arg' as the
+ * arg value. The new timer is returned in 'timerp'.
+ *
+ * Notes:
+ *
+ *\li For ticker timers, the timer will generate a 'tick' event every
+ * 'interval' seconds. The value of 'expires' is ignored.
+ *
+ *\li For once timers, 'expires' specifies the time when a life timeout
+ * event should be generated. If 'expires' is 0 (the epoch), then no life
+ * timeout will be generated. 'interval' specifies how long the timer
+ * can be idle before it generates an idle timeout. If 0, then no
+ * idle timeout will be generated.
+ *
+ *\li If 'expires' is NULL, the epoch will be used.
+ *
+ * If 'interval' is NULL, the zero interval will be used.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid manager
+ *
+ *\li 'task' is a valid task
+ *
+ *\li 'action' is a valid action
+ *
+ *\li 'expires' points to a valid time, or is NULL.
+ *
+ *\li 'interval' points to a valid interval, or is NULL.
+ *
+ *\li type == isc_timertype_inactive ||
+ * ('expires' and 'interval' are not both 0)
+ *
+ *\li 'timerp' is a valid pointer, and *timerp == NULL
+ *
+ * Ensures:
+ *
+ *\li '*timerp' is attached to the newly created timer
+ *
+ *\li The timer is attached to the task
+ *
+ *\li An idle timeout will not be generated until at least Now + the
+ * timer's interval if 'timer' is a once timer with a non-zero
+ * interval.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li No memory
+ *\li Unexpected error
+ */
+
+isc_result_t
+isc_timer_reset(isc_timer_t *timer,
+ isc_timertype_t type,
+ isc_time_t *expires,
+ isc_interval_t *interval,
+ isc_boolean_t purge);
+/*%<
+ * Change the timer's type, expires, and interval values to the given
+ * values. If 'purge' is TRUE, any pending events from this timer
+ * are purged from its task's event queue.
+ *
+ * Notes:
+ *
+ *\li If 'expires' is NULL, the epoch will be used.
+ *
+ *\li If 'interval' is NULL, the zero interval will be used.
+ *
+ * Requires:
+ *
+ *\li 'timer' is a valid timer
+ *
+ *\li The same requirements that isc_timer_create() imposes on 'type',
+ * 'expires' and 'interval' apply.
+ *
+ * Ensures:
+ *
+ *\li An idle timeout will not be generated until at least Now + the
+ * timer's interval if 'timer' is a once timer with a non-zero
+ * interval.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li No memory
+ *\li Unexpected error
+ */
+
+isc_result_t
+isc_timer_touch(isc_timer_t *timer);
+/*%<
+ * Set the last-touched time of 'timer' to the current time.
+ *
+ * Requires:
+ *
+ *\li 'timer' is a valid once timer.
+ *
+ * Ensures:
+ *
+ *\li An idle timeout will not be generated until at least Now + the
+ * timer's interval if 'timer' is a once timer with a non-zero
+ * interval.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li Unexpected error
+ */
+
+void
+isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp);
+/*%<
+ * Attach *timerp to timer.
+ *
+ * Requires:
+ *
+ *\li 'timer' is a valid timer.
+ *
+ *\li 'timerp' points to a NULL timer.
+ *
+ * Ensures:
+ *
+ *\li *timerp is attached to timer.
+ */
+
+void
+isc_timer_detach(isc_timer_t **timerp);
+/*%<
+ * Detach *timerp from its timer.
+ *
+ * Requires:
+ *
+ *\li 'timerp' points to a valid timer.
+ *
+ * Ensures:
+ *
+ *\li *timerp is NULL.
+ *
+ *\li If '*timerp' is the last reference to the timer,
+ * then:
+ *
+ *\code
+ * The timer will be shutdown
+ *
+ * The timer will detach from its task
+ *
+ * All resources used by the timer have been freed
+ *
+ * Any events already posted by the timer will be purged.
+ * Therefore, if isc_timer_detach() is called in the context
+ * of the timer's task, it is guaranteed that no more
+ * timer event callbacks will run after the call.
+ *\endcode
+ */
+
+isc_timertype_t
+isc_timer_gettype(isc_timer_t *timer);
+/*%<
+ * Return the timer type.
+ *
+ * Requires:
+ *
+ *\li 'timer' to be a valid timer.
+ */
+
+isc_result_t
+isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp);
+/*%<
+ * Create a timer manager.
+ *
+ * Notes:
+ *
+ *\li All memory will be allocated in memory context 'mctx'.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li 'managerp' points to a NULL isc_timermgr_t.
+ *
+ * Ensures:
+ *
+ *\li '*managerp' is a valid isc_timermgr_t.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li No memory
+ *\li Unexpected error
+ */
+
+void
+isc_timermgr_destroy(isc_timermgr_t **managerp);
+/*%<
+ * Destroy a timer manager.
+ *
+ * Notes:
+ *
+ *\li This routine blocks until there are no timers left in the manager,
+ * so if the caller holds any timer references using the manager, it
+ * must detach them before calling isc_timermgr_destroy() or it will
+ * block forever.
+ *
+ * Requires:
+ *
+ *\li '*managerp' is a valid isc_timermgr_t.
+ *
+ * Ensures:
+ *
+ *\li *managerp == NULL
+ *
+ *\li All resources used by the manager have been freed.
+ */
+
+void isc_timermgr_poke(isc_timermgr_t *m);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TIMER_H */
diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h
new file mode 100644
index 0000000..35a0be7
--- /dev/null
+++ b/lib/isc/include/isc/types.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2004, 2005 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: types.h,v 1.35.18.2 2005/04/29 00:17:04 marka Exp $ */
+
+#ifndef ISC_TYPES_H
+#define ISC_TYPES_H 1
+
+/*! \file
+ * \brief
+ * OS-specific types, from the OS-specific include directories.
+ */
+#include <isc/int.h>
+#include <isc/offset.h>
+
+/*
+ * XXXDCL should isc_boolean_t be moved here, requiring an explicit include
+ * of <isc/boolean.h> when ISC_TRUE/ISC_FALSE/ISC_TF() are desired?
+ */
+#include <isc/boolean.h>
+/*
+ * XXXDCL This is just for ISC_LIST and ISC_LINK, but gets all of the other
+ * list macros too.
+ */
+#include <isc/list.h>
+
+/* Core Types. Alphabetized by defined type. */
+
+typedef struct isc_bitstring isc_bitstring_t; /*%< Bitstring */
+typedef struct isc_buffer isc_buffer_t; /*%< Buffer */
+typedef ISC_LIST(isc_buffer_t) isc_bufferlist_t; /*%< Buffer List */
+typedef struct isc_constregion isc_constregion_t; /*%< Const region */
+typedef struct isc_consttextregion isc_consttextregion_t; /*%< Const Text Region */
+typedef struct isc_entropy isc_entropy_t; /*%< Entropy */
+typedef struct isc_entropysource isc_entropysource_t; /*%< Entropy Source */
+typedef struct isc_event isc_event_t; /*%< Event */
+typedef ISC_LIST(isc_event_t) isc_eventlist_t; /*%< Event List */
+typedef unsigned int isc_eventtype_t; /*%< Event Type */
+typedef isc_uint32_t isc_fsaccess_t; /*%< FS Access */
+typedef struct isc_hash isc_hash_t; /*%< Hash */
+typedef struct isc_interface isc_interface_t; /*%< Interface */
+typedef struct isc_interfaceiter isc_interfaceiter_t; /*%< Interface Iterator */
+typedef struct isc_interval isc_interval_t; /*%< Interval */
+typedef struct isc_lex isc_lex_t; /*%< Lex */
+typedef struct isc_log isc_log_t; /*%< Log */
+typedef struct isc_logcategory isc_logcategory_t; /*%< Log Category */
+typedef struct isc_logconfig isc_logconfig_t; /*%< Log Configuration */
+typedef struct isc_logmodule isc_logmodule_t; /*%< Log Module */
+typedef struct isc_mem isc_mem_t; /*%< Memory */
+typedef struct isc_mempool isc_mempool_t; /*%< Memory Pool */
+typedef struct isc_msgcat isc_msgcat_t; /*%< Message Catalog */
+typedef struct isc_ondestroy isc_ondestroy_t; /*%< On Destroy */
+typedef struct isc_netaddr isc_netaddr_t; /*%< Net Address */
+typedef struct isc_quota isc_quota_t; /*%< Quota */
+typedef struct isc_random isc_random_t; /*%< Random */
+typedef struct isc_ratelimiter isc_ratelimiter_t; /*%< Rate Limiter */
+typedef struct isc_region isc_region_t; /*%< Region */
+typedef isc_uint64_t isc_resourcevalue_t; /*%< Resource Value */
+typedef unsigned int isc_result_t; /*%< Result */
+typedef struct isc_rwlock isc_rwlock_t; /*%< Read Write Lock */
+typedef struct isc_sockaddr isc_sockaddr_t; /*%< Socket Address */
+typedef struct isc_socket isc_socket_t; /*%< Socket */
+typedef struct isc_socketevent isc_socketevent_t; /*%< Socket Event */
+typedef struct isc_socketmgr isc_socketmgr_t; /*%< Socket Manager */
+typedef struct isc_symtab isc_symtab_t; /*%< Symbol Table */
+typedef struct isc_task isc_task_t; /*%< Task */
+typedef ISC_LIST(isc_task_t) isc_tasklist_t; /*%< Task List */
+typedef struct isc_taskmgr isc_taskmgr_t; /*%< Task Manager */
+typedef struct isc_textregion isc_textregion_t; /*%< Text Region */
+typedef struct isc_time isc_time_t; /*%< Time */
+typedef struct isc_timer isc_timer_t; /*%< Timer */
+typedef struct isc_timermgr isc_timermgr_t; /*%< Timer Manager */
+
+typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *);
+
+/*% Resource */
+typedef enum {
+ isc_resource_coresize = 1,
+ isc_resource_cputime,
+ isc_resource_datasize,
+ isc_resource_filesize,
+ isc_resource_lockedmemory,
+ isc_resource_openfiles,
+ isc_resource_processes,
+ isc_resource_residentsize,
+ isc_resource_stacksize
+} isc_resource_t;
+
+#endif /* ISC_TYPES_H */
diff --git a/lib/isc/include/isc/util.h b/lib/isc/include/isc/util.h
new file mode 100644
index 0000000..95fe436
--- /dev/null
+++ b/lib/isc/include/isc/util.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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.24.18.2 2005/04/29 00:17:04 marka Exp $ */
+
+#ifndef ISC_UTIL_H
+#define ISC_UTIL_H 1
+
+/*! \file util.h
+ * NOTE:
+ *
+ * This file is not to be included from any <isc/???.h> (or other) library
+ * files.
+ *
+ * \brief
+ * Including this file puts several macros in your name space that are
+ * not protected (as all the other ISC functions/macros do) by prepending
+ * ISC_ or isc_ to the name.
+ */
+
+/***
+ *** General Macros.
+ ***/
+
+/*%
+ * Use this to hide unused function arguments.
+ * \code
+ * int
+ * foo(char *bar)
+ * {
+ * UNUSED(bar);
+ * }
+ * \endcode
+ */
+#define UNUSED(x) (void)(x)
+
+#define ISC_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define ISC_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/*%
+ * Use this to remove the const qualifier of a variable to assign it to
+ * a non-const variable or pass it as a non-const function argument ...
+ * but only when you are sure it won't then be changed!
+ * This is necessary to sometimes shut up some compilers
+ * (as with gcc -Wcast-qual) when there is just no other good way to avoid the
+ * situation.
+ */
+#define DE_CONST(konst, var) \
+ do { \
+ union { const void *k; void *v; } _u; \
+ _u.k = konst; \
+ var = _u.v; \
+ } while (0)
+
+/*%
+ * Use this in translation units that would otherwise be empty, to
+ * suppress compiler warnings.
+ */
+#define EMPTY_TRANSLATION_UNIT static void isc__empty(void) { isc__empty(); }
+
+/*%
+ * We use macros instead of calling the routines directly because
+ * the capital letters make the locking stand out.
+ * We RUNTIME_CHECK for success since in general there's no way
+ * for us to continue if they fail.
+ */
+
+#ifdef ISC_UTIL_TRACEON
+#define ISC_UTIL_TRACE(a) a
+#include <stdio.h> /* Required for fprintf/stderr when tracing. */
+#include <isc/msgs.h> /* Required for isc_msgcat when tracing. */
+#else
+#define ISC_UTIL_TRACE(a)
+#endif
+
+#include <isc/result.h> /* Contractual promise. */
+
+#define LOCK(lp) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_LOCKING, "LOCKING"), \
+ (lp), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_mutex_lock((lp)) == ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_LOCKED, "LOCKED"), \
+ (lp), __FILE__, __LINE__)); \
+ } while (0)
+#define UNLOCK(lp) do { \
+ RUNTIME_CHECK(isc_mutex_unlock((lp)) == ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_UNLOCKED, "UNLOCKED"), \
+ (lp), __FILE__, __LINE__)); \
+ } while (0)
+#define ISLOCKED(lp) (1)
+#define DESTROYLOCK(lp) \
+ RUNTIME_CHECK(isc_mutex_destroy((lp)) == ISC_R_SUCCESS)
+
+
+#define BROADCAST(cvp) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_BROADCAST, "BROADCAST"),\
+ (cvp), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_condition_broadcast((cvp)) == ISC_R_SUCCESS); \
+ } while (0)
+#define SIGNAL(cvp) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_SIGNAL, "SIGNAL"), \
+ (cvp), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_condition_signal((cvp)) == ISC_R_SUCCESS); \
+ } while (0)
+#define WAIT(cvp, lp) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_UTILWAIT, "WAIT"), \
+ (cvp), \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_LOCK, "LOCK"), \
+ (lp), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_condition_wait((cvp), (lp)) == ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %p %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_WAITED, "WAITED"), \
+ (cvp), \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_LOCKED, "LOCKED"), \
+ (lp), __FILE__, __LINE__)); \
+ } while (0)
+
+/*
+ * isc_condition_waituntil can return ISC_R_TIMEDOUT, so we
+ * don't RUNTIME_CHECK the result.
+ *
+ * XXX Also, can't really debug this then...
+ */
+
+#define WAITUNTIL(cvp, lp, tp) \
+ isc_condition_waituntil((cvp), (lp), (tp))
+
+#define RWLOCK(lp, t) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p, %d %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_RWLOCK, "RWLOCK"), \
+ (lp), (t), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_rwlock_lock((lp), (t)) == ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p, %d %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_RWLOCKED, "RWLOCKED"), \
+ (lp), (t), __FILE__, __LINE__)); \
+ } while (0)
+#define RWUNLOCK(lp, t) do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "%s %p, %d %s %d\n", \
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \
+ ISC_MSG_RWUNLOCK, "RWUNLOCK"), \
+ (lp), (t), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_rwlock_unlock((lp), (t)) == ISC_R_SUCCESS); \
+ } while (0)
+
+#define DESTROYMUTEXBLOCK(bp, n) \
+ RUNTIME_CHECK(isc_mutexblock_destroy((bp), (n)) == ISC_R_SUCCESS)
+
+/*
+ * List Macros.
+ */
+#include <isc/list.h> /* Contractual promise. */
+
+#define LIST(type) ISC_LIST(type)
+#define INIT_LIST(type) ISC_LIST_INIT(type)
+#define LINK(type) ISC_LINK(type)
+#define INIT_LINK(elt, link) ISC_LINK_INIT(elt, link)
+#define HEAD(list) ISC_LIST_HEAD(list)
+#define TAIL(list) ISC_LIST_TAIL(list)
+#define EMPTY(list) ISC_LIST_EMPTY(list)
+#define PREV(elt, link) ISC_LIST_PREV(elt, link)
+#define NEXT(elt, link) ISC_LIST_NEXT(elt, link)
+#define APPEND(list, elt, link) ISC_LIST_APPEND(list, elt, link)
+#define PREPEND(list, elt, link) ISC_LIST_PREPEND(list, elt, link)
+#define UNLINK(list, elt, link) ISC_LIST_UNLINK(list, elt, link)
+#define ENQUEUE(list, elt, link) ISC_LIST_APPEND(list, elt, link)
+#define DEQUEUE(list, elt, link) ISC_LIST_UNLINK(list, elt, link)
+#define INSERTBEFORE(li, b, e, ln) ISC_LIST_INSERTBEFORE(li, b, e, ln)
+#define INSERTAFTER(li, a, e, ln) ISC_LIST_INSERTAFTER(li, a, e, ln)
+#define APPENDLIST(list1, list2, link) ISC_LIST_APPENDLIST(list1, list2, link)
+
+/*
+ * Assertions
+ */
+#include <isc/assertions.h> /* Contractual promise. */
+
+/*% Require Assertion */
+#define REQUIRE(e) ISC_REQUIRE(e)
+/*% Ensure Assertion */
+#define ENSURE(e) ISC_ENSURE(e)
+/*% Insist Assertion */
+#define INSIST(e) ISC_INSIST(e)
+/*% Invariant Assertion */
+#define INVARIANT(e) ISC_INVARIANT(e)
+
+/*
+ * Errors
+ */
+#include <isc/error.h> /* Contractual promise. */
+
+/*% Unexpected Error */
+#define UNEXPECTED_ERROR isc_error_unexpected
+/*% Fatal Error */
+#define FATAL_ERROR isc_error_fatal
+/*% Runtime Check */
+#define RUNTIME_CHECK(cond) ISC_ERROR_RUNTIMECHECK(cond)
+
+/*%
+ * Time
+ */
+#define TIME_NOW(tp) RUNTIME_CHECK(isc_time_now((tp)) == ISC_R_SUCCESS)
+
+#endif /* ISC_UTIL_H */
diff --git a/lib/isc/include/isc/version.h b/lib/isc/include/isc/version.h
new file mode 100644
index 0000000..82d4617
--- /dev/null
+++ b/lib/isc/include/isc/version.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005 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: version.h,v 1.3.18.2 2005/04/29 00:17:04 marka Exp $ */
+
+/*! \file */
+
+#include <isc/platform.h>
+
+LIBISC_EXTERNAL_DATA extern const char isc_version[];
+
+LIBISC_EXTERNAL_DATA extern const unsigned int isc_libinterface;
+LIBISC_EXTERNAL_DATA extern const unsigned int isc_librevision;
+LIBISC_EXTERNAL_DATA extern const unsigned int isc_libage;
diff --git a/lib/isc/inet_aton.c b/lib/isc/inet_aton.c
new file mode 100644
index 0000000..1602521
--- /dev/null
+++ b/lib/isc/inet_aton.c
@@ -0,0 +1,196 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-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.
+ */
+
+/*
+ * 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.
+ */
+/*! \file */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
+static char rcsid[] = "$Id: inet_aton.c,v 1.17.18.2 2005/04/29 00:16:46 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stddef.h> /* Required for NULL. */
+
+#include <isc/types.h>
+#include <isc/net.h>
+
+/*%
+ * 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
+isc_net_aton(const char *cp, struct in_addr *addr) {
+ unsigned long val;
+ int base, n;
+ unsigned char c;
+ isc_uint8_t parts[4];
+ isc_uint8_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(c & 0xff))
+ 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 (;;) {
+ /*
+ * isascii() is valid for all integer values, and
+ * when it is true, c is known to be in scope
+ * for isdigit(). No cast necessary. Similar
+ * comment applies for later ctype uses.
+ */
+ if (isascii(c) && isdigit(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(c)) {
+ val = (val << 4) |
+ (c + 10 - (islower(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 > 0xff)
+ return (0);
+ *pp++ = (isc_uint8_t)val;
+ c = *++cp;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (c != '\0' && (!isascii(c) || !isspace(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 > 0xffffff)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ 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/lib/isc/inet_ntop.c b/lib/isc/inet_ntop.c
new file mode 100644
index 0000000..c0d1161
--- /dev/null
+++ b/lib/isc/inet_ntop.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-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.
+ */
+
+/*! \file */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] =
+ "$Id: inet_ntop.c,v 1.14.18.3 2005/04/29 00:16:46 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/net.h>
+#include <isc/print.h>
+
+#define NS_INT16SZ 2
+#define NS_IN6ADDRSZ 16
+
+/*
+ * 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(const unsigned char *src, char *dst,
+ size_t size);
+
+#ifdef AF_INET6
+static const char *inet_ntop6(const unsigned char *src, char *dst,
+ size_t size);
+#endif
+
+/*! char *
+ * isc_net_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 *
+isc_net_ntop(int af, const void *src, char *dst, size_t size)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+#ifdef AF_INET6
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+/*! const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address
+ * \return
+ * `dst' (as a const)
+ * \note
+ * (1) uses no statics
+ * \note
+ * (2) takes a unsigned char* not an in_addr as input
+ * \author
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, size_t size)
+{
+ static const char *fmt = "%u.%u.%u.%u";
+ char tmp[sizeof("255.255.255.255")];
+
+ if ((size_t)sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) >= size)
+ {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+
+ return (dst);
+}
+
+/*! const char *
+ * isc_inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * \author
+ * Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static const char *
+inet_ntop6(const unsigned 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;
+ unsigned 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 == 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);
+}
+#endif /* AF_INET6 */
diff --git a/lib/isc/inet_pton.c b/lib/isc/inet_pton.c
new file mode 100644
index 0000000..a537e9c
--- /dev/null
+++ b/lib/isc/inet_pton.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+/*! \file */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] =
+ "$Id: inet_pton.c,v 1.13.18.4 2005/04/29 00:16:46 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <isc/net.h>
+
+/*% INT16 Size */
+#define NS_INT16SZ 2
+/*% IPv4 Address Size */
+#define NS_INADDRSZ 4
+/*% IPv6 Address Size */
+#define NS_IN6ADDRSZ 16
+
+/*
+ * 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(const char *src, unsigned char *dst);
+static int inet_pton6(const char *src, unsigned char *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
+isc_net_pton(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 */
+}
+
+/*!\fn static int inet_pton4(const char *src, unsigned char *dst)
+ * \brief
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * \return
+ * 1 if `src' is a valid dotted quad, else 0.
+ * \note
+ * does not touch `dst' unless it's returning 1.
+ * \author
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst) {
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned 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) {
+ unsigned 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);
+}
+
+/*%
+ * convert presentation level address to network order binary form.
+ * \return
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * \note
+ * (1) does not touch `dst' unless it's returning 1.
+ * \note
+ * (2) :: in a full address is silently ignored.
+ * \author
+ * inspired by Mark Andrews.
+ * \author
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, seen_xdigits;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ seen_xdigits = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (++seen_xdigits > 4)
+ return (0);
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!seen_xdigits) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ seen_xdigits = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ seen_xdigits = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (seen_xdigits) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned 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/lib/isc/lex.c b/lib/isc/lex.c
new file mode 100644
index 0000000..2e4e48a
--- /dev/null
+++ b/lib/isc/lex.c
@@ -0,0 +1,963 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: lex.c,v 1.78.18.5 2005/11/30 03:44:39 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/file.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/parseint.h>
+#include <isc/print.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+typedef struct inputsource {
+ isc_result_t result;
+ isc_boolean_t is_file;
+ isc_boolean_t need_close;
+ isc_boolean_t at_eof;
+ isc_buffer_t * pushback;
+ unsigned int ignored;
+ void * input;
+ char * name;
+ unsigned long line;
+ unsigned long saved_line;
+ ISC_LINK(struct inputsource) link;
+} inputsource;
+
+#define LEX_MAGIC ISC_MAGIC('L', 'e', 'x', '!')
+#define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC)
+
+struct isc_lex {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ size_t max_token;
+ char * data;
+ unsigned int comments;
+ isc_boolean_t comment_ok;
+ isc_boolean_t last_was_eol;
+ unsigned int paren_count;
+ unsigned int saved_paren_count;
+ isc_lexspecials_t specials;
+ LIST(struct inputsource) sources;
+};
+
+static inline isc_result_t
+grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
+ char *new;
+
+ new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1);
+ if (new == NULL)
+ return (ISC_R_NOMEMORY);
+ memcpy(new, lex->data, lex->max_token + 1);
+ *currp = new + (*currp - lex->data);
+ if (*prevp != NULL)
+ *prevp = new + (*prevp - lex->data);
+ isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
+ lex->data = new;
+ *remainingp += lex->max_token;
+ lex->max_token *= 2;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) {
+ isc_lex_t *lex;
+
+ /*
+ * Create a lexer.
+ */
+
+ REQUIRE(lexp != NULL && *lexp == NULL);
+ REQUIRE(max_token > 0U);
+
+ lex = isc_mem_get(mctx, sizeof(*lex));
+ if (lex == NULL)
+ return (ISC_R_NOMEMORY);
+ lex->data = isc_mem_get(mctx, max_token + 1);
+ if (lex->data == NULL) {
+ isc_mem_put(mctx, lex, sizeof(*lex));
+ return (ISC_R_NOMEMORY);
+ }
+ lex->mctx = mctx;
+ lex->max_token = max_token;
+ lex->comments = 0;
+ lex->comment_ok = ISC_TRUE;
+ lex->last_was_eol = ISC_TRUE;
+ lex->paren_count = 0;
+ lex->saved_paren_count = 0;
+ memset(lex->specials, 0, 256);
+ INIT_LIST(lex->sources);
+ lex->magic = LEX_MAGIC;
+
+ *lexp = lex;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_lex_destroy(isc_lex_t **lexp) {
+ isc_lex_t *lex;
+
+ /*
+ * Destroy the lexer.
+ */
+
+ REQUIRE(lexp != NULL);
+ lex = *lexp;
+ REQUIRE(VALID_LEX(lex));
+
+ while (!EMPTY(lex->sources))
+ RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
+ if (lex->data != NULL)
+ isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
+ lex->magic = 0;
+ isc_mem_put(lex->mctx, lex, sizeof(*lex));
+
+ *lexp = NULL;
+}
+
+unsigned int
+isc_lex_getcomments(isc_lex_t *lex) {
+ /*
+ * Return the current lexer commenting styles.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ return (lex->comments);
+}
+
+void
+isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
+ /*
+ * Set allowed lexer commenting styles.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ lex->comments = comments;
+}
+
+void
+isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
+ /*
+ * Put the current list of specials into 'specials'.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ memcpy(specials, lex->specials, 256);
+}
+
+void
+isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
+ /*
+ * The characters in 'specials' are returned as tokens. Along with
+ * whitespace, they delimit strings and numbers.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ memcpy(lex->specials, specials, 256);
+}
+
+static inline isc_result_t
+new_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close,
+ void *input, const char *name)
+{
+ inputsource *source;
+ isc_result_t result;
+
+ source = isc_mem_get(lex->mctx, sizeof(*source));
+ if (source == NULL)
+ return (ISC_R_NOMEMORY);
+ source->result = ISC_R_SUCCESS;
+ source->is_file = is_file;
+ source->need_close = need_close;
+ source->at_eof = ISC_FALSE;
+ source->input = input;
+ source->name = isc_mem_strdup(lex->mctx, name);
+ if (source->name == NULL) {
+ isc_mem_put(lex->mctx, source, sizeof(*source));
+ return (ISC_R_NOMEMORY);
+ }
+ source->pushback = NULL;
+ result = isc_buffer_allocate(lex->mctx, &source->pushback,
+ lex->max_token);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_free(lex->mctx, source->name);
+ isc_mem_put(lex->mctx, source, sizeof(*source));
+ return (result);
+ }
+ source->ignored = 0;
+ source->line = 1;
+ ISC_LIST_INITANDPREPEND(lex->sources, source, link);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_openfile(isc_lex_t *lex, const char *filename) {
+ isc_result_t result;
+ FILE *stream = NULL;
+
+ /*
+ * Open 'filename' and make it the current input source for 'lex'.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ result = isc_stdio_open(filename, "r", &stream);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename);
+ if (result != ISC_R_SUCCESS)
+ (void)fclose(stream);
+ return (result);
+}
+
+isc_result_t
+isc_lex_openstream(isc_lex_t *lex, FILE *stream) {
+ char name[128];
+
+ /*
+ * Make 'stream' the current input source for 'lex'.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ snprintf(name, sizeof(name), "stream-%p", stream);
+
+ return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name));
+}
+
+isc_result_t
+isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
+ char name[128];
+
+ /*
+ * Make 'buffer' the current input source for 'lex'.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ snprintf(name, sizeof(name), "buffer-%p", buffer);
+
+ return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name));
+}
+
+isc_result_t
+isc_lex_close(isc_lex_t *lex) {
+ inputsource *source;
+
+ /*
+ * Close the most recently opened object (i.e. file or buffer).
+ */
+
+ REQUIRE(VALID_LEX(lex));
+
+ source = HEAD(lex->sources);
+ if (source == NULL)
+ return (ISC_R_NOMORE);
+
+ ISC_LIST_UNLINK(lex->sources, source, link);
+ if (source->is_file) {
+ if (source->need_close)
+ (void)fclose((FILE *)(source->input));
+ }
+ isc_mem_free(lex->mctx, source->name);
+ isc_buffer_free(&source->pushback);
+ isc_mem_put(lex->mctx, source, sizeof(*source));
+
+ return (ISC_R_SUCCESS);
+}
+
+typedef enum {
+ lexstate_start,
+ lexstate_crlf,
+ lexstate_string,
+ lexstate_number,
+ lexstate_maybecomment,
+ lexstate_ccomment,
+ lexstate_ccommentend,
+ lexstate_eatline,
+ lexstate_qstring
+} lexstate;
+
+#define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
+
+static void
+pushback(inputsource *source, int c) {
+ REQUIRE(source->pushback->current > 0);
+ if (c == EOF) {
+ source->at_eof = ISC_FALSE;
+ return;
+ }
+ source->pushback->current--;
+ if (c == '\n')
+ source->line--;
+}
+
+static isc_result_t
+pushandgrow(isc_lex_t *lex, inputsource *source, int c) {
+ if (isc_buffer_availablelength(source->pushback) == 0) {
+ isc_buffer_t *tbuf = NULL;
+ unsigned int oldlen;
+ isc_region_t used;
+ isc_result_t result;
+
+ oldlen = isc_buffer_length(source->pushback);
+ result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_usedregion(source->pushback, &used);
+ result = isc_buffer_copyregion(tbuf, &used);
+ INSIST(result == ISC_R_SUCCESS);
+ tbuf->current = source->pushback->current;
+ isc_buffer_free(&source->pushback);
+ source->pushback = tbuf;
+ }
+ isc_buffer_putuint8(source->pushback, (isc_uint8_t)c);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
+ inputsource *source;
+ int c;
+ isc_boolean_t done = ISC_FALSE;
+ isc_boolean_t no_comments = ISC_FALSE;
+ isc_boolean_t escaped = ISC_FALSE;
+ lexstate state = lexstate_start;
+ lexstate saved_state = lexstate_start;
+ isc_buffer_t *buffer;
+ FILE *stream;
+ char *curr, *prev;
+ size_t remaining;
+ isc_uint32_t as_ulong;
+ unsigned int saved_options;
+ isc_result_t result;
+
+ /*
+ * Get the next token.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+ REQUIRE(tokenp != NULL);
+
+ if (source == NULL) {
+ if ((options & ISC_LEXOPT_NOMORE) != 0) {
+ tokenp->type = isc_tokentype_nomore;
+ return (ISC_R_SUCCESS);
+ }
+ return (ISC_R_NOMORE);
+ }
+
+ if (source->result != ISC_R_SUCCESS)
+ return (source->result);
+
+ lex->saved_paren_count = lex->paren_count;
+ source->saved_line = source->line;
+
+ if (isc_buffer_remaininglength(source->pushback) == 0 &&
+ source->at_eof)
+ {
+ if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
+ lex->paren_count != 0) {
+ lex->paren_count = 0;
+ return (ISC_R_UNBALANCED);
+ }
+ if ((options & ISC_LEXOPT_EOF) != 0) {
+ tokenp->type = isc_tokentype_eof;
+ return (ISC_R_SUCCESS);
+ }
+ return (ISC_R_EOF);
+ }
+
+ isc_buffer_compact(source->pushback);
+
+ saved_options = options;
+ if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
+ options &= ~IWSEOL;
+
+ curr = lex->data;
+ *curr = '\0';
+
+ prev = NULL;
+ remaining = lex->max_token;
+
+#ifdef HAVE_FLOCKFILE
+ if (source->is_file)
+ flockfile(source->input);
+#endif
+
+ do {
+ if (isc_buffer_remaininglength(source->pushback) == 0) {
+ if (source->is_file) {
+ stream = source->input;
+
+#if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED)
+ c = getc_unlocked(stream);
+#else
+ c = getc(stream);
+#endif
+ if (c == EOF) {
+ if (ferror(stream)) {
+ source->result = ISC_R_IOERROR;
+ result = source->result;
+ goto done;
+ }
+ source->at_eof = ISC_TRUE;
+ }
+ } else {
+ buffer = source->input;
+
+ if (buffer->current == buffer->used) {
+ c = EOF;
+ source->at_eof = ISC_TRUE;
+ } else {
+ c = *((char *)buffer->base +
+ buffer->current);
+ buffer->current++;
+ }
+ }
+ if (c != EOF) {
+ source->result = pushandgrow(lex, source, c);
+ if (source->result != ISC_R_SUCCESS) {
+ result = source->result;
+ goto done;
+ }
+ }
+ }
+
+ if (!source->at_eof) {
+ if (state == lexstate_start)
+ /* Token has not started yet. */
+ source->ignored =
+ isc_buffer_consumedlength(source->pushback);
+ c = isc_buffer_getuint8(source->pushback);
+ } else {
+ c = EOF;
+ }
+
+ if (c == '\n')
+ source->line++;
+
+ if (lex->comment_ok && !no_comments) {
+ if (!escaped && c == ';' &&
+ ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE)
+ != 0)) {
+ saved_state = state;
+ state = lexstate_eatline;
+ no_comments = ISC_TRUE;
+ continue;
+ } else if (c == '/' &&
+ (lex->comments &
+ (ISC_LEXCOMMENT_C|
+ ISC_LEXCOMMENT_CPLUSPLUS)) != 0) {
+ saved_state = state;
+ state = lexstate_maybecomment;
+ no_comments = ISC_TRUE;
+ continue;
+ } else if (c == '#' &&
+ ((lex->comments & ISC_LEXCOMMENT_SHELL)
+ != 0)) {
+ saved_state = state;
+ state = lexstate_eatline;
+ no_comments = ISC_TRUE;
+ continue;
+ }
+ }
+
+ no_read:
+ /* INSIST(c == EOF || (c >= 0 && c <= 255)); */
+ switch (state) {
+ case lexstate_start:
+ if (c == EOF) {
+ lex->last_was_eol = ISC_FALSE;
+ if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
+ lex->paren_count != 0) {
+ lex->paren_count = 0;
+ result = ISC_R_UNBALANCED;
+ goto done;
+ }
+ if ((options & ISC_LEXOPT_EOF) == 0) {
+ result = ISC_R_EOF;
+ goto done;
+ }
+ tokenp->type = isc_tokentype_eof;
+ done = ISC_TRUE;
+ } else if (c == ' ' || c == '\t') {
+ if (lex->last_was_eol &&
+ (options & ISC_LEXOPT_INITIALWS)
+ != 0) {
+ lex->last_was_eol = ISC_FALSE;
+ tokenp->type = isc_tokentype_initialws;
+ tokenp->value.as_char = c;
+ done = ISC_TRUE;
+ }
+ } else if (c == '\n') {
+ if ((options & ISC_LEXOPT_EOL) != 0) {
+ tokenp->type = isc_tokentype_eol;
+ done = ISC_TRUE;
+ }
+ lex->last_was_eol = ISC_TRUE;
+ } else if (c == '\r') {
+ if ((options & ISC_LEXOPT_EOL) != 0)
+ state = lexstate_crlf;
+ } else if (c == '"' &&
+ (options & ISC_LEXOPT_QSTRING) != 0) {
+ lex->last_was_eol = ISC_FALSE;
+ no_comments = ISC_TRUE;
+ state = lexstate_qstring;
+ } else if (lex->specials[c]) {
+ lex->last_was_eol = ISC_FALSE;
+ if ((c == '(' || c == ')') &&
+ (options & ISC_LEXOPT_DNSMULTILINE) != 0) {
+ if (c == '(') {
+ if (lex->paren_count == 0)
+ options &= ~IWSEOL;
+ lex->paren_count++;
+ } else {
+ if (lex->paren_count == 0) {
+ result = ISC_R_UNBALANCED;
+ goto done;
+ }
+ lex->paren_count--;
+ if (lex->paren_count == 0)
+ options =
+ saved_options;
+ }
+ continue;
+ }
+ tokenp->type = isc_tokentype_special;
+ tokenp->value.as_char = c;
+ done = ISC_TRUE;
+ } else if (isdigit((unsigned char)c) &&
+ (options & ISC_LEXOPT_NUMBER) != 0) {
+ lex->last_was_eol = ISC_FALSE;
+ if ((options & ISC_LEXOPT_OCTAL) != 0 &&
+ (c == '8' || c == '9'))
+ state = lexstate_string;
+ else
+ state = lexstate_number;
+ goto no_read;
+ } else {
+ lex->last_was_eol = ISC_FALSE;
+ state = lexstate_string;
+ goto no_read;
+ }
+ break;
+ case lexstate_crlf:
+ if (c != '\n')
+ pushback(source, c);
+ tokenp->type = isc_tokentype_eol;
+ done = ISC_TRUE;
+ lex->last_was_eol = ISC_TRUE;
+ break;
+ case lexstate_number:
+ if (c == EOF || !isdigit((unsigned char)c)) {
+ if (c == ' ' || c == '\t' || c == '\r' ||
+ c == '\n' || c == EOF ||
+ lex->specials[c]) {
+ int base;
+ if ((options & ISC_LEXOPT_OCTAL) != 0)
+ base = 8;
+ else if ((options & ISC_LEXOPT_CNUMBER) != 0)
+ base = 0;
+ else
+ base = 10;
+ pushback(source, c);
+
+ result = isc_parse_uint32(&as_ulong,
+ lex->data,
+ base);
+ if (result == ISC_R_SUCCESS) {
+ tokenp->type =
+ isc_tokentype_number;
+ tokenp->value.as_ulong =
+ as_ulong;
+ } else if (result == ISC_R_BADNUMBER) {
+ isc_tokenvalue_t *v;
+
+ tokenp->type =
+ isc_tokentype_string;
+ v = &(tokenp->value);
+ v->as_textregion.base =
+ lex->data;
+ v->as_textregion.length =
+ lex->max_token -
+ remaining;
+ } else
+ goto done;
+ done = ISC_TRUE;
+ continue;
+ } else if (!(options & ISC_LEXOPT_CNUMBER) ||
+ ((c != 'x' && c != 'X') ||
+ (curr != &lex->data[1]) ||
+ (lex->data[0] != '0'))) {
+ /* Above test supports hex numbers */
+ state = lexstate_string;
+ }
+ } else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
+ (c == '8' || c == '9')) {
+ state = lexstate_string;
+ }
+ if (remaining == 0U) {
+ result = grow_data(lex, &remaining,
+ &curr, &prev);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ }
+ INSIST(remaining > 0U);
+ *curr++ = c;
+ *curr = '\0';
+ remaining--;
+ break;
+ case lexstate_string:
+ /*
+ * EOF needs to be checked before lex->specials[c]
+ * as lex->specials[EOF] is not a good idea.
+ */
+ if (c == '\r' || c == '\n' || c == EOF ||
+ (!escaped &&
+ (c == ' ' || c == '\t' || lex->specials[c]))) {
+ pushback(source, c);
+ if (source->result != ISC_R_SUCCESS) {
+ result = source->result;
+ goto done;
+ }
+ tokenp->type = isc_tokentype_string;
+ tokenp->value.as_textregion.base = lex->data;
+ tokenp->value.as_textregion.length =
+ lex->max_token - remaining;
+ done = ISC_TRUE;
+ continue;
+ }
+ if ((options & ISC_LEXOPT_ESCAPE) != 0)
+ escaped = (!escaped && c == '\\') ?
+ ISC_TRUE : ISC_FALSE;
+ if (remaining == 0U) {
+ result = grow_data(lex, &remaining,
+ &curr, &prev);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ }
+ INSIST(remaining > 0U);
+ *curr++ = c;
+ *curr = '\0';
+ remaining--;
+ break;
+ case lexstate_maybecomment:
+ if (c == '*' &&
+ (lex->comments & ISC_LEXCOMMENT_C) != 0) {
+ state = lexstate_ccomment;
+ continue;
+ } else if (c == '/' &&
+ (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
+ state = lexstate_eatline;
+ continue;
+ }
+ pushback(source, c);
+ c = '/';
+ no_comments = ISC_FALSE;
+ state = saved_state;
+ goto no_read;
+ case lexstate_ccomment:
+ if (c == EOF) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto done;
+ }
+ if (c == '*')
+ state = lexstate_ccommentend;
+ break;
+ case lexstate_ccommentend:
+ if (c == EOF) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto done;
+ }
+ if (c == '/') {
+ /*
+ * C-style comments become a single space.
+ * We do this to ensure that a comment will
+ * act as a delimiter for strings and
+ * numbers.
+ */
+ c = ' ';
+ no_comments = ISC_FALSE;
+ state = saved_state;
+ goto no_read;
+ } else if (c != '*')
+ state = lexstate_ccomment;
+ break;
+ case lexstate_eatline:
+ if (c == EOF) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto done;
+ }
+ if (c == '\n') {
+ no_comments = ISC_FALSE;
+ state = saved_state;
+ goto no_read;
+ }
+ break;
+ case lexstate_qstring:
+ if (c == EOF) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto done;
+ }
+ if (c == '"') {
+ if (escaped) {
+ escaped = ISC_FALSE;
+ /*
+ * Overwrite the preceding backslash.
+ */
+ INSIST(prev != NULL);
+ *prev = '"';
+ } else {
+ tokenp->type = isc_tokentype_qstring;
+ tokenp->value.as_textregion.base =
+ lex->data;
+ tokenp->value.as_textregion.length =
+ lex->max_token - remaining;
+ no_comments = ISC_FALSE;
+ done = ISC_TRUE;
+ }
+ } else {
+ if (c == '\n' && !escaped &&
+ (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
+ pushback(source, c);
+ result = ISC_R_UNBALANCEDQUOTES;
+ goto done;
+ }
+ if (c == '\\' && !escaped)
+ escaped = ISC_TRUE;
+ else
+ escaped = ISC_FALSE;
+ if (remaining == 0U) {
+ result = grow_data(lex, &remaining,
+ &curr, &prev);
+ if (result != ISC_R_SUCCESS)
+ goto done;
+ }
+ INSIST(remaining > 0U);
+ prev = curr;
+ *curr++ = c;
+ *curr = '\0';
+ remaining--;
+ }
+ break;
+ default:
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX,
+ ISC_MSG_UNEXPECTEDSTATE,
+ "Unexpected state %d"),
+ state);
+ /* Does not return. */
+ }
+
+ } while (!done);
+
+ result = ISC_R_SUCCESS;
+ done:
+#ifdef HAVE_FLOCKFILE
+ if (source->is_file)
+ funlockfile(source->input);
+#endif
+ return (result);
+}
+
+isc_result_t
+isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
+ isc_tokentype_t expect, isc_boolean_t eol)
+{
+ unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
+ ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
+ isc_result_t result;
+
+ if (expect == isc_tokentype_qstring)
+ options |= ISC_LEXOPT_QSTRING;
+ else if (expect == isc_tokentype_number)
+ options |= ISC_LEXOPT_NUMBER;
+ result = isc_lex_gettoken(lex, options, token);
+ if (result == ISC_R_RANGE)
+ isc_lex_ungettoken(lex, token);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (eol && ((token->type == isc_tokentype_eol) ||
+ (token->type == isc_tokentype_eof)))
+ return (ISC_R_SUCCESS);
+ if (token->type == isc_tokentype_string &&
+ expect == isc_tokentype_qstring)
+ return (ISC_R_SUCCESS);
+ if (token->type != expect) {
+ isc_lex_ungettoken(lex, token);
+ if (token->type == isc_tokentype_eol ||
+ token->type == isc_tokentype_eof)
+ return (ISC_R_UNEXPECTEDEND);
+ if (expect == isc_tokentype_number)
+ return (ISC_R_BADNUMBER);
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol)
+{
+ unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
+ ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE|
+ ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL;
+ isc_result_t result;
+
+ result = isc_lex_gettoken(lex, options, token);
+ if (result == ISC_R_RANGE)
+ isc_lex_ungettoken(lex, token);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (eol && ((token->type == isc_tokentype_eol) ||
+ (token->type == isc_tokentype_eof)))
+ return (ISC_R_SUCCESS);
+ if (token->type != isc_tokentype_number) {
+ isc_lex_ungettoken(lex, token);
+ if (token->type == isc_tokentype_eol ||
+ token->type == isc_tokentype_eof)
+ return (ISC_R_UNEXPECTEDEND);
+ return (ISC_R_BADNUMBER);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
+ inputsource *source;
+ /*
+ * Unget the current token.
+ */
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+ REQUIRE(source != NULL);
+ REQUIRE(tokenp != NULL);
+ REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
+ tokenp->type == isc_tokentype_eof);
+
+ UNUSED(tokenp);
+
+ isc_buffer_first(source->pushback);
+ lex->paren_count = lex->saved_paren_count;
+ source->line = source->saved_line;
+ source->at_eof = ISC_FALSE;
+}
+
+void
+isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
+{
+ inputsource *source;
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+ REQUIRE(source != NULL);
+ REQUIRE(tokenp != NULL);
+ REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
+ tokenp->type == isc_tokentype_eof);
+
+ UNUSED(tokenp);
+
+ INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
+ r->base = (unsigned char *)isc_buffer_base(source->pushback) +
+ source->ignored;
+ r->length = isc_buffer_consumedlength(source->pushback) -
+ source->ignored;
+}
+
+
+char *
+isc_lex_getsourcename(isc_lex_t *lex) {
+ inputsource *source;
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+
+ if (source == NULL)
+ return (NULL);
+
+ return (source->name);
+}
+
+unsigned long
+isc_lex_getsourceline(isc_lex_t *lex) {
+ inputsource *source;
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+
+ if (source == NULL)
+ return (0);
+
+ return (source->line);
+}
+
+
+isc_result_t
+isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
+ inputsource *source;
+ char *newname;
+
+ REQUIRE(VALID_LEX(lex));
+ source = HEAD(lex->sources);
+
+ if (source == NULL)
+ return(ISC_R_NOTFOUND);
+ newname = isc_mem_strdup(lex->mctx, name);
+ if (newname == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_mem_free(lex->mctx, source->name);
+ source->name = newname;
+ return (ISC_R_SUCCESS);
+}
+
+isc_boolean_t
+isc_lex_isfile(isc_lex_t *lex) {
+ inputsource *source;
+
+ REQUIRE(VALID_LEX(lex));
+
+ source = HEAD(lex->sources);
+
+ if (source == NULL)
+ return (ISC_FALSE);
+
+ return (source->is_file);
+}
diff --git a/lib/isc/lfsr.c b/lib/isc/lfsr.c
new file mode 100644
index 0000000..61f9386
--- /dev/null
+++ b/lib/isc/lfsr.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2004, 2005 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: lfsr.c,v 1.14.18.4 2005/10/14 01:28:29 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <isc/assertions.h>
+#include <isc/lfsr.h>
+#include <isc/util.h>
+
+#define VALID_LFSR(x) (x != NULL)
+
+void
+isc_lfsr_init(isc_lfsr_t *lfsr, isc_uint32_t state, unsigned int bits,
+ isc_uint32_t tap, unsigned int count,
+ isc_lfsrreseed_t reseed, void *arg)
+{
+ REQUIRE(VALID_LFSR(lfsr));
+ REQUIRE(8 <= bits && bits <= 32);
+ REQUIRE(tap != 0);
+
+ lfsr->state = state;
+ lfsr->bits = bits;
+ lfsr->tap = tap;
+ lfsr->count = count;
+ lfsr->reseed = reseed;
+ lfsr->arg = arg;
+
+ if (count == 0 && reseed != NULL)
+ reseed(lfsr, arg);
+ if (lfsr->state == 0)
+ lfsr->state = 0xffffffffU >> (32 - lfsr->bits);
+}
+
+/*!
+ * Return the next state of the lfsr.
+ */
+static inline isc_uint32_t
+lfsr_generate(isc_lfsr_t *lfsr)
+{
+
+ /*
+ * If the previous state is zero, we must fill it with something
+ * here, or we will begin to generate an extremely predictable output.
+ *
+ * First, give the reseed function a crack at it. If the state is
+ * still 0, set it to all ones.
+ */
+ if (lfsr->state == 0) {
+ if (lfsr->reseed != NULL)
+ lfsr->reseed(lfsr, lfsr->arg);
+ if (lfsr->state == 0)
+ lfsr->state = 0xffffffffU >> (32 - lfsr->bits);
+ }
+
+ if (lfsr->state & 0x01) {
+ lfsr->state = (lfsr->state >> 1) ^ lfsr->tap;
+ return (1);
+ } else {
+ lfsr->state >>= 1;
+ return (0);
+ }
+}
+
+void
+isc_lfsr_generate(isc_lfsr_t *lfsr, void *data, unsigned int count)
+{
+ unsigned char *p;
+ unsigned int bit;
+ unsigned int byte;
+
+ REQUIRE(VALID_LFSR(lfsr));
+ REQUIRE(data != NULL);
+ REQUIRE(count > 0);
+
+ p = data;
+ byte = count;
+
+ while (byte--) {
+ *p = 0;
+ for (bit = 0; bit < 7; bit++) {
+ *p |= lfsr_generate(lfsr);
+ *p <<= 1;
+ }
+ *p |= lfsr_generate(lfsr);
+ p++;
+ }
+
+ if (lfsr->count != 0 && lfsr->reseed != NULL) {
+ if (lfsr->count <= count * 8)
+ lfsr->reseed(lfsr, lfsr->arg);
+ else
+ lfsr->count -= (count * 8);
+ }
+}
+
+static inline isc_uint32_t
+lfsr_skipgenerate(isc_lfsr_t *lfsr, unsigned int skip)
+{
+ while (skip--)
+ (void)lfsr_generate(lfsr);
+
+ (void)lfsr_generate(lfsr);
+
+ return (lfsr->state);
+}
+
+/*
+ * Skip "skip" states in "lfsr".
+ */
+void
+isc_lfsr_skip(isc_lfsr_t *lfsr, unsigned int skip)
+{
+ REQUIRE(VALID_LFSR(lfsr));
+
+ while (skip--)
+ (void)lfsr_generate(lfsr);
+}
+
+/*
+ * Skip states in lfsr1 and lfsr2 using the other's current state.
+ * Return the final state of lfsr1 ^ lfsr2.
+ */
+isc_uint32_t
+isc_lfsr_generate32(isc_lfsr_t *lfsr1, isc_lfsr_t *lfsr2)
+{
+ isc_uint32_t state1, state2;
+ isc_uint32_t skip1, skip2;
+
+ REQUIRE(VALID_LFSR(lfsr1));
+ REQUIRE(VALID_LFSR(lfsr2));
+
+ skip1 = lfsr1->state & 0x01;
+ skip2 = lfsr2->state & 0x01;
+
+ /* cross-skip. */
+ state1 = lfsr_skipgenerate(lfsr1, skip2);
+ state2 = lfsr_skipgenerate(lfsr2, skip1);
+
+ return (state1 ^ state2);
+}
diff --git a/lib/isc/lib.c b/lib/isc/lib.c
new file mode 100644
index 0000000..7a70c12
--- /dev/null
+++ b/lib/isc/lib.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2004, 2005 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: lib.c,v 1.10.18.2 2005/04/29 00:16:47 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <isc/once.h>
+#include <isc/msgs.h>
+#include <isc/lib.h>
+
+/***
+ *** Globals
+ ***/
+
+LIBISC_EXTERNAL_DATA isc_msgcat_t * isc_msgcat = NULL;
+
+
+/***
+ *** Private
+ ***/
+
+static isc_once_t msgcat_once = ISC_ONCE_INIT;
+
+
+/***
+ *** Functions
+ ***/
+
+static void
+open_msgcat(void) {
+ isc_msgcat_open("libisc.cat", &isc_msgcat);
+}
+
+void
+isc_lib_initmsgcat(void) {
+ isc_result_t result;
+
+ /*!
+ * Initialize the ISC library's message catalog, isc_msgcat, if it
+ * has not already been initialized.
+ */
+
+ result = isc_once_do(&msgcat_once, open_msgcat);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * Normally we'd use RUNTIME_CHECK() or FATAL_ERROR(), but
+ * we can't do that here, since they might call us!
+ * (Note that the catalog might be open anyway, so we might
+ * as well try to provide an internationalized message.)
+ */
+ fprintf(stderr, "%s:%d: %s: isc_once_do() %s.\n",
+ __FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FATALERROR, "fatal error"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ abort();
+ }
+}
diff --git a/lib/isc/log.c b/lib/isc/log.c
new file mode 100644
index 0000000..27c01d1
--- /dev/null
+++ b/lib/isc/log.c
@@ -0,0 +1,1761 @@
+/*
+ * Copyright (C) 2004-2006 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: log.c,v 1.84.18.8 2006/03/02 00:37:22 marka Exp $ */
+
+/*! \file
+ * \author Principal Authors: DCL */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <time.h>
+
+#include <sys/types.h> /* dev_t FreeBSD 2.1 */
+
+#include <isc/dir.h>
+#include <isc/file.h>
+#include <isc/log.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/print.h>
+#include <isc/stat.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#define LCTX_MAGIC ISC_MAGIC('L', 'c', 't', 'x')
+#define VALID_CONTEXT(lctx) ISC_MAGIC_VALID(lctx, LCTX_MAGIC)
+
+#define LCFG_MAGIC ISC_MAGIC('L', 'c', 'f', 'g')
+#define VALID_CONFIG(lcfg) ISC_MAGIC_VALID(lcfg, LCFG_MAGIC)
+
+/*
+ * XXXDCL make dynamic?
+ */
+#define LOG_BUFFER_SIZE (8 * 1024)
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024 /* AIX and others don't define this. */
+#endif
+
+/*!
+ * This is the structure that holds each named channel. A simple linked
+ * list chains all of the channels together, so an individual channel is
+ * found by doing strcmp()s with the names down the list. Their should
+ * be no peformance penalty from this as it is expected that the number
+ * of named channels will be no more than a dozen or so, and name lookups
+ * from the head of the list are only done when isc_log_usechannel() is
+ * called, which should also be very infrequent.
+ */
+typedef struct isc_logchannel isc_logchannel_t;
+
+struct isc_logchannel {
+ char * name;
+ unsigned int type;
+ int level;
+ unsigned int flags;
+ isc_logdestination_t destination;
+ ISC_LINK(isc_logchannel_t) link;
+};
+
+/*!
+ * The logchannellist structure associates categories and modules with
+ * channels. First the appropriate channellist is found based on the
+ * category, and then each structure in the linked list is checked for
+ * a matching module. It is expected that the number of channels
+ * associated with any given category will be very short, no more than
+ * three or four in the more unusual cases.
+ */
+typedef struct isc_logchannellist isc_logchannellist_t;
+
+struct isc_logchannellist {
+ const isc_logmodule_t * module;
+ isc_logchannel_t * channel;
+ ISC_LINK(isc_logchannellist_t) link;
+};
+
+/*!
+ * This structure is used to remember messages for pruning via
+ * isc_log_[v]write1().
+ */
+typedef struct isc_logmessage isc_logmessage_t;
+
+struct isc_logmessage {
+ char * text;
+ isc_time_t time;
+ ISC_LINK(isc_logmessage_t) link;
+};
+
+/*!
+ * The isc_logconfig structure is used to store the configurable information
+ * about where messages are actually supposed to be sent -- the information
+ * that could changed based on some configuration file, as opposed to the
+ * the category/module specification of isc_log_[v]write[1] that is compiled
+ * into a program, or the debug_level which is dynamic state information.
+ */
+struct isc_logconfig {
+ unsigned int magic;
+ isc_log_t * lctx;
+ ISC_LIST(isc_logchannel_t) channels;
+ ISC_LIST(isc_logchannellist_t) *channellists;
+ unsigned int channellist_count;
+ unsigned int duplicate_interval;
+ int highest_level;
+ char * tag;
+ isc_boolean_t dynamic;
+};
+
+/*!
+ * This isc_log structure provides the context for the isc_log functions.
+ * The log context locks itself in isc_log_doit, the internal backend to
+ * isc_log_write. The locking is necessary both to provide exclusive access
+ * to the the buffer into which the message is formatted and to guard against
+ * competing threads trying to write to the same syslog resource. (On
+ * some systems, such as BSD/OS, stdio is thread safe but syslog is not.)
+ * Unfortunately, the lock cannot guard against a _different_ logging
+ * context in the same program competing for syslog's attention. Thus
+ * There Can Be Only One, but this is not enforced.
+ * XXXDCL enforce it?
+ *
+ * Note that the category and module information is not locked.
+ * This is because in the usual case, only one isc_log_t is ever created
+ * in a program, and the category/module registration happens only once.
+ * XXXDCL it might be wise to add more locking overall.
+ */
+struct isc_log {
+ /* Not locked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ isc_logcategory_t * categories;
+ unsigned int category_count;
+ isc_logmodule_t * modules;
+ unsigned int module_count;
+ int debug_level;
+ isc_mutex_t lock;
+ /* Locked by isc_log lock. */
+ isc_logconfig_t * logconfig;
+ char buffer[LOG_BUFFER_SIZE];
+ ISC_LIST(isc_logmessage_t) messages;
+};
+
+/*!
+ * Used when ISC_LOG_PRINTLEVEL is enabled for a channel.
+ */
+static const char *log_level_strings[] = {
+ "debug",
+ "info",
+ "notice",
+ "warning",
+ "error",
+ "critical"
+};
+
+/*!
+ * Used to convert ISC_LOG_* priorities into syslog priorities.
+ * XXXDCL This will need modification for NT.
+ */
+static const int syslog_map[] = {
+ LOG_DEBUG,
+ LOG_INFO,
+ LOG_NOTICE,
+ LOG_WARNING,
+ LOG_ERR,
+ LOG_CRIT
+};
+
+/*!
+ * When adding new categories, a corresponding ISC_LOGCATEGORY_foo
+ * definition needs to be added to <isc/log.h>.
+ *
+ * The default category is provided so that the internal default can
+ * be overridden. Since the default is always looked up as the first
+ * channellist in the log context, it must come first in isc_categories[].
+ */
+LIBISC_EXTERNAL_DATA isc_logcategory_t isc_categories[] = {
+ { "default", 0 }, /* "default" must come first. */
+ { "general", 0 },
+ { NULL, 0 }
+};
+
+/*!
+ * See above comment for categories on LIBISC_EXTERNAL_DATA, and apply it to modules.
+ */
+LIBISC_EXTERNAL_DATA isc_logmodule_t isc_modules[] = {
+ { "socket", 0 },
+ { "time", 0 },
+ { "interface", 0 },
+ { "timer", 0 },
+ { NULL, 0 }
+};
+
+/*!
+ * This essentially constant structure must be filled in at run time,
+ * because its channel member is pointed to a channel that is created
+ * dynamically with isc_log_createchannel.
+ */
+static isc_logchannellist_t default_channel;
+
+/*!
+ * libisc logs to this context.
+ */
+LIBISC_EXTERNAL_DATA isc_log_t *isc_lctx = NULL;
+
+/*!
+ * Forward declarations.
+ */
+static isc_result_t
+assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
+ const isc_logmodule_t *module, isc_logchannel_t *channel);
+
+static isc_result_t
+sync_channellist(isc_logconfig_t *lcfg);
+
+static isc_result_t
+greatest_version(isc_logchannel_t *channel, int *greatest);
+
+static isc_result_t
+roll_log(isc_logchannel_t *channel);
+
+static void
+isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, isc_boolean_t write_once,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, va_list args)
+ ISC_FORMAT_PRINTF(9, 0);
+
+/*@{*/
+/*!
+ * Convenience macros.
+ */
+
+#define FACILITY(channel) (channel->destination.facility)
+#define FILE_NAME(channel) (channel->destination.file.name)
+#define FILE_STREAM(channel) (channel->destination.file.stream)
+#define FILE_VERSIONS(channel) (channel->destination.file.versions)
+#define FILE_MAXSIZE(channel) (channel->destination.file.maximum_size)
+#define FILE_MAXREACHED(channel) (channel->destination.file.maximum_reached)
+
+/*@}*/
+/****
+ **** Public interfaces.
+ ****/
+
+/*
+ * Establish a new logging context, with default channels.
+ */
+isc_result_t
+isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
+ isc_log_t *lctx;
+ isc_logconfig_t *lcfg = NULL;
+ isc_result_t result;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(lctxp != NULL && *lctxp == NULL);
+ REQUIRE(lcfgp == NULL || *lcfgp == NULL);
+
+ lctx = isc_mem_get(mctx, sizeof(*lctx));
+ if (lctx != NULL) {
+ lctx->mctx = mctx;
+ lctx->categories = NULL;
+ lctx->category_count = 0;
+ lctx->modules = NULL;
+ lctx->module_count = 0;
+ lctx->debug_level = 0;
+
+ ISC_LIST_INIT(lctx->messages);
+
+ result = isc_mutex_init(&lctx->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, lctx, sizeof(*lctx));
+ return (result);
+ }
+
+ /*
+ * Normally setting the magic number is the last step done
+ * in a creation function, but a valid log context is needed
+ * by isc_log_registercategories and isc_logconfig_create.
+ * If either fails, the lctx is destroyed and not returned
+ * to the caller.
+ */
+ lctx->magic = LCTX_MAGIC;
+
+ isc_log_registercategories(lctx, isc_categories);
+ isc_log_registermodules(lctx, isc_modules);
+ result = isc_logconfig_create(lctx, &lcfg);
+
+ } else
+ result = ISC_R_NOMEMORY;
+
+ if (result == ISC_R_SUCCESS)
+ result = sync_channellist(lcfg);
+
+ if (result == ISC_R_SUCCESS) {
+ lctx->logconfig = lcfg;
+
+ *lctxp = lctx;
+ if (lcfgp != NULL)
+ *lcfgp = lcfg;
+
+ } else {
+ if (lcfg != NULL)
+ isc_logconfig_destroy(&lcfg);
+ if (lctx != NULL)
+ isc_log_destroy(&lctx);
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) {
+ isc_logconfig_t *lcfg;
+ isc_logdestination_t destination;
+ isc_result_t result = ISC_R_SUCCESS;
+ int level = ISC_LOG_INFO;
+
+ REQUIRE(lcfgp != NULL && *lcfgp == NULL);
+ REQUIRE(VALID_CONTEXT(lctx));
+
+ lcfg = isc_mem_get(lctx->mctx, sizeof(*lcfg));
+
+ if (lcfg != NULL) {
+ lcfg->lctx = lctx;
+ lcfg->channellists = NULL;
+ lcfg->channellist_count = 0;
+ lcfg->duplicate_interval = 0;
+ lcfg->highest_level = level;
+ lcfg->tag = NULL;
+ lcfg->dynamic = ISC_FALSE;
+
+ ISC_LIST_INIT(lcfg->channels);
+
+ /*
+ * Normally the magic number is the last thing set in the
+ * structure, but isc_log_createchannel() needs a valid
+ * config. If the channel creation fails, the lcfg is not
+ * returned to the caller.
+ */
+ lcfg->magic = LCFG_MAGIC;
+
+ } else
+ result = ISC_R_NOMEMORY;
+
+ /*
+ * Create the default channels:
+ * default_syslog, default_stderr, default_debug and null.
+ */
+ if (result == ISC_R_SUCCESS) {
+ destination.facility = LOG_DAEMON;
+ result = isc_log_createchannel(lcfg, "default_syslog",
+ ISC_LOG_TOSYSLOG, level,
+ &destination, 0);
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ destination.file.stream = stderr;
+ destination.file.name = NULL;
+ destination.file.versions = ISC_LOG_ROLLNEVER;
+ destination.file.maximum_size = 0;
+ result = isc_log_createchannel(lcfg, "default_stderr",
+ ISC_LOG_TOFILEDESC,
+ level,
+ &destination,
+ ISC_LOG_PRINTTIME);
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ /*
+ * Set the default category's channel to default_stderr,
+ * which is at the head of the channels list because it was
+ * just created.
+ */
+ default_channel.channel = ISC_LIST_HEAD(lcfg->channels);
+
+ destination.file.stream = stderr;
+ destination.file.name = NULL;
+ destination.file.versions = ISC_LOG_ROLLNEVER;
+ destination.file.maximum_size = 0;
+ result = isc_log_createchannel(lcfg, "default_debug",
+ ISC_LOG_TOFILEDESC,
+ ISC_LOG_DYNAMIC,
+ &destination,
+ ISC_LOG_PRINTTIME);
+ }
+
+ if (result == ISC_R_SUCCESS)
+ result = isc_log_createchannel(lcfg, "null",
+ ISC_LOG_TONULL,
+ ISC_LOG_DYNAMIC,
+ NULL, 0);
+
+ if (result == ISC_R_SUCCESS)
+ *lcfgp = lcfg;
+
+ else
+ if (lcfg != NULL)
+ isc_logconfig_destroy(&lcfg);
+
+ return (result);
+}
+
+isc_logconfig_t *
+isc_logconfig_get(isc_log_t *lctx) {
+ REQUIRE(VALID_CONTEXT(lctx));
+
+ ENSURE(lctx->logconfig != NULL);
+
+ return (lctx->logconfig);
+}
+
+isc_result_t
+isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg) {
+ isc_logconfig_t *old_cfg;
+ isc_result_t result;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+ REQUIRE(VALID_CONFIG(lcfg));
+ REQUIRE(lcfg->lctx == lctx);
+
+ /*
+ * Ensure that lcfg->channellist_count == lctx->category_count.
+ * They won't be equal if isc_log_usechannel has not been called
+ * since any call to isc_log_registercategories.
+ */
+ result = sync_channellist(lcfg);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ LOCK(&lctx->lock);
+
+ old_cfg = lctx->logconfig;
+ lctx->logconfig = lcfg;
+
+ UNLOCK(&lctx->lock);
+
+ isc_logconfig_destroy(&old_cfg);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_log_destroy(isc_log_t **lctxp) {
+ isc_log_t *lctx;
+ isc_logconfig_t *lcfg;
+ isc_mem_t *mctx;
+ isc_logmessage_t *message;
+
+ REQUIRE(lctxp != NULL && VALID_CONTEXT(*lctxp));
+
+ lctx = *lctxp;
+ mctx = lctx->mctx;
+
+ if (lctx->logconfig != NULL) {
+ lcfg = lctx->logconfig;
+ lctx->logconfig = NULL;
+ isc_logconfig_destroy(&lcfg);
+ }
+
+ DESTROYLOCK(&lctx->lock);
+
+ while ((message = ISC_LIST_HEAD(lctx->messages)) != NULL) {
+ ISC_LIST_UNLINK(lctx->messages, message, link);
+
+ isc_mem_put(mctx, message,
+ sizeof(*message) + strlen(message->text) + 1);
+ }
+
+ lctx->buffer[0] = '\0';
+ lctx->debug_level = 0;
+ lctx->categories = NULL;
+ lctx->category_count = 0;
+ lctx->modules = NULL;
+ lctx->module_count = 0;
+ lctx->mctx = NULL;
+ lctx->magic = 0;
+
+ isc_mem_put(mctx, lctx, sizeof(*lctx));
+
+ *lctxp = NULL;
+}
+
+void
+isc_logconfig_destroy(isc_logconfig_t **lcfgp) {
+ isc_logconfig_t *lcfg;
+ isc_mem_t *mctx;
+ isc_logchannel_t *channel;
+ isc_logchannellist_t *item;
+ char *filename;
+ unsigned int i;
+
+ REQUIRE(lcfgp != NULL && VALID_CONFIG(*lcfgp));
+
+ lcfg = *lcfgp;
+
+ /*
+ * This function cannot be called with a logconfig that is in
+ * use by a log context.
+ */
+ REQUIRE(lcfg->lctx != NULL && lcfg->lctx->logconfig != lcfg);
+
+ mctx = lcfg->lctx->mctx;
+
+ while ((channel = ISC_LIST_HEAD(lcfg->channels)) != NULL) {
+ ISC_LIST_UNLINK(lcfg->channels, channel, link);
+
+ if (channel->type == ISC_LOG_TOFILE) {
+ /*
+ * The filename for the channel may have ultimately
+ * started its life in user-land as a const string,
+ * but in isc_log_createchannel it gets copied
+ * into writable memory and is not longer truly const.
+ */
+ DE_CONST(FILE_NAME(channel), filename);
+ isc_mem_free(mctx, filename);
+
+ if (FILE_STREAM(channel) != NULL)
+ (void)fclose(FILE_STREAM(channel));
+ }
+
+ isc_mem_free(mctx, channel->name);
+ isc_mem_put(mctx, channel, sizeof(*channel));
+ }
+
+ for (i = 0; i < lcfg->channellist_count; i++)
+ while ((item = ISC_LIST_HEAD(lcfg->channellists[i])) != NULL) {
+ ISC_LIST_UNLINK(lcfg->channellists[i], item, link);
+ isc_mem_put(mctx, item, sizeof(*item));
+ }
+
+ if (lcfg->channellist_count > 0)
+ isc_mem_put(mctx, lcfg->channellists,
+ lcfg->channellist_count *
+ sizeof(ISC_LIST(isc_logchannellist_t)));
+
+ lcfg->dynamic = ISC_FALSE;
+ if (lcfg->tag != NULL)
+ isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
+ lcfg->tag = NULL;
+ lcfg->highest_level = 0;
+ lcfg->duplicate_interval = 0;
+ lcfg->magic = 0;
+
+ isc_mem_put(mctx, lcfg, sizeof(*lcfg));
+
+ *lcfgp = NULL;
+}
+
+void
+isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]) {
+ isc_logcategory_t *catp;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+ REQUIRE(categories != NULL && categories[0].name != NULL);
+
+ /*
+ * XXXDCL This somewhat sleazy situation of using the last pointer
+ * in one category array to point to the next array exists because
+ * this registration function returns void and I didn't want to have
+ * change everything that used it by making it return an isc_result_t.
+ * It would need to do that if it had to allocate memory to store
+ * pointers to each array passed in.
+ */
+ if (lctx->categories == NULL)
+ lctx->categories = categories;
+
+ else {
+ /*
+ * Adjust the last (NULL) pointer of the already registered
+ * categories to point to the incoming array.
+ */
+ for (catp = lctx->categories; catp->name != NULL; )
+ if (catp->id == UINT_MAX)
+ /*
+ * The name pointer points to the next array.
+ * Ick.
+ */
+ DE_CONST(catp->name, catp);
+ else
+ catp++;
+
+ catp->name = (void *)categories;
+ catp->id = UINT_MAX;
+ }
+
+ /*
+ * Update the id number of the category with its new global id.
+ */
+ for (catp = categories; catp->name != NULL; catp++)
+ catp->id = lctx->category_count++;
+}
+
+isc_logcategory_t *
+isc_log_categorybyname(isc_log_t *lctx, const char *name) {
+ isc_logcategory_t *catp;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+ REQUIRE(name != NULL);
+
+ for (catp = lctx->categories; catp->name != NULL; )
+ if (catp->id == UINT_MAX)
+ /*
+ * catp is neither modified nor returned to the
+ * caller, so removing its const qualifier is ok.
+ */
+ DE_CONST(catp->name, catp);
+ else {
+ if (strcmp(catp->name, name) == 0)
+ return (catp);
+ catp++;
+ }
+
+ return (NULL);
+}
+
+void
+isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]) {
+ isc_logmodule_t *modp;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+ REQUIRE(modules != NULL && modules[0].name != NULL);
+
+ /*
+ * XXXDCL This somewhat sleazy situation of using the last pointer
+ * in one category array to point to the next array exists because
+ * this registration function returns void and I didn't want to have
+ * change everything that used it by making it return an isc_result_t.
+ * It would need to do that if it had to allocate memory to store
+ * pointers to each array passed in.
+ */
+ if (lctx->modules == NULL)
+ lctx->modules = modules;
+
+ else {
+ /*
+ * Adjust the last (NULL) pointer of the already registered
+ * modules to point to the incoming array.
+ */
+ for (modp = lctx->modules; modp->name != NULL; )
+ if (modp->id == UINT_MAX)
+ /*
+ * The name pointer points to the next array.
+ * Ick.
+ */
+ DE_CONST(modp->name, modp);
+ else
+ modp++;
+
+ modp->name = (void *)modules;
+ modp->id = UINT_MAX;
+ }
+
+ /*
+ * Update the id number of the module with its new global id.
+ */
+ for (modp = modules; modp->name != NULL; modp++)
+ modp->id = lctx->module_count++;
+}
+
+isc_logmodule_t *
+isc_log_modulebyname(isc_log_t *lctx, const char *name) {
+ isc_logmodule_t *modp;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+ REQUIRE(name != NULL);
+
+ for (modp = lctx->modules; modp->name != NULL; )
+ if (modp->id == UINT_MAX)
+ /*
+ * modp is neither modified nor returned to the
+ * caller, so removing its const qualifier is ok.
+ */
+ DE_CONST(modp->name, modp);
+ else {
+ if (strcmp(modp->name, name) == 0)
+ return (modp);
+ modp++;
+ }
+
+ return (NULL);
+}
+
+isc_result_t
+isc_log_createchannel(isc_logconfig_t *lcfg, const char *name,
+ unsigned int type, int level,
+ const isc_logdestination_t *destination,
+ unsigned int flags)
+{
+ isc_logchannel_t *channel;
+ isc_mem_t *mctx;
+
+ REQUIRE(VALID_CONFIG(lcfg));
+ REQUIRE(name != NULL);
+ REQUIRE(type == ISC_LOG_TOSYSLOG || type == ISC_LOG_TOFILE ||
+ type == ISC_LOG_TOFILEDESC || type == ISC_LOG_TONULL);
+ REQUIRE(destination != NULL || type == ISC_LOG_TONULL);
+ REQUIRE(level >= ISC_LOG_CRITICAL);
+ REQUIRE((flags &
+ (unsigned int)~(ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY)) == 0);
+
+ /* XXXDCL find duplicate names? */
+
+ mctx = lcfg->lctx->mctx;
+
+ channel = isc_mem_get(mctx, sizeof(*channel));
+ if (channel == NULL)
+ return (ISC_R_NOMEMORY);
+
+ channel->name = isc_mem_strdup(mctx, name);
+ if (channel->name == NULL) {
+ isc_mem_put(mctx, channel, sizeof(*channel));
+ return (ISC_R_NOMEMORY);
+ }
+
+ channel->type = type;
+ channel->level = level;
+ channel->flags = flags;
+ ISC_LINK_INIT(channel, link);
+
+ switch (type) {
+ case ISC_LOG_TOSYSLOG:
+ FACILITY(channel) = destination->facility;
+ break;
+
+ case ISC_LOG_TOFILE:
+ /*
+ * The file name is copied because greatest_version wants
+ * to scribble on it, so it needs to be definitely in
+ * writable memory.
+ */
+ FILE_NAME(channel) =
+ isc_mem_strdup(mctx, destination->file.name);
+ FILE_STREAM(channel) = NULL;
+ FILE_VERSIONS(channel) = destination->file.versions;
+ FILE_MAXSIZE(channel) = destination->file.maximum_size;
+ FILE_MAXREACHED(channel) = ISC_FALSE;
+ break;
+
+ case ISC_LOG_TOFILEDESC:
+ FILE_NAME(channel) = NULL;
+ FILE_STREAM(channel) = destination->file.stream;
+ FILE_MAXSIZE(channel) = 0;
+ FILE_VERSIONS(channel) = ISC_LOG_ROLLNEVER;
+ break;
+
+ case ISC_LOG_TONULL:
+ /* Nothing. */
+ break;
+
+ default:
+ isc_mem_put(mctx, channel->name, strlen(channel->name) + 1);
+ isc_mem_put(mctx, channel, sizeof(*channel));
+ return (ISC_R_UNEXPECTED);
+ }
+
+ ISC_LIST_PREPEND(lcfg->channels, channel, link);
+
+ /*
+ * If default_stderr was redefined, make the default category
+ * point to the new default_stderr.
+ */
+ if (strcmp(name, "default_stderr") == 0)
+ default_channel.channel = channel;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
+ const isc_logcategory_t *category,
+ const isc_logmodule_t *module)
+{
+ isc_log_t *lctx;
+ isc_logchannel_t *channel;
+ isc_result_t result = ISC_R_SUCCESS;
+ unsigned int i;
+
+ REQUIRE(VALID_CONFIG(lcfg));
+ REQUIRE(name != NULL);
+
+ lctx = lcfg->lctx;
+
+ REQUIRE(category == NULL || category->id < lctx->category_count);
+ REQUIRE(module == NULL || module->id < lctx->module_count);
+
+ for (channel = ISC_LIST_HEAD(lcfg->channels); channel != NULL;
+ channel = ISC_LIST_NEXT(channel, link))
+ if (strcmp(name, channel->name) == 0)
+ break;
+
+ if (channel == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (category != NULL)
+ result = assignchannel(lcfg, category->id, module, channel);
+
+ else
+ /*
+ * Assign to all categories. Note that this includes
+ * the default channel.
+ */
+ for (i = 0; i < lctx->category_count; i++) {
+ result = assignchannel(lcfg, i, module, channel);
+ if (result != ISC_R_SUCCESS)
+ break;
+ }
+
+ return (result);
+}
+
+void
+isc_log_write(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format, ...)
+{
+ va_list args;
+
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+
+ va_start(args, format);
+ isc_log_doit(lctx, category, module, level, ISC_FALSE,
+ NULL, 0, 0, format, args);
+ va_end(args);
+}
+
+void
+isc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ const char *format, va_list args)
+{
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+ isc_log_doit(lctx, category, module, level, ISC_FALSE,
+ NULL, 0, 0, format, args);
+}
+
+void
+isc_log_write1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format, ...)
+{
+ va_list args;
+
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+
+ va_start(args, format);
+ isc_log_doit(lctx, category, module, level, ISC_TRUE,
+ NULL, 0, 0, format, args);
+ va_end(args);
+}
+
+void
+isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ const char *format, va_list args)
+{
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+ isc_log_doit(lctx, category, module, level, ISC_TRUE,
+ NULL, 0, 0, format, args);
+}
+
+void
+isc_log_iwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, ...)
+{
+ va_list args;
+
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+
+ va_start(args, format);
+ isc_log_doit(lctx, category, module, level, ISC_FALSE,
+ msgcat, msgset, msg, format, args);
+ va_end(args);
+}
+
+void
+isc_log_ivwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, va_list args)
+{
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+ isc_log_doit(lctx, category, module, level, ISC_FALSE,
+ msgcat, msgset, msg, format, args);
+}
+
+void
+isc_log_iwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, ...)
+{
+ va_list args;
+
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+
+ va_start(args, format);
+ isc_log_doit(lctx, category, module, level, ISC_TRUE,
+ msgcat, msgset, msg, format, args);
+ va_end(args);
+}
+
+void
+isc_log_ivwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, va_list args)
+{
+ /*
+ * Contract checking is done in isc_log_doit().
+ */
+ isc_log_doit(lctx, category, module, level, ISC_TRUE,
+ msgcat, msgset, msg, format, args);
+}
+
+void
+isc_log_setcontext(isc_log_t *lctx) {
+ isc_lctx = lctx;
+}
+
+void
+isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level) {
+ isc_logchannel_t *channel;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+
+ LOCK(&lctx->lock);
+
+ lctx->debug_level = level;
+ /*
+ * Close ISC_LOG_DEBUGONLY channels if level is zero.
+ */
+ if (lctx->debug_level == 0)
+ for (channel = ISC_LIST_HEAD(lctx->logconfig->channels);
+ channel != NULL;
+ channel = ISC_LIST_NEXT(channel, link))
+ if (channel->type == ISC_LOG_TOFILE &&
+ (channel->flags & ISC_LOG_DEBUGONLY) != 0 &&
+ FILE_STREAM(channel) != NULL) {
+ (void)fclose(FILE_STREAM(channel));
+ FILE_STREAM(channel) = NULL;
+ }
+ UNLOCK(&lctx->lock);
+}
+
+unsigned int
+isc_log_getdebuglevel(isc_log_t *lctx) {
+ REQUIRE(VALID_CONTEXT(lctx));
+
+ return (lctx->debug_level);
+}
+
+void
+isc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval) {
+ REQUIRE(VALID_CONFIG(lcfg));
+
+ lcfg->duplicate_interval = interval;
+}
+
+unsigned int
+isc_log_getduplicateinterval(isc_logconfig_t *lcfg) {
+ REQUIRE(VALID_CONTEXT(lcfg));
+
+ return (lcfg->duplicate_interval);
+}
+
+isc_result_t
+isc_log_settag(isc_logconfig_t *lcfg, const char *tag) {
+ REQUIRE(VALID_CONFIG(lcfg));
+
+ if (tag != NULL && *tag != '\0') {
+ if (lcfg->tag != NULL)
+ isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
+ lcfg->tag = isc_mem_strdup(lcfg->lctx->mctx, tag);
+ if (lcfg->tag == NULL)
+ return (ISC_R_NOMEMORY);
+
+ } else {
+ if (lcfg->tag != NULL)
+ isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
+ lcfg->tag = NULL;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+char *
+isc_log_gettag(isc_logconfig_t *lcfg) {
+ REQUIRE(VALID_CONFIG(lcfg));
+
+ return (lcfg->tag);
+}
+
+/* XXXDCL NT -- This interface will assuredly be changing. */
+void
+isc_log_opensyslog(const char *tag, int options, int facility) {
+ (void)openlog(tag, options, facility);
+}
+
+void
+isc_log_closefilelogs(isc_log_t *lctx) {
+ isc_logchannel_t *channel;
+
+ REQUIRE(VALID_CONTEXT(lctx));
+
+ LOCK(&lctx->lock);
+ for (channel = ISC_LIST_HEAD(lctx->logconfig->channels);
+ channel != NULL;
+ channel = ISC_LIST_NEXT(channel, link))
+
+ if (channel->type == ISC_LOG_TOFILE &&
+ FILE_STREAM(channel) != NULL) {
+ (void)fclose(FILE_STREAM(channel));
+ FILE_STREAM(channel) = NULL;
+ }
+ UNLOCK(&lctx->lock);
+}
+
+/****
+ **** Internal functions
+ ****/
+
+static isc_result_t
+assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
+ const isc_logmodule_t *module, isc_logchannel_t *channel)
+{
+ isc_logchannellist_t *new_item;
+ isc_log_t *lctx;
+ isc_result_t result;
+
+ REQUIRE(VALID_CONFIG(lcfg));
+
+ lctx = lcfg->lctx;
+
+ REQUIRE(category_id < lctx->category_count);
+ REQUIRE(module == NULL || module->id < lctx->module_count);
+ REQUIRE(channel != NULL);
+
+ /*
+ * Ensure lcfg->channellist_count == lctx->category_count.
+ */
+ result = sync_channellist(lcfg);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ new_item = isc_mem_get(lctx->mctx, sizeof(*new_item));
+ if (new_item == NULL)
+ return (ISC_R_NOMEMORY);
+
+ new_item->channel = channel;
+ new_item->module = module;
+ ISC_LIST_INITANDPREPEND(lcfg->channellists[category_id],
+ new_item, link);
+
+ /*
+ * Remember the highest logging level set by any channel in the
+ * logging config, so isc_log_doit() can quickly return if the
+ * message is too high to be logged by any channel.
+ */
+ if (channel->type != ISC_LOG_TONULL) {
+ if (lcfg->highest_level < channel->level)
+ lcfg->highest_level = channel->level;
+ if (channel->level == ISC_LOG_DYNAMIC)
+ lcfg->dynamic = ISC_TRUE;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This would ideally be part of isc_log_registercategories(), except then
+ * that function would have to return isc_result_t instead of void.
+ */
+static isc_result_t
+sync_channellist(isc_logconfig_t *lcfg) {
+ unsigned int bytes;
+ isc_log_t *lctx;
+ void *lists;
+
+ REQUIRE(VALID_CONFIG(lcfg));
+
+ lctx = lcfg->lctx;
+
+ REQUIRE(lctx->category_count != 0);
+
+ if (lctx->category_count == lcfg->channellist_count)
+ return (ISC_R_SUCCESS);
+
+ bytes = lctx->category_count * sizeof(ISC_LIST(isc_logchannellist_t));
+
+ lists = isc_mem_get(lctx->mctx, bytes);
+
+ if (lists == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(lists, 0, bytes);
+
+ if (lcfg->channellist_count != 0) {
+ bytes = lcfg->channellist_count *
+ sizeof(ISC_LIST(isc_logchannellist_t));
+ memcpy(lists, lcfg->channellists, bytes);
+ isc_mem_put(lctx->mctx, lcfg->channellists, bytes);
+ }
+
+ lcfg->channellists = lists;
+ lcfg->channellist_count = lctx->category_count;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+greatest_version(isc_logchannel_t *channel, int *greatestp) {
+ /* XXXDCL HIGHLY NT */
+ char *basename, *digit_end;
+ const char *dirname;
+ int version, greatest = -1;
+ unsigned int basenamelen;
+ isc_dir_t dir;
+ isc_result_t result;
+ char sep = '/';
+#ifdef _WIN32
+ char *basename2;
+#endif
+
+ REQUIRE(channel->type == ISC_LOG_TOFILE);
+
+ /*
+ * It is safe to DE_CONST the file.name because it was copied
+ * with isc_mem_strdup in isc_log_createchannel.
+ */
+ basename = strrchr(FILE_NAME(channel), sep);
+#ifdef _WIN32
+ basename2 = strrchr(FILE_NAME(channel), '\\');
+ if ((basename != NULL && basename2 != NULL && basename2 > basename) ||
+ (basename == NULL && basename2 != NULL)) {
+ basename = basename2;
+ sep = '\\';
+ }
+#endif
+ if (basename != NULL) {
+ *basename++ = '\0';
+ dirname = FILE_NAME(channel);
+ } else {
+ DE_CONST(FILE_NAME(channel), basename);
+ dirname = ".";
+ }
+ basenamelen = strlen(basename);
+
+ isc_dir_init(&dir);
+ result = isc_dir_open(&dir, dirname);
+
+ /*
+ * Replace the file separator if it was taken out.
+ */
+ if (basename != FILE_NAME(channel))
+ *(basename - 1) = sep;
+
+ /*
+ * Return if the directory open failed.
+ */
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
+ if (dir.entry.length > basenamelen &&
+ strncmp(dir.entry.name, basename, basenamelen) == 0 &&
+ dir.entry.name[basenamelen] == '.') {
+
+ version = strtol(&dir.entry.name[basenamelen + 1],
+ &digit_end, 10);
+ if (*digit_end == '\0' && version > greatest)
+ greatest = version;
+ }
+ }
+ isc_dir_close(&dir);
+
+ *greatestp = ++greatest;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+roll_log(isc_logchannel_t *channel) {
+ int i, n, greatest;
+ char current[PATH_MAX + 1];
+ char new[PATH_MAX + 1];
+ const char *path;
+ isc_result_t result;
+
+ /*
+ * Do nothing (not even excess version trimming) if ISC_LOG_ROLLNEVER
+ * is specified. Apparently complete external control over the log
+ * files is desired.
+ */
+ if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER)
+ return (ISC_R_SUCCESS);
+
+ path = FILE_NAME(channel);
+
+ /*
+ * Set greatest_version to the greatest existing version
+ * (not the maximum requested version). This is 1 based even
+ * though the file names are 0 based, so an oldest log of log.1
+ * is a greatest_version of 2.
+ */
+ result = greatest_version(channel, &greatest);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Now greatest should be set to the highest version number desired.
+ * Since the highest number is one less than FILE_VERSIONS(channel)
+ * when not doing infinite log rolling, greatest will need to be
+ * decremented when it is equal to -- or greater than --
+ * FILE_VERSIONS(channel). When greatest is less than
+ * FILE_VERSIONS(channel), it is already suitable for use as
+ * the maximum version number.
+ */
+
+ if (FILE_VERSIONS(channel) == ISC_LOG_ROLLINFINITE ||
+ FILE_VERSIONS(channel) > greatest)
+ ; /* Do nothing. */
+ else
+ /*
+ * When greatest is >= FILE_VERSIONS(channel), it needs to
+ * be reduced until it is FILE_VERSIONS(channel) - 1.
+ * Remove any excess logs on the way to that value.
+ */
+ while (--greatest >= FILE_VERSIONS(channel)) {
+ n = snprintf(current, sizeof(current), "%s.%d",
+ path, greatest);
+ if (n >= (int)sizeof(current) || n < 0)
+ result = ISC_R_NOSPACE;
+ else
+ result = isc_file_remove(current);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_FILENOTFOUND)
+ syslog(LOG_ERR,
+ "unable to remove log file '%s.%d': %s",
+ path, greatest,
+ isc_result_totext(result));
+ }
+
+ for (i = greatest; i > 0; i--) {
+ result = ISC_R_SUCCESS;
+ n = snprintf(current, sizeof(current), "%s.%d", path, i - 1);
+ if (n >= (int)sizeof(current) || n < 0)
+ result = ISC_R_NOSPACE;
+ if (result == ISC_R_SUCCESS) {
+ n = snprintf(new, sizeof(new), "%s.%d", path, i);
+ if (n >= (int)sizeof(new) || n < 0)
+ result = ISC_R_NOSPACE;
+ }
+ if (result == ISC_R_SUCCESS)
+ result = isc_file_rename(current, new);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_FILENOTFOUND)
+ syslog(LOG_ERR,
+ "unable to rename log file '%s.%d' to "
+ "'%s.%d': %s", path, i - 1, path, i,
+ isc_result_totext(result));
+ }
+
+ if (FILE_VERSIONS(channel) != 0) {
+ n = snprintf(new, sizeof(new), "%s.0", path);
+ if (n >= (int)sizeof(new) || n < 0)
+ result = ISC_R_NOSPACE;
+ else
+ result = isc_file_rename(path, new);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_FILENOTFOUND)
+ syslog(LOG_ERR,
+ "unable to rename log file '%s' to '%s.0': %s",
+ path, path, isc_result_totext(result));
+ } else {
+ result = isc_file_remove(path);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_FILENOTFOUND)
+ syslog(LOG_ERR, "unable to remove log file '%s': %s",
+ path, isc_result_totext(result));
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+isc_log_open(isc_logchannel_t *channel) {
+ struct stat statbuf;
+ isc_boolean_t regular_file;
+ isc_boolean_t roll = ISC_FALSE;
+ isc_result_t result = ISC_R_SUCCESS;
+ const char *path;
+
+ REQUIRE(channel->type == ISC_LOG_TOFILE);
+ REQUIRE(FILE_STREAM(channel) == NULL);
+
+ path = FILE_NAME(channel);
+
+ REQUIRE(path != NULL && *path != '\0');
+
+ /*
+ * Determine type of file; only regular files will be
+ * version renamed, and only if the base file exists
+ * and either has no size limit or has reached its size limit.
+ */
+ if (stat(path, &statbuf) == 0) {
+ regular_file = S_ISREG(statbuf.st_mode) ? ISC_TRUE : ISC_FALSE;
+ /* XXXDCL if not regular_file complain? */
+ if ((FILE_MAXSIZE(channel) == 0 &&
+ FILE_VERSIONS(channel) != ISC_LOG_ROLLNEVER) ||
+ (FILE_MAXSIZE(channel) > 0 &&
+ statbuf.st_size >= FILE_MAXSIZE(channel)))
+ roll = regular_file;
+ } else if (errno == ENOENT)
+ regular_file = ISC_TRUE;
+ else
+ result = ISC_R_INVALIDFILE;
+
+ /*
+ * Version control.
+ */
+ if (result == ISC_R_SUCCESS && roll) {
+ if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER)
+ return (ISC_R_MAXSIZE);
+ result = roll_log(channel);
+ if (result != ISC_R_SUCCESS) {
+ if ((channel->flags & ISC_LOG_OPENERR) == 0) {
+ syslog(LOG_ERR,
+ "isc_log_open: roll_log '%s' "
+ "failed: %s",
+ FILE_NAME(channel),
+ isc_result_totext(result));
+ channel->flags |= ISC_LOG_OPENERR;
+ }
+ return (result);
+ }
+ }
+
+ result = isc_stdio_open(path, "a", &FILE_STREAM(channel));
+
+ return (result);
+}
+
+isc_boolean_t
+isc_log_wouldlog(isc_log_t *lctx, int level) {
+ /*
+ * Try to avoid locking the mutex for messages which can't
+ * possibly be logged to any channels -- primarily debugging
+ * messages that the debug level is not high enough to print.
+ *
+ * If the level is (mathematically) less than or equal to the
+ * highest_level, or if there is a dynamic channel and the level is
+ * less than or equal to the debug level, the main loop must be
+ * entered to see if the message should really be output.
+ *
+ * NOTE: this is UNLOCKED access to the logconfig. However,
+ * the worst thing that can happen is that a bad decision is made
+ * about returning without logging, and that's not a big concern,
+ * because that's a risk anyway if the logconfig is being
+ * dynamically changed.
+ */
+
+ if (lctx == NULL || lctx->logconfig == NULL)
+ return (ISC_FALSE);
+
+ return (ISC_TF(level <= lctx->logconfig->highest_level ||
+ (lctx->logconfig->dynamic &&
+ level <= lctx->debug_level)));
+}
+
+static void
+isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, isc_boolean_t write_once,
+ isc_msgcat_t *msgcat, int msgset, int msg,
+ const char *format, va_list args)
+{
+ int syslog_level;
+ char time_string[64];
+ char level_string[24];
+ const char *iformat;
+ struct stat statbuf;
+ isc_boolean_t matched = ISC_FALSE;
+ isc_boolean_t printtime, printtag;
+ isc_boolean_t printcategory, printmodule, printlevel;
+ isc_logconfig_t *lcfg;
+ isc_logchannel_t *channel;
+ isc_logchannellist_t *category_channels;
+ isc_result_t result;
+
+ REQUIRE(lctx == NULL || VALID_CONTEXT(lctx));
+ REQUIRE(category != NULL);
+ REQUIRE(module != NULL);
+ REQUIRE(level != ISC_LOG_DYNAMIC);
+ REQUIRE(format != NULL);
+
+ /*
+ * Programs can use libraries that use this logging code without
+ * wanting to do any logging, thus the log context is allowed to
+ * be non-existent.
+ */
+ if (lctx == NULL)
+ return;
+
+ REQUIRE(category->id < lctx->category_count);
+ REQUIRE(module->id < lctx->module_count);
+
+ if (! isc_log_wouldlog(lctx, level))
+ return;
+
+ if (msgcat != NULL)
+ iformat = isc_msgcat_get(msgcat, msgset, msg, format);
+ else
+ iformat = format;
+
+ time_string[0] = '\0';
+ level_string[0] = '\0';
+
+ LOCK(&lctx->lock);
+
+ lctx->buffer[0] = '\0';
+
+ lcfg = lctx->logconfig;
+
+ category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]);
+
+ /*
+ * XXXDCL add duplicate filtering? (To not write multiple times to
+ * the same source via various channels).
+ */
+ do {
+ /*
+ * If the channel list end was reached and a match was made,
+ * everything is finished.
+ */
+ if (category_channels == NULL && matched)
+ break;
+
+ if (category_channels == NULL && ! matched &&
+ category_channels != ISC_LIST_HEAD(lcfg->channellists[0]))
+ /*
+ * No category/module pair was explicitly configured.
+ * Try the category named "default".
+ */
+ category_channels =
+ ISC_LIST_HEAD(lcfg->channellists[0]);
+
+ if (category_channels == NULL && ! matched)
+ /*
+ * No matching module was explicitly configured
+ * for the category named "default". Use the internal
+ * default channel.
+ */
+ category_channels = &default_channel;
+
+ if (category_channels->module != NULL &&
+ category_channels->module != module) {
+ category_channels = ISC_LIST_NEXT(category_channels,
+ link);
+ continue;
+ }
+
+ matched = ISC_TRUE;
+
+ channel = category_channels->channel;
+ category_channels = ISC_LIST_NEXT(category_channels, link);
+
+ if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) &&
+ lctx->debug_level == 0)
+ continue;
+
+ if (channel->level == ISC_LOG_DYNAMIC) {
+ if (lctx->debug_level < level)
+ continue;
+ } else if (channel->level < level)
+ continue;
+
+ if ((channel->flags & ISC_LOG_PRINTTIME) != 0 &&
+ time_string[0] == '\0') {
+ isc_time_t isctime;
+
+ TIME_NOW(&isctime);
+ isc_time_formattimestamp(&isctime, time_string,
+ sizeof(time_string));
+ }
+
+ if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 &&
+ level_string[0] == '\0') {
+ if (level < ISC_LOG_CRITICAL)
+ snprintf(level_string, sizeof(level_string),
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_LOG,
+ ISC_MSG_LEVEL,
+ "level %d: "),
+ level);
+ else if (level > ISC_LOG_DYNAMIC)
+ snprintf(level_string, sizeof(level_string),
+ "%s %d: ", log_level_strings[0],
+ level);
+ else
+ snprintf(level_string, sizeof(level_string),
+ "%s: ", log_level_strings[-level]);
+ }
+
+ /*
+ * Only format the message once.
+ */
+ if (lctx->buffer[0] == '\0') {
+ (void)vsnprintf(lctx->buffer, sizeof(lctx->buffer),
+ iformat, args);
+
+ /*
+ * Check for duplicates.
+ */
+ if (write_once) {
+ isc_logmessage_t *message, *new;
+ isc_time_t oldest;
+ isc_interval_t interval;
+
+ isc_interval_set(&interval,
+ lcfg->duplicate_interval, 0);
+
+ /*
+ * 'oldest' is the age of the oldest messages
+ * which fall within the duplicate_interval
+ * range.
+ */
+ TIME_NOW(&oldest);
+ if (isc_time_subtract(&oldest, &interval, &oldest)
+ != ISC_R_SUCCESS)
+ /*
+ * Can't effectively do the checking
+ * without having a valid time.
+ */
+ message = NULL;
+ else
+ message =ISC_LIST_HEAD(lctx->messages);
+
+ while (message != NULL) {
+ if (isc_time_compare(&message->time,
+ &oldest) < 0) {
+ /*
+ * This message is older
+ * than the duplicate_interval,
+ * so it should be dropped from
+ * the history.
+ *
+ * Setting the interval to be
+ * to be longer will obviously
+ * not cause the expired
+ * message to spring back into
+ * existence.
+ */
+ new = ISC_LIST_NEXT(message,
+ link);
+
+ ISC_LIST_UNLINK(lctx->messages,
+ message, link);
+
+ isc_mem_put(lctx->mctx,
+ message,
+ sizeof(*message) + 1 +
+ strlen(message->text));
+
+ message = new;
+ continue;
+ }
+
+ /*
+ * This message is in the duplicate
+ * filtering interval ...
+ */
+ if (strcmp(lctx->buffer, message->text)
+ == 0) {
+ /*
+ * ... and it is a duplicate.
+ * Unlock the mutex and
+ * get the hell out of Dodge.
+ */
+ UNLOCK(&lctx->lock);
+ return;
+ }
+
+ message = ISC_LIST_NEXT(message, link);
+ }
+
+ /*
+ * It wasn't in the duplicate interval,
+ * so add it to the message list.
+ */
+ new = isc_mem_get(lctx->mctx,
+ sizeof(isc_logmessage_t) +
+ strlen(lctx->buffer) + 1);
+ if (new != NULL) {
+ /*
+ * Put the text immediately after
+ * the struct. The strcpy is safe.
+ */
+ new->text = (char *)(new + 1);
+ strcpy(new->text, lctx->buffer);
+
+ TIME_NOW(&new->time);
+
+ ISC_LIST_APPEND(lctx->messages,
+ new, link);
+ }
+ }
+ }
+
+ printtime = ISC_TF((channel->flags & ISC_LOG_PRINTTIME)
+ != 0);
+ printtag = ISC_TF((channel->flags & ISC_LOG_PRINTTAG)
+ != 0 && lcfg->tag != NULL);
+ printcategory = ISC_TF((channel->flags & ISC_LOG_PRINTCATEGORY)
+ != 0);
+ printmodule = ISC_TF((channel->flags & ISC_LOG_PRINTMODULE)
+ != 0);
+ printlevel = ISC_TF((channel->flags & ISC_LOG_PRINTLEVEL)
+ != 0);
+
+ switch (channel->type) {
+ case ISC_LOG_TOFILE:
+ if (FILE_MAXREACHED(channel)) {
+ /*
+ * If the file can be rolled, OR
+ * If the file no longer exists, OR
+ * If the file is less than the maximum size,
+ * (such as if it had been renamed and
+ * a new one touched, or it was truncated
+ * in place)
+ * ... then close it to trigger reopening.
+ */
+ if (FILE_VERSIONS(channel) !=
+ ISC_LOG_ROLLNEVER ||
+ (stat(FILE_NAME(channel), &statbuf) != 0 &&
+ errno == ENOENT) ||
+ statbuf.st_size < FILE_MAXSIZE(channel)) {
+ (void)fclose(FILE_STREAM(channel));
+ FILE_STREAM(channel) = NULL;
+ FILE_MAXREACHED(channel) = ISC_FALSE;
+ } else
+ /*
+ * Eh, skip it.
+ */
+ break;
+ }
+
+ if (FILE_STREAM(channel) == NULL) {
+ result = isc_log_open(channel);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_MAXSIZE &&
+ (channel->flags & ISC_LOG_OPENERR) == 0) {
+ syslog(LOG_ERR,
+ "isc_log_open '%s' failed: %s",
+ FILE_NAME(channel),
+ isc_result_totext(result));
+ channel->flags |= ISC_LOG_OPENERR;
+ }
+ if (result != ISC_R_SUCCESS)
+ break;
+ channel->flags &= ~ISC_LOG_OPENERR;
+ }
+ /* FALLTHROUGH */
+
+ case ISC_LOG_TOFILEDESC:
+ fprintf(FILE_STREAM(channel), "%s%s%s%s%s%s%s%s%s%s\n",
+ printtime ? time_string : "",
+ printtime ? " " : "",
+ printtag ? lcfg->tag : "",
+ printtag ? ": " : "",
+ printcategory ? category->name : "",
+ printcategory ? ": " : "",
+ printmodule ? (module != NULL ? module->name
+ : "no_module")
+ : "",
+ printmodule ? ": " : "",
+ printlevel ? level_string : "",
+ lctx->buffer);
+
+ fflush(FILE_STREAM(channel));
+
+ /*
+ * If the file now exceeds its maximum size
+ * threshold, note it so that it will not be logged
+ * to any more.
+ */
+ if (FILE_MAXSIZE(channel) > 0) {
+ INSIST(channel->type == ISC_LOG_TOFILE);
+
+ /* XXXDCL NT fstat/fileno */
+ /* XXXDCL complain if fstat fails? */
+ if (fstat(fileno(FILE_STREAM(channel)),
+ &statbuf) >= 0 &&
+ statbuf.st_size > FILE_MAXSIZE(channel))
+ FILE_MAXREACHED(channel) = ISC_TRUE;
+ }
+
+ break;
+
+ case ISC_LOG_TOSYSLOG:
+ if (level > 0)
+ syslog_level = LOG_DEBUG;
+ else if (level < ISC_LOG_CRITICAL)
+ syslog_level = LOG_CRIT;
+ else
+ syslog_level = syslog_map[-level];
+
+ (void)syslog(FACILITY(channel) | syslog_level,
+ "%s%s%s%s%s%s%s%s%s%s",
+ printtime ? time_string : "",
+ printtime ? " " : "",
+ printtag ? lcfg->tag : "",
+ printtag ? ": " : "",
+ printcategory ? category->name : "",
+ printcategory ? ": " : "",
+ printmodule ? (module != NULL ? module->name
+ : "no_module")
+ : "",
+ printmodule ? ": " : "",
+ printlevel ? level_string : "",
+ lctx->buffer);
+ break;
+
+ case ISC_LOG_TONULL:
+ break;
+
+ }
+
+ } while (1);
+
+ UNLOCK(&lctx->lock);
+}
diff --git a/lib/isc/md5.c b/lib/isc/md5.c
new file mode 100644
index 0000000..07d7546
--- /dev/null
+++ b/lib/isc/md5.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2004, 2005 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: md5.c,v 1.10.18.2 2005/04/29 00:16:47 marka Exp $ */
+
+/*! \file
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include "config.h"
+
+#include <isc/assertions.h>
+#include <isc/md5.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+static void
+byteSwap(isc_uint32_t *buf, unsigned words)
+{
+ unsigned char *p = (unsigned char *)buf;
+
+ do {
+ *buf++ = (isc_uint32_t)((unsigned)p[3] << 8 | p[2]) << 16 |
+ ((unsigned)p[1] << 8 | p[0]);
+ p += 4;
+ } while (--words);
+}
+
+/*!
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+isc_md5_init(isc_md5_t *ctx) {
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bytes[0] = 0;
+ ctx->bytes[1] = 0;
+}
+
+void
+isc_md5_invalidate(isc_md5_t *ctx) {
+ memset(ctx, 0, sizeof(isc_md5_t));
+}
+
+/*@{*/
+/*! The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+/*@}*/
+
+/*! This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+ (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*!
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+transform(isc_uint32_t buf[4], isc_uint32_t const in[16]) {
+ register isc_uint32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*!
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) {
+ isc_uint32_t t;
+
+ /* Update byte count */
+
+ t = ctx->bytes[0];
+ if ((ctx->bytes[0] = t + len) < t)
+ ctx->bytes[1]++; /* Carry from low to high */
+
+ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
+ if (t > len) {
+ memcpy((unsigned char *)ctx->in + 64 - t, buf, len);
+ return;
+ }
+ /* First chunk is an odd size */
+ memcpy((unsigned char *)ctx->in + 64 - t, buf, t);
+ byteSwap(ctx->in, 16);
+ transform(ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+
+ /* Process data in 64-byte chunks */
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteSwap(ctx->in, 16);
+ transform(ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy(ctx->in, buf, len);
+}
+
+/*!
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
+ int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
+ unsigned char *p = (unsigned char *)ctx->in + count;
+
+ /* Set the first char of padding to 0x80. There is always room. */
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 56 bytes (-8..55) */
+ count = 56 - 1 - count;
+
+ if (count < 0) { /* Padding forces an extra block */
+ memset(p, 0, count + 8);
+ byteSwap(ctx->in, 16);
+ transform(ctx->buf, ctx->in);
+ p = (unsigned char *)ctx->in;
+ count = 56;
+ }
+ memset(p, 0, count);
+ byteSwap(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ctx->in[14] = ctx->bytes[0] << 3;
+ ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+ transform(ctx->buf, ctx->in);
+
+ byteSwap(ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(isc_md5_t)); /* In case it's sensitive */
+}
diff --git a/lib/isc/mem.c b/lib/isc/mem.c
new file mode 100644
index 0000000..aec6118
--- /dev/null
+++ b/lib/isc/mem.c
@@ -0,0 +1,1955 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: mem.c,v 1.116.18.18 2007/10/30 23:31:43 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include <limits.h>
+
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/once.h>
+#include <isc/ondestroy.h>
+#include <isc/string.h>
+
+#include <isc/mutex.h>
+#include <isc/util.h>
+
+#define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
+#define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
+
+#ifndef ISC_MEM_DEBUGGING
+#define ISC_MEM_DEBUGGING 0
+#endif
+LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
+
+/*
+ * Constants.
+ */
+
+#define DEF_MAX_SIZE 1100
+#define DEF_MEM_TARGET 4096
+#define ALIGNMENT_SIZE 8 /*%< must be a power of 2 */
+#define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */
+#define TABLE_INCREMENT 1024
+#define DEBUGLIST_COUNT 1024
+
+/*
+ * Types.
+ */
+#if ISC_MEM_TRACKLINES
+typedef struct debuglink debuglink_t;
+struct debuglink {
+ ISC_LINK(debuglink_t) link;
+ const void *ptr[DEBUGLIST_COUNT];
+ unsigned int size[DEBUGLIST_COUNT];
+ const char *file[DEBUGLIST_COUNT];
+ unsigned int line[DEBUGLIST_COUNT];
+ unsigned int count;
+};
+
+#define FLARG_PASS , file, line
+#define FLARG , const char *file, int line
+#else
+#define FLARG_PASS
+#define FLARG
+#endif
+
+typedef struct element element;
+struct element {
+ element * next;
+};
+
+typedef struct {
+ /*!
+ * This structure must be ALIGNMENT_SIZE bytes.
+ */
+ union {
+ size_t size;
+ isc_mem_t *ctx;
+ char bytes[ALIGNMENT_SIZE];
+ } u;
+} size_info;
+
+struct stats {
+ unsigned long gets;
+ unsigned long totalgets;
+ unsigned long blocks;
+ unsigned long freefrags;
+};
+
+#define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
+#define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
+
+#if ISC_MEM_TRACKLINES
+typedef ISC_LIST(debuglink_t) debuglist_t;
+#endif
+
+/* List of all active memory contexts. */
+
+static ISC_LIST(isc_mem_t) contexts;
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_mutex_t lock;
+
+struct isc_mem {
+ unsigned int magic;
+ isc_ondestroy_t ondestroy;
+ unsigned int flags;
+ isc_mutex_t lock;
+ isc_memalloc_t memalloc;
+ isc_memfree_t memfree;
+ void * arg;
+ size_t max_size;
+ isc_boolean_t checkfree;
+ struct stats * stats;
+ unsigned int references;
+ size_t quota;
+ size_t total;
+ size_t inuse;
+ size_t maxinuse;
+ size_t hi_water;
+ size_t lo_water;
+ isc_boolean_t hi_called;
+ isc_mem_water_t water;
+ void * water_arg;
+ ISC_LIST(isc_mempool_t) pools;
+
+ /* ISC_MEMFLAG_INTERNAL */
+ size_t mem_target;
+ element ** freelists;
+ element * basic_blocks;
+ unsigned char ** basic_table;
+ unsigned int basic_table_count;
+ unsigned int basic_table_size;
+ unsigned char * lowest;
+ unsigned char * highest;
+
+#if ISC_MEM_TRACKLINES
+ debuglist_t * debuglist;
+#endif
+
+ unsigned int memalloc_failures;
+ ISC_LINK(isc_mem_t) link;
+};
+
+#define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
+#define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
+
+struct isc_mempool {
+ /* always unlocked */
+ unsigned int magic; /*%< magic number */
+ isc_mutex_t *lock; /*%< optional lock */
+ isc_mem_t *mctx; /*%< our memory context */
+ /*%< locked via the memory context's lock */
+ ISC_LINK(isc_mempool_t) link; /*%< next pool in this mem context */
+ /*%< optionally locked from here down */
+ element *items; /*%< low water item list */
+ size_t size; /*%< size of each item on this pool */
+ unsigned int maxalloc; /*%< max number of items allowed */
+ unsigned int allocated; /*%< # of items currently given out */
+ unsigned int freecount; /*%< # of items on reserved list */
+ unsigned int freemax; /*%< # of items allowed on free list */
+ unsigned int fillcount; /*%< # of items to fetch on each fill */
+ /*%< Stats only. */
+ unsigned int gets; /*%< # of requests to this pool */
+ /*%< Debugging only. */
+#if ISC_MEMPOOL_NAMES
+ char name[16]; /*%< printed name in stats reports */
+#endif
+};
+
+/*
+ * Private Inline-able.
+ */
+
+#if ! ISC_MEM_TRACKLINES
+#define ADD_TRACE(a, b, c, d, e)
+#define DELETE_TRACE(a, b, c, d, e)
+#else
+#define ADD_TRACE(a, b, c, d, e) \
+ do { \
+ if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
+ ISC_MEM_DEBUGRECORD)) != 0 && \
+ b != NULL) \
+ add_trace_entry(a, b, c, d, e); \
+ } while (0)
+#define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
+
+static void
+print_active(isc_mem_t *ctx, FILE *out);
+
+/*!
+ * mctx must be locked.
+ */
+static inline void
+add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size
+ FLARG)
+{
+ debuglink_t *dl;
+ unsigned int i;
+
+ if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
+ fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_ADDTRACE,
+ "add %p size %u "
+ "file %s line %u mctx %p\n"),
+ ptr, size, file, line, mctx);
+
+ if (mctx->debuglist == NULL)
+ return;
+
+ if (size > mctx->max_size)
+ size = mctx->max_size;
+
+ dl = ISC_LIST_HEAD(mctx->debuglist[size]);
+ while (dl != NULL) {
+ if (dl->count == DEBUGLIST_COUNT)
+ goto next;
+ for (i = 0; i < DEBUGLIST_COUNT; i++) {
+ if (dl->ptr[i] == NULL) {
+ dl->ptr[i] = ptr;
+ dl->size[i] = size;
+ dl->file[i] = file;
+ dl->line[i] = line;
+ dl->count++;
+ return;
+ }
+ }
+ next:
+ dl = ISC_LIST_NEXT(dl, link);
+ }
+
+ dl = malloc(sizeof(debuglink_t));
+ INSIST(dl != NULL);
+
+ ISC_LINK_INIT(dl, link);
+ for (i = 1; i < DEBUGLIST_COUNT; i++) {
+ dl->ptr[i] = NULL;
+ dl->size[i] = 0;
+ dl->file[i] = NULL;
+ dl->line[i] = 0;
+ }
+
+ dl->ptr[0] = ptr;
+ dl->size[0] = size;
+ dl->file[0] = file;
+ dl->line[0] = line;
+ dl->count = 1;
+
+ ISC_LIST_PREPEND(mctx->debuglist[size], dl, link);
+}
+
+static inline void
+delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size,
+ const char *file, unsigned int line)
+{
+ debuglink_t *dl;
+ unsigned int i;
+
+ if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
+ fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_DELTRACE,
+ "del %p size %u "
+ "file %s line %u mctx %p\n"),
+ ptr, size, file, line, mctx);
+
+ if (mctx->debuglist == NULL)
+ return;
+
+ if (size > mctx->max_size)
+ size = mctx->max_size;
+
+ dl = ISC_LIST_HEAD(mctx->debuglist[size]);
+ while (dl != NULL) {
+ for (i = 0; i < DEBUGLIST_COUNT; i++) {
+ if (dl->ptr[i] == ptr) {
+ dl->ptr[i] = NULL;
+ dl->size[i] = 0;
+ dl->file[i] = NULL;
+ dl->line[i] = 0;
+
+ INSIST(dl->count > 0);
+ dl->count--;
+ if (dl->count == 0) {
+ ISC_LIST_UNLINK(mctx->debuglist[size],
+ dl, link);
+ free(dl);
+ }
+ return;
+ }
+ }
+ dl = ISC_LIST_NEXT(dl, link);
+ }
+
+ /*
+ * If we get here, we didn't find the item on the list. We're
+ * screwed.
+ */
+ INSIST(dl != NULL);
+}
+#endif /* ISC_MEM_TRACKLINES */
+
+static inline size_t
+rmsize(size_t size) {
+ /*
+ * round down to ALIGNMENT_SIZE
+ */
+ return (size & (~(ALIGNMENT_SIZE - 1)));
+}
+
+static inline size_t
+quantize(size_t size) {
+ /*!
+ * Round up the result in order to get a size big
+ * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
+ * byte boundaries.
+ */
+
+ if (size == 0U)
+ return (ALIGNMENT_SIZE);
+ return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
+}
+
+static inline isc_boolean_t
+more_basic_blocks(isc_mem_t *ctx) {
+ void *new;
+ unsigned char *curr, *next;
+ unsigned char *first, *last;
+ unsigned char **table;
+ unsigned int table_size;
+ size_t increment;
+ int i;
+
+ /* Require: we hold the context lock. */
+
+ /*
+ * Did we hit the quota for this context?
+ */
+ increment = NUM_BASIC_BLOCKS * ctx->mem_target;
+ if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
+ return (ISC_FALSE);
+
+ INSIST(ctx->basic_table_count <= ctx->basic_table_size);
+ if (ctx->basic_table_count == ctx->basic_table_size) {
+ table_size = ctx->basic_table_size + TABLE_INCREMENT;
+ table = (ctx->memalloc)(ctx->arg,
+ table_size * sizeof(unsigned char *));
+ if (table == NULL) {
+ ctx->memalloc_failures++;
+ return (ISC_FALSE);
+ }
+ if (ctx->basic_table_size != 0) {
+ memcpy(table, ctx->basic_table,
+ ctx->basic_table_size *
+ sizeof(unsigned char *));
+ (ctx->memfree)(ctx->arg, ctx->basic_table);
+ }
+ ctx->basic_table = table;
+ ctx->basic_table_size = table_size;
+ }
+
+ new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
+ if (new == NULL) {
+ ctx->memalloc_failures++;
+ return (ISC_FALSE);
+ }
+ ctx->total += increment;
+ ctx->basic_table[ctx->basic_table_count] = new;
+ ctx->basic_table_count++;
+
+ curr = new;
+ next = curr + ctx->mem_target;
+ for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
+ ((element *)curr)->next = (element *)next;
+ curr = next;
+ next += ctx->mem_target;
+ }
+ /*
+ * curr is now pointing at the last block in the
+ * array.
+ */
+ ((element *)curr)->next = NULL;
+ first = new;
+ last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
+ if (first < ctx->lowest || ctx->lowest == NULL)
+ ctx->lowest = first;
+ if (last > ctx->highest)
+ ctx->highest = last;
+ ctx->basic_blocks = new;
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+more_frags(isc_mem_t *ctx, size_t new_size) {
+ int i, frags;
+ size_t total_size;
+ void *new;
+ unsigned char *curr, *next;
+
+ /*!
+ * Try to get more fragments by chopping up a basic block.
+ */
+
+ if (ctx->basic_blocks == NULL) {
+ if (!more_basic_blocks(ctx)) {
+ /*
+ * We can't get more memory from the OS, or we've
+ * hit the quota for this context.
+ */
+ /*
+ * XXXRTH "At quota" notification here.
+ */
+ return (ISC_FALSE);
+ }
+ }
+
+ total_size = ctx->mem_target;
+ new = ctx->basic_blocks;
+ ctx->basic_blocks = ctx->basic_blocks->next;
+ frags = total_size / new_size;
+ ctx->stats[new_size].blocks++;
+ ctx->stats[new_size].freefrags += frags;
+ /*
+ * Set up a linked-list of blocks of size
+ * "new_size".
+ */
+ curr = new;
+ next = curr + new_size;
+ total_size -= new_size;
+ for (i = 0; i < (frags - 1); i++) {
+ ((element *)curr)->next = (element *)next;
+ curr = next;
+ next += new_size;
+ total_size -= new_size;
+ }
+ /*
+ * Add the remaining fragment of the basic block to a free list.
+ */
+ total_size = rmsize(total_size);
+ if (total_size > 0U) {
+ ((element *)next)->next = ctx->freelists[total_size];
+ ctx->freelists[total_size] = (element *)next;
+ ctx->stats[total_size].freefrags++;
+ }
+ /*
+ * curr is now pointing at the last block in the
+ * array.
+ */
+ ((element *)curr)->next = NULL;
+ ctx->freelists[new_size] = new;
+
+ return (ISC_TRUE);
+}
+
+static inline void *
+mem_getunlocked(isc_mem_t *ctx, size_t size) {
+ size_t new_size = quantize(size);
+ void *ret;
+
+ if (size >= ctx->max_size || new_size >= ctx->max_size) {
+ /*
+ * memget() was called on something beyond our upper limit.
+ */
+ if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
+ ret = NULL;
+ goto done;
+ }
+ ret = (ctx->memalloc)(ctx->arg, size);
+ if (ret == NULL) {
+ ctx->memalloc_failures++;
+ goto done;
+ }
+ ctx->total += size;
+ ctx->inuse += size;
+ ctx->stats[ctx->max_size].gets++;
+ ctx->stats[ctx->max_size].totalgets++;
+ /*
+ * If we don't set new_size to size, then the
+ * ISC_MEM_FILL code might write over bytes we
+ * don't own.
+ */
+ new_size = size;
+ goto done;
+ }
+
+ /*
+ * 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 (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
+ return (NULL);
+
+ /*
+ * The free list uses the "rounded-up" size "new_size".
+ */
+ ret = ctx->freelists[new_size];
+ ctx->freelists[new_size] = ctx->freelists[new_size]->next;
+
+ /*
+ * 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.
+ */
+ ctx->stats[size].gets++;
+ ctx->stats[size].totalgets++;
+ ctx->stats[new_size].freefrags--;
+ ctx->inuse += new_size;
+
+ done:
+
+#if ISC_MEM_FILL
+ if (ret != NULL)
+ memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
+#endif
+
+ return (ret);
+}
+
+#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
+static inline void
+check_overrun(void *mem, size_t size, size_t new_size) {
+ unsigned char *cp;
+
+ cp = (unsigned char *)mem;
+ cp += size;
+ while (size < new_size) {
+ INSIST(*cp == 0xbe);
+ cp++;
+ size++;
+ }
+}
+#endif
+
+static inline void
+mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) {
+ size_t new_size = quantize(size);
+
+ if (size == ctx->max_size || new_size >= ctx->max_size) {
+ /*
+ * memput() called on something beyond our upper limit.
+ */
+#if ISC_MEM_FILL
+ memset(mem, 0xde, size); /* Mnemonic for "dead". */
+#endif
+ (ctx->memfree)(ctx->arg, mem);
+ INSIST(ctx->stats[ctx->max_size].gets != 0U);
+ ctx->stats[ctx->max_size].gets--;
+ INSIST(size <= ctx->total);
+ ctx->inuse -= size;
+ ctx->total -= size;
+ return;
+ }
+
+#if ISC_MEM_FILL
+#if ISC_MEM_CHECKOVERRUN
+ check_overrun(mem, size, new_size);
+#endif
+ memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
+#endif
+
+ /*
+ * The free list uses the "rounded-up" size "new_size".
+ */
+ ((element *)mem)->next = ctx->freelists[new_size];
+ ctx->freelists[new_size] = (element *)mem;
+
+ /*
+ * 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(ctx->stats[size].gets != 0U);
+ ctx->stats[size].gets--;
+ ctx->stats[new_size].freefrags++;
+ ctx->inuse -= new_size;
+}
+
+/*!
+ * Perform a malloc, doing memory filling and overrun detection as necessary.
+ */
+static inline void *
+mem_get(isc_mem_t *ctx, size_t size) {
+ char *ret;
+
+#if ISC_MEM_CHECKOVERRUN
+ size += 1;
+#endif
+
+ ret = (ctx->memalloc)(ctx->arg, size);
+ if (ret == NULL)
+ ctx->memalloc_failures++;
+
+#if ISC_MEM_FILL
+ if (ret != NULL)
+ memset(ret, 0xbe, size); /* Mnemonic for "beef". */
+#else
+# if ISC_MEM_CHECKOVERRUN
+ if (ret != NULL)
+ ret[size-1] = 0xbe;
+# endif
+#endif
+
+ return (ret);
+}
+
+/*!
+ * Perform a free, doing memory filling and overrun detection as necessary.
+ */
+static inline void
+mem_put(isc_mem_t *ctx, void *mem, size_t size) {
+#if ISC_MEM_CHECKOVERRUN
+ INSIST(((unsigned char *)mem)[size] == 0xbe);
+#endif
+#if ISC_MEM_FILL
+ memset(mem, 0xde, size); /* Mnemonic for "dead". */
+#else
+ UNUSED(size);
+#endif
+ (ctx->memfree)(ctx->arg, mem);
+}
+
+/*!
+ * Update internal counters after a memory get.
+ */
+static inline void
+mem_getstats(isc_mem_t *ctx, size_t size) {
+ ctx->total += size;
+ ctx->inuse += size;
+
+ if (size > ctx->max_size) {
+ ctx->stats[ctx->max_size].gets++;
+ ctx->stats[ctx->max_size].totalgets++;
+ } else {
+ ctx->stats[size].gets++;
+ ctx->stats[size].totalgets++;
+ }
+}
+
+/*!
+ * Update internal counters after a memory put.
+ */
+static inline void
+mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) {
+ UNUSED(ptr);
+
+ INSIST(ctx->inuse >= size);
+ ctx->inuse -= size;
+
+ if (size > ctx->max_size) {
+ INSIST(ctx->stats[ctx->max_size].gets > 0U);
+ ctx->stats[ctx->max_size].gets--;
+ } else {
+ INSIST(ctx->stats[size].gets > 0U);
+ ctx->stats[size].gets--;
+ }
+}
+
+/*
+ * Private.
+ */
+
+static void *
+default_memalloc(void *arg, size_t size) {
+ UNUSED(arg);
+ if (size == 0U)
+ size = 1;
+ return (malloc(size));
+}
+
+static void
+default_memfree(void *arg, void *ptr) {
+ UNUSED(arg);
+ free(ptr);
+}
+
+static void
+initialize_action(void) {
+ RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
+ ISC_LIST_INIT(contexts);
+}
+
+/*
+ * Public.
+ */
+
+isc_result_t
+isc_mem_createx(size_t init_max_size, size_t target_size,
+ isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
+ isc_mem_t **ctxp)
+{
+ return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
+ arg, ctxp, ISC_MEMFLAG_DEFAULT));
+
+}
+
+isc_result_t
+isc_mem_createx2(size_t init_max_size, size_t target_size,
+ isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
+ isc_mem_t **ctxp, unsigned int flags)
+{
+ isc_mem_t *ctx;
+ isc_result_t result;
+
+ REQUIRE(ctxp != NULL && *ctxp == NULL);
+ REQUIRE(memalloc != NULL);
+ REQUIRE(memfree != NULL);
+
+ INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+ ctx = (memalloc)(arg, sizeof(*ctx));
+ if (ctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
+ result = isc_mutex_init(&ctx->lock);
+ if (result != ISC_R_SUCCESS) {
+ (memfree)(arg, ctx);
+ return (result);
+ }
+ }
+
+ if (init_max_size == 0U)
+ ctx->max_size = DEF_MAX_SIZE;
+ else
+ ctx->max_size = init_max_size;
+ ctx->flags = flags;
+ ctx->references = 1;
+ ctx->quota = 0;
+ ctx->total = 0;
+ ctx->inuse = 0;
+ ctx->maxinuse = 0;
+ ctx->hi_water = 0;
+ ctx->lo_water = 0;
+ ctx->hi_called = ISC_FALSE;
+ ctx->water = NULL;
+ ctx->water_arg = NULL;
+ ctx->magic = MEM_MAGIC;
+ isc_ondestroy_init(&ctx->ondestroy);
+ ctx->memalloc = memalloc;
+ ctx->memfree = memfree;
+ ctx->arg = arg;
+ ctx->stats = NULL;
+ ctx->checkfree = ISC_TRUE;
+#if ISC_MEM_TRACKLINES
+ ctx->debuglist = NULL;
+#endif
+ ISC_LIST_INIT(ctx->pools);
+ ctx->freelists = NULL;
+ ctx->basic_blocks = NULL;
+ ctx->basic_table = NULL;
+ ctx->basic_table_count = 0;
+ ctx->basic_table_size = 0;
+ ctx->lowest = NULL;
+ ctx->highest = NULL;
+
+ ctx->stats = (memalloc)(arg,
+ (ctx->max_size+1) * sizeof(struct stats));
+ if (ctx->stats == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto error;
+ }
+ memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
+
+ if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ if (target_size == 0U)
+ ctx->mem_target = DEF_MEM_TARGET;
+ else
+ ctx->mem_target = target_size;
+ ctx->freelists = (memalloc)(arg, ctx->max_size *
+ sizeof(element *));
+ if (ctx->freelists == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto error;
+ }
+ memset(ctx->freelists, 0,
+ ctx->max_size * sizeof(element *));
+ }
+
+#if ISC_MEM_TRACKLINES
+ if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
+ unsigned int i;
+
+ ctx->debuglist = (memalloc)(arg,
+ (ctx->max_size+1) * sizeof(debuglist_t));
+ if (ctx->debuglist == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto error;
+ }
+ for (i = 0; i <= ctx->max_size; i++)
+ ISC_LIST_INIT(ctx->debuglist[i]);
+ }
+#endif
+
+ ctx->memalloc_failures = 0;
+
+ LOCK(&lock);
+ ISC_LIST_INITANDAPPEND(contexts, ctx, link);
+ UNLOCK(&lock);
+
+ *ctxp = ctx;
+ return (ISC_R_SUCCESS);
+
+ error:
+ if (ctx != NULL) {
+ if (ctx->stats != NULL)
+ (memfree)(arg, ctx->stats);
+ if (ctx->freelists != NULL)
+ (memfree)(arg, ctx->freelists);
+#if ISC_MEM_TRACKLINES
+ if (ctx->debuglist != NULL)
+ (ctx->memfree)(ctx->arg, ctx->debuglist);
+#endif /* ISC_MEM_TRACKLINES */
+ if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
+ DESTROYLOCK(&ctx->lock);
+ (memfree)(arg, ctx);
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_mem_create(size_t init_max_size, size_t target_size,
+ isc_mem_t **ctxp)
+{
+ return (isc_mem_createx2(init_max_size, target_size,
+ default_memalloc, default_memfree, NULL,
+ ctxp, ISC_MEMFLAG_DEFAULT));
+}
+
+isc_result_t
+isc_mem_create2(size_t init_max_size, size_t target_size,
+ isc_mem_t **ctxp, unsigned int flags)
+{
+ return (isc_mem_createx2(init_max_size, target_size,
+ default_memalloc, default_memfree, NULL,
+ ctxp, flags));
+}
+
+static void
+destroy(isc_mem_t *ctx) {
+ unsigned int i;
+ isc_ondestroy_t ondest;
+
+ ctx->magic = 0;
+
+ LOCK(&lock);
+ ISC_LIST_UNLINK(contexts, ctx, link);
+ UNLOCK(&lock);
+
+ INSIST(ISC_LIST_EMPTY(ctx->pools));
+
+#if ISC_MEM_TRACKLINES
+ if (ctx->debuglist != NULL) {
+ if (ctx->checkfree) {
+ for (i = 0; i <= ctx->max_size; i++) {
+ if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
+ print_active(ctx, stderr);
+ INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
+ }
+ } else {
+ debuglink_t *dl;
+
+ for (i = 0; i <= ctx->max_size; i++)
+ for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
+ dl != NULL;
+ dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
+ ISC_LIST_UNLINK(ctx->debuglist[i],
+ dl, link);
+ free(dl);
+ }
+ }
+ (ctx->memfree)(ctx->arg, ctx->debuglist);
+ }
+#endif
+ INSIST(ctx->references == 0);
+
+ if (ctx->checkfree) {
+ for (i = 0; i <= ctx->max_size; i++) {
+#if ISC_MEM_TRACKLINES
+ if (ctx->stats[i].gets != 0U)
+ print_active(ctx, stderr);
+#endif
+ INSIST(ctx->stats[i].gets == 0U);
+ }
+ }
+
+ (ctx->memfree)(ctx->arg, ctx->stats);
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ for (i = 0; i < ctx->basic_table_count; i++)
+ (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
+ (ctx->memfree)(ctx->arg, ctx->freelists);
+ (ctx->memfree)(ctx->arg, ctx->basic_table);
+ }
+
+ ondest = ctx->ondestroy;
+
+ if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
+ DESTROYLOCK(&ctx->lock);
+ (ctx->memfree)(ctx->arg, ctx);
+
+ isc_ondestroy_notify(&ondest, ctx);
+}
+
+void
+isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
+ REQUIRE(VALID_CONTEXT(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ MCTXLOCK(source, &source->lock);
+ source->references++;
+ MCTXUNLOCK(source, &source->lock);
+
+ *targetp = source;
+}
+
+void
+isc_mem_detach(isc_mem_t **ctxp) {
+ isc_mem_t *ctx;
+ isc_boolean_t want_destroy = ISC_FALSE;
+
+ REQUIRE(ctxp != NULL);
+ ctx = *ctxp;
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ MCTXLOCK(ctx, &ctx->lock);
+ INSIST(ctx->references > 0);
+ ctx->references--;
+ if (ctx->references == 0)
+ want_destroy = ISC_TRUE;
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (want_destroy)
+ destroy(ctx);
+
+ *ctxp = NULL;
+}
+
+/*
+ * isc_mem_putanddetach() is the equivalent of:
+ *
+ * mctx = NULL;
+ * isc_mem_attach(ptr->mctx, &mctx);
+ * isc_mem_detach(&ptr->mctx);
+ * isc_mem_put(mctx, ptr, sizeof(*ptr);
+ * isc_mem_detach(&mctx);
+ */
+
+void
+isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
+ isc_mem_t *ctx;
+ isc_boolean_t want_destroy = ISC_FALSE;
+ size_info *si;
+ size_t oldsize;
+
+ REQUIRE(ctxp != NULL);
+ ctx = *ctxp;
+ REQUIRE(VALID_CONTEXT(ctx));
+ REQUIRE(ptr != NULL);
+
+ /*
+ * Must be before mem_putunlocked() as ctxp is usually within
+ * [ptr..ptr+size).
+ */
+ *ctxp = NULL;
+
+ if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
+ if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
+ si = &(((size_info *)ptr)[-1]);
+ oldsize = si->u.size - ALIGNMENT_SIZE;
+ if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
+ oldsize -= ALIGNMENT_SIZE;
+ INSIST(oldsize == size);
+ }
+ isc__mem_free(ctx, ptr FLARG_PASS);
+
+ MCTXLOCK(ctx, &ctx->lock);
+ ctx->references--;
+ if (ctx->references == 0)
+ want_destroy = ISC_TRUE;
+ MCTXUNLOCK(ctx, &ctx->lock);
+ if (want_destroy)
+ destroy(ctx);
+
+ return;
+ }
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ MCTXLOCK(ctx, &ctx->lock);
+ mem_putunlocked(ctx, ptr, size);
+ } else {
+ mem_put(ctx, ptr, size);
+ MCTXLOCK(ctx, &ctx->lock);
+ mem_putstats(ctx, ptr, size);
+ }
+
+ DELETE_TRACE(ctx, ptr, size, file, line);
+ INSIST(ctx->references > 0);
+ ctx->references--;
+ if (ctx->references == 0)
+ want_destroy = ISC_TRUE;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (want_destroy)
+ destroy(ctx);
+}
+
+void
+isc_mem_destroy(isc_mem_t **ctxp) {
+ isc_mem_t *ctx;
+
+ /*
+ * This routine provides legacy support for callers who use mctxs
+ * without attaching/detaching.
+ */
+
+ REQUIRE(ctxp != NULL);
+ ctx = *ctxp;
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ MCTXLOCK(ctx, &ctx->lock);
+#if ISC_MEM_TRACKLINES
+ if (ctx->references != 1)
+ print_active(ctx, stderr);
+#endif
+ REQUIRE(ctx->references == 1);
+ ctx->references--;
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ destroy(ctx);
+
+ *ctxp = NULL;
+}
+
+isc_result_t
+isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
+ isc_result_t res;
+
+ MCTXLOCK(ctx, &ctx->lock);
+ res = isc_ondestroy_register(&ctx->ondestroy, task, event);
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ return (res);
+}
+
+
+void *
+isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
+ void *ptr;
+ isc_boolean_t call_water = ISC_FALSE;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
+ return (isc__mem_allocate(ctx, size FLARG_PASS));
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ MCTXLOCK(ctx, &ctx->lock);
+ ptr = mem_getunlocked(ctx, size);
+ } else {
+ ptr = mem_get(ctx, size);
+ MCTXLOCK(ctx, &ctx->lock);
+ if (ptr != NULL)
+ mem_getstats(ctx, size);
+ }
+
+ ADD_TRACE(ctx, ptr, size, file, line);
+ if (ctx->hi_water != 0U && !ctx->hi_called &&
+ ctx->inuse > ctx->hi_water) {
+ ctx->hi_called = ISC_TRUE;
+ call_water = ISC_TRUE;
+ }
+ if (ctx->inuse > ctx->maxinuse) {
+ ctx->maxinuse = ctx->inuse;
+ if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
+ (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
+ fprintf(stderr, "maxinuse = %lu\n",
+ (unsigned long)ctx->inuse);
+ }
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (call_water)
+ (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
+
+ return (ptr);
+}
+
+void
+isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
+{
+ isc_boolean_t call_water = ISC_FALSE;
+ size_info *si;
+ size_t oldsize;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ REQUIRE(ptr != NULL);
+
+ if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
+ if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
+ si = &(((size_info *)ptr)[-1]);
+ oldsize = si->u.size - ALIGNMENT_SIZE;
+ if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
+ oldsize -= ALIGNMENT_SIZE;
+ INSIST(oldsize == size);
+ }
+ isc__mem_free(ctx, ptr FLARG_PASS);
+ return;
+ }
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ MCTXLOCK(ctx, &ctx->lock);
+ mem_putunlocked(ctx, ptr, size);
+ } else {
+ mem_put(ctx, ptr, size);
+ MCTXLOCK(ctx, &ctx->lock);
+ mem_putstats(ctx, ptr, size);
+ }
+
+ DELETE_TRACE(ctx, ptr, size, file, line);
+
+ /*
+ * The check against ctx->lo_water == 0 is for the condition
+ * when the context was pushed over hi_water but then had
+ * isc_mem_setwater() called with 0 for hi_water and lo_water.
+ */
+ if (ctx->hi_called &&
+ (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
+ ctx->hi_called = ISC_FALSE;
+
+ if (ctx->water != NULL)
+ call_water = ISC_TRUE;
+ }
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (call_water)
+ (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
+}
+
+#if ISC_MEM_TRACKLINES
+static void
+print_active(isc_mem_t *mctx, FILE *out) {
+ if (mctx->debuglist != NULL) {
+ debuglink_t *dl;
+ unsigned int i, j;
+ const char *format;
+ isc_boolean_t found;
+
+ fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_DUMPALLOC,
+ "Dump of all outstanding "
+ "memory allocations:\n"));
+ found = ISC_FALSE;
+ format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_PTRFILELINE,
+ "\tptr %p size %u file %s line %u\n");
+ for (i = 0; i <= mctx->max_size; i++) {
+ dl = ISC_LIST_HEAD(mctx->debuglist[i]);
+
+ if (dl != NULL)
+ found = ISC_TRUE;
+
+ while (dl != NULL) {
+ for (j = 0; j < DEBUGLIST_COUNT; j++)
+ if (dl->ptr[j] != NULL)
+ fprintf(out, format,
+ dl->ptr[j],
+ dl->size[j],
+ dl->file[j],
+ dl->line[j]);
+ dl = ISC_LIST_NEXT(dl, link);
+ }
+ }
+ if (!found)
+ fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_NONE, "\tNone.\n"));
+ }
+}
+#endif
+
+/*
+ * Print the stats[] on the stream "out" with suitable formatting.
+ */
+void
+isc_mem_stats(isc_mem_t *ctx, FILE *out) {
+ size_t i;
+ const struct stats *s;
+ const isc_mempool_t *pool;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ for (i = 0; i <= ctx->max_size; i++) {
+ s = &ctx->stats[i];
+
+ if (s->totalgets == 0U && s->gets == 0U)
+ continue;
+ fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
+ (i == ctx->max_size) ? ">=" : " ",
+ (unsigned long) i, s->totalgets, s->gets);
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
+ (s->blocks != 0U || s->freefrags != 0U))
+ fprintf(out, " (%lu bl, %lu ff)",
+ s->blocks, s->freefrags);
+ fputc('\n', out);
+ }
+
+ /*
+ * Note that since a pool can be locked now, these stats might be
+ * somewhat off if the pool is in active use at the time the stats
+ * are dumped. The link fields are protected by the isc_mem_t's
+ * lock, however, so walking this list and extracting integers from
+ * stats fields is always safe.
+ */
+ pool = ISC_LIST_HEAD(ctx->pools);
+ if (pool != NULL) {
+ fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLSTATS,
+ "[Pool statistics]\n"));
+ fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLNAME, "name"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLSIZE, "size"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLMAXALLOC, "maxalloc"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLALLOCATED, "allocated"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLFREECOUNT, "freecount"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLFREEMAX, "freemax"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLFILLCOUNT, "fillcount"),
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+ ISC_MSG_POOLGETS, "gets"),
+ "L");
+ }
+ while (pool != NULL) {
+ fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
+ pool->name, (unsigned long) pool->size, pool->maxalloc,
+ pool->allocated, pool->freecount, pool->freemax,
+ pool->fillcount, pool->gets,
+ (pool->lock == NULL ? "N" : "Y"));
+ pool = ISC_LIST_NEXT(pool, link);
+ }
+
+#if ISC_MEM_TRACKLINES
+ print_active(ctx, out);
+#endif
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+}
+
+/*
+ * Replacements for malloc() and free() -- they implicitly remember the
+ * size of the object allocated (with some additional overhead).
+ */
+
+static void *
+isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) {
+ size_info *si;
+
+ size += ALIGNMENT_SIZE;
+ if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
+ size += ALIGNMENT_SIZE;
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
+ si = mem_getunlocked(ctx, size);
+ else
+ si = mem_get(ctx, size);
+
+ if (si == NULL)
+ return (NULL);
+ if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
+ si->u.ctx = ctx;
+ si++;
+ }
+ si->u.size = size;
+ return (&si[1]);
+}
+
+void *
+isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
+ size_info *si;
+ isc_boolean_t call_water = ISC_FALSE;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ MCTXLOCK(ctx, &ctx->lock);
+ si = isc__mem_allocateunlocked(ctx, size);
+ } else {
+ si = isc__mem_allocateunlocked(ctx, size);
+ MCTXLOCK(ctx, &ctx->lock);
+ if (si != NULL)
+ mem_getstats(ctx, si[-1].u.size);
+ }
+
+#if ISC_MEM_TRACKLINES
+ ADD_TRACE(ctx, si, si[-1].u.size, file, line);
+#endif
+ if (ctx->hi_water != 0U && !ctx->hi_called &&
+ ctx->inuse > ctx->hi_water) {
+ ctx->hi_called = ISC_TRUE;
+ call_water = ISC_TRUE;
+ }
+ if (ctx->inuse > ctx->maxinuse) {
+ ctx->maxinuse = ctx->inuse;
+ if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
+ (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
+ fprintf(stderr, "maxinuse = %lu\n",
+ (unsigned long)ctx->inuse);
+ }
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (call_water)
+ (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
+
+ return (si);
+}
+
+void
+isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
+ size_info *si;
+ size_t size;
+ isc_boolean_t call_water= ISC_FALSE;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ REQUIRE(ptr != NULL);
+
+ if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
+ si = &(((size_info *)ptr)[-2]);
+ REQUIRE(si->u.ctx == ctx);
+ size = si[1].u.size;
+ } else {
+ si = &(((size_info *)ptr)[-1]);
+ size = si->u.size;
+ }
+
+ if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ MCTXLOCK(ctx, &ctx->lock);
+ mem_putunlocked(ctx, si, size);
+ } else {
+ mem_put(ctx, si, size);
+ MCTXLOCK(ctx, &ctx->lock);
+ mem_putstats(ctx, si, size);
+ }
+
+ DELETE_TRACE(ctx, ptr, size, file, line);
+
+ /*
+ * The check against ctx->lo_water == 0 is for the condition
+ * when the context was pushed over hi_water but then had
+ * isc_mem_setwater() called with 0 for hi_water and lo_water.
+ */
+ if (ctx->hi_called &&
+ (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
+ ctx->hi_called = ISC_FALSE;
+
+ if (ctx->water != NULL)
+ call_water = ISC_TRUE;
+ }
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (call_water)
+ (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
+}
+
+
+/*
+ * Other useful things.
+ */
+
+char *
+isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
+ size_t len;
+ char *ns;
+
+ REQUIRE(VALID_CONTEXT(mctx));
+ REQUIRE(s != NULL);
+
+ len = strlen(s);
+
+ ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS);
+
+ if (ns != NULL)
+ strncpy(ns, s, len + 1);
+
+ return (ns);
+}
+
+void
+isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ ctx->checkfree = flag;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+}
+
+/*
+ * Quotas
+ */
+
+void
+isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ ctx->quota = quota;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+}
+
+size_t
+isc_mem_getquota(isc_mem_t *ctx) {
+ size_t quota;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ quota = ctx->quota;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ return (quota);
+}
+
+size_t
+isc_mem_inuse(isc_mem_t *ctx) {
+ size_t inuse;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ MCTXLOCK(ctx, &ctx->lock);
+
+ inuse = ctx->inuse;
+
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ return (inuse);
+}
+
+void
+isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
+ size_t hiwater, size_t lowater)
+{
+ isc_boolean_t callwater = ISC_FALSE;
+ isc_mem_water_t oldwater;
+ void *oldwater_arg;
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ REQUIRE(hiwater >= lowater);
+
+ MCTXLOCK(ctx, &ctx->lock);
+ oldwater = ctx->water;
+ oldwater_arg = ctx->water_arg;
+ if (water == NULL) {
+ callwater = ctx->hi_called;
+ ctx->water = NULL;
+ ctx->water_arg = NULL;
+ ctx->hi_water = 0;
+ ctx->lo_water = 0;
+ ctx->hi_called = ISC_FALSE;
+ } else {
+ if (ctx->hi_called &&
+ (ctx->water != water || ctx->water_arg != water_arg ||
+ ctx->inuse < lowater || lowater == 0U))
+ callwater = ISC_TRUE;
+ ctx->water = water;
+ ctx->water_arg = water_arg;
+ ctx->hi_water = hiwater;
+ ctx->lo_water = lowater;
+ ctx->hi_called = ISC_FALSE;
+ }
+ MCTXUNLOCK(ctx, &ctx->lock);
+
+ if (callwater && oldwater != NULL)
+ (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
+}
+
+/*
+ * Memory pool stuff
+ */
+
+isc_result_t
+isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
+ isc_mempool_t *mpctx;
+
+ REQUIRE(VALID_CONTEXT(mctx));
+ REQUIRE(size > 0U);
+ REQUIRE(mpctxp != NULL && *mpctxp == NULL);
+
+ /*
+ * Allocate space for this pool, initialize values, and if all works
+ * well, attach to the memory context.
+ */
+ mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t));
+ if (mpctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ mpctx->magic = MEMPOOL_MAGIC;
+ mpctx->lock = NULL;
+ mpctx->mctx = mctx;
+ mpctx->size = size;
+ mpctx->maxalloc = UINT_MAX;
+ mpctx->allocated = 0;
+ mpctx->freecount = 0;
+ mpctx->freemax = 1;
+ mpctx->fillcount = 1;
+ mpctx->gets = 0;
+#if ISC_MEMPOOL_NAMES
+ mpctx->name[0] = 0;
+#endif
+ mpctx->items = NULL;
+
+ *mpctxp = mpctx;
+
+ MCTXLOCK(mctx, &mctx->lock);
+ ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
+ MCTXUNLOCK(mctx, &mctx->lock);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
+ REQUIRE(name != NULL);
+
+#if ISC_MEMPOOL_NAMES
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
+ mpctx->name[sizeof(mpctx->name) - 1] = '\0';
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+#else
+ UNUSED(mpctx);
+ UNUSED(name);
+#endif
+}
+
+void
+isc_mempool_destroy(isc_mempool_t **mpctxp) {
+ isc_mempool_t *mpctx;
+ isc_mem_t *mctx;
+ isc_mutex_t *lock;
+ element *item;
+
+ REQUIRE(mpctxp != NULL);
+ mpctx = *mpctxp;
+ REQUIRE(VALID_MEMPOOL(mpctx));
+#if ISC_MEMPOOL_NAMES
+ if (mpctx->allocated > 0)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_mempool_destroy(): mempool %s "
+ "leaked memory",
+ mpctx->name);
+#endif
+ REQUIRE(mpctx->allocated == 0);
+
+ mctx = mpctx->mctx;
+
+ lock = mpctx->lock;
+
+ if (lock != NULL)
+ LOCK(lock);
+
+ /*
+ * Return any items on the free list
+ */
+ MCTXLOCK(mctx, &mctx->lock);
+ while (mpctx->items != NULL) {
+ INSIST(mpctx->freecount > 0);
+ mpctx->freecount--;
+ item = mpctx->items;
+ mpctx->items = item->next;
+
+ if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ mem_putunlocked(mctx, item, mpctx->size);
+ } else {
+ mem_put(mctx, item, mpctx->size);
+ mem_putstats(mctx, item, mpctx->size);
+ }
+ }
+ MCTXUNLOCK(mctx, &mctx->lock);
+
+ /*
+ * Remove our linked list entry from the memory context.
+ */
+ MCTXLOCK(mctx, &mctx->lock);
+ ISC_LIST_UNLINK(mctx->pools, mpctx, link);
+ MCTXUNLOCK(mctx, &mctx->lock);
+
+ mpctx->magic = 0;
+
+ isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t));
+
+ if (lock != NULL)
+ UNLOCK(lock);
+
+ *mpctxp = NULL;
+}
+
+void
+isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
+ REQUIRE(VALID_MEMPOOL(mpctx));
+ REQUIRE(mpctx->lock == NULL);
+ REQUIRE(lock != NULL);
+
+ mpctx->lock = lock;
+}
+
+void *
+isc__mempool_get(isc_mempool_t *mpctx FLARG) {
+ element *item;
+ isc_mem_t *mctx;
+ unsigned int i;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ mctx = mpctx->mctx;
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ /*
+ * Don't let the caller go over quota
+ */
+ if (mpctx->allocated >= mpctx->maxalloc) {
+ item = NULL;
+ goto out;
+ }
+
+ /*
+ * if we have a free list item, return the first here
+ */
+ item = mpctx->items;
+ if (item != NULL) {
+ mpctx->items = item->next;
+ INSIST(mpctx->freecount > 0);
+ mpctx->freecount--;
+ mpctx->gets++;
+ mpctx->allocated++;
+ goto out;
+ }
+
+ /*
+ * We need to dip into the well. Lock the memory context here and
+ * fill up our free list.
+ */
+ MCTXLOCK(mctx, &mctx->lock);
+ for (i = 0; i < mpctx->fillcount; i++) {
+ if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ item = mem_getunlocked(mctx, mpctx->size);
+ } else {
+ item = mem_get(mctx, mpctx->size);
+ if (item != NULL)
+ mem_getstats(mctx, mpctx->size);
+ }
+ if (item == NULL)
+ break;
+ item->next = mpctx->items;
+ mpctx->items = item;
+ mpctx->freecount++;
+ }
+ MCTXUNLOCK(mctx, &mctx->lock);
+
+ /*
+ * If we didn't get any items, return NULL.
+ */
+ item = mpctx->items;
+ if (item == NULL)
+ goto out;
+
+ mpctx->items = item->next;
+ mpctx->freecount--;
+ mpctx->gets++;
+ mpctx->allocated++;
+
+ out:
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+#if ISC_MEM_TRACKLINES
+ if (item != NULL) {
+ MCTXLOCK(mctx, &mctx->lock);
+ ADD_TRACE(mctx, item, mpctx->size, file, line);
+ MCTXUNLOCK(mctx, &mctx->lock);
+ }
+#endif /* ISC_MEM_TRACKLINES */
+
+ return (item);
+}
+
+void
+isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
+ isc_mem_t *mctx;
+ element *item;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+ REQUIRE(mem != NULL);
+
+ mctx = mpctx->mctx;
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ INSIST(mpctx->allocated > 0);
+ mpctx->allocated--;
+
+#if ISC_MEM_TRACKLINES
+ MCTXLOCK(mctx, &mctx->lock);
+ DELETE_TRACE(mctx, mem, mpctx->size, file, line);
+ MCTXUNLOCK(mctx, &mctx->lock);
+#endif /* ISC_MEM_TRACKLINES */
+
+ /*
+ * If our free list is full, return this to the mctx directly.
+ */
+ if (mpctx->freecount >= mpctx->freemax) {
+ if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+ MCTXLOCK(mctx, &mctx->lock);
+ mem_putunlocked(mctx, mem, mpctx->size);
+ MCTXUNLOCK(mctx, &mctx->lock);
+ } else {
+ mem_put(mctx, mem, mpctx->size);
+ MCTXLOCK(mctx, &mctx->lock);
+ mem_putstats(mctx, mem, mpctx->size);
+ MCTXUNLOCK(mctx, &mctx->lock);
+ }
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+ return;
+ }
+
+ /*
+ * Otherwise, attach it to our free list and bump the counter.
+ */
+ mpctx->freecount++;
+ item = (element *)mem;
+ item->next = mpctx->items;
+ mpctx->items = item;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+}
+
+/*
+ * Quotas
+ */
+
+void
+isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ mpctx->freemax = limit;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+}
+
+unsigned int
+isc_mempool_getfreemax(isc_mempool_t *mpctx) {
+ unsigned int freemax;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ freemax = mpctx->freemax;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+ return (freemax);
+}
+
+unsigned int
+isc_mempool_getfreecount(isc_mempool_t *mpctx) {
+ unsigned int freecount;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ freecount = mpctx->freecount;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+ return (freecount);
+}
+
+void
+isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
+ REQUIRE(limit > 0);
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ mpctx->maxalloc = limit;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+}
+
+unsigned int
+isc_mempool_getmaxalloc(isc_mempool_t *mpctx) {
+ unsigned int maxalloc;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ maxalloc = mpctx->maxalloc;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+ return (maxalloc);
+}
+
+unsigned int
+isc_mempool_getallocated(isc_mempool_t *mpctx) {
+ unsigned int allocated;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ allocated = mpctx->allocated;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+ return (allocated);
+}
+
+void
+isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
+ REQUIRE(limit > 0);
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ mpctx->fillcount = limit;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+}
+
+unsigned int
+isc_mempool_getfillcount(isc_mempool_t *mpctx) {
+ unsigned int fillcount;
+
+ REQUIRE(VALID_MEMPOOL(mpctx));
+
+ if (mpctx->lock != NULL)
+ LOCK(mpctx->lock);
+
+ fillcount = mpctx->fillcount;
+
+ if (mpctx->lock != NULL)
+ UNLOCK(mpctx->lock);
+
+ return (fillcount);
+}
+
+void
+isc_mem_printactive(isc_mem_t *ctx, FILE *file) {
+
+ REQUIRE(VALID_CONTEXT(ctx));
+ REQUIRE(file != NULL);
+
+#if !ISC_MEM_TRACKLINES
+ UNUSED(ctx);
+ UNUSED(file);
+#else
+ print_active(ctx, file);
+#endif
+}
+
+void
+isc_mem_printallactive(FILE *file) {
+#if !ISC_MEM_TRACKLINES
+ UNUSED(file);
+#else
+ isc_mem_t *ctx;
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+ LOCK(&lock);
+ for (ctx = ISC_LIST_HEAD(contexts);
+ ctx != NULL;
+ ctx = ISC_LIST_NEXT(ctx, link)) {
+ fprintf(file, "context: %p\n", ctx);
+ print_active(ctx, file);
+ }
+ UNLOCK(&lock);
+#endif
+}
+
+void
+isc_mem_checkdestroyed(FILE *file) {
+
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+ LOCK(&lock);
+ if (!ISC_LIST_EMPTY(contexts)) {
+#if ISC_MEM_TRACKLINES
+ isc_mem_t *ctx;
+
+ for (ctx = ISC_LIST_HEAD(contexts);
+ ctx != NULL;
+ ctx = ISC_LIST_NEXT(ctx, link)) {
+ fprintf(file, "context: %p\n", ctx);
+ print_active(ctx, file);
+ }
+ fflush(file);
+#endif
+ INSIST(0);
+ }
+ UNLOCK(&lock);
+}
diff --git a/lib/isc/mips/Makefile.in b/lib/isc/mips/Makefile.in
new file mode 100644
index 0000000..c8e77e4
--- /dev/null
+++ b/lib/isc/mips/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/mips/include/Makefile.in b/lib/isc/mips/include/Makefile.in
new file mode 100644
index 0000000..f4dd2f6
--- /dev/null
+++ b/lib/isc/mips/include/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/mips/include/isc/Makefile.in b/lib/isc/mips/include/isc/Makefile.in
new file mode 100644
index 0000000..6760ce6
--- /dev/null
+++ b/lib/isc/mips/include/isc/Makefile.in
@@ -0,0 +1,36 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc ; \
+ done
diff --git a/lib/isc/mips/include/isc/atomic.h b/lib/isc/mips/include/isc/atomic.h
new file mode 100644
index 0000000..368a6ef
--- /dev/null
+++ b/lib/isc/mips/include/isc/atomic.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.1.2.1 2005/07/09 07:14:00 jinmei Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ */
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, int val) {
+ isc_int32_t orig;
+
+ /* add is a cheat, since MIPS has no mov instruction */
+ __asm__ volatile (
+ "1:"
+ "ll $3, %1\n"
+ "add %0, $0, $3\n"
+ "add $3, $3, %2\n"
+ "sc $3, %1\n"
+ "beq $3, 0, 1b"
+ : "=&r"(orig)
+ : "m"(*p), "r"(val)
+ : "memory", "$3"
+ );
+
+ return (orig);
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+ __asm__ volatile (
+ "1:"
+ "ll $3, %0\n"
+ "add $3, $0, %1\n"
+ "sc $3, %0\n"
+ "beq $3, 0, 1b"
+ :
+ : "m"(*p), "r"(val)
+ : "memory", "$3"
+ );
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, int cmpval, int val) {
+ isc_int32_t orig;
+
+ __asm__ volatile(
+ "1:"
+ "ll $3, %1\n"
+ "add %0, $0, $3\n"
+ "bne $3, %2, 2f\n"
+ "add $3, $0, %3\n"
+ "sc $3, %1\n"
+ "beq $3, 0, 1b\n"
+ "2:"
+ : "=&r"(orig)
+ : "m"(*p), "r"(cmpval), "r"(val)
+ : "memory", "$3"
+ );
+
+ return (orig);
+}
+
+#else /* !ISC_PLATFORM_USEGCCASM */
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/mutexblock.c b/lib/isc/mutexblock.c
new file mode 100644
index 0000000..d8a82cc
--- /dev/null
+++ b/lib/isc/mutexblock.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004, 2005 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: mutexblock.c,v 1.16.18.2 2005/04/29 00:16:47 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mutexblock.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_mutexblock_init(isc_mutex_t *block, unsigned int count) {
+ isc_result_t result;
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ result = isc_mutex_init(&block[i]);
+ if (result != ISC_R_SUCCESS) {
+ i--;
+ while (i > 0) {
+ DESTROYLOCK(&block[i]);
+ i--;
+ }
+ return (result);
+ }
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_mutexblock_destroy(isc_mutex_t *block, unsigned int count) {
+ isc_result_t result;
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ result = isc_mutex_destroy(&block[i]);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/netaddr.c b/lib/isc/netaddr.c
new file mode 100644
index 0000000..e56e05b
--- /dev/null
+++ b/lib/isc/netaddr.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2004, 2005 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: netaddr.c,v 1.27.18.8 2005/04/27 05:02:03 sra Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <isc/buffer.h>
+#include <isc/msgs.h>
+#include <isc/net.h>
+#include <isc/netaddr.h>
+#include <isc/print.h>
+#include <isc/sockaddr.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+isc_boolean_t
+isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
+ REQUIRE(a != NULL && b != NULL);
+
+ if (a->family != b->family)
+ return (ISC_FALSE);
+
+ if (a->zone != b->zone)
+ return (ISC_FALSE);
+
+ switch (a->family) {
+ case AF_INET:
+ if (a->type.in.s_addr != b->type.in.s_addr)
+ return (ISC_FALSE);
+ break;
+ case AF_INET6:
+ if (memcmp(&a->type.in6, &b->type.in6,
+ sizeof(a->type.in6)) != 0 ||
+ a->zone != b->zone)
+ return (ISC_FALSE);
+ break;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ case AF_UNIX:
+ if (strcmp(a->type.un, b->type.un) != 0)
+ return (ISC_FALSE);
+ break;
+#endif
+ default:
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+isc_boolean_t
+isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
+ unsigned int prefixlen)
+{
+ const unsigned char *pa, *pb;
+ unsigned int ipabytes; /* Length of whole IP address in bytes */
+ unsigned int nbytes; /* Number of significant whole bytes */
+ unsigned int nbits; /* Number of significant leftover bits */
+
+ REQUIRE(a != NULL && b != NULL);
+
+ if (a->family != b->family)
+ return (ISC_FALSE);
+
+ if (a->zone != b->zone)
+ return (ISC_FALSE);
+
+ switch (a->family) {
+ case AF_INET:
+ pa = (const unsigned char *) &a->type.in;
+ pb = (const unsigned char *) &b->type.in;
+ ipabytes = 4;
+ break;
+ case AF_INET6:
+ pa = (const unsigned char *) &a->type.in6;
+ pb = (const unsigned char *) &b->type.in6;
+ ipabytes = 16;
+ break;
+ default:
+ pa = pb = NULL; /* Avoid silly compiler warning. */
+ ipabytes = 0; /* Ditto. */
+ return (ISC_FALSE);
+ }
+
+ /*
+ * Don't crash if we get a pattern like 10.0.0.1/9999999.
+ */
+ if (prefixlen > ipabytes * 8)
+ prefixlen = ipabytes * 8;
+
+ nbytes = prefixlen / 8;
+ nbits = prefixlen % 8;
+
+ if (nbytes > 0) {
+ if (memcmp(pa, pb, nbytes) != 0)
+ return (ISC_FALSE);
+ }
+ if (nbits > 0) {
+ unsigned int bytea, byteb, mask;
+ INSIST(nbytes < ipabytes);
+ INSIST(nbits < 8);
+ bytea = pa[nbytes];
+ byteb = pb[nbytes];
+ mask = (0xFF << (8-nbits)) & 0xFF;
+ if ((bytea & mask) != (byteb & mask))
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+isc_result_t
+isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) {
+ char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
+ char zbuf[sizeof("%4294967295")];
+ unsigned int alen;
+ int zlen;
+ const char *r;
+ const void *type;
+
+ REQUIRE(netaddr != NULL);
+
+ switch (netaddr->family) {
+ case AF_INET:
+ type = &netaddr->type.in;
+ break;
+ case AF_INET6:
+ type = &netaddr->type.in6;
+ break;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ case AF_UNIX:
+ alen = strlen(netaddr->type.un);
+ if (alen > isc_buffer_availablelength(target))
+ return (ISC_R_NOSPACE);
+ isc_buffer_putmem(target,
+ (const unsigned char *)(netaddr->type.un),
+ alen);
+ return (ISC_R_SUCCESS);
+#endif
+ default:
+ return (ISC_R_FAILURE);
+ }
+ r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf));
+ if (r == NULL)
+ return (ISC_R_FAILURE);
+
+ alen = strlen(abuf);
+ INSIST(alen < sizeof(abuf));
+
+ zlen = 0;
+ if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
+ zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
+ if (zlen < 0)
+ return (ISC_R_FAILURE);
+ INSIST((unsigned int)zlen < sizeof(zbuf));
+ }
+
+ if (alen + zlen > isc_buffer_availablelength(target))
+ return (ISC_R_NOSPACE);
+
+ isc_buffer_putmem(target, (unsigned char *)abuf, alen);
+ isc_buffer_putmem(target, (unsigned char *)zbuf, zlen);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
+ isc_result_t result;
+ isc_buffer_t buf;
+
+ isc_buffer_init(&buf, array, size);
+ result = isc_netaddr_totext(na, &buf);
+
+ /*
+ * Null terminate.
+ */
+ if (result == ISC_R_SUCCESS) {
+ if (isc_buffer_availablelength(&buf) >= 1)
+ isc_buffer_putuint8(&buf, 0);
+ else
+ result = ISC_R_NOSPACE;
+ }
+
+ if (result != ISC_R_SUCCESS) {
+ snprintf(array, size,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
+ ISC_MSG_UNKNOWNADDR,
+ "<unknown address, family %u>"),
+ na->family);
+ array[size - 1] = '\0';
+ }
+}
+
+
+isc_result_t
+isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
+ static const unsigned char zeros[16];
+ unsigned int nbits, nbytes, ipbytes;
+ const unsigned char *p;
+
+ switch (na->family) {
+ case AF_INET:
+ p = (const unsigned char *) &na->type.in;
+ ipbytes = 4;
+ if (prefixlen > 32)
+ return (ISC_R_RANGE);
+ break;
+ case AF_INET6:
+ p = (const unsigned char *) &na->type.in6;
+ ipbytes = 16;
+ if (prefixlen > 128)
+ return (ISC_R_RANGE);
+ break;
+ default:
+ ipbytes = 0;
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+ nbytes = prefixlen / 8;
+ nbits = prefixlen % 8;
+ if (nbits != 0) {
+ if ((p[nbytes] & (0xff>>nbits)) != 0U)
+ return (ISC_R_FAILURE);
+ nbytes++;
+ }
+ if (memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0)
+ return (ISC_R_FAILURE);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
+ unsigned int nbits, nbytes, ipbytes, i;
+ const unsigned char *p;
+
+ switch (s->family) {
+ case AF_INET:
+ p = (const unsigned char *) &s->type.in;
+ ipbytes = 4;
+ break;
+ case AF_INET6:
+ p = (const unsigned char *) &s->type.in6;
+ ipbytes = 16;
+ break;
+ default:
+ ipbytes = 0;
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+ nbytes = nbits = 0;
+ for (i = 0; i < ipbytes; i++) {
+ if (p[i] != 0xFF)
+ break;
+ }
+ nbytes = i;
+ if (i < ipbytes) {
+ unsigned int c = p[nbytes];
+ while ((c & 0x80) != 0 && nbits < 8) {
+ c <<= 1; nbits++;
+ }
+ if ((c & 0xFF) != 0)
+ return (ISC_R_MASKNONCONTIG);
+ i++;
+ }
+ for (; i < ipbytes; i++) {
+ if (p[i] != 0)
+ return (ISC_R_MASKNONCONTIG);
+ i++;
+ }
+ *lenp = nbytes * 8 + nbits;
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) {
+ memset(netaddr, 0, sizeof(*netaddr));
+ netaddr->family = AF_INET;
+ netaddr->type.in = *ina;
+}
+
+void
+isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
+ memset(netaddr, 0, sizeof(*netaddr));
+ netaddr->family = AF_INET6;
+ netaddr->type.in6 = *ina6;
+}
+
+isc_result_t
+isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) {
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ if (strlen(path) > sizeof(netaddr->type.un) - 1)
+ return (ISC_R_NOSPACE);
+
+ memset(netaddr, 0, sizeof(*netaddr));
+ netaddr->family = AF_UNIX;
+ strcpy(netaddr->type.un, path);
+ netaddr->zone = 0;
+ return (ISC_R_SUCCESS);
+#else
+ UNUSED(netaddr);
+ UNUSED(path);
+ return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+
+void
+isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) {
+ /* we currently only support AF_INET6. */
+ REQUIRE(netaddr->family == AF_INET6);
+
+ netaddr->zone = zone;
+}
+
+isc_uint32_t
+isc_netaddr_getzone(const isc_netaddr_t *netaddr) {
+ return (netaddr->zone);
+}
+
+void
+isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
+ int family = s->type.sa.sa_family;
+ t->family = family;
+ switch (family) {
+ case AF_INET:
+ t->type.in = s->type.sin.sin_addr;
+ t->zone = 0;
+ break;
+ case AF_INET6:
+ memcpy(&t->type.in6, &s->type.sin6.sin6_addr, 16);
+#ifdef ISC_PLATFORM_HAVESCOPEID
+ t->zone = s->type.sin6.sin6_scope_id;
+#else
+ t->zone = 0;
+#endif
+ break;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ case AF_UNIX:
+ memcpy(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un));
+ t->zone = 0;
+ break;
+#endif
+ default:
+ INSIST(0);
+ }
+}
+
+void
+isc_netaddr_any(isc_netaddr_t *netaddr) {
+ memset(netaddr, 0, sizeof(*netaddr));
+ netaddr->family = AF_INET;
+ netaddr->type.in.s_addr = INADDR_ANY;
+}
+
+void
+isc_netaddr_any6(isc_netaddr_t *netaddr) {
+ memset(netaddr, 0, sizeof(*netaddr));
+ netaddr->family = AF_INET6;
+ netaddr->type.in6 = in6addr_any;
+}
+
+isc_boolean_t
+isc_netaddr_ismulticast(isc_netaddr_t *na) {
+ switch (na->family) {
+ case AF_INET:
+ return (ISC_TF(ISC_IPADDR_ISMULTICAST(na->type.in.s_addr)));
+ case AF_INET6:
+ return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na->type.in6)));
+ default:
+ return (ISC_FALSE); /* XXXMLG ? */
+ }
+}
+
+isc_boolean_t
+isc_netaddr_isexperimental(isc_netaddr_t *na) {
+ switch (na->family) {
+ case AF_INET:
+ return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr)));
+ default:
+ return (ISC_FALSE); /* XXXMLG ? */
+ }
+}
+
+isc_boolean_t
+isc_netaddr_islinklocal(isc_netaddr_t *na) {
+ switch (na->family) {
+ case AF_INET:
+ return (ISC_FALSE);
+ case AF_INET6:
+ return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na->type.in6)));
+ default:
+ return (ISC_FALSE);
+ }
+}
+
+isc_boolean_t
+isc_netaddr_issitelocal(isc_netaddr_t *na) {
+ switch (na->family) {
+ case AF_INET:
+ return (ISC_FALSE);
+ case AF_INET6:
+ return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na->type.in6)));
+ default:
+ return (ISC_FALSE);
+ }
+}
+
+void
+isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
+ isc_netaddr_t *src;
+
+ DE_CONST(s, src); /* Must come before IN6_IS_ADDR_V4MAPPED. */
+
+ REQUIRE(s->family == AF_INET6);
+ REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6));
+
+ memset(t, 0, sizeof(*t));
+ t->family = AF_INET;
+ memcpy(&t->type.in, (char *)&src->type.in6 + 12, 4);
+ return;
+}
diff --git a/lib/isc/netscope.c b/lib/isc/netscope.c
new file mode 100644
index 0000000..75827d2
--- /dev/null
+++ b/lib/isc/netscope.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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.
+ */
+
+/*! \file */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] =
+ "$Id: netscope.c,v 1.7.18.4 2006/08/25 05:25:51 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <isc/string.h>
+#include <isc/net.h>
+#include <isc/netscope.h>
+#include <isc/result.h>
+
+isc_result_t
+isc_netscope_pton(int af, char *scopename, void *addr, isc_uint32_t *zoneid) {
+ char *ep;
+#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
+ unsigned int ifid;
+#endif
+ struct in6_addr *in6;
+ isc_uint32_t zone;
+ isc_uint64_t llz;
+
+ /* at this moment, we only support AF_INET6 */
+ if (af != AF_INET6)
+ return (ISC_R_FAILURE);
+
+ in6 = (struct in6_addr *)addr;
+
+ /*
+ * Basically, "names" are more stable than numeric IDs in terms of
+ * renumbering, and are more preferred. However, since there is no
+ * standard naming convention and APIs to deal with the names. Thus,
+ * we only handle the case of link-local addresses, for which we use
+ * interface names as link names, assuming one to one mapping between
+ * interfaces and links.
+ */
+#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
+ if (IN6_IS_ADDR_LINKLOCAL(in6) &&
+ (ifid = if_nametoindex((const char *)scopename)) != 0)
+ zone = (isc_uint32_t)ifid;
+ else {
+#endif
+ llz = isc_string_touint64(scopename, &ep, 10);
+ if (ep == scopename)
+ return (ISC_R_FAILURE);
+
+ /* check overflow */
+ zone = (isc_uint32_t)(llz & 0xffffffffUL);
+ if (zone != llz)
+ return (ISC_R_FAILURE);
+#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
+ }
+#endif
+
+ *zoneid = zone;
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/nls/Makefile.in b/lib/isc/nls/Makefile.in
new file mode 100644
index 0000000..8211d9b
--- /dev/null
+++ b/lib/isc/nls/Makefile.in
@@ -0,0 +1,37 @@
+# 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: Makefile.in,v 1.12 2004/03/05 05:11:05 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+CINCLUDES = -I../unix/include \
+ -I${srcdir}/../unix/include \
+ -I../include \
+ -I${srcdir}/../include
+
+CDEFINES =
+CWARNINGS =
+
+OBJS = msgcat.@O@
+
+SRCS = msgcat.c
+
+SUBDIRS =
+TARGETS = ${OBJS}
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/nls/msgcat.c b/lib/isc/nls/msgcat.c
new file mode 100644
index 0000000..ae56de7
--- /dev/null
+++ b/lib/isc/nls/msgcat.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2004, 2005 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: msgcat.c,v 1.13.18.3 2005/06/08 02:07:57 marka Exp $ */
+
+/*! \file msgcat.c
+ *
+ * \author Principal Author: Bob Halley
+ */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <isc/magic.h>
+#include <isc/msgcat.h>
+#include <isc/util.h>
+
+#ifdef HAVE_CATGETS
+#include <nl_types.h> /* Required for nl_catd. */
+#endif
+
+/*
+ * Implementation Notes:
+ *
+ * We use malloc() and free() instead of isc_mem_get() and isc_mem_put()
+ * because we don't want to require a memory context to be specified
+ * in order to use a message catalog.
+ */
+
+struct isc_msgcat {
+ unsigned int magic;
+#ifdef HAVE_CATGETS
+ nl_catd catalog;
+#endif
+};
+
+#define MSGCAT_MAGIC ISC_MAGIC('M', 'C', 'a', 't')
+#define VALID_MSGCAT(m) ISC_MAGIC_VALID(m, MSGCAT_MAGIC)
+
+void
+isc_msgcat_open(const char *name, isc_msgcat_t **msgcatp) {
+ isc_msgcat_t *msgcat;
+
+ /*
+ * Open a message catalog.
+ */
+
+ REQUIRE(name != NULL);
+ REQUIRE(msgcatp != NULL && *msgcatp == NULL);
+
+ msgcat = malloc(sizeof(*msgcat));
+ if (msgcat == NULL) {
+ *msgcatp = NULL;
+ return;
+ }
+
+#ifdef HAVE_CATGETS
+ /*
+ * We don't check if catopen() fails because we don't care.
+ * If it does fail, then when we call catgets(), it will use
+ * the default string.
+ */
+ msgcat->catalog = catopen(name, 0);
+#endif
+ msgcat->magic = MSGCAT_MAGIC;
+
+ *msgcatp = msgcat;
+}
+
+void
+isc_msgcat_close(isc_msgcat_t **msgcatp) {
+ isc_msgcat_t *msgcat;
+
+ /*
+ * Close a message catalog.
+ */
+
+ REQUIRE(msgcatp != NULL);
+ msgcat = *msgcatp;
+ REQUIRE(VALID_MSGCAT(msgcat) || msgcat == NULL);
+
+ if (msgcat != NULL) {
+#ifdef HAVE_CATGETS
+ if (msgcat->catalog != (nl_catd)(-1))
+ (void)catclose(msgcat->catalog);
+#endif
+ msgcat->magic = 0;
+ free(msgcat);
+ }
+
+ *msgcatp = NULL;
+}
+
+const char *
+isc_msgcat_get(isc_msgcat_t *msgcat, int set, int message,
+ const char *default_text)
+{
+ /*
+ * Get message 'message' from message set 'set' in 'msgcat'. If it
+ * is not available, use 'default'.
+ */
+
+ REQUIRE(VALID_MSGCAT(msgcat) || msgcat == NULL);
+ REQUIRE(set > 0);
+ REQUIRE(message > 0);
+ REQUIRE(default_text != NULL);
+
+#ifdef HAVE_CATGETS
+ if (msgcat == NULL)
+ return (default_text);
+ return (catgets(msgcat->catalog, set, message, default_text));
+#else
+ return (default_text);
+#endif
+}
diff --git a/lib/isc/noatomic/Makefile.in b/lib/isc/noatomic/Makefile.in
new file mode 100644
index 0000000..c8e77e4
--- /dev/null
+++ b/lib/isc/noatomic/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/noatomic/include/Makefile.in b/lib/isc/noatomic/include/Makefile.in
new file mode 100644
index 0000000..f4dd2f6
--- /dev/null
+++ b/lib/isc/noatomic/include/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/noatomic/include/isc/Makefile.in b/lib/isc/noatomic/include/isc/Makefile.in
new file mode 100644
index 0000000..6760ce6
--- /dev/null
+++ b/lib/isc/noatomic/include/isc/Makefile.in
@@ -0,0 +1,36 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc ; \
+ done
diff --git a/lib/isc/noatomic/include/isc/atomic.h b/lib/isc/noatomic/include/isc/atomic.h
new file mode 100644
index 0000000..1c7035f
--- /dev/null
+++ b/lib/isc/noatomic/include/isc/atomic.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.2.2.1 2005/06/04 06:23:44 jinmei Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+/* This file is inherently empty. */
+
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/nothreads/Makefile.in b/lib/isc/nothreads/Makefile.in
new file mode 100644
index 0000000..c9e8637
--- /dev/null
+++ b/lib/isc/nothreads/Makefile.in
@@ -0,0 +1,38 @@
+# 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: Makefile.in,v 1.5 2004/03/05 05:11:08 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+CINCLUDES = -I${srcdir}/include \
+ -I${srcdir}/../unix/include \
+ -I../include \
+ -I${srcdir}/../include \
+ -I${srcdir}/..
+
+CDEFINES =
+CWARNINGS =
+
+OBJS = condition.@O@ mutex.@O@ thread.@O@
+
+SRCS = condition.c mutex.c thread.c
+
+SUBDIRS = include
+TARGETS = ${OBJS}
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/nothreads/condition.c b/lib/isc/nothreads/condition.c
new file mode 100644
index 0000000..329fbc8
--- /dev/null
+++ b/lib/isc/nothreads/condition.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2004, 2006 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: condition.c,v 1.6.18.2 2006/08/25 05:25:51 marka Exp $ */
+
+#include <config.h>
+
+#include <isc/util.h>
+
+EMPTY_TRANSLATION_UNIT
diff --git a/lib/isc/nothreads/include/Makefile.in b/lib/isc/nothreads/include/Makefile.in
new file mode 100644
index 0000000..ecfc329
--- /dev/null
+++ b/lib/isc/nothreads/include/Makefile.in
@@ -0,0 +1,25 @@
+# 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: Makefile.in,v 1.3 2004/03/05 05:11:11 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/nothreads/include/isc/Makefile.in b/lib/isc/nothreads/include/isc/Makefile.in
new file mode 100644
index 0000000..f6482fb
--- /dev/null
+++ b/lib/isc/nothreads/include/isc/Makefile.in
@@ -0,0 +1,37 @@
+# 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: Makefile.in,v 1.5 2004/03/05 05:11:13 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = condition.h mutex.h once.h thread.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc ; \
+ done
diff --git a/lib/isc/nothreads/include/isc/condition.h b/lib/isc/nothreads/include/isc/condition.h
new file mode 100644
index 0000000..39889b1
--- /dev/null
+++ b/lib/isc/nothreads/include/isc/condition.h
@@ -0,0 +1,59 @@
+/*
+ * 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: condition.h,v 1.4 2004/03/05 05:11:13 marka Exp $ */
+
+/*
+ * This provides a limited subset of the isc_condition_t
+ * functionality for use by single-threaded programs that
+ * need to block waiting for events. Only a single
+ * call to isc_condition_wait() may be blocked at any given
+ * time, and the _waituntil and _broadcast functions are not
+ * supported. This is intended primarily for use by the omapi
+ * library, and may go away once omapi goes away. Use for
+ * other purposes is strongly discouraged.
+ */
+
+#ifndef ISC_CONDITION_H
+#define ISC_CONDITION_H 1
+
+#include <isc/mutex.h>
+
+typedef int isc_condition_t;
+
+isc_result_t isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp);
+isc_result_t isc__nothread_signal_hack(isc_condition_t *cp);
+
+#define isc_condition_init(cp) \
+ (*(cp) = 0, ISC_R_SUCCESS)
+
+#define isc_condition_wait(cp, mp) \
+ isc__nothread_wait_hack(cp, mp)
+
+#define isc_condition_waituntil(cp, mp, tp) \
+ ((void)(cp), (void)(mp), (void)(tp), ISC_R_NOTIMPLEMENTED)
+
+#define isc_condition_signal(cp) \
+ isc__nothread_signal_hack(cp)
+
+#define isc_condition_broadcast(cp) \
+ ((void)(cp), ISC_R_NOTIMPLEMENTED)
+
+#define isc_condition_destroy(cp) \
+ (*(cp) == 0 ? (*(cp) = -1, ISC_R_SUCCESS) : ISC_R_UNEXPECTED)
+
+#endif /* ISC_CONDITION_H */
diff --git a/lib/isc/nothreads/include/isc/mutex.h b/lib/isc/nothreads/include/isc/mutex.h
new file mode 100644
index 0000000..a586435
--- /dev/null
+++ b/lib/isc/nothreads/include/isc/mutex.h
@@ -0,0 +1,39 @@
+/*
+ * 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: mutex.h,v 1.4 2004/03/05 05:11:13 marka Exp $ */
+
+#ifndef ISC_MUTEX_H
+#define ISC_MUTEX_H 1
+
+#include <isc/result.h> /* for ISC_R_ codes */
+
+typedef int isc_mutex_t;
+
+#define isc_mutex_init(mp) \
+ (*(mp) = 0, ISC_R_SUCCESS)
+#define isc_mutex_lock(mp) \
+ ((*(mp))++ == 0 ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#define isc_mutex_unlock(mp) \
+ (--(*(mp)) == 0 ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#define isc_mutex_trylock(mp) \
+ (*(mp) == 0 ? ((*(mp))++, ISC_R_SUCCESS) : ISC_R_LOCKBUSY)
+#define isc_mutex_destroy(mp) \
+ (*(mp) == 0 ? (*(mp) = -1, ISC_R_SUCCESS) : ISC_R_UNEXPECTED)
+#define isc_mutex_stats(fp)
+
+#endif /* ISC_MUTEX_H */
diff --git a/lib/isc/nothreads/include/isc/once.h b/lib/isc/nothreads/include/isc/once.h
new file mode 100644
index 0000000..470120a
--- /dev/null
+++ b/lib/isc/nothreads/include/isc/once.h
@@ -0,0 +1,32 @@
+/*
+ * 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: once.h,v 1.4 2004/03/05 05:11:13 marka Exp $ */
+
+#ifndef ISC_ONCE_H
+#define ISC_ONCE_H 1
+
+#include <isc/result.h>
+
+typedef isc_boolean_t isc_once_t;
+
+#define ISC_ONCE_INIT ISC_FALSE
+
+#define isc_once_do(op, f) \
+ (!*(op) ? (f(), *(op) = ISC_TRUE, ISC_R_SUCCESS) : ISC_R_SUCCESS)
+
+#endif /* ISC_ONCE_H */
diff --git a/lib/isc/nothreads/include/isc/thread.h b/lib/isc/nothreads/include/isc/thread.h
new file mode 100644
index 0000000..6c85913
--- /dev/null
+++ b/lib/isc/nothreads/include/isc/thread.h
@@ -0,0 +1,35 @@
+/*
+ * 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: thread.h,v 1.4 2004/03/05 05:11:13 marka Exp $ */
+
+#ifndef ISC_THREAD_H
+#define ISC_THREAD_H 1
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_thread_setconcurrency(unsigned int level);
+
+#define isc_thread_self() ((unsigned long)0)
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_THREAD_H */
diff --git a/lib/isc/nothreads/mutex.c b/lib/isc/nothreads/mutex.c
new file mode 100644
index 0000000..0048d87
--- /dev/null
+++ b/lib/isc/nothreads/mutex.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2004, 2006 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: mutex.c,v 1.6.18.2 2006/08/25 05:25:51 marka Exp $ */
+
+#include <config.h>
+
+#include <isc/util.h>
+
+EMPTY_TRANSLATION_UNIT
+
diff --git a/lib/isc/nothreads/thread.c b/lib/isc/nothreads/thread.c
new file mode 100644
index 0000000..0f20927
--- /dev/null
+++ b/lib/isc/nothreads/thread.c
@@ -0,0 +1,28 @@
+/*
+ * 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: thread.c,v 1.3 2004/03/05 05:11:09 marka Exp $ */
+
+#include <config.h>
+
+#include <isc/thread.h>
+#include <isc/util.h>
+
+void
+isc_thread_setconcurrency(unsigned int level) {
+ UNUSED(level);
+}
diff --git a/lib/isc/ondestroy.c b/lib/isc/ondestroy.c
new file mode 100644
index 0000000..2cd9687
--- /dev/null
+++ b/lib/isc/ondestroy.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2004, 2005 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: ondestroy.c,v 1.12.18.2 2005/04/29 00:16:48 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/event.h>
+#include <isc/magic.h>
+#include <isc/ondestroy.h>
+#include <isc/task.h>
+#include <isc/util.h>
+
+#define ONDESTROY_MAGIC ISC_MAGIC('D', 'e', 'S', 't')
+#define VALID_ONDESTROY(s) ISC_MAGIC_VALID(s, ONDESTROY_MAGIC)
+
+void
+isc_ondestroy_init(isc_ondestroy_t *ondest) {
+ ondest->magic = ONDESTROY_MAGIC;
+ ISC_LIST_INIT(ondest->events);
+}
+
+isc_result_t
+isc_ondestroy_register(isc_ondestroy_t *ondest, isc_task_t *task,
+ isc_event_t **eventp)
+{
+ isc_event_t *theevent;
+ isc_task_t *thetask = NULL;
+
+ REQUIRE(VALID_ONDESTROY(ondest));
+ REQUIRE(task != NULL);
+ REQUIRE(eventp != NULL);
+
+ theevent = *eventp;
+
+ REQUIRE(theevent != NULL);
+
+ isc_task_attach(task, &thetask);
+
+ theevent->ev_sender = thetask;
+
+ ISC_LIST_APPEND(ondest->events, theevent, ev_link);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_ondestroy_notify(isc_ondestroy_t *ondest, void *sender) {
+ isc_event_t *eventp;
+ isc_task_t *task;
+
+ REQUIRE(VALID_ONDESTROY(ondest));
+
+ eventp = ISC_LIST_HEAD(ondest->events);
+ while (eventp != NULL) {
+ ISC_LIST_UNLINK(ondest->events, eventp, ev_link);
+
+ task = eventp->ev_sender;
+ eventp->ev_sender = sender;
+
+ isc_task_sendanddetach(&task, &eventp);
+
+ eventp = ISC_LIST_HEAD(ondest->events);
+ }
+}
+
+
diff --git a/lib/isc/parseint.c b/lib/isc/parseint.c
new file mode 100644
index 0000000..0696344
--- /dev/null
+++ b/lib/isc/parseint.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2004, 2005 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: parseint.c,v 1.4.18.2 2005/04/29 00:16:48 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <isc/parseint.h>
+#include <isc/result.h>
+#include <isc/stdlib.h>
+
+isc_result_t
+isc_parse_uint32(isc_uint32_t *uip, const char *string, int base) {
+ unsigned long n;
+ char *e;
+ if (! isalnum((unsigned char)(string[0])))
+ return (ISC_R_BADNUMBER);
+ errno = 0;
+ n = strtoul(string, &e, base);
+ if (*e != '\0')
+ return (ISC_R_BADNUMBER);
+ if (n == ULONG_MAX && errno == ERANGE)
+ return (ISC_R_RANGE);
+ *uip = n;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_parse_uint16(isc_uint16_t *uip, const char *string, int base) {
+ isc_uint32_t val;
+ isc_result_t result;
+ result = isc_parse_uint32(&val, string, base);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (val > 0xFFFF)
+ return (ISC_R_RANGE);
+ *uip = (isc_uint16_t) val;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_parse_uint8(isc_uint8_t *uip, const char *string, int base) {
+ isc_uint32_t val;
+ isc_result_t result;
+ result = isc_parse_uint32(&val, string, base);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (val > 0xFF)
+ return (ISC_R_RANGE);
+ *uip = (isc_uint8_t) val;
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/powerpc/Makefile.in b/lib/isc/powerpc/Makefile.in
new file mode 100644
index 0000000..c8e77e4
--- /dev/null
+++ b/lib/isc/powerpc/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/powerpc/include/Makefile.in b/lib/isc/powerpc/include/Makefile.in
new file mode 100644
index 0000000..f4dd2f6
--- /dev/null
+++ b/lib/isc/powerpc/include/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/powerpc/include/isc/Makefile.in b/lib/isc/powerpc/include/isc/Makefile.in
new file mode 100644
index 0000000..6760ce6
--- /dev/null
+++ b/lib/isc/powerpc/include/isc/Makefile.in
@@ -0,0 +1,36 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc ; \
+ done
diff --git a/lib/isc/powerpc/include/isc/atomic.h b/lib/isc/powerpc/include/isc/atomic.h
new file mode 100644
index 0000000..30db328
--- /dev/null
+++ b/lib/isc/powerpc/include/isc/atomic.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.1.6.6 2007/08/28 07:20:06 tbox Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+/*!\file
+ * static inline isc_int32_t
+ * isc_atomic_xadd(isc_int32_t *p, isc_int32_t val);
+ *
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ *
+ * static inline void
+ * isc_atomic_store(void *p, isc_int32_t val);
+ *
+ * This routine atomically stores the value 'val' in 'p'.
+ *
+ * static inline isc_int32_t
+ * isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val);
+ *
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+
+#if defined(_AIX)
+
+#include <sys/atomic_op.h>
+
+#define isc_atomic_xadd(p, v) fetch_and_add(p, v)
+#define isc_atomic_store(p, v) _clear_lock(p, v)
+
+#ifdef __GNUC__
+static inline int
+#else
+static int
+#endif
+isc_atomic_cmpxchg(atomic_p p, int old, int new) {
+ int orig = old;
+
+#ifdef __GNUC__
+ asm("ics");
+#else
+ __isync();
+#endif
+ if (compare_and_swap(p, &orig, new))
+ return (old);
+ return (orig);
+}
+
+#elif defined(ISC_PLATFORM_USEGCCASM) || defined(ISC_PLATFORM_USEMACASM)
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+ isc_int32_t orig;
+
+ __asm__ volatile (
+#ifdef ISC_PLATFORM_USEMACASM
+ "1:"
+ "lwarx r6, 0, %1\n"
+ "mr %0, r6\n"
+ "add r6, r6, %2\n"
+ "stwcx. r6, 0, %1\n"
+ "bne- 1b"
+#else
+ "1:"
+ "lwarx 6, 0, %1\n"
+ "mr %0, 6\n"
+ "add 6, 6, %2\n"
+ "stwcx. 6, 0, %1\n"
+ "bne- 1b"
+#endif
+ : "=&r"(orig)
+ : "r"(p), "r"(val)
+ : "r6", "memory"
+ );
+
+ return (orig);
+}
+
+static inline void
+isc_atomic_store(void *p, isc_int32_t val) {
+ __asm__ volatile (
+#ifdef ISC_PLATFORM_USEMACASM
+ "1:"
+ "lwarx r6, 0, %0\n"
+ "lwz r6, %1\n"
+ "stwcx. r6, 0, %0\n"
+ "bne- 1b"
+#else
+ "1:"
+ "lwarx 6, 0, %0\n"
+ "lwz 6, %1\n"
+ "stwcx. 6, 0, %0\n"
+ "bne- 1b"
+#endif
+ :
+ : "r"(p), "m"(val)
+ : "r6", "memory"
+ );
+}
+
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+ isc_int32_t orig;
+
+ __asm__ volatile (
+#ifdef ISC_PLATFORM_USEMACASM
+ "1:"
+ "lwarx r6, 0, %1\n"
+ "mr %0,r6\n"
+ "cmpw r6, %2\n"
+ "bne 2f\n"
+ "mr r6, %3\n"
+ "stwcx. r6, 0, %1\n"
+ "bne- 1b\n"
+ "2:"
+#else
+ "1:"
+ "lwarx 6, 0, %1\n"
+ "mr %0,6\n"
+ "cmpw 6, %2\n"
+ "bne 2f\n"
+ "mr 6, %3\n"
+ "stwcx. 6, 0, %1\n"
+ "bne- 1b\n"
+ "2:"
+#endif
+ : "=&r" (orig)
+ : "r"(p), "r"(cmpval), "r"(val)
+ : "r6", "memory"
+ );
+
+ return (orig);
+}
+
+#else
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/print.c b/lib/isc/print.c
new file mode 100644
index 0000000..59c528b
--- /dev/null
+++ b/lib/isc/print.c
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) 2004-2006 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: print.c,v 1.27.18.3 2006/04/17 18:27:33 explorer Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdio.h> /* for sprintf() */
+#include <string.h> /* for strlen() */
+
+#define ISC__PRINT_SOURCE /* Used to get the isc_print_* prototypes. */
+
+#include <isc/assertions.h>
+#include <isc/int.h>
+#include <isc/msgs.h>
+#include <isc/print.h>
+#include <isc/stdlib.h>
+#include <isc/util.h>
+
+int
+isc_print_sprintf(char *str, const char *format, ...) {
+ va_list ap;
+
+ va_start(ap, format);
+ vsprintf(str, format, ap);
+ va_end(ap);
+ return (strlen(str));
+}
+
+/*!
+ * Return length of string that would have been written if not truncated.
+ */
+
+int
+isc_print_snprintf(char *str, size_t size, const char *format, ...) {
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return (ret);
+
+}
+
+/*!
+ * Return length of string that would have been written if not truncated.
+ */
+
+int
+isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
+ int h;
+ int l;
+ int q;
+ int alt;
+ int zero;
+ int left;
+ int plus;
+ int space;
+ int neg;
+ isc_int64_t tmpi;
+ isc_uint64_t tmpui;
+ unsigned long width;
+ unsigned long precision;
+ unsigned int length;
+ char buf[1024];
+ char c;
+ void *v;
+ char *save = str;
+ const char *cp;
+ const char *head;
+ int count = 0;
+ int pad;
+ int zeropad;
+ int dot;
+ double dbl;
+#ifdef HAVE_LONG_DOUBLE
+ long double ldbl;
+#endif
+ char fmt[32];
+
+ INSIST(str != NULL);
+ INSIST(format != NULL);
+
+ while (*format != '\0') {
+ if (*format != '%') {
+ if (size > 1) {
+ *str++ = *format;
+ size--;
+ }
+ count++;
+ format++;
+ continue;
+ }
+ format++;
+
+ /*
+ * Reset flags.
+ */
+ dot = neg = space = plus = left = zero = alt = h = l = q = 0;
+ width = precision = 0;
+ head = "";
+ length = pad = zeropad = 0;
+
+ do {
+ if (*format == '#') {
+ alt = 1;
+ format++;
+ } else if (*format == '-') {
+ left = 1;
+ zero = 0;
+ format++;
+ } else if (*format == ' ') {
+ if (!plus)
+ space = 1;
+ format++;
+ } else if (*format == '+') {
+ plus = 1;
+ space = 0;
+ format++;
+ } else if (*format == '0') {
+ if (!left)
+ zero = 1;
+ format++;
+ } else
+ break;
+ } while (1);
+
+ /*
+ * Width.
+ */
+ if (*format == '*') {
+ width = va_arg(ap, int);
+ format++;
+ } else if (isdigit((unsigned char)*format)) {
+ char *e;
+ width = strtoul(format, &e, 10);
+ format = e;
+ }
+
+ /*
+ * Precision.
+ */
+ if (*format == '.') {
+ format++;
+ dot = 1;
+ if (*format == '*') {
+ precision = va_arg(ap, int);
+ format++;
+ } else if (isdigit((unsigned char)*format)) {
+ char *e;
+ precision = strtoul(format, &e, 10);
+ format = e;
+ }
+ }
+
+ switch (*format) {
+ case '\0':
+ continue;
+ case '%':
+ if (size > 1) {
+ *str++ = *format;
+ size--;
+ }
+ count++;
+ break;
+ case 'q':
+ q = 1;
+ format++;
+ goto doint;
+ case 'h':
+ h = 1;
+ format++;
+ goto doint;
+ case 'l':
+ l = 1;
+ format++;
+ if (*format == 'l') {
+ q = 1;
+ format++;
+ }
+ goto doint;
+ case 'n':
+ case 'i':
+ case 'd':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ doint:
+ if (precision != 0)
+ zero = 0;
+ switch (*format) {
+ case 'n':
+ if (h) {
+ short int *p;
+ p = va_arg(ap, short *);
+ REQUIRE(p != NULL);
+ *p = str - save;
+ } else if (l) {
+ long int *p;
+ p = va_arg(ap, long *);
+ REQUIRE(p != NULL);
+ *p = str - save;
+ } else {
+ int *p;
+ p = va_arg(ap, int *);
+ REQUIRE(p != NULL);
+ *p = str - save;
+ }
+ break;
+ case 'i':
+ case 'd':
+ if (q)
+ tmpi = va_arg(ap, isc_int64_t);
+ else if (l)
+ tmpi = va_arg(ap, long int);
+ else
+ tmpi = va_arg(ap, int);
+ if (tmpi < 0) {
+ head = "-";
+ tmpui = -tmpi;
+ } else {
+ if (plus)
+ head = "+";
+ else if (space)
+ head = " ";
+ else
+ head = "";
+ tmpui = tmpi;
+ }
+ sprintf(buf, "%" ISC_PRINT_QUADFORMAT "u",
+ tmpui);
+ goto printint;
+ case 'o':
+ if (q)
+ tmpui = va_arg(ap, isc_uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, long int);
+ else
+ tmpui = va_arg(ap, int);
+ sprintf(buf,
+ alt ? "%#" ISC_PRINT_QUADFORMAT "o"
+ : "%" ISC_PRINT_QUADFORMAT "o",
+ tmpui);
+ goto printint;
+ case 'u':
+ if (q)
+ tmpui = va_arg(ap, isc_uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ sprintf(buf, "%" ISC_PRINT_QUADFORMAT "u",
+ tmpui);
+ goto printint;
+ case 'x':
+ if (q)
+ tmpui = va_arg(ap, isc_uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ if (alt) {
+ head = "0x";
+ if (precision > 2)
+ precision -= 2;
+ }
+ sprintf(buf, "%" ISC_PRINT_QUADFORMAT "x",
+ tmpui);
+ goto printint;
+ case 'X':
+ if (q)
+ tmpui = va_arg(ap, isc_uint64_t);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ if (alt) {
+ head = "0X";
+ if (precision > 2)
+ precision -= 2;
+ }
+ sprintf(buf, "%" ISC_PRINT_QUADFORMAT "X",
+ tmpui);
+ goto printint;
+ printint:
+ if (precision != 0 || width != 0) {
+ length = strlen(buf);
+ if (length < precision)
+ zeropad = precision - length;
+ else if (length < width && zero)
+ zeropad = width - length;
+ if (width != 0) {
+ pad = width - length -
+ zeropad - strlen(head);
+ if (pad < 0)
+ pad = 0;
+ }
+ }
+ count += strlen(head) + strlen(buf) + pad +
+ zeropad;
+ if (!left) {
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ }
+ cp = head;
+ while (*cp != '\0' && size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (zeropad > 0 && size > 1) {
+ *str++ = '0';
+ size--;
+ zeropad--;
+ }
+ cp = buf;
+ while (*cp != '\0' && size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case 's':
+ cp = va_arg(ap, char *);
+ REQUIRE(cp != NULL);
+
+ if (precision != 0) {
+ /*
+ * cp need not be NULL terminated.
+ */
+ const char *tp;
+ unsigned long n;
+
+ n = precision;
+ tp = cp;
+ while (n != 0 && *tp != '\0')
+ n--, tp++;
+ length = precision - n;
+ } else {
+ length = strlen(cp);
+ }
+ if (width != 0) {
+ pad = width - length;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += pad + length;
+ if (!left)
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ if (precision != 0)
+ while (precision > 0 && *cp != '\0' &&
+ size > 1) {
+ *str++ = *cp++;
+ size--;
+ precision--;
+ }
+ else
+ while (*cp != '\0' && size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ case 'c':
+ c = va_arg(ap, int);
+ if (width > 0) {
+ count += width;
+ width--;
+ if (left) {
+ *str++ = c;
+ size--;
+ }
+ while (width-- > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ }
+ if (!left && size > 1) {
+ *str++ = c;
+ size--;
+ }
+ } else {
+ count++;
+ if (size > 1) {
+ *str++ = c;
+ size--;
+ }
+ }
+ break;
+ case 'p':
+ v = va_arg(ap, void *);
+ sprintf(buf, "%p", v);
+ length = strlen(buf);
+ if (precision > length)
+ zeropad = precision - length;
+ if (width > 0) {
+ pad = width - length - zeropad;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += length + pad + zeropad;
+ if (!left)
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ cp = buf;
+ if (zeropad > 0 && buf[0] == '0' &&
+ (buf[1] == 'x' || buf[1] == 'X')) {
+ if (size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ if (size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (zeropad > 0 && size > 1) {
+ *str++ = '0';
+ size--;
+ zeropad--;
+ }
+ }
+ while (*cp != '\0' && size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ case 'D': /*deprecated*/
+ INSIST("use %ld instead of %D" == NULL);
+ case 'O': /*deprecated*/
+ INSIST("use %lo instead of %O" == NULL);
+ case 'U': /*deprecated*/
+ INSIST("use %lu instead of %U" == NULL);
+
+ case 'L':
+#ifdef HAVE_LONG_DOUBLE
+ l = 1;
+#else
+ INSIST("long doubles are not supported" == NULL);
+#endif
+ /*FALLTHROUGH*/
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (!dot)
+ precision = 6;
+ /*
+ * IEEE floating point.
+ * MIN 2.2250738585072014E-308
+ * MAX 1.7976931348623157E+308
+ * VAX floating point has a smaller range than IEEE.
+ *
+ * precisions > 324 don't make much sense.
+ * if we cap the precision at 512 we will not
+ * overflow buf.
+ */
+ if (precision > 512)
+ precision = 512;
+ sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
+ plus ? "+" : space ? " " : "",
+ precision, l ? "L" : "", *format);
+ switch (*format) {
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+#ifdef HAVE_LONG_DOUBLE
+ if (l) {
+ ldbl = va_arg(ap, long double);
+ sprintf(buf, fmt, ldbl);
+ } else
+#endif
+ {
+ dbl = va_arg(ap, double);
+ sprintf(buf, fmt, dbl);
+ }
+ length = strlen(buf);
+ if (width > 0) {
+ pad = width - length;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += length + pad;
+ if (!left)
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ cp = buf;
+ while (*cp != ' ' && size > 1) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ format++;
+ }
+ if (size > 0)
+ *str = '\0';
+ return (count);
+}
diff --git a/lib/isc/pthreads/Makefile.in b/lib/isc/pthreads/Makefile.in
new file mode 100644
index 0000000..b9cc906
--- /dev/null
+++ b/lib/isc/pthreads/Makefile.in
@@ -0,0 +1,38 @@
+# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-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: Makefile.in,v 1.17 2004/03/05 05:11:16 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+CINCLUDES = -I${srcdir}/include \
+ -I${srcdir}/../unix/include \
+ -I../include \
+ -I${srcdir}/../include \
+ -I${srcdir}/..
+
+CDEFINES =
+CWARNINGS =
+
+OBJS = condition.@O@ mutex.@O@ thread.@O@
+
+SRCS = condition.c mutex.c thread.c
+
+SUBDIRS = include
+TARGETS = ${OBJS}
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/pthreads/condition.c b/lib/isc/pthreads/condition.c
new file mode 100644
index 0000000..b9c26c6
--- /dev/null
+++ b/lib/isc/pthreads/condition.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: condition.c,v 1.32.18.2 2005/04/29 00:17:05 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+
+#include <isc/condition.h>
+#include <isc/msgs.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *c, isc_mutex_t *m, isc_time_t *t) {
+ int presult;
+ isc_result_t result;
+ struct timespec ts;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(c != NULL && m != NULL && t != NULL);
+
+ /*
+ * POSIX defines a timespec's tv_sec as time_t.
+ */
+ result = isc_time_secondsastimet(t, &ts.tv_sec);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*!
+ * POSIX defines a timespec's tv_nsec as long. isc_time_nanoseconds
+ * ensures its return value is < 1 billion, which will fit in a long.
+ */
+ ts.tv_nsec = (long)isc_time_nanoseconds(t);
+
+ do {
+#if ISC_MUTEX_PROFILE
+ presult = pthread_cond_timedwait(c, &m->mutex, &ts);
+#else
+ presult = pthread_cond_timedwait(c, m, &ts);
+#endif
+ if (presult == 0)
+ return (ISC_R_SUCCESS);
+ if (presult == ETIMEDOUT)
+ return (ISC_R_TIMEDOUT);
+ } while (presult == EINTR);
+
+ isc__strerror(presult, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "pthread_cond_timedwait() %s %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_RETURNED, "returned"),
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+}
diff --git a/lib/isc/pthreads/include/Makefile.in b/lib/isc/pthreads/include/Makefile.in
new file mode 100644
index 0000000..b1164b6
--- /dev/null
+++ b/lib/isc/pthreads/include/Makefile.in
@@ -0,0 +1,25 @@
+# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-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: Makefile.in,v 1.12 2004/03/05 05:11:19 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/pthreads/include/isc/Makefile.in b/lib/isc/pthreads/include/isc/Makefile.in
new file mode 100644
index 0000000..2e11f6c
--- /dev/null
+++ b/lib/isc/pthreads/include/isc/Makefile.in
@@ -0,0 +1,37 @@
+# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-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: Makefile.in,v 1.14 2004/03/05 05:11:40 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = condition.h mutex.h once.h thread.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc ; \
+ done
diff --git a/lib/isc/pthreads/include/isc/condition.h b/lib/isc/pthreads/include/isc/condition.h
new file mode 100644
index 0000000..f7cea75
--- /dev/null
+++ b/lib/isc/pthreads/include/isc/condition.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: condition.h,v 1.22.18.2 2005/04/29 00:17:05 marka Exp $ */
+
+#ifndef ISC_CONDITION_H
+#define ISC_CONDITION_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/result.h>
+#include <isc/types.h>
+
+typedef pthread_cond_t isc_condition_t;
+
+#define isc_condition_init(cp) \
+ ((pthread_cond_init((cp), NULL) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#if ISC_MUTEX_PROFILE
+#define isc_condition_wait(cp, mp) \
+ ((pthread_cond_wait((cp), &((mp)->mutex)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#else
+#define isc_condition_wait(cp, mp) \
+ ((pthread_cond_wait((cp), (mp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#define isc_condition_signal(cp) \
+ ((pthread_cond_signal((cp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_condition_broadcast(cp) \
+ ((pthread_cond_broadcast((cp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_condition_destroy(cp) \
+ ((pthread_cond_destroy((cp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *, isc_mutex_t *, isc_time_t *);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_CONDITION_H */
diff --git a/lib/isc/pthreads/include/isc/mutex.h b/lib/isc/pthreads/include/isc/mutex.h
new file mode 100644
index 0000000..edafaf6
--- /dev/null
+++ b/lib/isc/pthreads/include/isc/mutex.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: mutex.h,v 1.25.18.3 2005/07/12 01:22:33 marka Exp $ */
+
+#ifndef ISC_MUTEX_H
+#define ISC_MUTEX_H 1
+
+/*! \file */
+
+#include <pthread.h>
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/result.h> /* for ISC_R_ codes */
+
+ISC_LANG_BEGINDECLS
+
+/*!
+ * Supply mutex attributes that enable deadlock detection
+ * (helpful when debugging). This is system dependent and
+ * currently only supported on NetBSD.
+ */
+#if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK)
+extern pthread_mutexattr_t isc__mutex_attrs;
+#define ISC__MUTEX_ATTRS &isc__mutex_attrs
+#else
+#define ISC__MUTEX_ATTRS NULL
+#endif
+
+/* XXX We could do fancier error handling... */
+
+/*!
+ * Define ISC_MUTEX_PROFILE to turn on profiling of mutexes by line. When
+ * enabled, isc_mutex_stats() can be used to print a table showing the
+ * number of times each type of mutex was locked and the amount of time
+ * waiting to obtain the lock.
+ */
+#ifndef ISC_MUTEX_PROFILE
+#define ISC_MUTEX_PROFILE 0
+#endif
+
+#if ISC_MUTEX_PROFILE
+typedef struct isc_mutexstats isc_mutexstats_t;
+
+typedef struct {
+ pthread_mutex_t mutex; /*%< The actual mutex. */
+ isc_mutexstats_t * stats; /*%< Mutex statistics. */
+} isc_mutex_t;
+#else
+typedef pthread_mutex_t isc_mutex_t;
+#endif
+
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_init(mp) \
+ isc_mutex_init_profile((mp), __FILE__, __LINE__)
+#else
+#if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)
+#define isc_mutex_init(mp) \
+ isc_mutex_init_errcheck((mp))
+#else
+#define isc_mutex_init(mp) \
+ isc__mutex_init((mp), __FILE__, __LINE__)
+isc_result_t isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line);
+#endif
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_lock(mp) \
+ isc_mutex_lock_profile((mp), __FILE__, __LINE__)
+#else
+#define isc_mutex_lock(mp) \
+ ((pthread_mutex_lock((mp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_unlock(mp) \
+ isc_mutex_unlock_profile((mp), __FILE__, __LINE__)
+#else
+#define isc_mutex_unlock(mp) \
+ ((pthread_mutex_unlock((mp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_trylock(mp) \
+ ((pthread_mutex_trylock((&(mp)->mutex)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_LOCKBUSY)
+#else
+#define isc_mutex_trylock(mp) \
+ ((pthread_mutex_trylock((mp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_LOCKBUSY)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_destroy(mp) \
+ ((pthread_mutex_destroy((&(mp)->mutex)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#else
+#define isc_mutex_destroy(mp) \
+ ((pthread_mutex_destroy((mp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_stats(fp) isc_mutex_statsprofile(fp);
+#else
+#define isc_mutex_stats(fp)
+#endif
+
+#if ISC_MUTEX_PROFILE
+
+isc_result_t
+isc_mutex_init_profile(isc_mutex_t *mp, const char * _file, int _line);
+isc_result_t
+isc_mutex_lock_profile(isc_mutex_t *mp, const char * _file, int _line);
+isc_result_t
+isc_mutex_unlock_profile(isc_mutex_t *mp, const char * _file, int _line);
+
+void
+isc_mutex_statsprofile(FILE *fp);
+
+isc_result_t
+isc_mutex_init_errcheck(isc_mutex_t *mp);
+
+#endif /* ISC_MUTEX_PROFILE */
+
+ISC_LANG_ENDDECLS
+#endif /* ISC_MUTEX_H */
diff --git a/lib/isc/pthreads/include/isc/once.h b/lib/isc/pthreads/include/isc/once.h
new file mode 100644
index 0000000..7e9f672
--- /dev/null
+++ b/lib/isc/pthreads/include/isc/once.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2004, 2005 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: once.h,v 1.9.18.2 2005/04/29 00:17:06 marka Exp $ */
+
+#ifndef ISC_ONCE_H
+#define ISC_ONCE_H 1
+
+/*! \file */
+
+#include <pthread.h>
+
+#include <isc/platform.h>
+#include <isc/result.h>
+
+typedef pthread_once_t isc_once_t;
+
+#ifdef ISC_PLATFORM_BRACEPTHREADONCEINIT
+/*!
+ * This accomodates systems that define PTHRAD_ONCE_INIT improperly.
+ */
+#define ISC_ONCE_INIT { PTHREAD_ONCE_INIT }
+#else
+/*!
+ * This is the usual case.
+ */
+#define ISC_ONCE_INIT PTHREAD_ONCE_INIT
+#endif
+
+/* XXX We could do fancier error handling... */
+
+#define isc_once_do(op, f) \
+ ((pthread_once((op), (f)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#endif /* ISC_ONCE_H */
diff --git a/lib/isc/pthreads/include/isc/thread.h b/lib/isc/pthreads/include/isc/thread.h
new file mode 100644
index 0000000..3262607
--- /dev/null
+++ b/lib/isc/pthreads/include/isc/thread.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: thread.h,v 1.20.18.4 2005/09/18 07:58:08 marka Exp $ */
+
+#ifndef ISC_THREAD_H
+#define ISC_THREAD_H 1
+
+/*! \file */
+
+#include <pthread.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef pthread_t isc_thread_t;
+typedef void * isc_threadresult_t;
+typedef void * isc_threadarg_t;
+typedef isc_threadresult_t (*isc_threadfunc_t)(isc_threadarg_t);
+typedef pthread_key_t isc_thread_key_t;
+
+isc_result_t
+isc_thread_create(isc_threadfunc_t, isc_threadarg_t, isc_thread_t *);
+
+void
+isc_thread_setconcurrency(unsigned int level);
+
+/* XXX We could do fancier error handling... */
+
+#define isc_thread_join(t, rp) \
+ ((pthread_join((t), (rp)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_thread_self \
+ (unsigned long)pthread_self
+
+#define isc_thread_key_create pthread_key_create
+#define isc_thread_key_getspecific pthread_getspecific
+#define isc_thread_key_setspecific pthread_setspecific
+#define isc_thread_key_delete pthread_key_delete
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_THREAD_H */
diff --git a/lib/isc/pthreads/mutex.c b/lib/isc/pthreads/mutex.c
new file mode 100644
index 0000000..7716980
--- /dev/null
+++ b/lib/isc/pthreads/mutex.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2004, 2005 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: mutex.c,v 1.8.18.4 2005/07/12 01:22:32 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include <isc/mutex.h>
+#include <isc/util.h>
+#include <isc/strerror.h>
+
+#if ISC_MUTEX_PROFILE
+
+/*@{*/
+/*% Operations on timevals; adapted from FreeBSD's sys/time.h */
+#define timevalclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
+#define timevaladd(vvp, uvp) \
+ do { \
+ (vvp)->tv_sec += (uvp)->tv_sec; \
+ (vvp)->tv_usec += (uvp)->tv_usec; \
+ if ((vvp)->tv_usec >= 1000000) { \
+ (vvp)->tv_sec++; \
+ (vvp)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#define timevalsub(vvp, uvp) \
+ do { \
+ (vvp)->tv_sec -= (uvp)->tv_sec; \
+ (vvp)->tv_usec -= (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+
+/*@}*/
+
+#define ISC_MUTEX_MAX_LOCKERS 32
+
+typedef struct {
+ const char * file;
+ int line;
+ unsigned count;
+ struct timeval locked_total;
+ struct timeval wait_total;
+} isc_mutexlocker_t;
+
+struct isc_mutexstats {
+ const char * file; /*%< File mutex was created in. */
+ int line; /*%< Line mutex was created on. */
+ unsigned count;
+ struct timeval lock_t;
+ struct timeval locked_total;
+ struct timeval wait_total;
+ isc_mutexlocker_t * cur_locker;
+ isc_mutexlocker_t lockers[ISC_MUTEX_MAX_LOCKERS];
+};
+
+#define TABLESIZE (8 * 1024)
+static isc_mutexstats_t stats[TABLESIZE];
+static isc_boolean_t stats_init = ISC_FALSE;
+static pthread_mutex_t statslock = PTHREAD_MUTEX_INITIALIZER;
+
+
+isc_result_t
+isc_mutex_init_profile(isc_mutex_t *mp, const char *file, int line) {
+ int i, err;
+
+ err = pthread_mutex_init(&mp->mutex, NULL);
+ if (err == ENOMEM)
+ return (ISC_R_NOMEMORY);
+ if (err != 0)
+ return (ISC_R_UNEXPECTED);
+
+ RUNTIME_CHECK(pthread_mutex_lock(&statslock) == 0);
+
+ if (stats_init == ISC_FALSE) {
+ for (i = 0; i < TABLESIZE; i++) {
+ stats[i].file = NULL;
+ }
+ stats_init = ISC_TRUE;
+ }
+
+ mp->stats = NULL;
+ for (i = 0; i < TABLESIZE; i++) {
+ if (stats[i].file == NULL) {
+ mp->stats = &stats[i];
+ break;
+ }
+ }
+ RUNTIME_CHECK(mp->stats != NULL);
+
+ RUNTIME_CHECK(pthread_mutex_unlock(&statslock) == 0);
+
+ mp->stats->file = file;
+ mp->stats->line = line;
+ mp->stats->count = 0;
+ timevalclear(&mp->stats->locked_total);
+ timevalclear(&mp->stats->wait_total);
+ for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
+ mp->stats->lockers[i].file = NULL;
+ mp->stats->lockers[i].line = 0;
+ mp->stats->lockers[i].count = 0;
+ timevalclear(&mp->stats->lockers[i].locked_total);
+ timevalclear(&mp->stats->lockers[i].wait_total);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_mutex_lock_profile(isc_mutex_t *mp, const char *file, int line) {
+ struct timeval prelock_t;
+ struct timeval postlock_t;
+ isc_mutexlocker_t *locker = NULL;
+ int i;
+
+ gettimeofday(&prelock_t, NULL);
+
+ if (pthread_mutex_lock(&mp->mutex) != 0)
+ return (ISC_R_UNEXPECTED);
+
+ gettimeofday(&postlock_t, NULL);
+ mp->stats->lock_t = postlock_t;
+
+ timevalsub(&postlock_t, &prelock_t);
+
+ mp->stats->count++;
+ timevaladd(&mp->stats->wait_total, &postlock_t);
+
+ for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
+ if (mp->stats->lockers[i].file == NULL) {
+ locker = &mp->stats->lockers[i];
+ locker->file = file;
+ locker->line = line;
+ break;
+ } else if (mp->stats->lockers[i].file == file &&
+ mp->stats->lockers[i].line == line) {
+ locker = &mp->stats->lockers[i];
+ break;
+ }
+ }
+
+ if (locker != NULL) {
+ locker->count++;
+ timevaladd(&locker->wait_total, &postlock_t);
+ }
+
+ mp->stats->cur_locker = locker;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_mutex_unlock_profile(isc_mutex_t *mp, const char *file, int line) {
+ struct timeval unlock_t;
+
+ UNUSED(file);
+ UNUSED(line);
+
+ if (mp->stats->cur_locker != NULL) {
+ gettimeofday(&unlock_t, NULL);
+ timevalsub(&unlock_t, &mp->stats->lock_t);
+ timevaladd(&mp->stats->locked_total, &unlock_t);
+ timevaladd(&mp->stats->cur_locker->locked_total, &unlock_t);
+ mp->stats->cur_locker = NULL;
+ }
+
+ return ((pthread_mutex_unlock((&mp->mutex)) == 0) ? \
+ ISC_R_SUCCESS : ISC_R_UNEXPECTED);
+}
+
+
+void
+isc_mutex_statsprofile(FILE *fp) {
+ isc_mutexlocker_t *locker;
+ int i, j;
+ fprintf(fp, "Mutex stats (in us)\n");
+ for (i = 0; i < TABLESIZE; i++) {
+ if (stats[i].file == NULL)
+ continue;
+ fprintf(fp, "%-12s %4d: %10u %lu.%06lu %lu.%06lu\n",
+ stats[i].file, stats[i].line, stats[i].count,
+ stats[i].locked_total.tv_sec,
+ stats[i].locked_total.tv_usec,
+ stats[i].wait_total.tv_sec,
+ stats[i].wait_total.tv_usec
+ );
+ for (j = 0; j < ISC_MUTEX_MAX_LOCKERS; j++) {
+ locker = &stats[i].lockers[j];
+ if (locker->file == NULL)
+ continue;
+ fprintf(fp, " %-11s %4d: %10u %lu.%06lu %lu.%06lu\n",
+ locker->file, locker->line, locker->count,
+ locker->locked_total.tv_sec,
+ locker->locked_total.tv_usec,
+ locker->wait_total.tv_sec,
+ locker->wait_total.tv_usec
+ );
+ }
+ }
+}
+
+#endif /* ISC_MUTEX_PROFILE */
+
+#if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)
+isc_result_t
+isc_mutex_init_errcheck(isc_mutex_t *mp)
+{
+ pthread_mutexattr_t attr;
+ int err;
+
+ if (pthread_mutexattr_init(&attr) != 0)
+ return (ISC_R_UNEXPECTED);
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
+ return (ISC_R_UNEXPECTED);
+
+ err = pthread_mutex_init(mp, &attr) != 0)
+ if (err == ENOMEM)
+ return (ISC_R_NOMEMORY);
+ return ((err == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED);
+}
+#endif
+
+#if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK)
+pthread_mutexattr_t isc__mutex_attrs = {
+ PTHREAD_MUTEX_ERRORCHECK, /* m_type */
+ 0 /* m_flags, which appears to be unused. */
+};
+#endif
+
+isc_result_t
+isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc_result_t result = ISC_R_SUCCESS;
+ int err;
+
+ err = pthread_mutex_init(mp, ISC__MUTEX_ATTRS);
+ if (err == ENOMEM)
+ return (ISC_R_NOMEMORY);
+ if (err != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(file, line, "isc_mutex_init() failed: %s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ }
+ return (result);
+}
diff --git a/lib/isc/pthreads/thread.c b/lib/isc/pthreads/thread.c
new file mode 100644
index 0000000..bdbb593
--- /dev/null
+++ b/lib/isc/pthreads/thread.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2004, 2005 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: thread.c,v 1.12.18.3 2005/04/29 00:17:05 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#ifndef THREAD_MINSTACKSIZE
+#define THREAD_MINSTACKSIZE (64U * 1024)
+#endif
+
+isc_result_t
+isc_thread_create(isc_threadfunc_t func, isc_threadarg_t arg,
+ isc_thread_t *thread)
+{
+ pthread_attr_t attr;
+ size_t stacksize;
+ int ret;
+
+ pthread_attr_init(&attr);
+
+#if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \
+ defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE)
+ ret = pthread_attr_getstacksize(&attr, &stacksize);
+ if (ret != 0)
+ return (ISC_R_UNEXPECTED);
+
+ if (stacksize < THREAD_MINSTACKSIZE) {
+ ret = pthread_attr_setstacksize(&attr, THREAD_MINSTACKSIZE);
+ if (ret != 0)
+ return (ISC_R_UNEXPECTED);
+ }
+#endif
+
+#if defined(PTHREAD_SCOPE_SYSTEM) && defined(NEED_PTHREAD_SCOPE_SYSTEM)
+ ret = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+ if (ret != 0)
+ return (ISC_R_UNEXPECTED);
+#endif
+
+ ret = pthread_create(thread, &attr, func, arg);
+ if (ret != 0)
+ return (ISC_R_UNEXPECTED);
+
+ pthread_attr_destroy(&attr);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_thread_setconcurrency(unsigned int level) {
+#if defined(CALL_PTHREAD_SETCONCURRENCY)
+ (void)pthread_setconcurrency(level);
+#else
+ UNUSED(level);
+#endif
+}
diff --git a/lib/isc/quota.c b/lib/isc/quota.c
new file mode 100644
index 0000000..9290167
--- /dev/null
+++ b/lib/isc/quota.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2004, 2005 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: quota.c,v 1.13.18.3 2005/07/27 02:44:21 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/quota.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_quota_init(isc_quota_t *quota, int max) {
+ quota->max = max;
+ quota->used = 0;
+ quota->soft = 0;
+ return (isc_mutex_init(&quota->lock));
+}
+
+void
+isc_quota_destroy(isc_quota_t *quota) {
+ INSIST(quota->used == 0);
+ quota->max = 0;
+ quota->used = 0;
+ quota->soft = 0;
+ DESTROYLOCK(&quota->lock);
+}
+
+void
+isc_quota_soft(isc_quota_t *quota, int soft) {
+ LOCK(&quota->lock);
+ quota->soft = soft;
+ UNLOCK(&quota->lock);
+}
+
+void
+isc_quota_max(isc_quota_t *quota, int max) {
+ LOCK(&quota->lock);
+ quota->max = max;
+ UNLOCK(&quota->lock);
+}
+
+isc_result_t
+isc_quota_reserve(isc_quota_t *quota) {
+ isc_result_t result;
+ LOCK(&quota->lock);
+ if (quota->max == 0 || quota->used < quota->max) {
+ if (quota->soft == 0 || quota->used < quota->soft)
+ result = ISC_R_SUCCESS;
+ else
+ result = ISC_R_SOFTQUOTA;
+ quota->used++;
+ } else
+ result = ISC_R_QUOTA;
+ UNLOCK(&quota->lock);
+ return (result);
+}
+
+void
+isc_quota_release(isc_quota_t *quota) {
+ LOCK(&quota->lock);
+ INSIST(quota->used > 0);
+ quota->used--;
+ UNLOCK(&quota->lock);
+}
+
+isc_result_t
+isc_quota_attach(isc_quota_t *quota, isc_quota_t **p)
+{
+ isc_result_t result;
+ INSIST(p != NULL && *p == NULL);
+ result = isc_quota_reserve(quota);
+ if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA)
+ *p = quota;
+ return (result);
+}
+
+void
+isc_quota_detach(isc_quota_t **p)
+{
+ INSIST(p != NULL && *p != NULL);
+ isc_quota_release(*p);
+ *p = NULL;
+}
diff --git a/lib/isc/random.c b/lib/isc/random.c
new file mode 100644
index 0000000..f6c7d6e
--- /dev/null
+++ b/lib/isc/random.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2004, 2005 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: random.c,v 1.21.18.2 2005/04/29 00:16:48 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <time.h> /* Required for time(). */
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/random.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+static isc_once_t once = ISC_ONCE_INIT;
+
+static void
+initialize_rand(void)
+{
+#ifndef HAVE_ARC4RANDOM
+ unsigned int pid = getpid();
+
+ /*
+ * The low bits of pid generally change faster.
+ * Xor them with the high bits of time which change slowly.
+ */
+ pid = ((pid << 16) & 0xffff0000) | ((pid >> 16) & 0xffff);
+
+ srand(time(NULL) ^ pid);
+#endif
+}
+
+static void
+initialize(void)
+{
+ RUNTIME_CHECK(isc_once_do(&once, initialize_rand) == ISC_R_SUCCESS);
+}
+
+void
+isc_random_seed(isc_uint32_t seed)
+{
+ initialize();
+
+#ifndef HAVE_ARC4RANDOM
+ srand(seed);
+#else
+ arc4random_addrandom((u_char *) &seed, sizeof(isc_uint32_t));
+#endif
+}
+
+void
+isc_random_get(isc_uint32_t *val)
+{
+ REQUIRE(val != NULL);
+
+ initialize();
+
+#ifndef HAVE_ARC4RANDOM
+ /*
+ * rand()'s lower bits are not random.
+ * rand()'s upper bit is zero.
+ */
+ *val = ((rand() >> 4) & 0xffff) | ((rand() << 12) & 0xffff0000);
+#else
+ *val = arc4random();
+#endif
+}
+
+isc_uint32_t
+isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter) {
+ REQUIRE(jitter < max);
+ if (jitter == 0)
+ return (max);
+ else
+#ifndef HAVE_ARC4RANDOM
+ return (max - rand() % jitter);
+#else
+ return (max - arc4random() % jitter);
+#endif
+}
diff --git a/lib/isc/ratelimiter.c b/lib/isc/ratelimiter.c
new file mode 100644
index 0000000..3d65139
--- /dev/null
+++ b/lib/isc/ratelimiter.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2004, 2005 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: ratelimiter.c,v 1.21.18.2 2005/04/29 00:16:49 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/ratelimiter.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+typedef enum {
+ isc_ratelimiter_stalled = 0,
+ isc_ratelimiter_ratelimited = 1,
+ isc_ratelimiter_idle = 2,
+ isc_ratelimiter_shuttingdown = 3
+} isc_ratelimiter_state_t;
+
+struct isc_ratelimiter {
+ isc_mem_t * mctx;
+ isc_mutex_t lock;
+ int refs;
+ isc_task_t * task;
+ isc_timer_t * timer;
+ isc_interval_t interval;
+ isc_uint32_t pertic;
+ isc_ratelimiter_state_t state;
+ isc_event_t shutdownevent;
+ ISC_LIST(isc_event_t) pending;
+};
+
+#define ISC_RATELIMITEREVENT_SHUTDOWN (ISC_EVENTCLASS_RATELIMITER + 1)
+
+static void
+ratelimiter_tick(isc_task_t *task, isc_event_t *event);
+
+static void
+ratelimiter_shutdowncomplete(isc_task_t *task, isc_event_t *event);
+
+isc_result_t
+isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
+ isc_task_t *task, isc_ratelimiter_t **ratelimiterp)
+{
+ isc_result_t result;
+ isc_ratelimiter_t *rl;
+ INSIST(ratelimiterp != NULL && *ratelimiterp == NULL);
+
+ rl = isc_mem_get(mctx, sizeof(*rl));
+ if (rl == NULL)
+ return ISC_R_NOMEMORY;
+ rl->mctx = mctx;
+ rl->refs = 1;
+ rl->task = task;
+ isc_interval_set(&rl->interval, 0, 0);
+ rl->timer = NULL;
+ rl->pertic = 1;
+ rl->state = isc_ratelimiter_idle;
+ ISC_LIST_INIT(rl->pending);
+
+ result = isc_mutex_init(&rl->lock);
+ if (result != ISC_R_SUCCESS)
+ goto free_mem;
+ result = isc_timer_create(timermgr, isc_timertype_inactive,
+ NULL, NULL, rl->task, ratelimiter_tick,
+ rl, &rl->timer);
+ if (result != ISC_R_SUCCESS)
+ goto free_mutex;
+
+ /*
+ * Increment the reference count to indicate that we may
+ * (soon) have events outstanding.
+ */
+ rl->refs++;
+
+ ISC_EVENT_INIT(&rl->shutdownevent,
+ sizeof(isc_event_t),
+ 0, NULL, ISC_RATELIMITEREVENT_SHUTDOWN,
+ ratelimiter_shutdowncomplete, rl, rl, NULL, NULL);
+
+ *ratelimiterp = rl;
+ return (ISC_R_SUCCESS);
+
+free_mutex:
+ DESTROYLOCK(&rl->lock);
+free_mem:
+ isc_mem_put(mctx, rl, sizeof(*rl));
+ return (result);
+}
+
+isc_result_t
+isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval) {
+ isc_result_t result = ISC_R_SUCCESS;
+ LOCK(&rl->lock);
+ rl->interval = *interval;
+ /*
+ * If the timer is currently running, change its rate.
+ */
+ if (rl->state == isc_ratelimiter_ratelimited) {
+ result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL,
+ &rl->interval, ISC_FALSE);
+ }
+ UNLOCK(&rl->lock);
+ return (result);
+}
+
+void
+isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, isc_uint32_t pertic) {
+ if (pertic == 0)
+ pertic = 1;
+ rl->pertic = pertic;
+}
+
+isc_result_t
+isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
+ isc_event_t **eventp)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_event_t *ev;
+
+ REQUIRE(eventp != NULL && *eventp != NULL);
+ REQUIRE(task != NULL);
+ ev = *eventp;
+ REQUIRE(ev->ev_sender == NULL);
+
+ LOCK(&rl->lock);
+ if (rl->state == isc_ratelimiter_ratelimited ||
+ rl->state == isc_ratelimiter_stalled) {
+ isc_event_t *ev = *eventp;
+ ev->ev_sender = task;
+ ISC_LIST_APPEND(rl->pending, ev, ev_link);
+ *eventp = NULL;
+ } else if (rl->state == isc_ratelimiter_idle) {
+ result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL,
+ &rl->interval, ISC_FALSE);
+ if (result == ISC_R_SUCCESS) {
+ ev->ev_sender = task;
+ rl->state = isc_ratelimiter_ratelimited;
+ }
+ } else {
+ INSIST(rl->state == isc_ratelimiter_shuttingdown);
+ result = ISC_R_SHUTTINGDOWN;
+ }
+ UNLOCK(&rl->lock);
+ if (*eventp != NULL && result == ISC_R_SUCCESS)
+ isc_task_send(task, eventp);
+ return (result);
+}
+
+static void
+ratelimiter_tick(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_ratelimiter_t *rl = (isc_ratelimiter_t *)event->ev_arg;
+ isc_event_t *p;
+ isc_uint32_t pertic;
+
+ UNUSED(task);
+
+ isc_event_free(&event);
+
+ pertic = rl->pertic;
+ while (pertic != 0) {
+ pertic--;
+ LOCK(&rl->lock);
+ p = ISC_LIST_HEAD(rl->pending);
+ if (p != NULL) {
+ /*
+ * There is work to do. Let's do it after unlocking.
+ */
+ ISC_LIST_UNLINK(rl->pending, p, ev_link);
+ } else {
+ /*
+ * No work left to do. Stop the timer so that we don't
+ * waste resources by having it fire periodically.
+ */
+ result = isc_timer_reset(rl->timer,
+ isc_timertype_inactive,
+ NULL, NULL, ISC_FALSE);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ rl->state = isc_ratelimiter_idle;
+ pertic = 0; /* Force the loop to exit. */
+ }
+ UNLOCK(&rl->lock);
+ if (p != NULL) {
+ isc_task_t *evtask = p->ev_sender;
+ isc_task_send(evtask, &p);
+ }
+ INSIST(p == NULL);
+ }
+}
+
+void
+isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) {
+ isc_event_t *ev;
+ isc_task_t *task;
+ LOCK(&rl->lock);
+ rl->state = isc_ratelimiter_shuttingdown;
+ (void)isc_timer_reset(rl->timer, isc_timertype_inactive,
+ NULL, NULL, ISC_FALSE);
+ while ((ev = ISC_LIST_HEAD(rl->pending)) != NULL) {
+ ISC_LIST_UNLINK(rl->pending, ev, ev_link);
+ ev->ev_attributes |= ISC_EVENTATTR_CANCELED;
+ task = ev->ev_sender;
+ isc_task_send(task, &ev);
+ }
+ isc_timer_detach(&rl->timer);
+ /*
+ * Send an event to our task. The delivery of this event
+ * indicates that no more timer events will be delivered.
+ */
+ ev = &rl->shutdownevent;
+ isc_task_send(rl->task, &ev);
+
+ UNLOCK(&rl->lock);
+}
+
+static void
+ratelimiter_shutdowncomplete(isc_task_t *task, isc_event_t *event) {
+ isc_ratelimiter_t *rl = (isc_ratelimiter_t *)event->ev_arg;
+
+ UNUSED(task);
+
+ isc_ratelimiter_detach(&rl);
+}
+
+static void
+ratelimiter_free(isc_ratelimiter_t *rl) {
+ DESTROYLOCK(&rl->lock);
+ isc_mem_put(rl->mctx, rl, sizeof(*rl));
+}
+
+void
+isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target) {
+ REQUIRE(source != NULL);
+ REQUIRE(target != NULL && *target == NULL);
+
+ LOCK(&source->lock);
+ REQUIRE(source->refs > 0);
+ source->refs++;
+ INSIST(source->refs > 0);
+ UNLOCK(&source->lock);
+ *target = source;
+}
+
+void
+isc_ratelimiter_detach(isc_ratelimiter_t **rlp) {
+ isc_ratelimiter_t *rl = *rlp;
+ isc_boolean_t free_now = ISC_FALSE;
+
+ LOCK(&rl->lock);
+ REQUIRE(rl->refs > 0);
+ rl->refs--;
+ if (rl->refs == 0)
+ free_now = ISC_TRUE;
+ UNLOCK(&rl->lock);
+
+ if (free_now)
+ ratelimiter_free(rl);
+
+ *rlp = NULL;
+}
+
+isc_result_t
+isc_ratelimiter_stall(isc_ratelimiter_t *rl) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ LOCK(&rl->lock);
+ switch (rl->state) {
+ case isc_ratelimiter_shuttingdown:
+ result = ISC_R_SHUTTINGDOWN;
+ break;
+ case isc_ratelimiter_ratelimited:
+ result = isc_timer_reset(rl->timer, isc_timertype_inactive,
+ NULL, NULL, ISC_FALSE);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ case isc_ratelimiter_idle:
+ case isc_ratelimiter_stalled:
+ rl->state = isc_ratelimiter_stalled;
+ break;
+ }
+ UNLOCK(&rl->lock);
+ return (result);
+}
+
+isc_result_t
+isc_ratelimiter_release(isc_ratelimiter_t *rl) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ LOCK(&rl->lock);
+ switch (rl->state) {
+ case isc_ratelimiter_shuttingdown:
+ result = ISC_R_SHUTTINGDOWN;
+ break;
+ case isc_ratelimiter_stalled:
+ if (!ISC_LIST_EMPTY(rl->pending)) {
+ result = isc_timer_reset(rl->timer,
+ isc_timertype_ticker, NULL,
+ &rl->interval, ISC_FALSE);
+ if (result == ISC_R_SUCCESS)
+ rl->state = isc_ratelimiter_ratelimited;
+ } else
+ rl->state = isc_ratelimiter_idle;
+ break;
+ case isc_ratelimiter_ratelimited:
+ case isc_ratelimiter_idle:
+ break;
+ }
+ UNLOCK(&rl->lock);
+ return (result);
+}
diff --git a/lib/isc/refcount.c b/lib/isc/refcount.c
new file mode 100644
index 0000000..d5095eb
--- /dev/null
+++ b/lib/isc/refcount.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: refcount.c,v 1.2.2.2 2005/07/25 00:51:46 marka Exp $ */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/mutex.h>
+#include <isc/refcount.h>
+#include <isc/result.h>
+
+isc_result_t
+isc_refcount_init(isc_refcount_t *ref, unsigned int n) {
+ REQUIRE(ref != NULL);
+
+ ref->refs = n;
+#if defined(ISC_PLATFORM_USETHREADS) && !defined(ISC_PLATFORM_HAVEXADD)
+ return (isc_mutex_init(&ref->lock));
+#else
+ return (ISC_R_SUCCESS);
+#endif
+}
diff --git a/lib/isc/region.c b/lib/isc/region.c
new file mode 100644
index 0000000..bc32b86
--- /dev/null
+++ b/lib/isc/region.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: region.c,v 1.3.18.2 2005/04/29 00:16:49 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/region.h>
+#include <isc/util.h>
+
+int
+isc_region_compare(isc_region_t *r1, isc_region_t *r2) {
+ unsigned int l;
+ int result;
+
+ REQUIRE(r1 != NULL);
+ REQUIRE(r2 != NULL);
+
+ l = (r1->length < r2->length) ? r1->length : r2->length;
+
+ if ((result = memcmp(r1->base, r2->base, l)) != 0)
+ return ((result < 0) ? -1 : 1);
+ else
+ return ((r1->length == r2->length) ? 0 :
+ (r1->length < r2->length) ? -1 : 1);
+}
diff --git a/lib/isc/result.c b/lib/isc/result.c
new file mode 100644
index 0000000..e0c8653
--- /dev/null
+++ b/lib/isc/result.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2004, 2005 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: result.c,v 1.62.18.6 2005/06/22 22:05:48 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <isc/lib.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/resultclass.h>
+#include <isc/util.h>
+
+typedef struct resulttable {
+ unsigned int base;
+ unsigned int last;
+ const char ** text;
+ isc_msgcat_t * msgcat;
+ int set;
+ ISC_LINK(struct resulttable) link;
+} resulttable;
+
+static const char *text[ISC_R_NRESULTS] = {
+ "success", /*%< 0 */
+ "out of memory", /*%< 1 */
+ "timed out", /*%< 2 */
+ "no available threads", /*%< 3 */
+ "address not available", /*%< 4 */
+ "address in use", /*%< 5 */
+ "permission denied", /*%< 6 */
+ "no pending connections", /*%< 7 */
+ "network unreachable", /*%< 8 */
+ "host unreachable", /*%< 9 */
+ "network down", /*%< 10 */
+ "host down", /*%< 11 */
+ "connection refused", /*%< 12 */
+ "not enough free resources", /*%< 13 */
+ "end of file", /*%< 14 */
+ "socket already bound", /*%< 15 */
+ "reload", /*%< 16 */
+ "lock busy", /*%< 17 */
+ "already exists", /*%< 18 */
+ "ran out of space", /*%< 19 */
+ "operation canceled", /*%< 20 */
+ "socket is not bound", /*%< 21 */
+ "shutting down", /*%< 22 */
+ "not found", /*%< 23 */
+ "unexpected end of input", /*%< 24 */
+ "failure", /*%< 25 */
+ "I/O error", /*%< 26 */
+ "not implemented", /*%< 27 */
+ "unbalanced parentheses", /*%< 28 */
+ "no more", /*%< 29 */
+ "invalid file", /*%< 30 */
+ "bad base64 encoding", /*%< 31 */
+ "unexpected token", /*%< 32 */
+ "quota reached", /*%< 33 */
+ "unexpected error", /*%< 34 */
+ "already running", /*%< 35 */
+ "ignore", /*%< 36 */
+ "address mask not contiguous", /*%< 37 */
+ "file not found", /*%< 38 */
+ "file already exists", /*%< 39 */
+ "socket is not connected", /*%< 40 */
+ "out of range", /*%< 41 */
+ "out of entropy", /*%< 42 */
+ "invalid use of multicast address", /*%< 43 */
+ "not a file", /*%< 44 */
+ "not a directory", /*%< 45 */
+ "queue is full", /*%< 46 */
+ "address family mismatch", /*%< 47 */
+ "address family not supported", /*%< 48 */
+ "bad hex encoding", /*%< 49 */
+ "too many open files", /*%< 50 */
+ "not blocking", /*%< 51 */
+ "unbalanced quotes", /*%< 52 */
+ "operation in progress", /*%< 53 */
+ "connection reset", /*%< 54 */
+ "soft quota reached", /*%< 55 */
+ "not a valid number", /*%< 56 */
+ "disabled", /*%< 57 */
+ "max size", /*%< 58 */
+ "invalid address format" /*%< 59 */
+};
+
+#define ISC_RESULT_RESULTSET 2
+#define ISC_RESULT_UNAVAILABLESET 3
+
+static isc_once_t once = ISC_ONCE_INIT;
+static ISC_LIST(resulttable) tables;
+static isc_mutex_t lock;
+
+static isc_result_t
+register_table(unsigned int base, unsigned int nresults, const char **text,
+ isc_msgcat_t *msgcat, int set)
+{
+ resulttable *table;
+
+ REQUIRE(base % ISC_RESULTCLASS_SIZE == 0);
+ REQUIRE(nresults <= ISC_RESULTCLASS_SIZE);
+ REQUIRE(text != NULL);
+
+ /*
+ * We use malloc() here because we we want to be able to use
+ * isc_result_totext() even if there is no memory context.
+ */
+ table = malloc(sizeof(*table));
+ if (table == NULL)
+ return (ISC_R_NOMEMORY);
+ table->base = base;
+ table->last = base + nresults - 1;
+ table->text = text;
+ table->msgcat = msgcat;
+ table->set = set;
+ ISC_LINK_INIT(table, link);
+
+ LOCK(&lock);
+
+ ISC_LIST_APPEND(tables, table, link);
+
+ UNLOCK(&lock);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+initialize_action(void) {
+ isc_result_t result;
+
+ RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
+ ISC_LIST_INIT(tables);
+
+ result = register_table(ISC_RESULTCLASS_ISC, ISC_R_NRESULTS, text,
+ isc_msgcat, ISC_RESULT_RESULTSET);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "register_table() %s: %u",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ result);
+}
+
+static void
+initialize(void) {
+ isc_lib_initmsgcat();
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+const char *
+isc_result_totext(isc_result_t result) {
+ resulttable *table;
+ const char *text, *default_text;
+ int index;
+
+ initialize();
+
+ LOCK(&lock);
+
+ text = NULL;
+ for (table = ISC_LIST_HEAD(tables);
+ table != NULL;
+ table = ISC_LIST_NEXT(table, link)) {
+ if (result >= table->base && result <= table->last) {
+ index = (int)(result - table->base);
+ default_text = table->text[index];
+ /*
+ * Note: we use 'index + 1' as the message number
+ * instead of index because isc_msgcat_get() requires
+ * the message number to be > 0.
+ */
+ text = isc_msgcat_get(table->msgcat, table->set,
+ index + 1, default_text);
+ break;
+ }
+ }
+ if (text == NULL)
+ text = isc_msgcat_get(isc_msgcat, ISC_RESULT_UNAVAILABLESET,
+ 1, "(result code text not available)");
+
+ UNLOCK(&lock);
+
+ return (text);
+}
+
+isc_result_t
+isc_result_register(unsigned int base, unsigned int nresults,
+ const char **text, isc_msgcat_t *msgcat, int set)
+{
+ initialize();
+
+ return (register_table(base, nresults, text, msgcat, set));
+}
diff --git a/lib/isc/rwlock.c b/lib/isc/rwlock.c
new file mode 100644
index 0000000..69b8f56
--- /dev/null
+++ b/lib/isc/rwlock.c
@@ -0,0 +1,808 @@
+/*
+ * Copyright (C) 2004, 2005 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: rwlock.c,v 1.37.18.5 2005/07/12 01:22:30 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/atomic.h>
+#include <isc/magic.h>
+#include <isc/msgs.h>
+#include <isc/platform.h>
+#include <isc/rwlock.h>
+#include <isc/util.h>
+
+#define RWLOCK_MAGIC ISC_MAGIC('R', 'W', 'L', 'k')
+#define VALID_RWLOCK(rwl) ISC_MAGIC_VALID(rwl, RWLOCK_MAGIC)
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+#ifndef RWLOCK_DEFAULT_READ_QUOTA
+#define RWLOCK_DEFAULT_READ_QUOTA 4
+#endif
+
+#ifndef RWLOCK_DEFAULT_WRITE_QUOTA
+#define RWLOCK_DEFAULT_WRITE_QUOTA 4
+#endif
+
+#ifdef ISC_RWLOCK_TRACE
+#include <stdio.h> /* Required for fprintf/stderr. */
+#include <isc/thread.h> /* Requried for isc_thread_self(). */
+
+static void
+print_lock(const char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ fprintf(stderr,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PRINTLOCK,
+ "rwlock %p thread %lu %s(%s): %s, %u active, "
+ "%u granted, %u rwaiting, %u wwaiting\n"),
+ rwl, isc_thread_self(), operation,
+ (type == isc_rwlocktype_read ?
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_READ, "read") :
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_WRITE, "write")),
+ (rwl->type == isc_rwlocktype_read ?
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_READING, "reading") :
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_WRITING, "writing")),
+ rwl->active, rwl->granted, rwl->readers_waiting,
+ rwl->writers_waiting);
+}
+#endif
+
+isc_result_t
+isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
+ unsigned int write_quota)
+{
+ isc_result_t result;
+
+ REQUIRE(rwl != NULL);
+
+ /*
+ * In case there's trouble initializing, we zero magic now. If all
+ * goes well, we'll set it to RWLOCK_MAGIC.
+ */
+ rwl->magic = 0;
+
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+ rwl->write_requests = 0;
+ rwl->write_completions = 0;
+ rwl->cnt_and_flag = 0;
+ rwl->readers_waiting = 0;
+ rwl->write_granted = 0;
+ if (read_quota != 0) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "read quota is not supported");
+ }
+ if (write_quota == 0)
+ write_quota = RWLOCK_DEFAULT_WRITE_QUOTA;
+ rwl->write_quota = write_quota;
+#else
+ rwl->type = isc_rwlocktype_read;
+ rwl->original = isc_rwlocktype_none;
+ rwl->active = 0;
+ rwl->granted = 0;
+ rwl->readers_waiting = 0;
+ rwl->writers_waiting = 0;
+ if (read_quota == 0)
+ read_quota = RWLOCK_DEFAULT_READ_QUOTA;
+ rwl->read_quota = read_quota;
+ if (write_quota == 0)
+ write_quota = RWLOCK_DEFAULT_WRITE_QUOTA;
+ rwl->write_quota = write_quota;
+#endif
+
+ result = isc_mutex_init(&rwl->lock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = isc_condition_init(&rwl->readable);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init(readable) %s: %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto destroy_lock;
+ }
+ result = isc_condition_init(&rwl->writeable);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init(writeable) %s: %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto destroy_rcond;
+ }
+
+ rwl->magic = RWLOCK_MAGIC;
+
+ return (ISC_R_SUCCESS);
+
+ destroy_rcond:
+ (void)isc_condition_destroy(&rwl->readable);
+ destroy_lock:
+ DESTROYLOCK(&rwl->lock);
+
+ return (result);
+}
+
+void
+isc_rwlock_destroy(isc_rwlock_t *rwl) {
+ REQUIRE(VALID_RWLOCK(rwl));
+
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+ REQUIRE(rwl->write_requests == rwl->write_completions &&
+ rwl->cnt_and_flag == 0 && rwl->readers_waiting == 0);
+#else
+ LOCK(&rwl->lock);
+ REQUIRE(rwl->active == 0 &&
+ rwl->readers_waiting == 0 &&
+ rwl->writers_waiting == 0);
+ UNLOCK(&rwl->lock);
+#endif
+
+ rwl->magic = 0;
+ (void)isc_condition_destroy(&rwl->readable);
+ (void)isc_condition_destroy(&rwl->writeable);
+ DESTROYLOCK(&rwl->lock);
+}
+
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+
+/*
+ * When some architecture-dependent atomic operations are available,
+ * rwlock can be more efficient than the generic algorithm defined below.
+ * The basic algorithm is described in the following URL:
+ * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html
+ *
+ * The key is to use the following integer variables modified atomically:
+ * write_requests, write_completions, and cnt_and_flag.
+ *
+ * write_requests and write_completions act as a waiting queue for writers
+ * in order to ensure the FIFO order. Both variables begin with the initial
+ * value of 0. When a new writer tries to get a write lock, it increments
+ * write_requests and gets the previous value of the variable as a "ticket".
+ * When write_completions reaches the ticket number, the new writer can start
+ * writing. When the writer completes its work, it increments
+ * write_completions so that another new writer can start working. If the
+ * write_requests is not equal to write_completions, it means a writer is now
+ * working or waiting. In this case, a new readers cannot start reading, or
+ * in other words, this algorithm basically prefers writers.
+ *
+ * cnt_and_flag is a "lock" shared by all readers and writers. This integer
+ * variable is a kind of structure with two members: writer_flag (1 bit) and
+ * reader_count (31 bits). The writer_flag shows whether a writer is working,
+ * and the reader_count shows the number of readers currently working or almost
+ * ready for working. A writer who has the current "ticket" tries to get the
+ * lock by exclusively setting the writer_flag to 1, provided that the whole
+ * 32-bit is 0 (meaning no readers or writers working). On the other hand,
+ * a new reader tries to increment the "reader_count" field provided that
+ * the writer_flag is 0 (meaning there is no writer working).
+ *
+ * If some of the above operations fail, the reader or the writer sleeps
+ * until the related condition changes. When a working reader or writer
+ * completes its work, some readers or writers are sleeping, and the condition
+ * that suspended the reader or writer has changed, it wakes up the sleeping
+ * readers or writers.
+ *
+ * As already noted, this algorithm basically prefers writers. In order to
+ * prevent readers from starving, however, the algorithm also introduces the
+ * "writer quota" (Q). When Q consecutive writers have completed their work,
+ * suspending readers, the last writer will wake up the readers, even if a new
+ * writer is waiting.
+ *
+ * Implementation specific note: due to the combination of atomic operations
+ * and a mutex lock, ordering between the atomic operation and locks can be
+ * very sensitive in some cases. In particular, it is generally very important
+ * to check the atomic variable that requires a reader or writer to sleep after
+ * locking the mutex and before actually sleeping; otherwise, it could be very
+ * likely to cause a deadlock. For example, assume "var" is a variable
+ * atomically modified, then the corresponding code would be:
+ * if (var == need_sleep) {
+ * LOCK(lock);
+ * if (var == need_sleep)
+ * WAIT(cond, lock);
+ * UNLOCK(lock);
+ * }
+ * The second check is important, since "var" is protected by the atomic
+ * operation, not by the mutex, and can be changed just before sleeping.
+ * (The first "if" could be omitted, but this is also important in order to
+ * make the code efficient by avoiding the use of the mutex unless it is
+ * really necessary.)
+ */
+
+#define WRITER_ACTIVE 0x1
+#define READER_INCR 0x2
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ isc_int32_t cntflag;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PRELOCK, "prelock"), rwl, type);
+#endif
+
+ if (type == isc_rwlocktype_read) {
+ if (rwl->write_requests != rwl->write_completions) {
+ /* there is a waiting or active writer */
+ LOCK(&rwl->lock);
+ if (rwl->write_requests != rwl->write_completions) {
+ rwl->readers_waiting++;
+ WAIT(&rwl->readable, &rwl->lock);
+ rwl->readers_waiting--;
+ }
+ UNLOCK(&rwl->lock);
+ }
+
+ cntflag = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+ while (1) {
+ if ((rwl->cnt_and_flag & WRITER_ACTIVE) == 0)
+ break;
+
+ /* A writer is still working */
+ LOCK(&rwl->lock);
+ rwl->readers_waiting++;
+ if ((rwl->cnt_and_flag & WRITER_ACTIVE) != 0)
+ WAIT(&rwl->readable, &rwl->lock);
+ rwl->readers_waiting--;
+ UNLOCK(&rwl->lock);
+
+ /*
+ * Typically, the reader should be able to get a lock
+ * at this stage:
+ * (1) there should have been no pending writer when
+ * the reader was trying to increment the
+ * counter; otherwise, the writer should be in
+ * the waiting queue, preventing the reader from
+ * proceeding to this point.
+ * (2) once the reader increments the counter, no
+ * more writer can get a lock.
+ * Still, it is possible another writer can work at
+ * this point, e.g. in the following scenario:
+ * A previous writer unlocks the writer lock.
+ * This reader proceeds to point (1).
+ * A new writer appears, and gets a new lock before
+ * the reader increments the counter.
+ * The reader then increments the counter.
+ * The previous writer notices there is a waiting
+ * reader who is almost ready, and wakes it up.
+ * So, the reader needs to confirm whether it can now
+ * read explicitly (thus we loop). Note that this is
+ * not an infinite process, since the reader has
+ * incremented the counter at this point.
+ */
+ }
+
+ /*
+ * If we are temporarily preferred to writers due to the writer
+ * quota, reset the condition (race among readers doesn't
+ * matter).
+ */
+ rwl->write_granted = 0;
+ } else {
+ isc_int32_t prev_writer;
+
+ /* enter the waiting queue, and wait for our turn */
+ prev_writer = isc_atomic_xadd(&rwl->write_requests, 1);
+ while (rwl->write_completions != prev_writer) {
+ LOCK(&rwl->lock);
+ if (rwl->write_completions != prev_writer) {
+ WAIT(&rwl->writeable, &rwl->lock);
+ UNLOCK(&rwl->lock);
+ continue;
+ }
+ UNLOCK(&rwl->lock);
+ break;
+ }
+
+ while (1) {
+ cntflag = isc_atomic_cmpxchg(&rwl->cnt_and_flag, 0,
+ WRITER_ACTIVE);
+ if (cntflag == 0)
+ break;
+
+ /* Another active reader or writer is working. */
+ LOCK(&rwl->lock);
+ if (rwl->cnt_and_flag != 0)
+ WAIT(&rwl->writeable, &rwl->lock);
+ UNLOCK(&rwl->lock);
+ }
+
+ INSIST((rwl->cnt_and_flag & WRITER_ACTIVE) != 0);
+ rwl->write_granted++;
+ }
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_POSTLOCK, "postlock"), rwl, type);
+#endif
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ isc_int32_t cntflag;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PRELOCK, "prelock"), rwl, type);
+#endif
+
+ if (type == isc_rwlocktype_read) {
+ /* If a writer is waiting or working, we fail. */
+ if (rwl->write_requests != rwl->write_completions)
+ return (ISC_R_LOCKBUSY);
+
+ /* Otherwise, be ready for reading. */
+ cntflag = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+ if ((cntflag & WRITER_ACTIVE) != 0) {
+ /*
+ * A writer is working. We lose, and cancel the read
+ * request.
+ */
+ cntflag = isc_atomic_xadd(&rwl->cnt_and_flag,
+ -READER_INCR);
+ /*
+ * If no other readers are waiting and we've suspended
+ * new writers in this short period, wake them up.
+ */
+ if (cntflag == READER_INCR &&
+ rwl->write_completions != rwl->write_requests) {
+ LOCK(&rwl->lock);
+ BROADCAST(&rwl->writeable);
+ UNLOCK(&rwl->lock);
+ }
+
+ return (ISC_R_LOCKBUSY);
+ }
+ } else {
+ /* Try locking without entering the waiting queue. */
+ cntflag = isc_atomic_cmpxchg(&rwl->cnt_and_flag, 0,
+ WRITER_ACTIVE);
+ if (cntflag != 0)
+ return (ISC_R_LOCKBUSY);
+
+ /*
+ * XXXJT: jump into the queue, possibly breaking the writer
+ * order.
+ */
+ (void)isc_atomic_xadd(&rwl->write_completions, -1);
+
+ rwl->write_granted++;
+ }
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_POSTLOCK, "postlock"), rwl, type);
+#endif
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
+ isc_int32_t prevcnt;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+
+ /* Try to acquire write access. */
+ prevcnt = isc_atomic_cmpxchg(&rwl->cnt_and_flag,
+ READER_INCR, WRITER_ACTIVE);
+ /*
+ * There must have been no writer, and there must have been at least
+ * one reader.
+ */
+ INSIST((prevcnt & WRITER_ACTIVE) == 0 &&
+ (prevcnt & ~WRITER_ACTIVE) != 0);
+
+ if (prevcnt == READER_INCR) {
+ /*
+ * We are the only reader and have been upgraded.
+ * Now jump into the head of the writer waiting queue.
+ */
+ (void)isc_atomic_xadd(&rwl->write_completions, -1);
+ } else
+ return (ISC_R_LOCKBUSY);
+
+ return (ISC_R_SUCCESS);
+
+}
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl) {
+ isc_int32_t prev_readers;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+
+ /* Become an active reader. */
+ prev_readers = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+ /* We must have been a writer. */
+ INSIST((prev_readers & WRITER_ACTIVE) != 0);
+
+ /* Complete write */
+ (void)isc_atomic_xadd(&rwl->cnt_and_flag, -WRITER_ACTIVE);
+ (void)isc_atomic_xadd(&rwl->write_completions, 1);
+
+ /* Resume other readers */
+ LOCK(&rwl->lock);
+ if (rwl->readers_waiting > 0)
+ BROADCAST(&rwl->readable);
+ UNLOCK(&rwl->lock);
+}
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ isc_int32_t prev_cnt;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PREUNLOCK, "preunlock"), rwl, type);
+#endif
+
+ if (type == isc_rwlocktype_read) {
+ prev_cnt = isc_atomic_xadd(&rwl->cnt_and_flag, -READER_INCR);
+
+ /*
+ * If we're the last reader and any writers are waiting, wake
+ * them up. We need to wake up all of them to ensure the
+ * FIFO order.
+ */
+ if (prev_cnt == READER_INCR &&
+ rwl->write_completions != rwl->write_requests) {
+ LOCK(&rwl->lock);
+ BROADCAST(&rwl->writeable);
+ UNLOCK(&rwl->lock);
+ }
+ } else {
+ isc_boolean_t wakeup_writers = ISC_TRUE;
+
+ /*
+ * Reset the flag, and (implicitly) tell other writers
+ * we are done.
+ */
+ (void)isc_atomic_xadd(&rwl->cnt_and_flag, -WRITER_ACTIVE);
+ (void)isc_atomic_xadd(&rwl->write_completions, 1);
+
+ if (rwl->write_granted >= rwl->write_quota ||
+ rwl->write_requests == rwl->write_completions ||
+ (rwl->cnt_and_flag & ~WRITER_ACTIVE) != 0) {
+ /*
+ * We have passed the write quota, no writer is
+ * waiting, or some readers are almost ready, pending
+ * possible writers. Note that the last case can
+ * happen even if write_requests != write_completions
+ * (which means a new writer in the queue), so we need
+ * to catch the case explicitly.
+ */
+ LOCK(&rwl->lock);
+ if (rwl->readers_waiting > 0) {
+ wakeup_writers = ISC_FALSE;
+ BROADCAST(&rwl->readable);
+ }
+ UNLOCK(&rwl->lock);
+ }
+
+ if (rwl->write_requests != rwl->write_completions &&
+ wakeup_writers) {
+ LOCK(&rwl->lock);
+ BROADCAST(&rwl->writeable);
+ UNLOCK(&rwl->lock);
+ }
+ }
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_POSTUNLOCK, "postunlock"),
+ rwl, type);
+#endif
+
+ return (ISC_R_SUCCESS);
+}
+
+#else /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+
+static isc_result_t
+doit(isc_rwlock_t *rwl, isc_rwlocktype_t type, isc_boolean_t nonblock) {
+ isc_boolean_t skip = ISC_FALSE;
+ isc_boolean_t done = ISC_FALSE;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+
+ LOCK(&rwl->lock);
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PRELOCK, "prelock"), rwl, type);
+#endif
+
+ if (type == isc_rwlocktype_read) {
+ if (rwl->readers_waiting != 0)
+ skip = ISC_TRUE;
+ while (!done) {
+ if (!skip &&
+ ((rwl->active == 0 ||
+ (rwl->type == isc_rwlocktype_read &&
+ (rwl->writers_waiting == 0 ||
+ rwl->granted < rwl->read_quota)))))
+ {
+ rwl->type = isc_rwlocktype_read;
+ rwl->active++;
+ rwl->granted++;
+ done = ISC_TRUE;
+ } else if (nonblock) {
+ result = ISC_R_LOCKBUSY;
+ done = ISC_TRUE;
+ } else {
+ skip = ISC_FALSE;
+ rwl->readers_waiting++;
+ WAIT(&rwl->readable, &rwl->lock);
+ rwl->readers_waiting--;
+ }
+ }
+ } else {
+ if (rwl->writers_waiting != 0)
+ skip = ISC_TRUE;
+ while (!done) {
+ if (!skip && rwl->active == 0) {
+ rwl->type = isc_rwlocktype_write;
+ rwl->active = 1;
+ rwl->granted++;
+ done = ISC_TRUE;
+ } else if (nonblock) {
+ result = ISC_R_LOCKBUSY;
+ done = ISC_TRUE;
+ } else {
+ skip = ISC_FALSE;
+ rwl->writers_waiting++;
+ WAIT(&rwl->writeable, &rwl->lock);
+ rwl->writers_waiting--;
+ }
+ }
+ }
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_POSTLOCK, "postlock"), rwl, type);
+#endif
+
+ UNLOCK(&rwl->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ return (doit(rwl, type, ISC_FALSE));
+}
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ return (doit(rwl, type, ISC_TRUE));
+}
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+ LOCK(&rwl->lock);
+ REQUIRE(rwl->type == isc_rwlocktype_read);
+ REQUIRE(rwl->active != 0);
+
+ /* If we are the only reader then succeed. */
+ if (rwl->active == 1) {
+ rwl->original = (rwl->original == isc_rwlocktype_none) ?
+ isc_rwlocktype_read : isc_rwlocktype_none;
+ rwl->type = isc_rwlocktype_write;
+ } else
+ result = ISC_R_LOCKBUSY;
+
+ UNLOCK(&rwl->lock);
+ return (result);
+}
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl) {
+
+ REQUIRE(VALID_RWLOCK(rwl));
+ LOCK(&rwl->lock);
+ REQUIRE(rwl->type == isc_rwlocktype_write);
+ REQUIRE(rwl->active == 1);
+
+ rwl->type = isc_rwlocktype_read;
+ rwl->original = (rwl->original == isc_rwlocktype_none) ?
+ isc_rwlocktype_write : isc_rwlocktype_none;
+ /*
+ * Resume processing any read request that were blocked when
+ * we upgraded.
+ */
+ if (rwl->original == isc_rwlocktype_none &&
+ (rwl->writers_waiting == 0 || rwl->granted < rwl->read_quota) &&
+ rwl->readers_waiting > 0)
+ BROADCAST(&rwl->readable);
+
+ UNLOCK(&rwl->lock);
+}
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+
+ REQUIRE(VALID_RWLOCK(rwl));
+ LOCK(&rwl->lock);
+ REQUIRE(rwl->type == type);
+
+ UNUSED(type);
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PREUNLOCK, "preunlock"), rwl, type);
+#endif
+
+ INSIST(rwl->active > 0);
+ rwl->active--;
+ if (rwl->active == 0) {
+ if (rwl->original != isc_rwlocktype_none) {
+ rwl->type = rwl->original;
+ rwl->original = isc_rwlocktype_none;
+ }
+ if (rwl->type == isc_rwlocktype_read) {
+ rwl->granted = 0;
+ if (rwl->writers_waiting > 0) {
+ rwl->type = isc_rwlocktype_write;
+ SIGNAL(&rwl->writeable);
+ } else if (rwl->readers_waiting > 0) {
+ /* Does this case ever happen? */
+ BROADCAST(&rwl->readable);
+ }
+ } else {
+ if (rwl->readers_waiting > 0) {
+ if (rwl->writers_waiting > 0 &&
+ rwl->granted < rwl->write_quota) {
+ SIGNAL(&rwl->writeable);
+ } else {
+ rwl->granted = 0;
+ rwl->type = isc_rwlocktype_read;
+ BROADCAST(&rwl->readable);
+ }
+ } else if (rwl->writers_waiting > 0) {
+ rwl->granted = 0;
+ SIGNAL(&rwl->writeable);
+ } else {
+ rwl->granted = 0;
+ }
+ }
+ }
+ INSIST(rwl->original == isc_rwlocktype_none);
+
+#ifdef ISC_RWLOCK_TRACE
+ print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_POSTUNLOCK, "postunlock"),
+ rwl, type);
+#endif
+
+ UNLOCK(&rwl->lock);
+
+ return (ISC_R_SUCCESS);
+}
+
+#endif /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+#else /* ISC_PLATFORM_USETHREADS */
+
+isc_result_t
+isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
+ unsigned int write_quota)
+{
+ REQUIRE(rwl != NULL);
+
+ UNUSED(read_quota);
+ UNUSED(write_quota);
+
+ rwl->type = isc_rwlocktype_read;
+ rwl->active = 0;
+ rwl->magic = RWLOCK_MAGIC;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ REQUIRE(VALID_RWLOCK(rwl));
+
+ if (type == isc_rwlocktype_read) {
+ if (rwl->type != isc_rwlocktype_read && rwl->active != 0)
+ return (ISC_R_LOCKBUSY);
+ rwl->type = isc_rwlocktype_read;
+ rwl->active++;
+ } else {
+ if (rwl->active != 0)
+ return (ISC_R_LOCKBUSY);
+ rwl->type = isc_rwlocktype_write;
+ rwl->active = 1;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ return (isc_rwlock_lock(rwl, type));
+}
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_RWLOCK(rwl));
+ REQUIRE(rwl->type == isc_rwlocktype_read);
+ REQUIRE(rwl->active != 0);
+
+ /* If we are the only reader then succeed. */
+ if (rwl->active == 1)
+ rwl->type = isc_rwlocktype_write;
+ else
+ result = ISC_R_LOCKBUSY;
+ return (result);
+}
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl) {
+
+ REQUIRE(VALID_RWLOCK(rwl));
+ REQUIRE(rwl->type == isc_rwlocktype_write);
+ REQUIRE(rwl->active == 1);
+
+ rwl->type = isc_rwlocktype_read;
+}
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+ REQUIRE(VALID_RWLOCK(rwl));
+ REQUIRE(rwl->type == type);
+
+ UNUSED(type);
+
+ INSIST(rwl->active > 0);
+ rwl->active--;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_rwlock_destroy(isc_rwlock_t *rwl) {
+ REQUIRE(rwl != NULL);
+ REQUIRE(rwl->active == 0);
+ rwl->magic = 0;
+}
+
+#endif /* ISC_PLATFORM_USETHREADS */
diff --git a/lib/isc/serial.c b/lib/isc/serial.c
new file mode 100644
index 0000000..5d1bde7
--- /dev/null
+++ b/lib/isc/serial.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004, 2005 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: serial.c,v 1.8.18.2 2005/04/29 00:16:49 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/serial.h>
+
+isc_boolean_t
+isc_serial_lt(isc_uint32_t a, isc_uint32_t b) {
+ /*
+ * Undefined => ISC_FALSE
+ */
+ if (a == (b ^ 0x80000000U))
+ return (ISC_FALSE);
+ return (((isc_int32_t)(a - b) < 0) ? ISC_TRUE : ISC_FALSE);
+}
+
+isc_boolean_t
+isc_serial_gt(isc_uint32_t a, isc_uint32_t b) {
+ return (((isc_int32_t)(a - b) > 0) ? ISC_TRUE : ISC_FALSE);
+}
+
+isc_boolean_t
+isc_serial_le(isc_uint32_t a, isc_uint32_t b) {
+ return ((a == b) ? ISC_TRUE : isc_serial_lt(a, b));
+}
+
+isc_boolean_t
+isc_serial_ge(isc_uint32_t a, isc_uint32_t b) {
+ return ((a == b) ? ISC_TRUE : isc_serial_gt(a, b));
+}
+
+isc_boolean_t
+isc_serial_eq(isc_uint32_t a, isc_uint32_t b) {
+ return ((a == b) ? ISC_TRUE : ISC_FALSE);
+}
+
+isc_boolean_t
+isc_serial_ne(isc_uint32_t a, isc_uint32_t b) {
+ return ((a != b) ? ISC_TRUE : ISC_FALSE);
+}
diff --git a/lib/isc/sha1.c b/lib/isc/sha1.c
new file mode 100644
index 0000000..6f4af6d
--- /dev/null
+++ b/lib/isc/sha1.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2004, 2005 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: sha1.c,v 1.14.18.2 2005/04/29 00:16:49 marka Exp $ */
+
+/* $NetBSD: sha1.c,v 1.5 2000/01/22 22:19:14 mycroft Exp $ */
+/* $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $ */
+
+/*! \file
+ * SHA-1 in C
+ * \author By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ * \verbatim
+ * Test Vectors (from FIPS PUB 180-1)
+ * "abc"
+ * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+ * A million repetitions of "a"
+ * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+ * \endverbatim
+ */
+
+#include "config.h"
+
+#include <isc/assertions.h>
+#include <isc/sha1.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/*@{*/
+/*!
+ * blk0() and blk() perform the initial expand.
+ * I got the idea of expanding during the round function from SSLeay
+ */
+#if !defined(WORDS_BIGENDIAN)
+# define blk0(i) \
+ (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) \
+ | (rol(block->l[i], 8) & 0x00FF00FF))
+#else
+# define blk0(i) block->l[i]
+#endif
+#define blk(i) \
+ (block->l[i & 15] = rol(block->l[(i + 13) & 15] \
+ ^ block->l[(i + 8) & 15] \
+ ^ block->l[(i + 2) & 15] \
+ ^ block->l[i & 15], 1))
+
+/*@}*/
+/*@{*/
+/*!
+ * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
+ */
+#define R0(v,w,x,y,z,i) \
+ z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
+ w = rol(w, 30);
+#define R1(v,w,x,y,z,i) \
+ z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
+ w = rol(w, 30);
+#define R2(v,w,x,y,z,i) \
+ z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
+ w = rol(w, 30);
+#define R3(v,w,x,y,z,i) \
+ z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
+ w = rol(w, 30);
+#define R4(v,w,x,y,z,i) \
+ z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
+ w = rol(w, 30);
+
+/*@}*/
+
+typedef union {
+ unsigned char c[64];
+ unsigned int l[16];
+} CHAR64LONG16;
+
+#ifdef __sparc_v9__
+static void do_R01(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c,
+ isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *);
+static void do_R2(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c,
+ isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *);
+static void do_R3(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c,
+ isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *);
+static void do_R4(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c,
+ isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *);
+
+#define nR0(v,w,x,y,z,i) R0(*v,*w,*x,*y,*z,i)
+#define nR1(v,w,x,y,z,i) R1(*v,*w,*x,*y,*z,i)
+#define nR2(v,w,x,y,z,i) R2(*v,*w,*x,*y,*z,i)
+#define nR3(v,w,x,y,z,i) R3(*v,*w,*x,*y,*z,i)
+#define nR4(v,w,x,y,z,i) R4(*v,*w,*x,*y,*z,i)
+
+static void
+do_R01(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d,
+ isc_uint32_t *e, CHAR64LONG16 *block)
+{
+ nR0(a,b,c,d,e, 0); nR0(e,a,b,c,d, 1); nR0(d,e,a,b,c, 2);
+ nR0(c,d,e,a,b, 3); nR0(b,c,d,e,a, 4); nR0(a,b,c,d,e, 5);
+ nR0(e,a,b,c,d, 6); nR0(d,e,a,b,c, 7); nR0(c,d,e,a,b, 8);
+ nR0(b,c,d,e,a, 9); nR0(a,b,c,d,e,10); nR0(e,a,b,c,d,11);
+ nR0(d,e,a,b,c,12); nR0(c,d,e,a,b,13); nR0(b,c,d,e,a,14);
+ nR0(a,b,c,d,e,15); nR1(e,a,b,c,d,16); nR1(d,e,a,b,c,17);
+ nR1(c,d,e,a,b,18); nR1(b,c,d,e,a,19);
+}
+
+static void
+do_R2(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d,
+ isc_uint32_t *e, CHAR64LONG16 *block)
+{
+ nR2(a,b,c,d,e,20); nR2(e,a,b,c,d,21); nR2(d,e,a,b,c,22);
+ nR2(c,d,e,a,b,23); nR2(b,c,d,e,a,24); nR2(a,b,c,d,e,25);
+ nR2(e,a,b,c,d,26); nR2(d,e,a,b,c,27); nR2(c,d,e,a,b,28);
+ nR2(b,c,d,e,a,29); nR2(a,b,c,d,e,30); nR2(e,a,b,c,d,31);
+ nR2(d,e,a,b,c,32); nR2(c,d,e,a,b,33); nR2(b,c,d,e,a,34);
+ nR2(a,b,c,d,e,35); nR2(e,a,b,c,d,36); nR2(d,e,a,b,c,37);
+ nR2(c,d,e,a,b,38); nR2(b,c,d,e,a,39);
+}
+
+static void
+do_R3(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d,
+ isc_uint32_t *e, CHAR64LONG16 *block)
+{
+ nR3(a,b,c,d,e,40); nR3(e,a,b,c,d,41); nR3(d,e,a,b,c,42);
+ nR3(c,d,e,a,b,43); nR3(b,c,d,e,a,44); nR3(a,b,c,d,e,45);
+ nR3(e,a,b,c,d,46); nR3(d,e,a,b,c,47); nR3(c,d,e,a,b,48);
+ nR3(b,c,d,e,a,49); nR3(a,b,c,d,e,50); nR3(e,a,b,c,d,51);
+ nR3(d,e,a,b,c,52); nR3(c,d,e,a,b,53); nR3(b,c,d,e,a,54);
+ nR3(a,b,c,d,e,55); nR3(e,a,b,c,d,56); nR3(d,e,a,b,c,57);
+ nR3(c,d,e,a,b,58); nR3(b,c,d,e,a,59);
+}
+
+static void
+do_R4(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d,
+ isc_uint32_t *e, CHAR64LONG16 *block)
+{
+ nR4(a,b,c,d,e,60); nR4(e,a,b,c,d,61); nR4(d,e,a,b,c,62);
+ nR4(c,d,e,a,b,63); nR4(b,c,d,e,a,64); nR4(a,b,c,d,e,65);
+ nR4(e,a,b,c,d,66); nR4(d,e,a,b,c,67); nR4(c,d,e,a,b,68);
+ nR4(b,c,d,e,a,69); nR4(a,b,c,d,e,70); nR4(e,a,b,c,d,71);
+ nR4(d,e,a,b,c,72); nR4(c,d,e,a,b,73); nR4(b,c,d,e,a,74);
+ nR4(a,b,c,d,e,75); nR4(e,a,b,c,d,76); nR4(d,e,a,b,c,77);
+ nR4(c,d,e,a,b,78); nR4(b,c,d,e,a,79);
+}
+#endif
+
+/*!
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ */
+static void
+transform(isc_uint32_t state[5], const unsigned char buffer[64]) {
+ isc_uint32_t a, b, c, d, e;
+ CHAR64LONG16 *block;
+ CHAR64LONG16 workspace;
+
+ INSIST(buffer != NULL);
+ INSIST(state != NULL);
+
+ block = &workspace;
+ (void)memcpy(block, buffer, 64);
+
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+#ifdef __sparc_v9__
+ do_R01(&a, &b, &c, &d, &e, block);
+ do_R2(&a, &b, &c, &d, &e, block);
+ do_R3(&a, &b, &c, &d, &e, block);
+ do_R4(&a, &b, &c, &d, &e, block);
+#else
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+#endif
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/*!
+ * isc_sha1_init - Initialize new context
+ */
+void
+isc_sha1_init(isc_sha1_t *context)
+{
+ INSIST(context != NULL);
+
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = 0;
+ context->count[1] = 0;
+}
+
+void
+isc_sha1_invalidate(isc_sha1_t *context) {
+ memset(context, 0, sizeof(isc_sha1_t));
+}
+
+/*!
+ * Run your data through this.
+ */
+void
+isc_sha1_update(isc_sha1_t *context, const unsigned char *data,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ INSIST(context != 0);
+ INSIST(data != 0);
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1] += (len >> 29) + 1;
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ (void)memcpy(&context->buffer[j], data, (i = 64 - j));
+ transform(context->state, context->buffer);
+ for (; i + 63 < len; i += 64)
+ transform(context->state, &data[i]);
+ j = 0;
+ } else {
+ i = 0;
+ }
+
+ (void)memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/*!
+ * Add padding and return the message digest.
+ */
+
+static const unsigned char final_200 = 128;
+static const unsigned char final_0 = 0;
+
+void
+isc_sha1_final(isc_sha1_t *context, unsigned char *digest) {
+ unsigned int i;
+ unsigned char finalcount[8];
+
+ INSIST(digest != 0);
+ INSIST(context != 0);
+
+ for (i = 0; i < 8; i++) {
+ /* Endian independent */
+ finalcount[i] = (unsigned char)
+ ((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3 - (i & 3)) * 8)) & 255);
+ }
+
+ isc_sha1_update(context, &final_200, 1);
+ while ((context->count[0] & 504) != 448)
+ isc_sha1_update(context, &final_0, 1);
+ /* The next Update should cause a transform() */
+ isc_sha1_update(context, finalcount, 8);
+
+ if (digest) {
+ for (i = 0; i < 20; i++)
+ digest[i] = (unsigned char)
+ ((context->state[i >> 2]
+ >> ((3 - (i & 3)) * 8)) & 255);
+ }
+
+ memset(context, 0, sizeof(isc_sha1_t));
+}
diff --git a/lib/isc/sha2.c b/lib/isc/sha2.c
new file mode 100644
index 0000000..7b41a28
--- /dev/null
+++ b/lib/isc/sha2.c
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (C) 2005, 2006 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: sha2.c,v 1.2.2.12 2006/08/16 03:18:14 marka Exp $ */
+
+/* $FreeBSD$ */
+/* $KAME: sha2.c,v 1.8 2001/11/08 01:07:52 itojun Exp $ */
+
+/*
+ * sha2.c
+ *
+ * Version 1.0.0beta1
+ *
+ * Written by Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright 2000 Aaron D. Gifford. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+
+#include <config.h>
+
+#include <isc/assertions.h>
+#include <isc/sha2.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/*
+ * UNROLLED TRANSFORM LOOP NOTE:
+ * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
+ * loop version for the hash transform rounds (defined using macros
+ * later in this file). Either define on the command line, for example:
+ *
+ * cc -DISC_SHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
+ *
+ * or define below:
+ *
+ * #define ISC_SHA2_UNROLL_TRANSFORM
+ *
+ */
+
+/*** SHA-256/384/512 Machine Architecture Definitions *****************/
+/*
+ * BYTE_ORDER NOTE:
+ *
+ * Please make sure that your system defines BYTE_ORDER. If your
+ * architecture is little-endian, make sure it also defines
+ * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
+ * equivilent.
+ *
+ * If your system does not define the above, then you can do so by
+ * hand like this:
+ *
+ * #define LITTLE_ENDIAN 1234
+ * #define BIG_ENDIAN 4321
+ *
+ * And for little-endian machines, add:
+ *
+ * #define BYTE_ORDER LITTLE_ENDIAN
+ *
+ * Or for big-endian machines:
+ *
+ * #define BYTE_ORDER BIG_ENDIAN
+ *
+ * The FreeBSD machine this was written on defines BYTE_ORDER
+ * appropriately by including <sys/types.h> (which in turn includes
+ * <machine/endian.h> where the appropriate definitions are actually
+ * made).
+ */
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)
+#ifndef BYTE_ORDER
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+#ifdef WORDS_BIGENDIAN
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#else
+#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN
+#endif
+#endif
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+/* NOTE: Most of these are in sha2.h */
+#define ISC_SHA256_SHORT_BLOCK_LENGTH (ISC_SHA256_BLOCK_LENGTH - 8)
+#define ISC_SHA384_SHORT_BLOCK_LENGTH (ISC_SHA384_BLOCK_LENGTH - 16)
+#define ISC_SHA512_SHORT_BLOCK_LENGTH (ISC_SHA512_BLOCK_LENGTH - 16)
+
+
+/*** ENDIAN REVERSAL MACROS *******************************************/
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define REVERSE32(w,x) { \
+ isc_uint32_t tmp = (w); \
+ tmp = (tmp >> 16) | (tmp << 16); \
+ (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
+}
+#ifdef WIN32
+#define REVERSE64(w,x) { \
+ isc_uint64_t tmp = (w); \
+ tmp = (tmp >> 32) | (tmp << 32); \
+ tmp = ((tmp & 0xff00ff00ff00ff00UL) >> 8) | \
+ ((tmp & 0x00ff00ff00ff00ffUL) << 8); \
+ (x) = ((tmp & 0xffff0000ffff0000UL) >> 16) | \
+ ((tmp & 0x0000ffff0000ffffUL) << 16); \
+}
+#else
+#define REVERSE64(w,x) { \
+ isc_uint64_t tmp = (w); \
+ tmp = (tmp >> 32) | (tmp << 32); \
+ tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
+ ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
+ (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
+ ((tmp & 0x0000ffff0000ffffULL) << 16); \
+}
+#endif
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) { \
+ (w)[0] += (isc_uint64_t)(n); \
+ if ((w)[0] < (n)) { \
+ (w)[1]++; \
+ } \
+}
+
+/*** THE SIX LOGICAL FUNCTIONS ****************************************/
+/*
+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
+ *
+ * NOTE: The naming of R and S appears backwards here (R is a SHIFT and
+ * S is a ROTATION) because the SHA-256/384/512 description document
+ * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
+ * same "backwards" definition.
+ */
+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
+#define R(b,x) ((x) >> (b))
+/* 32-bit Rotate-right (used in SHA-256): */
+#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
+#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b))))
+
+/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
+#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+/* Four of six logical functions used in SHA-256: */
+#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x)))
+#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x)))
+#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
+#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
+
+/* Four of six logical functions used in SHA-384 and SHA-512: */
+#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
+#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
+#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x)))
+#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x)))
+
+/*** INTERNAL FUNCTION PROTOTYPES *************************************/
+/* NOTE: These should not be accessed directly from outside this
+ * library -- they are intended for private internal visibility/use
+ * only.
+ */
+void isc_sha512_last(isc_sha512_t *);
+void isc_sha256_transform(isc_sha256_t *, const isc_uint32_t*);
+void isc_sha512_transform(isc_sha512_t *, const isc_uint64_t*);
+
+
+/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
+/* Hash constant words K for SHA-224 and SHA-256: */
+static const isc_uint32_t K256[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+ 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+ 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+ 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+ 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+ 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+ 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+ 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+ 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+ 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+ 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+ 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+ 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Initial hash value H for SHA-224: */
+static const isc_uint32_t sha224_initial_hash_value[8] = {
+ 0xc1059ed8UL,
+ 0x367cd507UL,
+ 0x3070dd17UL,
+ 0xf70e5939UL,
+ 0xffc00b31UL,
+ 0x68581511UL,
+ 0x64f98fa7UL,
+ 0xbefa4fa4UL
+};
+
+/* Initial hash value H for SHA-256: */
+static const isc_uint32_t sha256_initial_hash_value[8] = {
+ 0x6a09e667UL,
+ 0xbb67ae85UL,
+ 0x3c6ef372UL,
+ 0xa54ff53aUL,
+ 0x510e527fUL,
+ 0x9b05688cUL,
+ 0x1f83d9abUL,
+ 0x5be0cd19UL
+};
+
+#ifdef WIN32
+/* Hash constant words K for SHA-384 and SHA-512: */
+static const isc_uint64_t K512[80] = {
+ 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL,
+ 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL,
+ 0x3956c25bf348b538UL, 0x59f111f1b605d019UL,
+ 0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL,
+ 0xd807aa98a3030242UL, 0x12835b0145706fbeUL,
+ 0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL,
+ 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL,
+ 0x9bdc06a725c71235UL, 0xc19bf174cf692694UL,
+ 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL,
+ 0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL,
+ 0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL,
+ 0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL,
+ 0x983e5152ee66dfabUL, 0xa831c66d2db43210UL,
+ 0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL,
+ 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL,
+ 0x06ca6351e003826fUL, 0x142929670a0e6e70UL,
+ 0x27b70a8546d22ffcUL, 0x2e1b21385c26c926UL,
+ 0x4d2c6dfc5ac42aedUL, 0x53380d139d95b3dfUL,
+ 0x650a73548baf63deUL, 0x766a0abb3c77b2a8UL,
+ 0x81c2c92e47edaee6UL, 0x92722c851482353bUL,
+ 0xa2bfe8a14cf10364UL, 0xa81a664bbc423001UL,
+ 0xc24b8b70d0f89791UL, 0xc76c51a30654be30UL,
+ 0xd192e819d6ef5218UL, 0xd69906245565a910UL,
+ 0xf40e35855771202aUL, 0x106aa07032bbd1b8UL,
+ 0x19a4c116b8d2d0c8UL, 0x1e376c085141ab53UL,
+ 0x2748774cdf8eeb99UL, 0x34b0bcb5e19b48a8UL,
+ 0x391c0cb3c5c95a63UL, 0x4ed8aa4ae3418acbUL,
+ 0x5b9cca4f7763e373UL, 0x682e6ff3d6b2b8a3UL,
+ 0x748f82ee5defb2fcUL, 0x78a5636f43172f60UL,
+ 0x84c87814a1f0ab72UL, 0x8cc702081a6439ecUL,
+ 0x90befffa23631e28UL, 0xa4506cebde82bde9UL,
+ 0xbef9a3f7b2c67915UL, 0xc67178f2e372532bUL,
+ 0xca273eceea26619cUL, 0xd186b8c721c0c207UL,
+ 0xeada7dd6cde0eb1eUL, 0xf57d4f7fee6ed178UL,
+ 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL,
+ 0x113f9804bef90daeUL, 0x1b710b35131c471bUL,
+ 0x28db77f523047d84UL, 0x32caab7b40c72493UL,
+ 0x3c9ebe0a15c9bebcUL, 0x431d67c49c100d4cUL,
+ 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL,
+ 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL
+};
+
+/* Initial hash value H for SHA-384: */
+static const isc_uint64_t sha384_initial_hash_value[8] = {
+ 0xcbbb9d5dc1059ed8UL,
+ 0x629a292a367cd507UL,
+ 0x9159015a3070dd17UL,
+ 0x152fecd8f70e5939UL,
+ 0x67332667ffc00b31UL,
+ 0x8eb44a8768581511UL,
+ 0xdb0c2e0d64f98fa7UL,
+ 0x47b5481dbefa4fa4UL
+};
+
+/* Initial hash value H for SHA-512: */
+static const isc_uint64_t sha512_initial_hash_value[8] = {
+ 0x6a09e667f3bcc908U,
+ 0xbb67ae8584caa73bUL,
+ 0x3c6ef372fe94f82bUL,
+ 0xa54ff53a5f1d36f1UL,
+ 0x510e527fade682d1UL,
+ 0x9b05688c2b3e6c1fUL,
+ 0x1f83d9abfb41bd6bUL,
+ 0x5be0cd19137e2179UL
+};
+#else
+/* Hash constant words K for SHA-384 and SHA-512: */
+static const isc_uint64_t K512[80] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+ 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+ 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+ 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+ 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+ 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+ 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+ 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+ 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+ 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+ 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+ 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+ 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+ 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+ 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+ 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+ 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+ 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+ 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+ 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+ 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+ 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+ 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+ 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+ 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+ 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+ 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/* Initial hash value H for SHA-384: */
+static const isc_uint64_t sha384_initial_hash_value[8] = {
+ 0xcbbb9d5dc1059ed8ULL,
+ 0x629a292a367cd507ULL,
+ 0x9159015a3070dd17ULL,
+ 0x152fecd8f70e5939ULL,
+ 0x67332667ffc00b31ULL,
+ 0x8eb44a8768581511ULL,
+ 0xdb0c2e0d64f98fa7ULL,
+ 0x47b5481dbefa4fa4ULL
+};
+
+/* Initial hash value H for SHA-512: */
+static const isc_uint64_t sha512_initial_hash_value[8] = {
+ 0x6a09e667f3bcc908ULL,
+ 0xbb67ae8584caa73bULL,
+ 0x3c6ef372fe94f82bULL,
+ 0xa54ff53a5f1d36f1ULL,
+ 0x510e527fade682d1ULL,
+ 0x9b05688c2b3e6c1fULL,
+ 0x1f83d9abfb41bd6bULL,
+ 0x5be0cd19137e2179ULL
+};
+#endif
+
+/*
+ * Constant used by SHA256/384/512_End() functions for converting the
+ * digest to a readable hexadecimal character string:
+ */
+static const char *sha2_hex_digits = "0123456789abcdef";
+
+
+
+/*** SHA-224: *********************************************************/
+void
+isc_sha224_init(isc_sha224_t *context) {
+ if (context == (isc_sha256_t *)0) {
+ return;
+ }
+ memcpy(context->state, sha224_initial_hash_value,
+ ISC_SHA256_DIGESTLENGTH);
+ memset(context->buffer, 0, ISC_SHA256_BLOCK_LENGTH);
+ context->bitcount = 0;
+}
+
+void
+isc_sha224_update(isc_sha224_t *context, const isc_uint8_t* data, size_t len) {
+ isc_sha256_update((isc_sha256_t *)context, data, len);
+}
+
+void
+isc_sha224_final(isc_uint8_t digest[], isc_sha224_t *context) {
+ isc_uint8_t sha256_digest[ISC_SHA256_DIGESTLENGTH];
+ isc_sha256_final(sha256_digest, (isc_sha256_t *)context);
+ memcpy(digest, sha256_digest, ISC_SHA224_DIGESTLENGTH);
+ memset(sha256_digest, 0, ISC_SHA256_DIGESTLENGTH);
+}
+
+char *
+isc_sha224_end(isc_sha224_t *context, char buffer[]) {
+ isc_uint8_t digest[ISC_SHA224_DIGESTLENGTH], *d = digest;
+ unsigned int i;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha224_t *)0);
+
+ if (buffer != (char*)0) {
+ isc_sha224_final(digest, context);
+
+ for (i = 0; i < ISC_SHA224_DIGESTLENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ memset(context, 0, sizeof(context));
+ }
+ memset(digest, 0, ISC_SHA224_DIGESTLENGTH);
+ return buffer;
+}
+
+char*
+isc_sha224_data(const isc_uint8_t *data, size_t len,
+ char digest[ISC_SHA224_DIGESTSTRINGLENGTH])
+{
+ isc_sha224_t context;
+
+ isc_sha224_init(&context);
+ isc_sha224_update(&context, data, len);
+ return (isc_sha224_end(&context, digest));
+}
+
+/*** SHA-256: *********************************************************/
+void
+isc_sha256_init(isc_sha256_t *context) {
+ if (context == (isc_sha256_t *)0) {
+ return;
+ }
+ memcpy(context->state, sha256_initial_hash_value,
+ ISC_SHA256_DIGESTLENGTH);
+ memset(context->buffer, 0, ISC_SHA256_BLOCK_LENGTH);
+ context->bitcount = 0;
+}
+
+#ifdef ISC_SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-256 round macros: */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ REVERSE32(*data++, W256[j]); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + W256[j]; \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + (W256[j] = *data++); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256(a,b,c,d,e,f,g,h) \
+ s0 = W256[(j+1)&0x0f]; \
+ s0 = sigma0_256(s0); \
+ s1 = W256[(j+14)&0x0f]; \
+ s1 = sigma1_256(s1); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+void isc_sha256_transform(isc_sha256_t *context, const isc_uint32_t* data) {
+ isc_uint32_t a, b, c, d, e, f, g, h, s0, s1;
+ isc_uint32_t T1, *W256;
+ int j;
+
+ W256 = (isc_uint32_t*)context->buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+ /* Rounds 0 to 15 (unrolled): */
+ ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
+ ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
+ ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
+ ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
+ ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
+ ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
+ ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
+ ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
+ } while (j < 16);
+
+ /* Now for the remaining rounds to 64: */
+ do {
+ ROUND256(a,b,c,d,e,f,g,h);
+ ROUND256(h,a,b,c,d,e,f,g);
+ ROUND256(g,h,a,b,c,d,e,f);
+ ROUND256(f,g,h,a,b,c,d,e);
+ ROUND256(e,f,g,h,a,b,c,d);
+ ROUND256(d,e,f,g,h,a,b,c);
+ ROUND256(c,d,e,f,g,h,a,b);
+ ROUND256(b,c,d,e,f,g,h,a);
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void
+isc_sha256_transform(isc_sha256_t *context, const isc_uint32_t* data) {
+ isc_uint32_t a, b, c, d, e, f, g, h, s0, s1;
+ isc_uint32_t T1, T2, *W256;
+ int j;
+
+ W256 = (isc_uint32_t*)context->buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Copy data while converting to host byte order */
+ REVERSE32(*data++,W256[j]);
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+ /* Apply the SHA-256 compression function to update a..h with copy */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W256[(j+1)&0x0f];
+ s0 = sigma0_256(s0);
+ s1 = W256[(j+14)&0x0f];
+ s1 = sigma1_256(s1);
+
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void
+isc_sha256_update(isc_sha256_t *context, const isc_uint8_t *data, size_t len) {
+ unsigned int freespace, usedspace;
+
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha256_t *)0 && data != (isc_uint8_t*)0);
+
+ usedspace = (unsigned int)((context->bitcount >> 3) %
+ ISC_SHA256_BLOCK_LENGTH);
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = ISC_SHA256_BLOCK_LENGTH - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ memcpy(&context->buffer[usedspace], data, freespace);
+ context->bitcount += freespace << 3;
+ len -= freespace;
+ data += freespace;
+ isc_sha256_transform(context,
+ (isc_uint32_t*)context->buffer);
+ } else {
+ /* The buffer is not yet full */
+ memcpy(&context->buffer[usedspace], data, len);
+ context->bitcount += len << 3;
+ /* Clean up: */
+ usedspace = freespace = 0;
+ return;
+ }
+ }
+ while (len >= ISC_SHA256_BLOCK_LENGTH) {
+ /* Process as many complete blocks as we can */
+ memcpy(context->buffer, data, ISC_SHA256_BLOCK_LENGTH);
+ isc_sha256_transform(context, (isc_uint32_t*)context->buffer);
+ context->bitcount += ISC_SHA256_BLOCK_LENGTH << 3;
+ len -= ISC_SHA256_BLOCK_LENGTH;
+ data += ISC_SHA256_BLOCK_LENGTH;
+ }
+ if (len > 0U) {
+ /* There's left-overs, so save 'em */
+ memcpy(context->buffer, data, len);
+ context->bitcount += len << 3;
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+}
+
+void
+isc_sha256_final(isc_uint8_t digest[], isc_sha256_t *context) {
+ isc_uint32_t *d = (isc_uint32_t*)digest;
+ unsigned int usedspace;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha256_t *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (isc_uint8_t*)0) {
+ usedspace = (unsigned int)((context->bitcount >> 3) %
+ ISC_SHA256_BLOCK_LENGTH);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->bitcount,context->bitcount);
+#endif
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->buffer[usedspace++] = 0x80;
+
+ if (usedspace <= ISC_SHA256_SHORT_BLOCK_LENGTH) {
+ /* Set-up for the last transform: */
+ memset(&context->buffer[usedspace], 0,
+ ISC_SHA256_SHORT_BLOCK_LENGTH - usedspace);
+ } else {
+ if (usedspace < ISC_SHA256_BLOCK_LENGTH) {
+ memset(&context->buffer[usedspace], 0,
+ ISC_SHA256_BLOCK_LENGTH -
+ usedspace);
+ }
+ /* Do second-to-last transform: */
+ isc_sha256_transform(context,
+ (isc_uint32_t*)context->buffer);
+
+ /* And set-up for the last transform: */
+ memset(context->buffer, 0,
+ ISC_SHA256_SHORT_BLOCK_LENGTH);
+ }
+ } else {
+ /* Set-up for the last transform: */
+ memset(context->buffer, 0, ISC_SHA256_SHORT_BLOCK_LENGTH);
+
+ /* Begin padding with a 1 bit: */
+ *context->buffer = 0x80;
+ }
+ /* Set the bit count: */
+ *(isc_uint64_t*)&context->buffer[ISC_SHA256_SHORT_BLOCK_LENGTH] = context->bitcount;
+
+ /* Final transform: */
+ isc_sha256_transform(context, (isc_uint32_t*)context->buffer);
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 8; j++) {
+ REVERSE32(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ memcpy(d, context->state, ISC_SHA256_DIGESTLENGTH);
+#endif
+ }
+
+ /* Clean up state data: */
+ memset(context, 0, sizeof(context));
+ usedspace = 0;
+}
+
+char *
+isc_sha256_end(isc_sha256_t *context, char buffer[]) {
+ isc_uint8_t digest[ISC_SHA256_DIGESTLENGTH], *d = digest;
+ unsigned int i;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha256_t *)0);
+
+ if (buffer != (char*)0) {
+ isc_sha256_final(digest, context);
+
+ for (i = 0; i < ISC_SHA256_DIGESTLENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ memset(context, 0, sizeof(context));
+ }
+ memset(digest, 0, ISC_SHA256_DIGESTLENGTH);
+ return buffer;
+}
+
+char *
+isc_sha256_data(const isc_uint8_t* data, size_t len,
+ char digest[ISC_SHA256_DIGESTSTRINGLENGTH])
+{
+ isc_sha256_t context;
+
+ isc_sha256_init(&context);
+ isc_sha256_update(&context, data, len);
+ return (isc_sha256_end(&context, digest));
+}
+
+
+/*** SHA-512: *********************************************************/
+void
+isc_sha512_init(isc_sha512_t *context) {
+ if (context == (isc_sha512_t *)0) {
+ return;
+ }
+ memcpy(context->state, sha512_initial_hash_value,
+ ISC_SHA512_DIGESTLENGTH);
+ memset(context->buffer, 0, ISC_SHA512_BLOCK_LENGTH);
+ context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+#ifdef ISC_SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-512 round macros: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
+ REVERSE64(*data++, W512[j]); \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+ K512[j] + W512[j]; \
+ (d) += T1, \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
+ j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+ K512[j] + (W512[j] = *data++); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+ j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512(a,b,c,d,e,f,g,h) \
+ s0 = W512[(j+1)&0x0f]; \
+ s0 = sigma0_512(s0); \
+ s1 = W512[(j+14)&0x0f]; \
+ s1 = sigma1_512(s1); \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+ j++
+
+void isc_sha512_transform(isc_sha512_t *context, const isc_uint64_t* data) {
+ isc_uint64_t a, b, c, d, e, f, g, h, s0, s1;
+ isc_uint64_t T1, *W512 = (isc_uint64_t*)context->buffer;
+ int j;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+ ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
+ ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
+ ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
+ ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
+ ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
+ ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
+ ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
+ ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
+ } while (j < 16);
+
+ /* Now for the remaining rounds up to 79: */
+ do {
+ ROUND512(a,b,c,d,e,f,g,h);
+ ROUND512(h,a,b,c,d,e,f,g);
+ ROUND512(g,h,a,b,c,d,e,f);
+ ROUND512(f,g,h,a,b,c,d,e);
+ ROUND512(e,f,g,h,a,b,c,d);
+ ROUND512(d,e,f,g,h,a,b,c);
+ ROUND512(c,d,e,f,g,h,a,b);
+ ROUND512(b,c,d,e,f,g,h,a);
+ } while (j < 80);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void
+isc_sha512_transform(isc_sha512_t *context, const isc_uint64_t* data) {
+ isc_uint64_t a, b, c, d, e, f, g, h, s0, s1;
+ isc_uint64_t T1, T2, *W512 = (isc_uint64_t*)context->buffer;
+ int j;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert TO host byte order */
+ REVERSE64(*data++, W512[j]);
+ /* Apply the SHA-512 compression function to update a..h */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+ /* Apply the SHA-512 compression function to update a..h with copy */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W512[(j+1)&0x0f];
+ s0 = sigma0_512(s0);
+ s1 = W512[(j+14)&0x0f];
+ s1 = sigma1_512(s1);
+
+ /* Apply the SHA-512 compression function to update a..h */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 80);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void isc_sha512_update(isc_sha512_t *context, const isc_uint8_t *data, size_t len) {
+ unsigned int freespace, usedspace;
+
+ if (len == 0U) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha512_t *)0 && data != (isc_uint8_t*)0);
+
+ usedspace = (unsigned int)((context->bitcount[0] >> 3) %
+ ISC_SHA512_BLOCK_LENGTH);
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = ISC_SHA512_BLOCK_LENGTH - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ memcpy(&context->buffer[usedspace], data, freespace);
+ ADDINC128(context->bitcount, freespace << 3);
+ len -= freespace;
+ data += freespace;
+ isc_sha512_transform(context,
+ (isc_uint64_t*)context->buffer);
+ } else {
+ /* The buffer is not yet full */
+ memcpy(&context->buffer[usedspace], data, len);
+ ADDINC128(context->bitcount, len << 3);
+ /* Clean up: */
+ usedspace = freespace = 0;
+ return;
+ }
+ }
+ while (len >= ISC_SHA512_BLOCK_LENGTH) {
+ /* Process as many complete blocks as we can */
+ memcpy(context->buffer, data, ISC_SHA512_BLOCK_LENGTH);
+ isc_sha512_transform(context, (isc_uint64_t*)context->buffer);
+ ADDINC128(context->bitcount, ISC_SHA512_BLOCK_LENGTH << 3);
+ len -= ISC_SHA512_BLOCK_LENGTH;
+ data += ISC_SHA512_BLOCK_LENGTH;
+ }
+ if (len > 0U) {
+ /* There's left-overs, so save 'em */
+ memcpy(context->buffer, data, len);
+ ADDINC128(context->bitcount, len << 3);
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+}
+
+void isc_sha512_last(isc_sha512_t *context) {
+ unsigned int usedspace;
+
+ usedspace = (unsigned int)((context->bitcount[0] >> 3) %
+ ISC_SHA512_BLOCK_LENGTH);
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->bitcount[0],context->bitcount[0]);
+ REVERSE64(context->bitcount[1],context->bitcount[1]);
+#endif
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->buffer[usedspace++] = 0x80;
+
+ if (usedspace <= ISC_SHA512_SHORT_BLOCK_LENGTH) {
+ /* Set-up for the last transform: */
+ memset(&context->buffer[usedspace], 0,
+ ISC_SHA512_SHORT_BLOCK_LENGTH - usedspace);
+ } else {
+ if (usedspace < ISC_SHA512_BLOCK_LENGTH) {
+ memset(&context->buffer[usedspace], 0,
+ ISC_SHA512_BLOCK_LENGTH - usedspace);
+ }
+ /* Do second-to-last transform: */
+ isc_sha512_transform(context,
+ (isc_uint64_t*)context->buffer);
+
+ /* And set-up for the last transform: */
+ memset(context->buffer, 0, ISC_SHA512_BLOCK_LENGTH - 2);
+ }
+ } else {
+ /* Prepare for final transform: */
+ memset(context->buffer, 0, ISC_SHA512_SHORT_BLOCK_LENGTH);
+
+ /* Begin padding with a 1 bit: */
+ *context->buffer = 0x80;
+ }
+ /* Store the length of input data (in bits): */
+ *(isc_uint64_t*)&context->buffer[ISC_SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
+ *(isc_uint64_t*)&context->buffer[ISC_SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0];
+
+ /* Final transform: */
+ isc_sha512_transform(context, (isc_uint64_t*)context->buffer);
+}
+
+void isc_sha512_final(isc_uint8_t digest[], isc_sha512_t *context) {
+ isc_uint64_t *d = (isc_uint64_t*)digest;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha512_t *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (isc_uint8_t*)0) {
+ isc_sha512_last(context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 8; j++) {
+ REVERSE64(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ memcpy(d, context->state, ISC_SHA512_DIGESTLENGTH);
+#endif
+ }
+
+ /* Zero out state data */
+ memset(context, 0, sizeof(context));
+}
+
+char *
+isc_sha512_end(isc_sha512_t *context, char buffer[]) {
+ isc_uint8_t digest[ISC_SHA512_DIGESTLENGTH], *d = digest;
+ unsigned int i;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha512_t *)0);
+
+ if (buffer != (char*)0) {
+ isc_sha512_final(digest, context);
+
+ for (i = 0; i < ISC_SHA512_DIGESTLENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ memset(context, 0, sizeof(context));
+ }
+ memset(digest, 0, ISC_SHA512_DIGESTLENGTH);
+ return buffer;
+}
+
+char *
+isc_sha512_data(const isc_uint8_t *data, size_t len,
+ char digest[ISC_SHA512_DIGESTSTRINGLENGTH])
+{
+ isc_sha512_t context;
+
+ isc_sha512_init(&context);
+ isc_sha512_update(&context, data, len);
+ return (isc_sha512_end(&context, digest));
+}
+
+
+/*** SHA-384: *********************************************************/
+void
+isc_sha384_init(isc_sha384_t *context) {
+ if (context == (isc_sha384_t *)0) {
+ return;
+ }
+ memcpy(context->state, sha384_initial_hash_value,
+ ISC_SHA512_DIGESTLENGTH);
+ memset(context->buffer, 0, ISC_SHA384_BLOCK_LENGTH);
+ context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+void
+isc_sha384_update(isc_sha384_t *context, const isc_uint8_t* data, size_t len) {
+ isc_sha512_update((isc_sha512_t *)context, data, len);
+}
+
+void
+isc_sha384_final(isc_uint8_t digest[], isc_sha384_t *context) {
+ isc_uint64_t *d = (isc_uint64_t*)digest;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha384_t *)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (isc_uint8_t*)0) {
+ isc_sha512_last((isc_sha512_t *)context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 6; j++) {
+ REVERSE64(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ memcpy(d, context->state, ISC_SHA384_DIGESTLENGTH);
+#endif
+ }
+
+ /* Zero out state data */
+ memset(context, 0, sizeof(context));
+}
+
+char *
+isc_sha384_end(isc_sha384_t *context, char buffer[]) {
+ isc_uint8_t digest[ISC_SHA384_DIGESTLENGTH], *d = digest;
+ unsigned int i;
+
+ /* Sanity check: */
+ REQUIRE(context != (isc_sha384_t *)0);
+
+ if (buffer != (char*)0) {
+ isc_sha384_final(digest, context);
+
+ for (i = 0; i < ISC_SHA384_DIGESTLENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ } else {
+ memset(context, 0, sizeof(context));
+ }
+ memset(digest, 0, ISC_SHA384_DIGESTLENGTH);
+ return buffer;
+}
+
+char*
+isc_sha384_data(const isc_uint8_t *data, size_t len,
+ char digest[ISC_SHA384_DIGESTSTRINGLENGTH])
+{
+ isc_sha384_t context;
+
+ isc_sha384_init(&context);
+ isc_sha384_update(&context, data, len);
+ return (isc_sha384_end(&context, digest));
+}
diff --git a/lib/isc/sockaddr.c b/lib/isc/sockaddr.c
new file mode 100644
index 0000000..2fd73af
--- /dev/null
+++ b/lib/isc/sockaddr.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2004-2006 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: sockaddr.c,v 1.59.18.9 2006/06/21 01:25:40 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <isc/buffer.h>
+#include <isc/hash.h>
+#include <isc/msgs.h>
+#include <isc/netaddr.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/sockaddr.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+isc_boolean_t
+isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
+ return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
+ ISC_SOCKADDR_CMPPORT|
+ ISC_SOCKADDR_CMPSCOPE));
+}
+
+isc_boolean_t
+isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
+ return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
+ ISC_SOCKADDR_CMPSCOPE));
+}
+
+isc_boolean_t
+isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+ unsigned int flags)
+{
+ REQUIRE(a != NULL && b != NULL);
+
+ if (a->length != b->length)
+ return (ISC_FALSE);
+
+ /*
+ * We don't just memcmp because the sin_zero field isn't always
+ * zero.
+ */
+
+ if (a->type.sa.sa_family != b->type.sa.sa_family)
+ return (ISC_FALSE);
+ switch (a->type.sa.sa_family) {
+ case AF_INET:
+ if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
+ memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
+ sizeof(a->type.sin.sin_addr)) != 0)
+ return (ISC_FALSE);
+ if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
+ a->type.sin.sin_port != b->type.sin.sin_port)
+ return (ISC_FALSE);
+ break;
+ case AF_INET6:
+ if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
+ memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
+ sizeof(a->type.sin6.sin6_addr)) != 0)
+ return (ISC_FALSE);
+#ifdef ISC_PLATFORM_HAVESCOPEID
+ /*
+ * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
+ * ISC_FALSE if one of the scopes in zero.
+ */
+ if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
+ a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
+ ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
+ (a->type.sin6.sin6_scope_id != 0 &&
+ b->type.sin6.sin6_scope_id != 0)))
+ return (ISC_FALSE);
+#endif
+ if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
+ a->type.sin6.sin6_port != b->type.sin6.sin6_port)
+ return (ISC_FALSE);
+ break;
+ default:
+ if (memcmp(&a->type, &b->type, a->length) != 0)
+ return (ISC_FALSE);
+ }
+ return (ISC_TRUE);
+}
+
+isc_boolean_t
+isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+ unsigned int prefixlen)
+{
+ isc_netaddr_t na, nb;
+ isc_netaddr_fromsockaddr(&na, a);
+ isc_netaddr_fromsockaddr(&nb, b);
+ return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
+}
+
+isc_result_t
+isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
+ isc_result_t result;
+ isc_netaddr_t netaddr;
+ char pbuf[sizeof("65000")];
+ unsigned int plen;
+ isc_region_t avail;
+
+ REQUIRE(sockaddr != NULL);
+
+ /*
+ * Do the port first, giving us the opportunity to check for
+ * unsupported address families before calling
+ * isc_netaddr_fromsockaddr().
+ */
+ switch (sockaddr->type.sa.sa_family) {
+ case AF_INET:
+ snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
+ break;
+ case AF_INET6:
+ snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
+ break;
+#ifdef ISC_PLAFORM_HAVESYSUNH
+ case AF_UNIX:
+ plen = strlen(sockaddr->type.sunix.sun_path);
+ if (plen >= isc_buffer_availablelength(target))
+ return (ISC_R_NOSPACE);
+
+ isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
+
+ /*
+ * Null terminate after used region.
+ */
+ isc_buffer_availableregion(target, &avail);
+ INSIST(avail.length >= 1);
+ avail.base[0] = '\0';
+
+ return (ISC_R_SUCCESS);
+#endif
+ default:
+ return (ISC_R_FAILURE);
+ }
+
+ plen = strlen(pbuf);
+ INSIST(plen < sizeof(pbuf));
+
+ isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+ result = isc_netaddr_totext(&netaddr, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (1 + plen + 1 > isc_buffer_availablelength(target))
+ return (ISC_R_NOSPACE);
+
+ isc_buffer_putmem(target, (const unsigned char *)"#", 1);
+ isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
+
+ /*
+ * Null terminate after used region.
+ */
+ isc_buffer_availableregion(target, &avail);
+ INSIST(avail.length >= 1);
+ avail.base[0] = '\0';
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
+ isc_result_t result;
+ isc_buffer_t buf;
+
+ isc_buffer_init(&buf, array, size);
+ result = isc_sockaddr_totext(sa, &buf);
+ if (result != ISC_R_SUCCESS) {
+ /*
+ * The message is the same as in netaddr.c.
+ */
+ snprintf(array, size,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
+ ISC_MSG_UNKNOWNADDR,
+ "<unknown address, family %u>"),
+ sa->type.sa.sa_family);
+ array[size - 1] = '\0';
+ }
+}
+
+unsigned int
+isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
+ unsigned int length = 0;
+ const unsigned char *s = NULL;
+ unsigned int h = 0;
+ unsigned int g;
+ unsigned int p = 0;
+ const struct in6_addr *in6;
+
+ REQUIRE(sockaddr != NULL);
+
+ switch (sockaddr->type.sa.sa_family) {
+ case AF_INET:
+ s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
+ p = ntohs(sockaddr->type.sin.sin_port);
+ length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
+ break;
+ case AF_INET6:
+ in6 = &sockaddr->type.sin6.sin6_addr;
+ if (IN6_IS_ADDR_V4MAPPED(in6)) {
+ s = (const unsigned char *)&in6[12];
+ length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
+ } else {
+ s = (const unsigned char *)in6;
+ length = sizeof(sockaddr->type.sin6.sin6_addr);
+ }
+ p = ntohs(sockaddr->type.sin6.sin6_port);
+ break;
+ default:
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_SOCKADDR,
+ ISC_MSG_UNKNOWNFAMILY,
+ "unknown address family: %d"),
+ (int)sockaddr->type.sa.sa_family);
+ s = (const unsigned char *)&sockaddr->type;
+ length = sockaddr->length;
+ p = 0;
+ }
+
+ h = isc_hash_calc(s, length, ISC_TRUE);
+ if (!address_only) {
+ g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
+ ISC_TRUE);
+ h = h ^ g; /* XXX: we should concatenate h and p first */
+ }
+
+ return (h);
+}
+
+void
+isc_sockaddr_any(isc_sockaddr_t *sockaddr)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin.sin_family = AF_INET;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
+#endif
+ sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
+ sockaddr->type.sin.sin_port = 0;
+ sockaddr->length = sizeof(sockaddr->type.sin);
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+void
+isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin6.sin6_family = AF_INET6;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
+#endif
+ sockaddr->type.sin6.sin6_addr = in6addr_any;
+ sockaddr->type.sin6.sin6_port = 0;
+ sockaddr->length = sizeof(sockaddr->type.sin6);
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+void
+isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
+ in_port_t port)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin.sin_family = AF_INET;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
+#endif
+ sockaddr->type.sin.sin_addr = *ina;
+ sockaddr->type.sin.sin_port = htons(port);
+ sockaddr->length = sizeof(sockaddr->type.sin);
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+void
+isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
+ switch (pf) {
+ case AF_INET:
+ isc_sockaddr_any(sockaddr);
+ break;
+ case AF_INET6:
+ isc_sockaddr_any6(sockaddr);
+ break;
+ default:
+ INSIST(0);
+ }
+}
+
+void
+isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
+ in_port_t port)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin6.sin6_family = AF_INET6;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
+#endif
+ sockaddr->type.sin6.sin6_addr = *ina6;
+ sockaddr->type.sin6.sin6_port = htons(port);
+ sockaddr->length = sizeof(sockaddr->type.sin6);
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+void
+isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
+ in_port_t port)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin6.sin6_family = AF_INET6;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
+#endif
+ sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
+ sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
+ memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
+ sockaddr->type.sin6.sin6_port = htons(port);
+ sockaddr->length = sizeof(sockaddr->type.sin6);
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+int
+isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
+
+ /*
+ * Get the protocol family of 'sockaddr'.
+ */
+
+#if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
+ /*
+ * Assume that PF_xxx == AF_xxx for all AF and PF.
+ */
+ return (sockaddr->type.sa.sa_family);
+#else
+ switch (sockaddr->type.sa.sa_family) {
+ case AF_INET:
+ return (PF_INET);
+ case AF_INET6:
+ return (PF_INET6);
+ default:
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
+ ISC_MSG_UNKNOWNFAMILY,
+ "unknown address family: %d"),
+ (int)sockaddr->type.sa.sa_family);
+ }
+#endif
+}
+
+void
+isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
+ in_port_t port)
+{
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->type.sin.sin_family = na->family;
+ switch (na->family) {
+ case AF_INET:
+ sockaddr->length = sizeof(sockaddr->type.sin);
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
+#endif
+ sockaddr->type.sin.sin_addr = na->type.in;
+ sockaddr->type.sin.sin_port = htons(port);
+ break;
+ case AF_INET6:
+ sockaddr->length = sizeof(sockaddr->type.sin6);
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
+#endif
+ memcpy(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
+#ifdef ISC_PLATFORM_HAVESCOPEID
+ sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
+#endif
+ sockaddr->type.sin6.sin6_port = htons(port);
+ break;
+ default:
+ INSIST(0);
+ }
+ ISC_LINK_INIT(sockaddr, link);
+}
+
+void
+isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
+ switch (sockaddr->type.sa.sa_family) {
+ case AF_INET:
+ sockaddr->type.sin.sin_port = htons(port);
+ break;
+ case AF_INET6:
+ sockaddr->type.sin6.sin6_port = htons(port);
+ break;
+ default:
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
+ ISC_MSG_UNKNOWNFAMILY,
+ "unknown address family: %d"),
+ (int)sockaddr->type.sa.sa_family);
+ }
+}
+
+in_port_t
+isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
+ in_port_t port = 0;
+
+ switch (sockaddr->type.sa.sa_family) {
+ case AF_INET:
+ port = ntohs(sockaddr->type.sin.sin_port);
+ break;
+ case AF_INET6:
+ port = ntohs(sockaddr->type.sin6.sin6_port);
+ break;
+ default:
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
+ ISC_MSG_UNKNOWNFAMILY,
+ "unknown address family: %d"),
+ (int)sockaddr->type.sa.sa_family);
+ }
+
+ return (port);
+}
+
+isc_boolean_t
+isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
+ isc_netaddr_t netaddr;
+
+ if (sockaddr->type.sa.sa_family == AF_INET ||
+ sockaddr->type.sa.sa_family == AF_INET6) {
+ isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+ return (isc_netaddr_ismulticast(&netaddr));
+ }
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
+ isc_netaddr_t netaddr;
+
+ if (sockaddr->type.sa.sa_family == AF_INET) {
+ isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+ return (isc_netaddr_isexperimental(&netaddr));
+ }
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
+ isc_netaddr_t netaddr;
+
+ if (sockaddr->type.sa.sa_family == AF_INET6) {
+ isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+ return (isc_netaddr_issitelocal(&netaddr));
+ }
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
+ isc_netaddr_t netaddr;
+
+ if (sockaddr->type.sa.sa_family == AF_INET6) {
+ isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+ return (isc_netaddr_islinklocal(&netaddr));
+ }
+ return (ISC_FALSE);
+}
+
+isc_result_t
+isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
+ return (ISC_R_NOSPACE);
+ memset(sockaddr, 0, sizeof(*sockaddr));
+ sockaddr->length = sizeof(sockaddr->type.sunix);
+ sockaddr->type.sunix.sun_family = AF_UNIX;
+#ifdef ISC_PLATFORM_HAVESALEN
+ sockaddr->type.sunix.sun_len =
+ (unsigned char)sizeof(sockaddr->type.sunix);
+#endif
+ strcpy(sockaddr->type.sunix.sun_path, path);
+ return (ISC_R_SUCCESS);
+#else
+ UNUSED(sockaddr);
+ UNUSED(path);
+ return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
diff --git a/lib/isc/sparc64/Makefile.in b/lib/isc/sparc64/Makefile.in
new file mode 100644
index 0000000..c8e77e4
--- /dev/null
+++ b/lib/isc/sparc64/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/sparc64/include/Makefile.in b/lib/isc/sparc64/include/Makefile.in
new file mode 100644
index 0000000..f4dd2f6
--- /dev/null
+++ b/lib/isc/sparc64/include/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/sparc64/include/isc/Makefile.in b/lib/isc/sparc64/include/isc/Makefile.in
new file mode 100644
index 0000000..6760ce6
--- /dev/null
+++ b/lib/isc/sparc64/include/isc/Makefile.in
@@ -0,0 +1,36 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc ; \
+ done
diff --git a/lib/isc/sparc64/include/isc/atomic.h b/lib/isc/sparc64/include/isc/atomic.h
new file mode 100644
index 0000000..5c254cf
--- /dev/null
+++ b/lib/isc/sparc64/include/isc/atomic.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.2.2.2 2005/06/16 22:01:02 jinmei Exp $ */
+
+/*
+ * This code was written based on FreeBSD's kernel source whose copyright
+ * follows:
+ */
+
+/*-
+ * Copyright (c) 1998 Doug Rabson.
+ * Copyright (c) 2001 Jake Burkholder.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ *
+ * from: FreeBSD: src/sys/i386/include/atomic.h,v 1.20 2001/02/11
+ * $FreeBSD$
+ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#define ASI_P 0x80 /* Primary Address Space Identifier */
+
+#ifdef ISC_PLATFORM_USEGCCASM
+
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ */
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+ isc_int32_t prev, swapped;
+
+ for (prev = *(volatile isc_int32_t *)p; ; prev = swapped) {
+ swapped = prev + val;
+ __asm__ volatile(
+ "casa [%1] %2, %3, %0"
+ : "+r"(swapped)
+ : "r"(p), "n"(ASI_P), "r"(prev));
+ if (swapped == prev)
+ break;
+ }
+
+ return (prev);
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+ isc_int32_t prev, swapped;
+
+ for (prev = *(volatile isc_int32_t *)p; ; prev = swapped) {
+ swapped = val;
+ __asm__ volatile(
+ "casa [%1] %2, %3, %0"
+ : "+r"(swapped)
+ : "r"(p), "n"(ASI_P), "r"(prev)
+ : "memory");
+ if (swapped == prev)
+ break;
+ }
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+ isc_int32_t temp = val;
+
+ __asm__ volatile(
+ "casa [%1] %2, %3, %0"
+ : "+r"(temp)
+ : "r"(p), "n"(ASI_P), "r"(cmpval));
+
+ return (temp);
+}
+
+#else /* ISC_PLATFORM_USEGCCASM */
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif /* ISC_PLATFORM_USEGCCASM */
+
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/string.c b/lib/isc/string.c
new file mode 100644
index 0000000..c09fa4f
--- /dev/null
+++ b/lib/isc/string.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2004-2006 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: string.c,v 1.10.18.7 2006/10/03 23:50:51 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+static char digits[] = "0123456789abcdefghijklmnoprstuvwxyz";
+
+isc_uint64_t
+isc_string_touint64(char *source, char **end, int base) {
+ isc_uint64_t tmp;
+ isc_uint64_t overflow;
+ char *s = source;
+ char *o;
+ char c;
+
+ if ((base < 0) || (base == 1) || (base > 36)) {
+ *end = source;
+ return (0);
+ }
+
+ while (*s != 0 && isascii(*s&0xff) && isspace(*s&0xff))
+ s++;
+ if (*s == '+' /* || *s == '-' */)
+ s++;
+ if (base == 0) {
+ if (*s == '0' && (*(s+1) == 'X' || *(s+1) == 'x')) {
+ s += 2;
+ base = 16;
+ } else if (*s == '0')
+ base = 8;
+ else
+ base = 10;
+ }
+ if (*s == 0) {
+ *end = source;
+ return (0);
+ }
+ overflow = ~0;
+ overflow /= base;
+ tmp = 0;
+
+ while ((c = *s) != 0) {
+ c = tolower(c&0xff);
+ /* end ? */
+ if ((o = strchr(digits, c)) == NULL) {
+ *end = s;
+ return (tmp);
+ }
+ /* end ? */
+ if ((o - digits) >= base) {
+ *end = s;
+ return (tmp);
+ }
+ /* overflow ? */
+ if (tmp > overflow) {
+ *end = source;
+ return (0);
+ }
+ tmp *= base;
+ /* overflow ? */
+ if ((tmp + (o - digits)) < tmp) {
+ *end = source;
+ return (0);
+ }
+ tmp += o - digits;
+ s++;
+ }
+ *end = s;
+ return (tmp);
+}
+
+isc_result_t
+isc_string_copy(char *target, size_t size, const char *source) {
+ REQUIRE(size > 0U);
+
+ if (strlcpy(target, source, size) >= size) {
+ memset(target, ISC_STRING_MAGIC, size);
+ return (ISC_R_NOSPACE);
+ }
+
+ ENSURE(strlen(target) < size);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_string_copy_truncate(char *target, size_t size, const char *source) {
+ REQUIRE(size > 0U);
+
+ strlcpy(target, source, size);
+
+ ENSURE(strlen(target) < size);
+}
+
+isc_result_t
+isc_string_append(char *target, size_t size, const char *source) {
+ REQUIRE(size > 0U);
+ REQUIRE(strlen(target) < size);
+
+ if (strlcat(target, source, size) >= size) {
+ memset(target, ISC_STRING_MAGIC, size);
+ return (ISC_R_NOSPACE);
+ }
+
+ ENSURE(strlen(target) < size);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_string_append_truncate(char *target, size_t size, const char *source) {
+ REQUIRE(size > 0U);
+ REQUIRE(strlen(target) < size);
+
+ strlcat(target, source, size);
+
+ ENSURE(strlen(target) < size);
+}
+
+isc_result_t
+isc_string_printf(char *target, size_t size, const char *format, ...) {
+ va_list args;
+ size_t n;
+
+ REQUIRE(size > 0U);
+
+ va_start(args, format);
+ n = vsnprintf(target, size, format, args);
+ va_end(args);
+
+ if (n >= size) {
+ memset(target, ISC_STRING_MAGIC, size);
+ return (ISC_R_NOSPACE);
+ }
+
+ ENSURE(strlen(target) < size);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_string_printf_truncate(char *target, size_t size, const char *format, ...) {
+ va_list args;
+ size_t n;
+
+ REQUIRE(size > 0U);
+
+ va_start(args, format);
+ n = vsnprintf(target, size, format, args);
+ va_end(args);
+
+ ENSURE(strlen(target) < size);
+}
+
+char *
+isc_string_regiondup(isc_mem_t *mctx, const isc_region_t *source) {
+ char *target;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(source != NULL);
+
+ target = (char *) isc_mem_allocate(mctx, source->length + 1);
+ if (target != NULL) {
+ memcpy(source->base, target, source->length);
+ target[source->length] = '\0';
+ }
+
+ return (target);
+}
+
+char *
+isc_string_separate(char **stringp, const char *delim) {
+ char *string = *stringp;
+ char *s;
+ const char *d;
+ char sc, dc;
+
+ if (string == NULL)
+ return (NULL);
+
+ for (s = string; (sc = *s) != '\0'; s++)
+ for (d = delim; (dc = *d) != '\0'; d++)
+ if (sc == dc) {
+ *s++ = '\0';
+ *stringp = s;
+ return (string);
+ }
+ *stringp = NULL;
+ return (string);
+}
+
+size_t
+isc_string_strlcpy(char *dst, const char *src, size_t size)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = size;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0U && --n != 0U) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0U);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0U) {
+ if (size != 0U)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+
+size_t
+isc_string_strlcat(char *dst, const char *src, size_t size)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = size;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0U && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = size - dlen;
+
+ if (n == 0U)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1U) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
diff --git a/lib/isc/strtoul.c b/lib/isc/strtoul.c
new file mode 100644
index 0000000..5070c08
--- /dev/null
+++ b/lib/isc/strtoul.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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.
+ */
+
+/*
+ * 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.
+ */
+
+/*! \file */
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+/* $Id: strtoul.c,v 1.3.18.2 2005/04/29 00:16:50 marka Exp $ */
+
+#include <config.h>
+
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <isc/stdlib.h>
+#include <isc/util.h>
+
+/*!
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+isc_strtoul(const char *nptr, char **endptr, int base) {
+ const char *s = nptr;
+ unsigned long acc;
+ unsigned char c;
+ unsigned long cutoff;
+ int neg = 0, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ do {
+ c = *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 = (unsigned long)ULONG_MAX / (unsigned long)base;
+ cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (!isascii(c))
+ break;
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ DE_CONST(any ? s - 1 : nptr, *endptr);
+ return (acc);
+}
diff --git a/lib/isc/symtab.c b/lib/isc/symtab.c
new file mode 100644
index 0000000..716ca88
--- /dev/null
+++ b/lib/isc/symtab.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-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: symtab.c,v 1.26.18.2 2005/04/29 00:16:50 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/symtab.h>
+#include <isc/util.h>
+
+typedef struct elt {
+ char * key;
+ unsigned int type;
+ isc_symvalue_t value;
+ LINK(struct elt) link;
+} elt_t;
+
+typedef LIST(elt_t) eltlist_t;
+
+#define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T')
+#define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
+
+struct isc_symtab {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ unsigned int size;
+ eltlist_t * table;
+ isc_symtabaction_t undefine_action;
+ void * undefine_arg;
+ isc_boolean_t case_sensitive;
+};
+
+isc_result_t
+isc_symtab_create(isc_mem_t *mctx, unsigned int size,
+ isc_symtabaction_t undefine_action,
+ void *undefine_arg,
+ isc_boolean_t case_sensitive,
+ isc_symtab_t **symtabp)
+{
+ isc_symtab_t *symtab;
+ unsigned int i;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(symtabp != NULL && *symtabp == NULL);
+ REQUIRE(size > 0); /* Should be prime. */
+
+ symtab = (isc_symtab_t *)isc_mem_get(mctx, sizeof(*symtab));
+ if (symtab == NULL)
+ return (ISC_R_NOMEMORY);
+ symtab->table = (eltlist_t *)isc_mem_get(mctx,
+ size * sizeof(eltlist_t));
+ if (symtab->table == NULL) {
+ isc_mem_put(mctx, symtab, sizeof(*symtab));
+ return (ISC_R_NOMEMORY);
+ }
+ for (i = 0; i < size; i++)
+ INIT_LIST(symtab->table[i]);
+ symtab->mctx = mctx;
+ symtab->size = size;
+ symtab->undefine_action = undefine_action;
+ symtab->undefine_arg = undefine_arg;
+ symtab->case_sensitive = case_sensitive;
+ symtab->magic = SYMTAB_MAGIC;
+
+ *symtabp = symtab;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_symtab_destroy(isc_symtab_t **symtabp) {
+ isc_symtab_t *symtab;
+ unsigned int i;
+ elt_t *elt, *nelt;
+
+ REQUIRE(symtabp != NULL);
+ symtab = *symtabp;
+ REQUIRE(VALID_SYMTAB(symtab));
+
+ for (i = 0; i < symtab->size; i++) {
+ for (elt = HEAD(symtab->table[i]); elt != NULL; elt = nelt) {
+ nelt = NEXT(elt, link);
+ if (symtab->undefine_action != NULL)
+ (symtab->undefine_action)(elt->key,
+ elt->type,
+ elt->value,
+ symtab->undefine_arg);
+ isc_mem_put(symtab->mctx, elt, sizeof(*elt));
+ }
+ }
+ isc_mem_put(symtab->mctx, symtab->table,
+ symtab->size * sizeof(eltlist_t));
+ symtab->magic = 0;
+ isc_mem_put(symtab->mctx, symtab, sizeof(*symtab));
+
+ *symtabp = NULL;
+}
+
+static inline unsigned int
+hash(const char *key, isc_boolean_t case_sensitive) {
+ const char *s;
+ unsigned int h = 0;
+ int c;
+
+ /*
+ * This hash function is similar to the one Ousterhout
+ * uses in Tcl.
+ */
+
+ if (case_sensitive) {
+ for (s = key; *s != '\0'; s++) {
+ h += (h << 3) + *s;
+ }
+ } else {
+ for (s = key; *s != '\0'; s++) {
+ c = *s;
+ c = tolower((unsigned char)c);
+ h += (h << 3) + c;
+ }
+ }
+
+ return (h);
+}
+
+#define FIND(s, k, t, b, e) \
+ b = hash((k), (s)->case_sensitive) % (s)->size; \
+ if ((s)->case_sensitive) { \
+ for (e = HEAD((s)->table[b]); e != NULL; e = NEXT(e, link)) { \
+ if (((t) == 0 || e->type == (t)) && \
+ strcmp(e->key, (k)) == 0) \
+ break; \
+ } \
+ } else { \
+ for (e = HEAD((s)->table[b]); e != NULL; e = NEXT(e, link)) { \
+ if (((t) == 0 || e->type == (t)) && \
+ strcasecmp(e->key, (k)) == 0) \
+ break; \
+ } \
+ }
+
+isc_result_t
+isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type,
+ isc_symvalue_t *value)
+{
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (elt == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (value != NULL)
+ *value = elt->value;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type,
+ isc_symvalue_t value, isc_symexists_t exists_policy)
+{
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+ REQUIRE(type != 0);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (exists_policy != isc_symexists_add && elt != NULL) {
+ if (exists_policy == isc_symexists_reject)
+ return (ISC_R_EXISTS);
+ INSIST(exists_policy == isc_symexists_replace);
+ UNLINK(symtab->table[bucket], elt, link);
+ if (symtab->undefine_action != NULL)
+ (symtab->undefine_action)(elt->key, elt->type,
+ elt->value,
+ symtab->undefine_arg);
+ } else {
+ elt = (elt_t *)isc_mem_get(symtab->mctx, sizeof(*elt));
+ if (elt == NULL)
+ return (ISC_R_NOMEMORY);
+ ISC_LINK_INIT(elt, link);
+ }
+
+ /*
+ * Though the "key" can be const coming in, it is not stored as const
+ * so that the calling program can easily have writable access to
+ * it in its undefine_action function. In the event that it *was*
+ * truly const coming in and then the caller modified it anyway ...
+ * well, don't do that!
+ */
+ DE_CONST(key, elt->key);
+ elt->type = type;
+ elt->value = value;
+
+ /*
+ * We prepend so that the most recent definition will be found.
+ */
+ PREPEND(symtab->table[bucket], elt, link);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type) {
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (elt == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (symtab->undefine_action != NULL)
+ (symtab->undefine_action)(elt->key, elt->type,
+ elt->value, symtab->undefine_arg);
+ UNLINK(symtab->table[bucket], elt, link);
+ isc_mem_put(symtab->mctx, elt, sizeof(*elt));
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/task.c b/lib/isc/task.c
new file mode 100644
index 0000000..5c80712
--- /dev/null
+++ b/lib/isc/task.c
@@ -0,0 +1,1298 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: task.c,v 1.91.18.6 2006/01/04 23:50:23 marka Exp $ */
+
+/*! \file
+ * \author Principal Author: Bob Halley
+ */
+
+/*
+ * XXXRTH Need to document the states a task can be in, and the rules
+ * for changing states.
+ */
+
+#include <config.h>
+
+#include <isc/condition.h>
+#include <isc/event.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/platform.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#ifndef ISC_PLATFORM_USETHREADS
+#include "task_p.h"
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#define ISC_TASK_NAMES 1
+
+#ifdef ISC_TASK_TRACE
+#define XTRACE(m) fprintf(stderr, "task %p thread %lu: %s\n", \
+ task, isc_thread_self(), (m))
+#define XTTRACE(t, m) fprintf(stderr, "task %p thread %lu: %s\n", \
+ (t), isc_thread_self(), (m))
+#define XTHREADTRACE(m) fprintf(stderr, "thread %lu: %s\n", \
+ isc_thread_self(), (m))
+#else
+#define XTRACE(m)
+#define XTTRACE(t, m)
+#define XTHREADTRACE(m)
+#endif
+
+/***
+ *** Types.
+ ***/
+
+typedef enum {
+ task_state_idle, task_state_ready, task_state_running,
+ task_state_done
+} task_state_t;
+
+#define TASK_MAGIC ISC_MAGIC('T', 'A', 'S', 'K')
+#define VALID_TASK(t) ISC_MAGIC_VALID(t, TASK_MAGIC)
+
+struct isc_task {
+ /* Not locked. */
+ unsigned int magic;
+ isc_taskmgr_t * manager;
+ isc_mutex_t lock;
+ /* Locked by task lock. */
+ task_state_t state;
+ unsigned int references;
+ isc_eventlist_t events;
+ isc_eventlist_t on_shutdown;
+ unsigned int quantum;
+ unsigned int flags;
+ isc_stdtime_t now;
+#ifdef ISC_TASK_NAMES
+ char name[16];
+ void * tag;
+#endif
+ /* Locked by task manager lock. */
+ LINK(isc_task_t) link;
+ LINK(isc_task_t) ready_link;
+};
+
+#define TASK_F_SHUTTINGDOWN 0x01
+
+#define TASK_SHUTTINGDOWN(t) (((t)->flags & TASK_F_SHUTTINGDOWN) \
+ != 0)
+
+#define TASK_MANAGER_MAGIC ISC_MAGIC('T', 'S', 'K', 'M')
+#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TASK_MANAGER_MAGIC)
+
+struct isc_taskmgr {
+ /* Not locked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ isc_mutex_t lock;
+#ifdef ISC_PLATFORM_USETHREADS
+ unsigned int workers;
+ isc_thread_t * threads;
+#endif /* ISC_PLATFORM_USETHREADS */
+ /* Locked by task manager lock. */
+ unsigned int default_quantum;
+ LIST(isc_task_t) tasks;
+ isc_tasklist_t ready_tasks;
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_condition_t work_available;
+ isc_condition_t exclusive_granted;
+#endif /* ISC_PLATFORM_USETHREADS */
+ unsigned int tasks_running;
+ isc_boolean_t exclusive_requested;
+ isc_boolean_t exiting;
+#ifndef ISC_PLATFORM_USETHREADS
+ unsigned int refs;
+#endif /* ISC_PLATFORM_USETHREADS */
+};
+
+#define DEFAULT_TASKMGR_QUANTUM 10
+#define DEFAULT_DEFAULT_QUANTUM 5
+#define FINISHED(m) ((m)->exiting && EMPTY((m)->tasks))
+
+#ifndef ISC_PLATFORM_USETHREADS
+static isc_taskmgr_t *taskmgr = NULL;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+/***
+ *** Tasks.
+ ***/
+
+static void
+task_finished(isc_task_t *task) {
+ isc_taskmgr_t *manager = task->manager;
+
+ REQUIRE(EMPTY(task->events));
+ REQUIRE(EMPTY(task->on_shutdown));
+ REQUIRE(task->references == 0);
+ REQUIRE(task->state == task_state_done);
+
+ XTRACE("task_finished");
+
+ LOCK(&manager->lock);
+ UNLINK(manager->tasks, task, link);
+#ifdef ISC_PLATFORM_USETHREADS
+ if (FINISHED(manager)) {
+ /*
+ * All tasks have completed and the
+ * task manager is exiting. Wake up
+ * any idle worker threads so they
+ * can exit.
+ */
+ BROADCAST(&manager->work_available);
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+ UNLOCK(&manager->lock);
+
+ DESTROYLOCK(&task->lock);
+ task->magic = 0;
+ isc_mem_put(manager->mctx, task, sizeof(*task));
+}
+
+isc_result_t
+isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
+ isc_task_t **taskp)
+{
+ isc_task_t *task;
+ isc_boolean_t exiting;
+ isc_result_t result;
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(taskp != NULL && *taskp == NULL);
+
+ task = isc_mem_get(manager->mctx, sizeof(*task));
+ if (task == NULL)
+ return (ISC_R_NOMEMORY);
+ XTRACE("isc_task_create");
+ task->manager = manager;
+ result = isc_mutex_init(&task->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(manager->mctx, task, sizeof(*task));
+ return (result);
+ }
+ task->state = task_state_idle;
+ task->references = 1;
+ INIT_LIST(task->events);
+ INIT_LIST(task->on_shutdown);
+ task->quantum = quantum;
+ task->flags = 0;
+ task->now = 0;
+#ifdef ISC_TASK_NAMES
+ memset(task->name, 0, sizeof(task->name));
+ task->tag = NULL;
+#endif
+ INIT_LINK(task, link);
+ INIT_LINK(task, ready_link);
+
+ exiting = ISC_FALSE;
+ LOCK(&manager->lock);
+ if (!manager->exiting) {
+ if (task->quantum == 0)
+ task->quantum = manager->default_quantum;
+ APPEND(manager->tasks, task, link);
+ } else
+ exiting = ISC_TRUE;
+ UNLOCK(&manager->lock);
+
+ if (exiting) {
+ DESTROYLOCK(&task->lock);
+ isc_mem_put(manager->mctx, task, sizeof(*task));
+ return (ISC_R_SHUTTINGDOWN);
+ }
+
+ task->magic = TASK_MAGIC;
+ *taskp = task;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_task_attach(isc_task_t *source, isc_task_t **targetp) {
+
+ /*
+ * Attach *targetp to source.
+ */
+
+ REQUIRE(VALID_TASK(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ XTTRACE(source, "isc_task_attach");
+
+ LOCK(&source->lock);
+ source->references++;
+ UNLOCK(&source->lock);
+
+ *targetp = source;
+}
+
+static inline isc_boolean_t
+task_shutdown(isc_task_t *task) {
+ isc_boolean_t was_idle = ISC_FALSE;
+ isc_event_t *event, *prev;
+
+ /*
+ * Caller must be holding the task's lock.
+ */
+
+ XTRACE("task_shutdown");
+
+ if (! TASK_SHUTTINGDOWN(task)) {
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_SHUTTINGDOWN, "shutting down"));
+ task->flags |= TASK_F_SHUTTINGDOWN;
+ if (task->state == task_state_idle) {
+ INSIST(EMPTY(task->events));
+ task->state = task_state_ready;
+ was_idle = ISC_TRUE;
+ }
+ INSIST(task->state == task_state_ready ||
+ task->state == task_state_running);
+ /*
+ * Note that we post shutdown events LIFO.
+ */
+ for (event = TAIL(task->on_shutdown);
+ event != NULL;
+ event = prev) {
+ prev = PREV(event, ev_link);
+ DEQUEUE(task->on_shutdown, event, ev_link);
+ ENQUEUE(task->events, event, ev_link);
+ }
+ }
+
+ return (was_idle);
+}
+
+static inline void
+task_ready(isc_task_t *task) {
+ isc_taskmgr_t *manager = task->manager;
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(task->state == task_state_ready);
+
+ XTRACE("task_ready");
+
+ LOCK(&manager->lock);
+
+ ENQUEUE(manager->ready_tasks, task, ready_link);
+#ifdef ISC_PLATFORM_USETHREADS
+ SIGNAL(&manager->work_available);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ UNLOCK(&manager->lock);
+}
+
+static inline isc_boolean_t
+task_detach(isc_task_t *task) {
+
+ /*
+ * Caller must be holding the task lock.
+ */
+
+ REQUIRE(task->references > 0);
+
+ XTRACE("detach");
+
+ task->references--;
+ if (task->references == 0 && task->state == task_state_idle) {
+ INSIST(EMPTY(task->events));
+ /*
+ * There are no references to this task, and no
+ * pending events. We could try to optimize and
+ * either initiate shutdown or clean up the task,
+ * depending on its state, but it's easier to just
+ * make the task ready and allow run() or the event
+ * loop to deal with shutting down and termination.
+ */
+ task->state = task_state_ready;
+ return (ISC_TRUE);
+ }
+
+ return (ISC_FALSE);
+}
+
+void
+isc_task_detach(isc_task_t **taskp) {
+ isc_task_t *task;
+ isc_boolean_t was_idle;
+
+ /*
+ * Detach *taskp from its task.
+ */
+
+ REQUIRE(taskp != NULL);
+ task = *taskp;
+ REQUIRE(VALID_TASK(task));
+
+ XTRACE("isc_task_detach");
+
+ LOCK(&task->lock);
+ was_idle = task_detach(task);
+ UNLOCK(&task->lock);
+
+ if (was_idle)
+ task_ready(task);
+
+ *taskp = NULL;
+}
+
+static inline isc_boolean_t
+task_send(isc_task_t *task, isc_event_t **eventp) {
+ isc_boolean_t was_idle = ISC_FALSE;
+ isc_event_t *event;
+
+ /*
+ * Caller must be holding the task lock.
+ */
+
+ REQUIRE(eventp != NULL);
+ event = *eventp;
+ REQUIRE(event != NULL);
+ REQUIRE(event->ev_type > 0);
+ REQUIRE(task->state != task_state_done);
+
+ XTRACE("task_send");
+
+ if (task->state == task_state_idle) {
+ was_idle = ISC_TRUE;
+ INSIST(EMPTY(task->events));
+ task->state = task_state_ready;
+ }
+ INSIST(task->state == task_state_ready ||
+ task->state == task_state_running);
+ ENQUEUE(task->events, event, ev_link);
+ *eventp = NULL;
+
+ return (was_idle);
+}
+
+void
+isc_task_send(isc_task_t *task, isc_event_t **eventp) {
+ isc_boolean_t was_idle;
+
+ /*
+ * Send '*event' to 'task'.
+ */
+
+ REQUIRE(VALID_TASK(task));
+
+ XTRACE("isc_task_send");
+
+ /*
+ * We're trying hard to hold locks for as short a time as possible.
+ * We're also trying to hold as few locks as possible. This is why
+ * some processing is deferred until after the lock is released.
+ */
+ LOCK(&task->lock);
+ was_idle = task_send(task, eventp);
+ UNLOCK(&task->lock);
+
+ if (was_idle) {
+ /*
+ * We need to add this task to the ready queue.
+ *
+ * We've waited until now to do it because making a task
+ * ready requires locking the manager. If we tried to do
+ * this while holding the task lock, we could deadlock.
+ *
+ * We've changed the state to ready, so no one else will
+ * be trying to add this task to the ready queue. The
+ * only way to leave the ready state is by executing the
+ * task. It thus doesn't matter if events are added,
+ * removed, or a shutdown is started in the interval
+ * between the time we released the task lock, and the time
+ * we add the task to the ready queue.
+ */
+ task_ready(task);
+ }
+}
+
+void
+isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) {
+ isc_boolean_t idle1, idle2;
+ isc_task_t *task;
+
+ /*
+ * Send '*event' to '*taskp' and then detach '*taskp' from its
+ * task.
+ */
+
+ REQUIRE(taskp != NULL);
+ task = *taskp;
+ REQUIRE(VALID_TASK(task));
+
+ XTRACE("isc_task_sendanddetach");
+
+ LOCK(&task->lock);
+ idle1 = task_send(task, eventp);
+ idle2 = task_detach(task);
+ UNLOCK(&task->lock);
+
+ /*
+ * If idle1, then idle2 shouldn't be true as well since we're holding
+ * the task lock, and thus the task cannot switch from ready back to
+ * idle.
+ */
+ INSIST(!(idle1 && idle2));
+
+ if (idle1 || idle2)
+ task_ready(task);
+
+ *taskp = NULL;
+}
+
+#define PURGE_OK(event) (((event)->ev_attributes & ISC_EVENTATTR_NOPURGE) == 0)
+
+static unsigned int
+dequeue_events(isc_task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag,
+ isc_eventlist_t *events, isc_boolean_t purging)
+{
+ isc_event_t *event, *next_event;
+ unsigned int count = 0;
+
+ REQUIRE(VALID_TASK(task));
+ REQUIRE(last >= first);
+
+ XTRACE("dequeue_events");
+
+ /*
+ * Events matching 'sender', whose type is >= first and <= last, and
+ * whose tag is 'tag' will be dequeued. If 'purging', matching events
+ * which are marked as unpurgable will not be dequeued.
+ *
+ * sender == NULL means "any sender", and tag == NULL means "any tag".
+ */
+
+ LOCK(&task->lock);
+
+ for (event = HEAD(task->events); event != NULL; event = next_event) {
+ next_event = NEXT(event, ev_link);
+ if (event->ev_type >= first && event->ev_type <= last &&
+ (sender == NULL || event->ev_sender == sender) &&
+ (tag == NULL || event->ev_tag == tag) &&
+ (!purging || PURGE_OK(event))) {
+ DEQUEUE(task->events, event, ev_link);
+ ENQUEUE(*events, event, ev_link);
+ count++;
+ }
+ }
+
+ UNLOCK(&task->lock);
+
+ return (count);
+}
+
+unsigned int
+isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag)
+{
+ unsigned int count;
+ isc_eventlist_t events;
+ isc_event_t *event, *next_event;
+
+ /*
+ * Purge events from a task's event queue.
+ */
+
+ XTRACE("isc_task_purgerange");
+
+ ISC_LIST_INIT(events);
+
+ count = dequeue_events(task, sender, first, last, tag, &events,
+ ISC_TRUE);
+
+ for (event = HEAD(events); event != NULL; event = next_event) {
+ next_event = NEXT(event, ev_link);
+ isc_event_free(&event);
+ }
+
+ /*
+ * Note that purging never changes the state of the task.
+ */
+
+ return (count);
+}
+
+unsigned int
+isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag)
+{
+ /*
+ * Purge events from a task's event queue.
+ */
+
+ XTRACE("isc_task_purge");
+
+ return (isc_task_purgerange(task, sender, type, type, tag));
+}
+
+isc_boolean_t
+isc_task_purgeevent(isc_task_t *task, isc_event_t *event) {
+ isc_event_t *curr_event, *next_event;
+
+ /*
+ * Purge 'event' from a task's event queue.
+ *
+ * XXXRTH: WARNING: This method may be removed before beta.
+ */
+
+ REQUIRE(VALID_TASK(task));
+
+ /*
+ * If 'event' is on the task's event queue, it will be purged,
+ * unless it is marked as unpurgeable. 'event' does not have to be
+ * on the task's event queue; in fact, it can even be an invalid
+ * pointer. Purging only occurs if the event is actually on the task's
+ * event queue.
+ *
+ * Purging never changes the state of the task.
+ */
+
+ LOCK(&task->lock);
+ for (curr_event = HEAD(task->events);
+ curr_event != NULL;
+ curr_event = next_event) {
+ next_event = NEXT(curr_event, ev_link);
+ if (curr_event == event && PURGE_OK(event)) {
+ DEQUEUE(task->events, curr_event, ev_link);
+ break;
+ }
+ }
+ UNLOCK(&task->lock);
+
+ if (curr_event == NULL)
+ return (ISC_FALSE);
+
+ isc_event_free(&curr_event);
+
+ return (ISC_TRUE);
+}
+
+unsigned int
+isc_task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag,
+ isc_eventlist_t *events)
+{
+ /*
+ * Remove events from a task's event queue.
+ */
+
+ XTRACE("isc_task_unsendrange");
+
+ return (dequeue_events(task, sender, first, last, tag, events,
+ ISC_FALSE));
+}
+
+unsigned int
+isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
+ void *tag, isc_eventlist_t *events)
+{
+ /*
+ * Remove events from a task's event queue.
+ */
+
+ XTRACE("isc_task_unsend");
+
+ return (dequeue_events(task, sender, type, type, tag, events,
+ ISC_FALSE));
+}
+
+isc_result_t
+isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+ isc_boolean_t disallowed = ISC_FALSE;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_event_t *event;
+
+ /*
+ * Send a shutdown event with action 'action' and argument 'arg' when
+ * 'task' is shutdown.
+ */
+
+ REQUIRE(VALID_TASK(task));
+ REQUIRE(action != NULL);
+
+ event = isc_event_allocate(task->manager->mctx,
+ NULL,
+ ISC_TASKEVENT_SHUTDOWN,
+ action,
+ arg,
+ sizeof(*event));
+ if (event == NULL)
+ return (ISC_R_NOMEMORY);
+
+ LOCK(&task->lock);
+ if (TASK_SHUTTINGDOWN(task)) {
+ disallowed = ISC_TRUE;
+ result = ISC_R_SHUTTINGDOWN;
+ } else
+ ENQUEUE(task->on_shutdown, event, ev_link);
+ UNLOCK(&task->lock);
+
+ if (disallowed)
+ isc_mem_put(task->manager->mctx, event, sizeof(*event));
+
+ return (result);
+}
+
+void
+isc_task_shutdown(isc_task_t *task) {
+ isc_boolean_t was_idle;
+
+ /*
+ * Shutdown 'task'.
+ */
+
+ REQUIRE(VALID_TASK(task));
+
+ LOCK(&task->lock);
+ was_idle = task_shutdown(task);
+ UNLOCK(&task->lock);
+
+ if (was_idle)
+ task_ready(task);
+}
+
+void
+isc_task_destroy(isc_task_t **taskp) {
+
+ /*
+ * Destroy '*taskp'.
+ */
+
+ REQUIRE(taskp != NULL);
+
+ isc_task_shutdown(*taskp);
+ isc_task_detach(taskp);
+}
+
+void
+isc_task_setname(isc_task_t *task, const char *name, void *tag) {
+
+ /*
+ * Name 'task'.
+ */
+
+ REQUIRE(VALID_TASK(task));
+
+#ifdef ISC_TASK_NAMES
+ LOCK(&task->lock);
+ memset(task->name, 0, sizeof(task->name));
+ strncpy(task->name, name, sizeof(task->name) - 1);
+ task->tag = tag;
+ UNLOCK(&task->lock);
+#else
+ UNUSED(name);
+ UNUSED(tag);
+#endif
+
+}
+
+const char *
+isc_task_getname(isc_task_t *task) {
+ return (task->name);
+}
+
+void *
+isc_task_gettag(isc_task_t *task) {
+ return (task->tag);
+}
+
+void
+isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t) {
+ REQUIRE(VALID_TASK(task));
+ REQUIRE(t != NULL);
+
+ LOCK(&task->lock);
+
+ *t = task->now;
+
+ UNLOCK(&task->lock);
+}
+
+/***
+ *** Task Manager.
+ ***/
+static void
+dispatch(isc_taskmgr_t *manager) {
+ isc_task_t *task;
+#ifndef ISC_PLATFORM_USETHREADS
+ unsigned int total_dispatch_count = 0;
+ isc_tasklist_t ready_tasks;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ REQUIRE(VALID_MANAGER(manager));
+
+ /*
+ * Again we're trying to hold the lock for as short a time as possible
+ * and to do as little locking and unlocking as possible.
+ *
+ * In both while loops, the appropriate lock must be held before the
+ * while body starts. Code which acquired the lock at the top of
+ * the loop would be more readable, but would result in a lot of
+ * extra locking. Compare:
+ *
+ * Straightforward:
+ *
+ * LOCK();
+ * ...
+ * UNLOCK();
+ * while (expression) {
+ * LOCK();
+ * ...
+ * UNLOCK();
+ *
+ * Unlocked part here...
+ *
+ * LOCK();
+ * ...
+ * UNLOCK();
+ * }
+ *
+ * Note how if the loop continues we unlock and then immediately lock.
+ * For N iterations of the loop, this code does 2N+1 locks and 2N+1
+ * unlocks. Also note that the lock is not held when the while
+ * condition is tested, which may or may not be important, depending
+ * on the expression.
+ *
+ * As written:
+ *
+ * LOCK();
+ * while (expression) {
+ * ...
+ * UNLOCK();
+ *
+ * Unlocked part here...
+ *
+ * LOCK();
+ * ...
+ * }
+ * UNLOCK();
+ *
+ * For N iterations of the loop, this code does N+1 locks and N+1
+ * unlocks. The while expression is always protected by the lock.
+ */
+
+#ifndef ISC_PLATFORM_USETHREADS
+ ISC_LIST_INIT(ready_tasks);
+#endif
+ LOCK(&manager->lock);
+ while (!FINISHED(manager)) {
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * For reasons similar to those given in the comment in
+ * isc_task_send() above, it is safe for us to dequeue
+ * the task while only holding the manager lock, and then
+ * change the task to running state while only holding the
+ * task lock.
+ */
+ while ((EMPTY(manager->ready_tasks) ||
+ manager->exclusive_requested) &&
+ !FINISHED(manager))
+ {
+ XTHREADTRACE(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_WAIT, "wait"));
+ WAIT(&manager->work_available, &manager->lock);
+ XTHREADTRACE(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TASK,
+ ISC_MSG_AWAKE, "awake"));
+ }
+#else /* ISC_PLATFORM_USETHREADS */
+ if (total_dispatch_count >= DEFAULT_TASKMGR_QUANTUM ||
+ EMPTY(manager->ready_tasks))
+ break;
+#endif /* ISC_PLATFORM_USETHREADS */
+ XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TASK,
+ ISC_MSG_WORKING, "working"));
+
+ task = HEAD(manager->ready_tasks);
+ if (task != NULL) {
+ unsigned int dispatch_count = 0;
+ isc_boolean_t done = ISC_FALSE;
+ isc_boolean_t requeue = ISC_FALSE;
+ isc_boolean_t finished = ISC_FALSE;
+ isc_event_t *event;
+
+ INSIST(VALID_TASK(task));
+
+ /*
+ * Note we only unlock the manager lock if we actually
+ * have a task to do. We must reacquire the manager
+ * lock before exiting the 'if (task != NULL)' block.
+ */
+ DEQUEUE(manager->ready_tasks, task, ready_link);
+ manager->tasks_running++;
+ UNLOCK(&manager->lock);
+
+ LOCK(&task->lock);
+ INSIST(task->state == task_state_ready);
+ task->state = task_state_running;
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_RUNNING, "running"));
+ isc_stdtime_get(&task->now);
+ do {
+ if (!EMPTY(task->events)) {
+ event = HEAD(task->events);
+ DEQUEUE(task->events, event, ev_link);
+
+ /*
+ * Execute the event action.
+ */
+ XTRACE(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TASK,
+ ISC_MSG_EXECUTE,
+ "execute action"));
+ if (event->ev_action != NULL) {
+ UNLOCK(&task->lock);
+ (event->ev_action)(task,event);
+ LOCK(&task->lock);
+ }
+ dispatch_count++;
+#ifndef ISC_PLATFORM_USETHREADS
+ total_dispatch_count++;
+#endif /* ISC_PLATFORM_USETHREADS */
+ }
+
+ if (task->references == 0 &&
+ EMPTY(task->events) &&
+ !TASK_SHUTTINGDOWN(task)) {
+ isc_boolean_t was_idle;
+
+ /*
+ * There are no references and no
+ * pending events for this task,
+ * which means it will not become
+ * runnable again via an external
+ * action (such as sending an event
+ * or detaching).
+ *
+ * We initiate shutdown to prevent
+ * it from becoming a zombie.
+ *
+ * We do this here instead of in
+ * the "if EMPTY(task->events)" block
+ * below because:
+ *
+ * If we post no shutdown events,
+ * we want the task to finish.
+ *
+ * If we did post shutdown events,
+ * will still want the task's
+ * quantum to be applied.
+ */
+ was_idle = task_shutdown(task);
+ INSIST(!was_idle);
+ }
+
+ if (EMPTY(task->events)) {
+ /*
+ * Nothing else to do for this task
+ * right now.
+ */
+ XTRACE(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TASK,
+ ISC_MSG_EMPTY,
+ "empty"));
+ if (task->references == 0 &&
+ TASK_SHUTTINGDOWN(task)) {
+ /*
+ * The task is done.
+ */
+ XTRACE(isc_msgcat_get(
+ isc_msgcat,
+ ISC_MSGSET_TASK,
+ ISC_MSG_DONE,
+ "done"));
+ finished = ISC_TRUE;
+ task->state = task_state_done;
+ } else
+ task->state = task_state_idle;
+ done = ISC_TRUE;
+ } else if (dispatch_count >= task->quantum) {
+ /*
+ * Our quantum has expired, but
+ * there is more work to be done.
+ * We'll requeue it to the ready
+ * queue later.
+ *
+ * We don't check quantum until
+ * dispatching at least one event,
+ * so the minimum quantum is one.
+ */
+ XTRACE(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TASK,
+ ISC_MSG_QUANTUM,
+ "quantum"));
+ task->state = task_state_ready;
+ requeue = ISC_TRUE;
+ done = ISC_TRUE;
+ }
+ } while (!done);
+ UNLOCK(&task->lock);
+
+ if (finished)
+ task_finished(task);
+
+ LOCK(&manager->lock);
+ manager->tasks_running--;
+#ifdef ISC_PLATFORM_USETHREADS
+ if (manager->exclusive_requested &&
+ manager->tasks_running == 1) {
+ SIGNAL(&manager->exclusive_granted);
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+ if (requeue) {
+ /*
+ * We know we're awake, so we don't have
+ * to wakeup any sleeping threads if the
+ * ready queue is empty before we requeue.
+ *
+ * A possible optimization if the queue is
+ * empty is to 'goto' the 'if (task != NULL)'
+ * block, avoiding the ENQUEUE of the task
+ * and the subsequent immediate DEQUEUE
+ * (since it is the only executable task).
+ * We don't do this because then we'd be
+ * skipping the exit_requested check. The
+ * cost of ENQUEUE is low anyway, especially
+ * when you consider that we'd have to do
+ * an extra EMPTY check to see if we could
+ * do the optimization. If the ready queue
+ * were usually nonempty, the 'optimization'
+ * might even hurt rather than help.
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+ ENQUEUE(manager->ready_tasks, task,
+ ready_link);
+#else
+ ENQUEUE(ready_tasks, task, ready_link);
+#endif
+ }
+ }
+ }
+#ifndef ISC_PLATFORM_USETHREADS
+ ISC_LIST_APPENDLIST(manager->ready_tasks, ready_tasks, ready_link);
+#endif
+ UNLOCK(&manager->lock);
+}
+
+#ifdef ISC_PLATFORM_USETHREADS
+static isc_threadresult_t
+#ifdef _WIN32
+WINAPI
+#endif
+run(void *uap) {
+ isc_taskmgr_t *manager = uap;
+
+ XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_STARTING, "starting"));
+
+ dispatch(manager);
+
+ XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_EXITING, "exiting"));
+
+ return ((isc_threadresult_t)0);
+}
+#endif /* ISC_PLATFORM_USETHREADS */
+
+static void
+manager_free(isc_taskmgr_t *manager) {
+ isc_mem_t *mctx;
+
+#ifdef ISC_PLATFORM_USETHREADS
+ (void)isc_condition_destroy(&manager->exclusive_granted);
+ (void)isc_condition_destroy(&manager->work_available);
+ isc_mem_free(manager->mctx, manager->threads);
+#endif /* ISC_PLATFORM_USETHREADS */
+ DESTROYLOCK(&manager->lock);
+ manager->magic = 0;
+ mctx = manager->mctx;
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ isc_mem_detach(&mctx);
+}
+
+isc_result_t
+isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
+ unsigned int default_quantum, isc_taskmgr_t **managerp)
+{
+ isc_result_t result;
+ unsigned int i, started = 0;
+ isc_taskmgr_t *manager;
+
+ /*
+ * Create a new task manager.
+ */
+
+ REQUIRE(workers > 0);
+ REQUIRE(managerp != NULL && *managerp == NULL);
+
+#ifndef ISC_PLATFORM_USETHREADS
+ UNUSED(i);
+ UNUSED(started);
+ UNUSED(workers);
+
+ if (taskmgr != NULL) {
+ taskmgr->refs++;
+ *managerp = taskmgr;
+ return (ISC_R_SUCCESS);
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ manager = isc_mem_get(mctx, sizeof(*manager));
+ if (manager == NULL)
+ return (ISC_R_NOMEMORY);
+ manager->magic = TASK_MANAGER_MAGIC;
+ manager->mctx = NULL;
+ result = isc_mutex_init(&manager->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_mgr;
+
+#ifdef ISC_PLATFORM_USETHREADS
+ manager->workers = 0;
+ manager->threads = isc_mem_allocate(mctx,
+ workers * sizeof(isc_thread_t));
+ if (manager->threads == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_lock;
+ }
+ if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_threads;
+ }
+ if (isc_condition_init(&manager->exclusive_granted) != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_workavailable;
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+ if (default_quantum == 0)
+ default_quantum = DEFAULT_DEFAULT_QUANTUM;
+ manager->default_quantum = default_quantum;
+ INIT_LIST(manager->tasks);
+ INIT_LIST(manager->ready_tasks);
+ manager->tasks_running = 0;
+ manager->exclusive_requested = ISC_FALSE;
+ manager->exiting = ISC_FALSE;
+
+ isc_mem_attach(mctx, &manager->mctx);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ LOCK(&manager->lock);
+ /*
+ * Start workers.
+ */
+ for (i = 0; i < workers; i++) {
+ if (isc_thread_create(run, manager,
+ &manager->threads[manager->workers]) ==
+ ISC_R_SUCCESS) {
+ manager->workers++;
+ started++;
+ }
+ }
+ UNLOCK(&manager->lock);
+
+ if (started == 0) {
+ manager_free(manager);
+ return (ISC_R_NOTHREADS);
+ }
+ isc_thread_setconcurrency(workers);
+#else /* ISC_PLATFORM_USETHREADS */
+ manager->refs = 1;
+ taskmgr = manager;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ *managerp = manager;
+
+ return (ISC_R_SUCCESS);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ cleanup_workavailable:
+ (void)isc_condition_destroy(&manager->work_available);
+ cleanup_threads:
+ isc_mem_free(mctx, manager->threads);
+ cleanup_lock:
+ DESTROYLOCK(&manager->lock);
+#endif
+ cleanup_mgr:
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ return (result);
+}
+
+void
+isc_taskmgr_destroy(isc_taskmgr_t **managerp) {
+ isc_taskmgr_t *manager;
+ isc_task_t *task;
+ unsigned int i;
+
+ /*
+ * Destroy '*managerp'.
+ */
+
+ REQUIRE(managerp != NULL);
+ manager = *managerp;
+ REQUIRE(VALID_MANAGER(manager));
+
+#ifndef ISC_PLATFORM_USETHREADS
+ UNUSED(i);
+
+ if (manager->refs > 1) {
+ manager->refs--;
+ *managerp = NULL;
+ return;
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ XTHREADTRACE("isc_taskmgr_destroy");
+ /*
+ * Only one non-worker thread may ever call this routine.
+ * If a worker thread wants to initiate shutdown of the
+ * task manager, it should ask some non-worker thread to call
+ * isc_taskmgr_destroy(), e.g. by signalling a condition variable
+ * that the startup thread is sleeping on.
+ */
+
+ /*
+ * Unlike elsewhere, we're going to hold this lock a long time.
+ * We need to do so, because otherwise the list of tasks could
+ * change while we were traversing it.
+ *
+ * This is also the only function where we will hold both the
+ * task manager lock and a task lock at the same time.
+ */
+
+ LOCK(&manager->lock);
+
+ /*
+ * Make sure we only get called once.
+ */
+ INSIST(!manager->exiting);
+ manager->exiting = ISC_TRUE;
+
+ /*
+ * Post shutdown event(s) to every task (if they haven't already been
+ * posted).
+ */
+ for (task = HEAD(manager->tasks);
+ task != NULL;
+ task = NEXT(task, link)) {
+ LOCK(&task->lock);
+ if (task_shutdown(task))
+ ENQUEUE(manager->ready_tasks, task, ready_link);
+ UNLOCK(&task->lock);
+ }
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Wake up any sleeping workers. This ensures we get work done if
+ * there's work left to do, and if there are already no tasks left
+ * it will cause the workers to see manager->exiting.
+ */
+ BROADCAST(&manager->work_available);
+ UNLOCK(&manager->lock);
+
+ /*
+ * Wait for all the worker threads to exit.
+ */
+ for (i = 0; i < manager->workers; i++)
+ (void)isc_thread_join(manager->threads[i], NULL);
+#else /* ISC_PLATFORM_USETHREADS */
+ /*
+ * Dispatch the shutdown events.
+ */
+ UNLOCK(&manager->lock);
+ while (isc__taskmgr_ready())
+ (void)isc__taskmgr_dispatch();
+ if (!ISC_LIST_EMPTY(manager->tasks))
+ isc_mem_printallactive(stderr);
+ INSIST(ISC_LIST_EMPTY(manager->tasks));
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ manager_free(manager);
+
+ *managerp = NULL;
+}
+
+#ifndef ISC_PLATFORM_USETHREADS
+isc_boolean_t
+isc__taskmgr_ready(void) {
+ if (taskmgr == NULL)
+ return (ISC_FALSE);
+ return (ISC_TF(!ISC_LIST_EMPTY(taskmgr->ready_tasks)));
+}
+
+isc_result_t
+isc__taskmgr_dispatch(void) {
+ isc_taskmgr_t *manager = taskmgr;
+
+ if (taskmgr == NULL)
+ return (ISC_R_NOTFOUND);
+
+ dispatch(manager);
+
+ return (ISC_R_SUCCESS);
+}
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+isc_result_t
+isc_task_beginexclusive(isc_task_t *task) {
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_taskmgr_t *manager = task->manager;
+ REQUIRE(task->state == task_state_running);
+ LOCK(&manager->lock);
+ if (manager->exclusive_requested) {
+ UNLOCK(&manager->lock);
+ return (ISC_R_LOCKBUSY);
+ }
+ manager->exclusive_requested = ISC_TRUE;
+ while (manager->tasks_running > 1) {
+ WAIT(&manager->exclusive_granted, &manager->lock);
+ }
+ UNLOCK(&manager->lock);
+#else
+ UNUSED(task);
+#endif
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_task_endexclusive(isc_task_t *task) {
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_taskmgr_t *manager = task->manager;
+ REQUIRE(task->state == task_state_running);
+ LOCK(&manager->lock);
+ REQUIRE(manager->exclusive_requested);
+ manager->exclusive_requested = ISC_FALSE;
+ BROADCAST(&manager->work_available);
+ UNLOCK(&manager->lock);
+#else
+ UNUSED(task);
+#endif
+}
diff --git a/lib/isc/task_p.h b/lib/isc/task_p.h
new file mode 100644
index 0000000..8ada721
--- /dev/null
+++ b/lib/isc/task_p.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2005 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: task_p.h,v 1.7.18.2 2005/04/29 00:16:50 marka Exp $ */
+
+#ifndef ISC_TASK_P_H
+#define ISC_TASK_P_H
+
+/*! \file */
+
+isc_boolean_t
+isc__taskmgr_ready(void);
+
+isc_result_t
+isc__taskmgr_dispatch(void);
+
+#endif /* ISC_TASK_P_H */
diff --git a/lib/isc/taskpool.c b/lib/isc/taskpool.c
new file mode 100644
index 0000000..f1f619d
--- /dev/null
+++ b/lib/isc/taskpool.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2004, 2005 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: taskpool.c,v 1.12.18.3 2005/11/30 03:44:39 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/taskpool.h>
+#include <isc/util.h>
+
+/***
+ *** Types.
+ ***/
+
+struct isc_taskpool {
+ isc_mem_t * mctx;
+ unsigned int ntasks;
+ isc_task_t ** tasks;
+};
+/***
+ *** Functions.
+ ***/
+
+isc_result_t
+isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx,
+ unsigned int ntasks, unsigned int quantum,
+ isc_taskpool_t **poolp)
+{
+ unsigned int i;
+ isc_taskpool_t *pool;
+ isc_result_t result;
+
+ INSIST(ntasks > 0);
+ pool = isc_mem_get(mctx, sizeof(*pool));
+ if (pool == NULL)
+ return (ISC_R_NOMEMORY);
+ pool->mctx = mctx;
+ pool->ntasks = ntasks;
+ pool->tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
+ if (pool->tasks == NULL) {
+ isc_mem_put(mctx, pool, sizeof(*pool));
+ return (ISC_R_NOMEMORY);
+ }
+ for (i = 0; i < ntasks; i++)
+ pool->tasks[i] = NULL;
+ for (i = 0; i < ntasks; i++) {
+ result = isc_task_create(tmgr, quantum, &pool->tasks[i]);
+ if (result != ISC_R_SUCCESS) {
+ isc_taskpool_destroy(&pool);
+ return (result);
+ }
+ }
+ *poolp = pool;
+ return (ISC_R_SUCCESS);
+}
+
+void isc_taskpool_gettask(isc_taskpool_t *pool, unsigned int hash,
+ isc_task_t **targetp)
+{
+ isc_task_attach(pool->tasks[hash % pool->ntasks], targetp);
+}
+
+void
+isc_taskpool_destroy(isc_taskpool_t **poolp) {
+ unsigned int i;
+ isc_taskpool_t *pool = *poolp;
+ for (i = 0; i < pool->ntasks; i++) {
+ if (pool->tasks[i] != NULL) {
+ isc_task_detach(&pool->tasks[i]);
+ }
+ }
+ isc_mem_put(pool->mctx, pool->tasks,
+ pool->ntasks * sizeof(isc_task_t *));
+ isc_mem_put(pool->mctx, pool, sizeof(*pool));
+ *poolp = NULL;
+}
+
+
diff --git a/lib/isc/timer.c b/lib/isc/timer.c
new file mode 100644
index 0000000..f67d091
--- /dev/null
+++ b/lib/isc/timer.c
@@ -0,0 +1,930 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2002 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: timer.c,v 1.73.18.7 2007/10/24 23:46:26 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/condition.h>
+#include <isc/heap.h>
+#include <isc/log.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/platform.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#ifndef ISC_PLATFORM_USETHREADS
+#include "timer_p.h"
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#ifdef ISC_TIMER_TRACE
+#define XTRACE(s) fprintf(stderr, "%s\n", (s))
+#define XTRACEID(s, t) fprintf(stderr, "%s %p\n", (s), (t))
+#define XTRACETIME(s, d) fprintf(stderr, "%s %u.%09u\n", (s), \
+ (d).seconds, (d).nanoseconds)
+#define XTRACETIME2(s, d, n) fprintf(stderr, "%s %u.%09u %u.%09u\n", (s), \
+ (d).seconds, (d).nanoseconds, (n).seconds, (n).nanoseconds)
+#define XTRACETIMER(s, t, d) fprintf(stderr, "%s %p %u.%09u\n", (s), (t), \
+ (d).seconds, (d).nanoseconds)
+#else
+#define XTRACE(s)
+#define XTRACEID(s, t)
+#define XTRACETIME(s, d)
+#define XTRACETIME2(s, d, n)
+#define XTRACETIMER(s, t, d)
+#endif /* ISC_TIMER_TRACE */
+
+#define TIMER_MAGIC ISC_MAGIC('T', 'I', 'M', 'R')
+#define VALID_TIMER(t) ISC_MAGIC_VALID(t, TIMER_MAGIC)
+
+struct isc_timer {
+ /*! Not locked. */
+ unsigned int magic;
+ isc_timermgr_t * manager;
+ isc_mutex_t lock;
+ /*! Locked by timer lock. */
+ unsigned int references;
+ isc_time_t idle;
+ /*! Locked by manager lock. */
+ isc_timertype_t type;
+ isc_time_t expires;
+ isc_interval_t interval;
+ isc_task_t * task;
+ isc_taskaction_t action;
+ void * arg;
+ unsigned int index;
+ isc_time_t due;
+ LINK(isc_timer_t) link;
+};
+
+#define TIMER_MANAGER_MAGIC ISC_MAGIC('T', 'I', 'M', 'M')
+#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TIMER_MANAGER_MAGIC)
+
+struct isc_timermgr {
+ /* Not locked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ isc_mutex_t lock;
+ /* Locked by manager lock. */
+ isc_boolean_t done;
+ LIST(isc_timer_t) timers;
+ unsigned int nscheduled;
+ isc_time_t due;
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_condition_t wakeup;
+ isc_thread_t thread;
+#else /* ISC_PLATFORM_USETHREADS */
+ unsigned int refs;
+#endif /* ISC_PLATFORM_USETHREADS */
+ isc_heap_t * heap;
+};
+
+#ifndef ISC_PLATFORM_USETHREADS
+/*!
+ * If threads are not in use, there can be only one.
+ */
+static isc_timermgr_t *timermgr = NULL;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+static inline isc_result_t
+schedule(isc_timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) {
+ isc_result_t result;
+ isc_timermgr_t *manager;
+ isc_time_t due;
+ int cmp;
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_boolean_t timedwait;
+#endif
+
+ /*!
+ * Note: the caller must ensure locking.
+ */
+
+ REQUIRE(timer->type != isc_timertype_inactive);
+
+#ifndef ISC_PLATFORM_USETHREADS
+ UNUSED(signal_ok);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ manager = timer->manager;
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*!
+ * If the manager was timed wait, we may need to signal the
+ * manager to force a wakeup.
+ */
+ timedwait = ISC_TF(manager->nscheduled > 0 &&
+ isc_time_seconds(&manager->due) != 0);
+#endif
+
+ /*
+ * Compute the new due time.
+ */
+ if (timer->type != isc_timertype_once) {
+ result = isc_time_add(now, &timer->interval, &due);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (timer->type == isc_timertype_limited &&
+ isc_time_compare(&timer->expires, &due) < 0)
+ due = timer->expires;
+ } else {
+ if (isc_time_isepoch(&timer->idle))
+ due = timer->expires;
+ else if (isc_time_isepoch(&timer->expires))
+ due = timer->idle;
+ else if (isc_time_compare(&timer->idle, &timer->expires) < 0)
+ due = timer->idle;
+ else
+ due = timer->expires;
+ }
+
+ /*
+ * Schedule the timer.
+ */
+
+ if (timer->index > 0) {
+ /*
+ * Already scheduled.
+ */
+ cmp = isc_time_compare(&due, &timer->due);
+ timer->due = due;
+ switch (cmp) {
+ case -1:
+ isc_heap_increased(manager->heap, timer->index);
+ break;
+ case 1:
+ isc_heap_decreased(manager->heap, timer->index);
+ break;
+ case 0:
+ /* Nothing to do. */
+ break;
+ }
+ } else {
+ timer->due = due;
+ result = isc_heap_insert(manager->heap, timer);
+ if (result != ISC_R_SUCCESS) {
+ INSIST(result == ISC_R_NOMEMORY);
+ return (ISC_R_NOMEMORY);
+ }
+ manager->nscheduled++;
+ }
+
+ XTRACETIMER(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+ ISC_MSG_SCHEDULE, "schedule"), timer, due);
+
+ /*
+ * If this timer is at the head of the queue, we need to ensure
+ * that we won't miss it if it has a more recent due time than
+ * the current "next" timer. We do this either by waking up the
+ * run thread, or explicitly setting the value in the manager.
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /*
+ * This is a temporary (probably) hack to fix a bug on tru64 5.1
+ * and 5.1a. Sometimes, pthread_cond_timedwait() doesn't actually
+ * return when the time expires, so here, we check to see if
+ * we're 15 seconds or more behind, and if we are, we signal
+ * the dispatcher. This isn't such a bad idea as a general purpose
+ * watchdog, so perhaps we should just leave it in here.
+ */
+ if (signal_ok && timedwait) {
+ isc_interval_t fifteen;
+ isc_time_t then;
+
+ isc_interval_set(&fifteen, 15, 0);
+ result = isc_time_add(&manager->due, &fifteen, &then);
+
+ if (result == ISC_R_SUCCESS &&
+ isc_time_compare(&then, now) < 0) {
+ SIGNAL(&manager->wakeup);
+ signal_ok = ISC_FALSE;
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_TIMER, ISC_LOG_WARNING,
+ "*** POKED TIMER ***");
+ }
+ }
+
+ if (timer->index == 1 && signal_ok) {
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+ ISC_MSG_SIGNALSCHED,
+ "signal (schedule)"));
+ SIGNAL(&manager->wakeup);
+ }
+#else /* ISC_PLATFORM_USETHREADS */
+ if (timer->index == 1 &&
+ isc_time_compare(&timer->due, &manager->due) < 0)
+ manager->due = timer->due;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+deschedule(isc_timer_t *timer) {
+ isc_boolean_t need_wakeup = ISC_FALSE;
+ isc_timermgr_t *manager;
+
+ /*
+ * The caller must ensure locking.
+ */
+
+ manager = timer->manager;
+ if (timer->index > 0) {
+ if (timer->index == 1)
+ need_wakeup = ISC_TRUE;
+ isc_heap_delete(manager->heap, timer->index);
+ timer->index = 0;
+ INSIST(manager->nscheduled > 0);
+ manager->nscheduled--;
+#ifdef ISC_PLATFORM_USETHREADS
+ if (need_wakeup) {
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+ ISC_MSG_SIGNALDESCHED,
+ "signal (deschedule)"));
+ SIGNAL(&manager->wakeup);
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+ }
+}
+
+static void
+destroy(isc_timer_t *timer) {
+ isc_timermgr_t *manager = timer->manager;
+
+ /*
+ * The caller must ensure it is safe to destroy the timer.
+ */
+
+ LOCK(&manager->lock);
+
+ (void)isc_task_purgerange(timer->task,
+ timer,
+ ISC_TIMEREVENT_FIRSTEVENT,
+ ISC_TIMEREVENT_LASTEVENT,
+ NULL);
+ deschedule(timer);
+ UNLINK(manager->timers, timer, link);
+
+ UNLOCK(&manager->lock);
+
+ isc_task_detach(&timer->task);
+ DESTROYLOCK(&timer->lock);
+ timer->magic = 0;
+ isc_mem_put(manager->mctx, timer, sizeof(*timer));
+}
+
+isc_result_t
+isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type,
+ isc_time_t *expires, isc_interval_t *interval,
+ isc_task_t *task, isc_taskaction_t action, const void *arg,
+ isc_timer_t **timerp)
+{
+ isc_timer_t *timer;
+ isc_result_t result;
+ isc_time_t now;
+
+ /*
+ * Create a new 'type' timer managed by 'manager'. The timers
+ * parameters are specified by 'expires' and 'interval'. Events
+ * will be posted to 'task' and when dispatched 'action' will be
+ * called with 'arg' as the arg value. The new timer is returned
+ * in 'timerp'.
+ */
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+ if (expires == NULL)
+ expires = isc_time_epoch;
+ if (interval == NULL)
+ interval = isc_interval_zero;
+ REQUIRE(type == isc_timertype_inactive ||
+ !(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
+ REQUIRE(timerp != NULL && *timerp == NULL);
+ REQUIRE(type != isc_timertype_limited ||
+ !(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
+
+ /*
+ * Get current time.
+ */
+ if (type != isc_timertype_inactive) {
+ TIME_NOW(&now);
+ } else {
+ /*
+ * We don't have to do this, but it keeps the compiler from
+ * complaining about "now" possibly being used without being
+ * set, even though it will never actually happen.
+ */
+ isc_time_settoepoch(&now);
+ }
+
+
+ timer = isc_mem_get(manager->mctx, sizeof(*timer));
+ if (timer == NULL)
+ return (ISC_R_NOMEMORY);
+
+ timer->manager = manager;
+ timer->references = 1;
+
+ if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
+ result = isc_time_add(&now, interval, &timer->idle);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(manager->mctx, timer, sizeof(*timer));
+ return (result);
+ }
+ } else
+ isc_time_settoepoch(&timer->idle);
+
+ timer->type = type;
+ timer->expires = *expires;
+ timer->interval = *interval;
+ timer->task = NULL;
+ isc_task_attach(task, &timer->task);
+ timer->action = action;
+ /*
+ * Removing the const attribute from "arg" is the best of two
+ * evils here. If the timer->arg member is made const, then
+ * it affects a great many recipients of the timer event
+ * which did not pass in an "arg" that was truly const.
+ * Changing isc_timer_create() to not have "arg" prototyped as const,
+ * though, can cause compilers warnings for calls that *do*
+ * have a truly const arg. The caller will have to carefully
+ * keep track of whether arg started as a true const.
+ */
+ DE_CONST(arg, timer->arg);
+ timer->index = 0;
+ result = isc_mutex_init(&timer->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_task_detach(&timer->task);
+ isc_mem_put(manager->mctx, timer, sizeof(*timer));
+ return (result);
+ }
+ ISC_LINK_INIT(timer, link);
+ timer->magic = TIMER_MAGIC;
+
+ LOCK(&manager->lock);
+
+ /*
+ * Note we don't have to lock the timer like we normally would because
+ * there are no external references to it yet.
+ */
+
+ if (type != isc_timertype_inactive)
+ result = schedule(timer, &now, ISC_TRUE);
+ else
+ result = ISC_R_SUCCESS;
+ if (result == ISC_R_SUCCESS)
+ APPEND(manager->timers, timer, link);
+
+ UNLOCK(&manager->lock);
+
+ if (result != ISC_R_SUCCESS) {
+ timer->magic = 0;
+ DESTROYLOCK(&timer->lock);
+ isc_task_detach(&timer->task);
+ isc_mem_put(manager->mctx, timer, sizeof(*timer));
+ return (result);
+ }
+
+ *timerp = timer;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_timer_reset(isc_timer_t *timer, isc_timertype_t type,
+ isc_time_t *expires, isc_interval_t *interval,
+ isc_boolean_t purge)
+{
+ isc_time_t now;
+ isc_timermgr_t *manager;
+ isc_result_t result;
+
+ /*
+ * Change the timer's type, expires, and interval values to the given
+ * values. If 'purge' is ISC_TRUE, any pending events from this timer
+ * are purged from its task's event queue.
+ */
+
+ REQUIRE(VALID_TIMER(timer));
+ manager = timer->manager;
+ REQUIRE(VALID_MANAGER(manager));
+ if (expires == NULL)
+ expires = isc_time_epoch;
+ if (interval == NULL)
+ interval = isc_interval_zero;
+ REQUIRE(type == isc_timertype_inactive ||
+ !(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
+ REQUIRE(type != isc_timertype_limited ||
+ !(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
+
+ /*
+ * Get current time.
+ */
+ if (type != isc_timertype_inactive) {
+ TIME_NOW(&now);
+ } else {
+ /*
+ * We don't have to do this, but it keeps the compiler from
+ * complaining about "now" possibly being used without being
+ * set, even though it will never actually happen.
+ */
+ isc_time_settoepoch(&now);
+ }
+
+ manager = timer->manager;
+
+ LOCK(&manager->lock);
+ LOCK(&timer->lock);
+
+ if (purge)
+ (void)isc_task_purgerange(timer->task,
+ timer,
+ ISC_TIMEREVENT_FIRSTEVENT,
+ ISC_TIMEREVENT_LASTEVENT,
+ NULL);
+ timer->type = type;
+ timer->expires = *expires;
+ timer->interval = *interval;
+ if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
+ result = isc_time_add(&now, interval, &timer->idle);
+ } else {
+ isc_time_settoepoch(&timer->idle);
+ result = ISC_R_SUCCESS;
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ if (type == isc_timertype_inactive) {
+ deschedule(timer);
+ result = ISC_R_SUCCESS;
+ } else
+ result = schedule(timer, &now, ISC_TRUE);
+ }
+
+ UNLOCK(&timer->lock);
+ UNLOCK(&manager->lock);
+
+ return (result);
+}
+
+isc_timertype_t
+isc_timer_gettype(isc_timer_t *timer) {
+ isc_timertype_t t;
+
+ REQUIRE(VALID_TIMER(timer));
+
+ LOCK(&timer->lock);
+ t = timer->type;
+ UNLOCK(&timer->lock);
+
+ return (t);
+}
+
+isc_result_t
+isc_timer_touch(isc_timer_t *timer) {
+ isc_result_t result;
+ isc_time_t now;
+
+ /*
+ * Set the last-touched time of 'timer' to the current time.
+ */
+
+ REQUIRE(VALID_TIMER(timer));
+
+ LOCK(&timer->lock);
+
+ /*
+ * We'd like to
+ *
+ * REQUIRE(timer->type == isc_timertype_once);
+ *
+ * but we cannot without locking the manager lock too, which we
+ * don't want to do.
+ */
+
+ TIME_NOW(&now);
+ result = isc_time_add(&now, &timer->interval, &timer->idle);
+
+ UNLOCK(&timer->lock);
+
+ return (result);
+}
+
+void
+isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp) {
+ /*
+ * Attach *timerp to timer.
+ */
+
+ REQUIRE(VALID_TIMER(timer));
+ REQUIRE(timerp != NULL && *timerp == NULL);
+
+ LOCK(&timer->lock);
+ timer->references++;
+ UNLOCK(&timer->lock);
+
+ *timerp = timer;
+}
+
+void
+isc_timer_detach(isc_timer_t **timerp) {
+ isc_timer_t *timer;
+ isc_boolean_t free_timer = ISC_FALSE;
+
+ /*
+ * Detach *timerp from its timer.
+ */
+
+ REQUIRE(timerp != NULL);
+ timer = *timerp;
+ REQUIRE(VALID_TIMER(timer));
+
+ LOCK(&timer->lock);
+ REQUIRE(timer->references > 0);
+ timer->references--;
+ if (timer->references == 0)
+ free_timer = ISC_TRUE;
+ UNLOCK(&timer->lock);
+
+ if (free_timer)
+ destroy(timer);
+
+ *timerp = NULL;
+}
+
+static void
+dispatch(isc_timermgr_t *manager, isc_time_t *now) {
+ isc_boolean_t done = ISC_FALSE, post_event, need_schedule;
+ isc_event_t *event;
+ isc_eventtype_t type = 0;
+ isc_timer_t *timer;
+ isc_result_t result;
+ isc_boolean_t idle;
+
+ /*!
+ * The caller must be holding the manager lock.
+ */
+
+ while (manager->nscheduled > 0 && !done) {
+ timer = isc_heap_element(manager->heap, 1);
+ INSIST(timer->type != isc_timertype_inactive);
+ if (isc_time_compare(now, &timer->due) >= 0) {
+ if (timer->type == isc_timertype_ticker) {
+ type = ISC_TIMEREVENT_TICK;
+ post_event = ISC_TRUE;
+ need_schedule = ISC_TRUE;
+ } else if (timer->type == isc_timertype_limited) {
+ int cmp;
+ cmp = isc_time_compare(now, &timer->expires);
+ if (cmp >= 0) {
+ type = ISC_TIMEREVENT_LIFE;
+ post_event = ISC_TRUE;
+ need_schedule = ISC_FALSE;
+ } else {
+ type = ISC_TIMEREVENT_TICK;
+ post_event = ISC_TRUE;
+ need_schedule = ISC_TRUE;
+ }
+ } else if (!isc_time_isepoch(&timer->expires) &&
+ isc_time_compare(now,
+ &timer->expires) >= 0) {
+ type = ISC_TIMEREVENT_LIFE;
+ post_event = ISC_TRUE;
+ need_schedule = ISC_FALSE;
+ } else {
+ idle = ISC_FALSE;
+
+ LOCK(&timer->lock);
+ if (!isc_time_isepoch(&timer->idle) &&
+ isc_time_compare(now,
+ &timer->idle) >= 0) {
+ idle = ISC_TRUE;
+ }
+ UNLOCK(&timer->lock);
+ if (idle) {
+ type = ISC_TIMEREVENT_IDLE;
+ post_event = ISC_TRUE;
+ need_schedule = ISC_FALSE;
+ } else {
+ /*
+ * Idle timer has been touched;
+ * reschedule.
+ */
+ XTRACEID(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TIMER,
+ ISC_MSG_IDLERESCHED,
+ "idle reschedule"),
+ timer);
+ post_event = ISC_FALSE;
+ need_schedule = ISC_TRUE;
+ }
+ }
+
+ if (post_event) {
+ XTRACEID(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TIMER,
+ ISC_MSG_POSTING,
+ "posting"), timer);
+ /*
+ * XXX We could preallocate this event.
+ */
+ event = isc_event_allocate(manager->mctx,
+ timer,
+ type,
+ timer->action,
+ timer->arg,
+ sizeof(*event));
+
+ if (event != NULL)
+ isc_task_send(timer->task, &event);
+ else
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TIMER,
+ ISC_MSG_EVENTNOTALLOC,
+ "couldn't "
+ "allocate event"));
+ }
+
+ timer->index = 0;
+ isc_heap_delete(manager->heap, 1);
+ manager->nscheduled--;
+
+ if (need_schedule) {
+ result = schedule(timer, now, ISC_FALSE);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_TIMER,
+ ISC_MSG_SCHEDFAIL,
+ "couldn't "
+ "schedule timer: %u"),
+ result);
+ }
+ } else {
+ manager->due = timer->due;
+ done = ISC_TRUE;
+ }
+ }
+}
+
+#ifdef ISC_PLATFORM_USETHREADS
+static isc_threadresult_t
+#ifdef _WIN32 /* XXXDCL */
+WINAPI
+#endif
+run(void *uap) {
+ isc_timermgr_t *manager = uap;
+ isc_time_t now;
+ isc_result_t result;
+
+ LOCK(&manager->lock);
+ while (!manager->done) {
+ TIME_NOW(&now);
+
+ XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_RUNNING,
+ "running"), now);
+
+ dispatch(manager, &now);
+
+ if (manager->nscheduled > 0) {
+ XTRACETIME2(isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_WAITUNTIL,
+ "waituntil"),
+ manager->due, now);
+ result = WAITUNTIL(&manager->wakeup, &manager->lock, &manager->due);
+ INSIST(result == ISC_R_SUCCESS ||
+ result == ISC_R_TIMEDOUT);
+ } else {
+ XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_WAIT, "wait"), now);
+ WAIT(&manager->wakeup, &manager->lock);
+ }
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+ ISC_MSG_WAKEUP, "wakeup"));
+ }
+ UNLOCK(&manager->lock);
+
+ return ((isc_threadresult_t)0);
+}
+#endif /* ISC_PLATFORM_USETHREADS */
+
+static isc_boolean_t
+sooner(void *v1, void *v2) {
+ isc_timer_t *t1, *t2;
+
+ t1 = v1;
+ t2 = v2;
+ REQUIRE(VALID_TIMER(t1));
+ REQUIRE(VALID_TIMER(t2));
+
+ if (isc_time_compare(&t1->due, &t2->due) < 0)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+static void
+set_index(void *what, unsigned int index) {
+ isc_timer_t *timer;
+
+ timer = what;
+ REQUIRE(VALID_TIMER(timer));
+
+ timer->index = index;
+}
+
+isc_result_t
+isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) {
+ isc_timermgr_t *manager;
+ isc_result_t result;
+
+ /*
+ * Create a timer manager.
+ */
+
+ REQUIRE(managerp != NULL && *managerp == NULL);
+
+#ifndef ISC_PLATFORM_USETHREADS
+ if (timermgr != NULL) {
+ timermgr->refs++;
+ *managerp = timermgr;
+ return (ISC_R_SUCCESS);
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ manager = isc_mem_get(mctx, sizeof(*manager));
+ if (manager == NULL)
+ return (ISC_R_NOMEMORY);
+
+ manager->magic = TIMER_MANAGER_MAGIC;
+ manager->mctx = NULL;
+ manager->done = ISC_FALSE;
+ INIT_LIST(manager->timers);
+ manager->nscheduled = 0;
+ isc_time_settoepoch(&manager->due);
+ manager->heap = NULL;
+ result = isc_heap_create(mctx, sooner, set_index, 0, &manager->heap);
+ if (result != ISC_R_SUCCESS) {
+ INSIST(result == ISC_R_NOMEMORY);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ return (ISC_R_NOMEMORY);
+ }
+ result = isc_mutex_init(&manager->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_heap_destroy(&manager->heap);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ return (result);
+ }
+ isc_mem_attach(mctx, &manager->mctx);
+#ifdef ISC_PLATFORM_USETHREADS
+ if (isc_condition_init(&manager->wakeup) != ISC_R_SUCCESS) {
+ isc_mem_detach(&manager->mctx);
+ DESTROYLOCK(&manager->lock);
+ isc_heap_destroy(&manager->heap);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ return (ISC_R_UNEXPECTED);
+ }
+ if (isc_thread_create(run, manager, &manager->thread) !=
+ ISC_R_SUCCESS) {
+ isc_mem_detach(&manager->mctx);
+ (void)isc_condition_destroy(&manager->wakeup);
+ DESTROYLOCK(&manager->lock);
+ isc_heap_destroy(&manager->heap);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_thread_create() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ return (ISC_R_UNEXPECTED);
+ }
+#else /* ISC_PLATFORM_USETHREADS */
+ manager->refs = 1;
+ timermgr = manager;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ *managerp = manager;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_timermgr_poke(isc_timermgr_t *manager) {
+#ifdef ISC_PLATFORM_USETHREADS
+ REQUIRE(VALID_MANAGER(manager));
+
+ SIGNAL(&manager->wakeup);
+#else
+ UNUSED(manager);
+#endif
+}
+
+void
+isc_timermgr_destroy(isc_timermgr_t **managerp) {
+ isc_timermgr_t *manager;
+ isc_mem_t *mctx;
+
+ /*
+ * Destroy a timer manager.
+ */
+
+ REQUIRE(managerp != NULL);
+ manager = *managerp;
+ REQUIRE(VALID_MANAGER(manager));
+
+ LOCK(&manager->lock);
+
+#ifndef ISC_PLATFORM_USETHREADS
+ if (manager->refs > 1) {
+ manager->refs--;
+ UNLOCK(&manager->lock);
+ *managerp = NULL;
+ return;
+ }
+
+ isc__timermgr_dispatch();
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ REQUIRE(EMPTY(manager->timers));
+ manager->done = ISC_TRUE;
+
+#ifdef ISC_PLATFORM_USETHREADS
+ XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+ ISC_MSG_SIGNALDESTROY, "signal (destroy)"));
+ SIGNAL(&manager->wakeup);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ UNLOCK(&manager->lock);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Wait for thread to exit.
+ */
+ if (isc_thread_join(manager->thread, NULL) != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_thread_join() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /*
+ * Clean up.
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+ (void)isc_condition_destroy(&manager->wakeup);
+#endif /* ISC_PLATFORM_USETHREADS */
+ DESTROYLOCK(&manager->lock);
+ isc_heap_destroy(&manager->heap);
+ manager->magic = 0;
+ mctx = manager->mctx;
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ isc_mem_detach(&mctx);
+
+ *managerp = NULL;
+}
+
+#ifndef ISC_PLATFORM_USETHREADS
+isc_result_t
+isc__timermgr_nextevent(isc_time_t *when) {
+ if (timermgr == NULL || timermgr->nscheduled == 0)
+ return (ISC_R_NOTFOUND);
+ *when = timermgr->due;
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc__timermgr_dispatch(void) {
+ isc_time_t now;
+ if (timermgr == NULL)
+ return;
+ TIME_NOW(&now);
+ dispatch(timermgr, &now);
+}
+#endif /* ISC_PLATFORM_USETHREADS */
diff --git a/lib/isc/timer_p.h b/lib/isc/timer_p.h
new file mode 100644
index 0000000..fcc7b6c
--- /dev/null
+++ b/lib/isc/timer_p.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2005 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: timer_p.h,v 1.6.18.2 2005/04/29 00:16:51 marka Exp $ */
+
+#ifndef ISC_TIMER_P_H
+#define ISC_TIMER_P_H
+
+/*! \file */
+
+isc_result_t
+isc__timermgr_nextevent(isc_time_t *when);
+
+void
+isc__timermgr_dispatch(void);
+
+#endif /* ISC_TIMER_P_H */
diff --git a/lib/isc/unix/Makefile.in b/lib/isc/unix/Makefile.in
new file mode 100644
index 0000000..afb77a6
--- /dev/null
+++ b/lib/isc/unix/Makefile.in
@@ -0,0 +1,51 @@
+# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-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: Makefile.in,v 1.38.18.1 2004/06/22 02:54:06 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+CINCLUDES = -I${srcdir}/include \
+ -I${srcdir}/../@ISC_THREAD_DIR@/include \
+ -I../include \
+ -I${srcdir}/../include \
+ -I${srcdir}/..
+
+CDEFINES =
+CWARNINGS =
+
+# Alphabetically
+OBJS = @ISC_IPV6_O@ \
+ app.@O@ dir.@O@ entropy.@O@ errno2result.@O@ file.@O@ \
+ fsaccess.@O@ interfaceiter.@O@ keyboard.@O@ net.@O@ \
+ os.@O@ resource.@O@ socket.@O@ stdio.@O@ stdtime.@O@ \
+ strerror.@O@ syslog.@O@ time.@O@
+
+# Alphabetically
+SRCS = @ISC_IPV6_C@ \
+ app.c dir.c entropy.c errno2result.c file.c \
+ fsaccess.c interfaceiter.c keyboard.c net.c \
+ os.c resource.c socket.c stdio.c stdtime.c \
+ strerror.c syslog.c time.c
+
+SUBDIRS = include
+TARGETS = ${OBJS}
+
+@BIND9_MAKE_RULES@
+
+interfaceiter.@O@: interfaceiter.c ifiter_ioctl.c ifiter_sysctl.c ifiter_getifaddrs.c
+
diff --git a/lib/isc/unix/app.c b/lib/isc/unix/app.c
new file mode 100644
index 0000000..59b1f6c
--- /dev/null
+++ b/lib/isc/unix/app.c
@@ -0,0 +1,683 @@
+/*
+ * Copyright (C) 2004, 2005 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: app.c,v 1.50.18.2 2005/04/29 00:17:06 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include <isc/app.h>
+#include <isc/boolean.h>
+#include <isc/condition.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/event.h>
+#include <isc/platform.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#ifdef ISC_PLATFORM_USETHREADS
+#include <pthread.h>
+#else /* ISC_PLATFORM_USETHREADS */
+#include "../timer_p.h"
+#include "../task_p.h"
+#include "socket_p.h"
+#endif /* ISC_PLATFORM_USETHREADS */
+
+static isc_eventlist_t on_run;
+static isc_mutex_t lock;
+static isc_boolean_t shutdown_requested = ISC_FALSE;
+static isc_boolean_t running = ISC_FALSE;
+/*!
+ * We assume that 'want_shutdown' can be read and written atomically.
+ */
+static isc_boolean_t want_shutdown = ISC_FALSE;
+/*
+ * We assume that 'want_reload' can be read and written atomically.
+ */
+static isc_boolean_t want_reload = ISC_FALSE;
+
+static isc_boolean_t blocked = ISC_FALSE;
+#ifdef ISC_PLATFORM_USETHREADS
+static pthread_t blockedthread;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#ifdef HAVE_LINUXTHREADS
+/*!
+ * Linux has sigwait(), but it appears to prevent signal handlers from
+ * running, even if they're not in the set being waited for. This makes
+ * it impossible to get the default actions for SIGILL, SIGSEGV, etc.
+ * Instead of messing with it, we just use sigsuspend() instead.
+ */
+#undef HAVE_SIGWAIT
+/*!
+ * We need to remember which thread is the main thread...
+ */
+static pthread_t main_thread;
+#endif
+
+#ifndef HAVE_SIGWAIT
+static void
+exit_action(int arg) {
+ UNUSED(arg);
+ want_shutdown = ISC_TRUE;
+}
+
+static void
+reload_action(int arg) {
+ UNUSED(arg);
+ want_reload = ISC_TRUE;
+}
+#endif
+
+static isc_result_t
+handle_signal(int sig, void (*handler)(int)) {
+ struct sigaction sa;
+ char strbuf[ISC_STRERRORSIZE];
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handler;
+
+ if (sigfillset(&sa.sa_mask) != 0 ||
+ sigaction(sig, &sa, NULL) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_APP,
+ ISC_MSG_SIGNALSETUP,
+ "handle_signal() %d setup: %s"),
+ sig, strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_start(void) {
+ isc_result_t result;
+ int presult;
+ sigset_t sset;
+ char strbuf[ISC_STRERRORSIZE];
+
+ /*
+ * Start an ISC library application.
+ */
+
+#ifdef NEED_PTHREAD_INIT
+ /*
+ * BSDI 3.1 seg faults in pthread_sigmask() if we don't do this.
+ */
+ presult = pthread_init();
+ if (presult != 0) {
+ isc__strerror(presult, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_start() pthread_init: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+#endif
+
+#ifdef HAVE_LINUXTHREADS
+ main_thread = pthread_self();
+#endif
+
+ result = isc_mutex_init(&lock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+#ifndef HAVE_SIGWAIT
+ /*
+ * Install do-nothing handlers for SIGINT and SIGTERM.
+ *
+ * We install them now because BSDI 3.1 won't block
+ * the default actions, regardless of what we do with
+ * pthread_sigmask().
+ */
+ result = handle_signal(SIGINT, exit_action);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = handle_signal(SIGTERM, exit_action);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#endif
+
+ /*
+ * Always ignore SIGPIPE.
+ */
+ result = handle_signal(SIGPIPE, SIG_IGN);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * On Solaris 2, delivery of a signal whose action is SIG_IGN
+ * will not cause sigwait() to return. We may have inherited
+ * unexpected actions for SIGHUP, SIGINT, and SIGTERM from our parent
+ * process (e.g, Solaris cron). Set an action of SIG_DFL to make
+ * sure sigwait() works as expected. Only do this for SIGTERM and
+ * SIGINT if we don't have sigwait(), since a different handler is
+ * installed above.
+ */
+ result = handle_signal(SIGHUP, SIG_DFL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+#ifdef HAVE_SIGWAIT
+ result = handle_signal(SIGTERM, SIG_DFL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = handle_signal(SIGINT, SIG_DFL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#endif
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Block SIGHUP, SIGINT, SIGTERM.
+ *
+ * If isc_app_start() is called from the main thread before any other
+ * threads have been created, then the pthread_sigmask() call below
+ * will result in all threads having SIGHUP, SIGINT and SIGTERM
+ * blocked by default, ensuring that only the thread that calls
+ * sigwait() for them will get those signals.
+ */
+ if (sigemptyset(&sset) != 0 ||
+ sigaddset(&sset, SIGHUP) != 0 ||
+ sigaddset(&sset, SIGINT) != 0 ||
+ sigaddset(&sset, SIGTERM) != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_start() sigsetops: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ presult = pthread_sigmask(SIG_BLOCK, &sset, NULL);
+ if (presult != 0) {
+ isc__strerror(presult, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_start() pthread_sigmask: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+#else /* ISC_PLATFORM_USETHREADS */
+ /*
+ * Unblock SIGHUP, SIGINT, SIGTERM.
+ *
+ * If we're not using threads, we need to make sure that SIGHUP,
+ * SIGINT and SIGTERM are not inherited as blocked from the parent
+ * process.
+ */
+ if (sigemptyset(&sset) != 0 ||
+ sigaddset(&sset, SIGHUP) != 0 ||
+ sigaddset(&sset, SIGINT) != 0 ||
+ sigaddset(&sset, SIGTERM) != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_start() sigsetops: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ presult = sigprocmask(SIG_UNBLOCK, &sset, NULL);
+ if (presult != 0) {
+ isc__strerror(presult, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_start() sigprocmask: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ ISC_LIST_INIT(on_run);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
+ void *arg)
+{
+ isc_event_t *event;
+ isc_task_t *cloned_task = NULL;
+ isc_result_t result;
+
+ LOCK(&lock);
+
+ if (running) {
+ result = ISC_R_ALREADYRUNNING;
+ goto unlock;
+ }
+
+ /*
+ * Note that we store the task to which we're going to send the event
+ * in the event's "sender" field.
+ */
+ isc_task_attach(task, &cloned_task);
+ event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN,
+ action, arg, sizeof(*event));
+ if (event == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto unlock;
+ }
+
+ ISC_LIST_APPEND(on_run, event, ev_link);
+
+ result = ISC_R_SUCCESS;
+
+ unlock:
+ UNLOCK(&lock);
+
+ return (result);
+}
+
+#ifndef ISC_PLATFORM_USETHREADS
+/*!
+ * Event loop for nonthreaded programs.
+ */
+static isc_result_t
+evloop() {
+ isc_result_t result;
+ while (!want_shutdown) {
+ int n;
+ isc_time_t when, now;
+ struct timeval tv, *tvp;
+ fd_set readfds, writefds;
+ int maxfd;
+ isc_boolean_t readytasks;
+ isc_boolean_t call_timer_dispatch = ISC_FALSE;
+
+ readytasks = isc__taskmgr_ready();
+ if (readytasks) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ call_timer_dispatch = ISC_TRUE;
+ } else {
+ result = isc__timermgr_nextevent(&when);
+ if (result != ISC_R_SUCCESS)
+ tvp = NULL;
+ else {
+ isc_uint64_t us;
+
+ TIME_NOW(&now);
+ us = isc_time_microdiff(&when, &now);
+ if (us == 0)
+ call_timer_dispatch = ISC_TRUE;
+ tv.tv_sec = us / 1000000;
+ tv.tv_usec = us % 1000000;
+ tvp = &tv;
+ }
+ }
+
+ isc__socketmgr_getfdsets(&readfds, &writefds, &maxfd);
+ n = select(maxfd, &readfds, &writefds, NULL, tvp);
+
+ if (n == 0 || call_timer_dispatch) {
+ /*
+ * We call isc__timermgr_dispatch() only when
+ * necessary, in order to reduce overhead. If the
+ * select() call indicates a timeout, we need the
+ * dispatch. Even if not, if we set the 0-timeout
+ * for the select() call, we need to check the timer
+ * events. In the 'readytasks' case, there may be no
+ * timeout event actually, but there is no other way
+ * to reduce the overhead.
+ * Note that we do not have to worry about the case
+ * where a new timer is inserted during the select()
+ * call, since this loop only runs in the non-thread
+ * mode.
+ */
+ isc__timermgr_dispatch();
+ }
+ if (n > 0)
+ (void)isc__socketmgr_dispatch(&readfds, &writefds,
+ maxfd);
+ (void)isc__taskmgr_dispatch();
+
+ if (want_reload) {
+ want_reload = ISC_FALSE;
+ return (ISC_R_RELOAD);
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This is a gross hack to support waiting for condition
+ * variables in nonthreaded programs in a limited way;
+ * see lib/isc/nothreads/include/isc/condition.h.
+ * We implement isc_condition_wait() by entering the
+ * event loop recursively until the want_shutdown flag
+ * is set by isc_condition_signal().
+ */
+
+/*!
+ * \brief True if we are currently executing in the recursive
+ * event loop.
+ */
+static isc_boolean_t in_recursive_evloop = ISC_FALSE;
+
+/*!
+ * \brief True if we are exiting the event loop as the result of
+ * a call to isc_condition_signal() rather than a shutdown
+ * or reload.
+ */
+static isc_boolean_t signalled = ISC_FALSE;
+
+isc_result_t
+isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp) {
+ isc_result_t result;
+
+ UNUSED(cp);
+ UNUSED(mp);
+
+ INSIST(!in_recursive_evloop);
+ in_recursive_evloop = ISC_TRUE;
+
+ INSIST(*mp == 1); /* Mutex must be locked on entry. */
+ --*mp;
+
+ result = evloop();
+ if (result == ISC_R_RELOAD)
+ want_reload = ISC_TRUE;
+ if (signalled) {
+ want_shutdown = ISC_FALSE;
+ signalled = ISC_FALSE;
+ }
+
+ ++*mp;
+ in_recursive_evloop = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__nothread_signal_hack(isc_condition_t *cp) {
+
+ UNUSED(cp);
+
+ INSIST(in_recursive_evloop);
+
+ want_shutdown = ISC_TRUE;
+ signalled = ISC_TRUE;
+ return (ISC_R_SUCCESS);
+}
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+isc_result_t
+isc_app_run(void) {
+ int result;
+ isc_event_t *event, *next_event;
+ isc_task_t *task;
+#ifdef ISC_PLATFORM_USETHREADS
+ sigset_t sset;
+ char strbuf[ISC_STRERRORSIZE];
+#endif /* ISC_PLATFORM_USETHREADS */
+#ifdef HAVE_SIGWAIT
+ int sig;
+#endif
+
+#ifdef HAVE_LINUXTHREADS
+ REQUIRE(main_thread == pthread_self());
+#endif
+
+ LOCK(&lock);
+
+ if (!running) {
+ running = ISC_TRUE;
+
+ /*
+ * Post any on-run events (in FIFO order).
+ */
+ for (event = ISC_LIST_HEAD(on_run);
+ event != NULL;
+ event = next_event) {
+ next_event = ISC_LIST_NEXT(event, ev_link);
+ ISC_LIST_UNLINK(on_run, event, ev_link);
+ task = event->ev_sender;
+ event->ev_sender = NULL;
+ isc_task_sendanddetach(&task, &event);
+ }
+
+ }
+
+ UNLOCK(&lock);
+
+#ifndef HAVE_SIGWAIT
+ /*
+ * Catch SIGHUP.
+ *
+ * We do this here to ensure that the signal handler is installed
+ * (i.e. that it wasn't a "one-shot" handler).
+ */
+ result = handle_signal(SIGHUP, reload_action);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_SUCCESS);
+#endif
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * There is no danger if isc_app_shutdown() is called before we wait
+ * for signals. Signals are blocked, so any such signal will simply
+ * be made pending and we will get it when we call sigwait().
+ */
+
+ while (!want_shutdown) {
+#ifdef HAVE_SIGWAIT
+ /*
+ * Wait for SIGHUP, SIGINT, or SIGTERM.
+ */
+ if (sigemptyset(&sset) != 0 ||
+ sigaddset(&sset, SIGHUP) != 0 ||
+ sigaddset(&sset, SIGINT) != 0 ||
+ sigaddset(&sset, SIGTERM) != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_run() sigsetops: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+
+#ifndef HAVE_UNIXWARE_SIGWAIT
+ result = sigwait(&sset, &sig);
+ if (result == 0) {
+ if (sig == SIGINT ||
+ sig == SIGTERM)
+ want_shutdown = ISC_TRUE;
+ else if (sig == SIGHUP)
+ want_reload = ISC_TRUE;
+ }
+
+#else /* Using UnixWare sigwait semantics. */
+ sig = sigwait(&sset);
+ if (sig >= 0) {
+ if (sig == SIGINT ||
+ sig == SIGTERM)
+ want_shutdown = ISC_TRUE;
+ else if (sig == SIGHUP)
+ want_reload = ISC_TRUE;
+ }
+
+#endif /* HAVE_UNIXWARE_SIGWAIT */
+#else /* Don't have sigwait(). */
+ /*
+ * Listen for all signals.
+ */
+ if (sigemptyset(&sset) != 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_run() sigsetops: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ result = sigsuspend(&sset);
+#endif /* HAVE_SIGWAIT */
+
+ if (want_reload) {
+ want_reload = ISC_FALSE;
+ return (ISC_R_RELOAD);
+ }
+
+ if (want_shutdown && blocked)
+ exit(1);
+ }
+
+#else /* ISC_PLATFORM_USETHREADS */
+
+ (void)isc__taskmgr_dispatch();
+
+ result = evloop();
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_shutdown(void) {
+ isc_boolean_t want_kill = ISC_TRUE;
+ char strbuf[ISC_STRERRORSIZE];
+
+ LOCK(&lock);
+
+ REQUIRE(running);
+
+ if (shutdown_requested)
+ want_kill = ISC_FALSE;
+ else
+ shutdown_requested = ISC_TRUE;
+
+ UNLOCK(&lock);
+
+ if (want_kill) {
+#ifdef HAVE_LINUXTHREADS
+ int result;
+
+ result = pthread_kill(main_thread, SIGTERM);
+ if (result != 0) {
+ isc__strerror(result, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_shutdown() pthread_kill: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+#else
+ if (kill(getpid(), SIGTERM) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_shutdown() kill: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+#endif
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_reload(void) {
+ isc_boolean_t want_kill = ISC_TRUE;
+ char strbuf[ISC_STRERRORSIZE];
+
+ LOCK(&lock);
+
+ REQUIRE(running);
+
+ /*
+ * Don't send the reload signal if we're shutting down.
+ */
+ if (shutdown_requested)
+ want_kill = ISC_FALSE;
+
+ UNLOCK(&lock);
+
+ if (want_kill) {
+#ifdef HAVE_LINUXTHREADS
+ int result;
+
+ result = pthread_kill(main_thread, SIGHUP);
+ if (result != 0) {
+ isc__strerror(result, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_reload() pthread_kill: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+#else
+ if (kill(getpid(), SIGHUP) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_reload() kill: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+#endif
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_app_finish(void) {
+ DESTROYLOCK(&lock);
+}
+
+void
+isc_app_block(void) {
+#ifdef ISC_PLATFORM_USETHREADS
+ sigset_t sset;
+#endif /* ISC_PLATFORM_USETHREADS */
+ REQUIRE(running);
+ REQUIRE(!blocked);
+
+ blocked = ISC_TRUE;
+#ifdef ISC_PLATFORM_USETHREADS
+ blockedthread = pthread_self();
+ RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
+ sigaddset(&sset, SIGINT) == 0 &&
+ sigaddset(&sset, SIGTERM) == 0);
+ RUNTIME_CHECK(pthread_sigmask(SIG_UNBLOCK, &sset, NULL) == 0);
+#endif /* ISC_PLATFORM_USETHREADS */
+}
+
+void
+isc_app_unblock(void) {
+#ifdef ISC_PLATFORM_USETHREADS
+ sigset_t sset;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ REQUIRE(running);
+ REQUIRE(blocked);
+
+ blocked = ISC_FALSE;
+
+#ifdef ISC_PLATFORM_USETHREADS
+ REQUIRE(blockedthread == pthread_self());
+
+ RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
+ sigaddset(&sset, SIGINT) == 0 &&
+ sigaddset(&sset, SIGTERM) == 0);
+ RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0);
+#endif /* ISC_PLATFORM_USETHREADS */
+}
diff --git a/lib/isc/unix/dir.c b/lib/isc/unix/dir.c
new file mode 100644
index 0000000..b627c88
--- /dev/null
+++ b/lib/isc/unix/dir.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2004, 2005 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: dir.c,v 1.20.18.3 2005/09/05 00:18:30 marka Exp $ */
+
+/*! \file
+ * \author Principal Authors: DCL */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <isc/dir.h>
+#include <isc/magic.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+#define ISC_DIR_MAGIC ISC_MAGIC('D', 'I', 'R', '*')
+#define VALID_DIR(dir) ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC)
+
+void
+isc_dir_init(isc_dir_t *dir) {
+ REQUIRE(dir != NULL);
+
+ dir->entry.name[0] = '\0';
+ dir->entry.length = 0;
+
+ dir->handle = NULL;
+
+ dir->magic = ISC_DIR_MAGIC;
+}
+
+/*!
+ * \brief Allocate workspace and open directory stream. If either one fails,
+ * NULL will be returned.
+ */
+isc_result_t
+isc_dir_open(isc_dir_t *dir, const char *dirname) {
+ char *p;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_DIR(dir));
+ REQUIRE(dirname != NULL);
+
+ /*
+ * Copy directory name. Need to have enough space for the name,
+ * a possible path separator, the wildcard, and the final NUL.
+ */
+ if (strlen(dirname) + 3 > sizeof(dir->dirname))
+ /* XXXDCL ? */
+ return (ISC_R_NOSPACE);
+ strcpy(dir->dirname, dirname);
+
+ /*
+ * Append path separator, if needed, and "*".
+ */
+ p = dir->dirname + strlen(dir->dirname);
+ if (dir->dirname < p && *(p - 1) != '/')
+ *p++ = '/';
+ *p++ = '*';
+ *p++ = '\0';
+
+ /*
+ * Open stream.
+ */
+ dir->handle = opendir(dirname);
+
+ if (dir->handle == NULL)
+ return isc__errno2result(errno);
+
+ return (result);
+}
+
+/*!
+ * \brief Return previously retrieved file or get next one.
+
+ * Unix's dirent has
+ * separate open and read functions, but the Win32 and DOS interfaces open
+ * the dir stream and reads the first file in one operation.
+ */
+isc_result_t
+isc_dir_read(isc_dir_t *dir) {
+ struct dirent *entry;
+
+ REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
+
+ /*
+ * Fetch next file in directory.
+ */
+ entry = readdir(dir->handle);
+
+ if (entry == NULL)
+ return (ISC_R_NOMORE);
+
+ /*
+ * Make sure that the space for the name is long enough.
+ */
+ if (sizeof(dir->entry.name) <= strlen(entry->d_name))
+ return (ISC_R_UNEXPECTED);
+
+ strcpy(dir->entry.name, entry->d_name);
+
+ /*
+ * Some dirents have d_namlen, but it is not portable.
+ */
+ dir->entry.length = strlen(entry->d_name);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*!
+ * \brief Close directory stream.
+ */
+void
+isc_dir_close(isc_dir_t *dir) {
+ REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
+
+ (void)closedir(dir->handle);
+ dir->handle = NULL;
+}
+
+/*!
+ * \brief Reposition directory stream at start.
+ */
+isc_result_t
+isc_dir_reset(isc_dir_t *dir) {
+ REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
+
+ rewinddir(dir->handle);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chdir(const char *dirname) {
+ /*!
+ * \brief Change the current directory to 'dirname'.
+ */
+
+ REQUIRE(dirname != NULL);
+
+ if (chdir(dirname) < 0)
+ return (isc__errno2result(errno));
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chroot(const char *dirname) {
+
+ REQUIRE(dirname != NULL);
+
+ if (chroot(dirname) < 0)
+ return (isc__errno2result(errno));
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_createunique(char *templet) {
+ isc_result_t result;
+ char *x;
+ char *p;
+ int i;
+ int pid;
+
+ REQUIRE(templet != NULL);
+
+ /*!
+ * \brief mkdtemp is not portable, so this emulates it.
+ */
+
+ pid = getpid();
+
+ /*
+ * Replace trailing Xs with the process-id, zero-filled.
+ */
+ for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet;
+ x--, pid /= 10)
+ *x = pid % 10 + '0';
+
+ x++; /* Set x to start of ex-Xs. */
+
+ do {
+ i = mkdir(templet, 0700);
+ if (i == 0 || errno != EEXIST)
+ break;
+
+ /*
+ * The BSD algorithm.
+ */
+ p = x;
+ while (*p != '\0') {
+ if (isdigit(*p & 0xff))
+ *p = 'a';
+ else if (*p != 'z')
+ ++*p;
+ else {
+ /*
+ * Reset character and move to next.
+ */
+ *p++ = 'a';
+ continue;
+ }
+
+ break;
+ }
+
+ if (*p == '\0') {
+ /*
+ * Tried all combinations. errno should already
+ * be EEXIST, but ensure it is anyway for
+ * isc__errno2result().
+ */
+ errno = EEXIST;
+ break;
+ }
+ } while (1);
+
+ if (i == -1)
+ result = isc__errno2result(errno);
+ else
+ result = ISC_R_SUCCESS;
+
+ return (result);
+}
diff --git a/lib/isc/unix/entropy.c b/lib/isc/unix/entropy.c
new file mode 100644
index 0000000..4c0d0d0
--- /dev/null
+++ b/lib/isc/unix/entropy.c
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) 2004-2006 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: entropy.c,v 1.71.18.7 2006/12/07 04:53:03 marka Exp $ */
+
+/* \file unix/entropy.c
+ * \brief
+ * This is the system dependent part of the ISC entropy API.
+ */
+
+#include <config.h>
+
+#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <unistd.h>
+
+#include <isc/platform.h>
+#include <isc/strerror.h>
+
+#ifdef ISC_PLATFORM_NEEDSYSSELECTH
+#include <sys/select.h>
+#endif
+
+#include "errno2result.h"
+
+/*%
+ * There is only one variable in the entropy data structures that is not
+ * system independent, but pulling the structure that uses it into this file
+ * ultimately means pulling several other independent structures here also to
+ * resolve their interdependencies. Thus only the problem variable's type
+ * is defined here.
+ */
+#define FILESOURCE_HANDLE_TYPE int
+
+typedef struct {
+ int handle;
+ enum {
+ isc_usocketsource_disconnected,
+ isc_usocketsource_connecting,
+ isc_usocketsource_connected,
+ isc_usocketsource_ndesired,
+ isc_usocketsource_wrote,
+ isc_usocketsource_reading
+ } status;
+ size_t sz_to_recv;
+} isc_entropyusocketsource_t;
+
+#include "../entropy.c"
+
+static unsigned int
+get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
+ isc_entropy_t *ent = source->ent;
+ unsigned char buf[128];
+ int fd = source->sources.file.handle;
+ ssize_t n, ndesired;
+ unsigned int added;
+
+ if (source->bad)
+ return (0);
+
+ desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
+
+ added = 0;
+ while (desired > 0) {
+ ndesired = ISC_MIN(desired, sizeof(buf));
+ n = read(fd, buf, ndesired);
+ if (n < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ goto out;
+ goto err;
+ }
+ if (n == 0)
+ goto err;
+
+ entropypool_adddata(ent, buf, n, n * 8);
+ added += n * 8;
+ desired -= n;
+ }
+ goto out;
+
+ err:
+ (void)close(fd);
+ source->sources.file.handle = -1;
+ source->bad = ISC_TRUE;
+
+ out:
+ return (added);
+}
+
+static unsigned int
+get_from_usocketsource(isc_entropysource_t *source, isc_uint32_t desired) {
+ isc_entropy_t *ent = source->ent;
+ unsigned char buf[128];
+ int fd = source->sources.usocket.handle;
+ ssize_t n = 0, ndesired;
+ unsigned int added;
+ size_t sz_to_recv = source->sources.usocket.sz_to_recv;
+
+ if (source->bad)
+ return (0);
+
+ desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
+
+ added = 0;
+ while (desired > 0) {
+ ndesired = ISC_MIN(desired, sizeof(buf));
+ eagain_loop:
+
+ switch ( source->sources.usocket.status ) {
+ case isc_usocketsource_ndesired:
+ buf[0] = ndesired;
+ if ((n = sendto(fd, buf, 1, 0, NULL, 0)) < 0) {
+ if (errno == EWOULDBLOCK || errno == EINTR ||
+ errno == ECONNRESET)
+ goto out;
+ goto err;
+ }
+ INSIST(n == 1);
+ source->sources.usocket.status =
+ isc_usocketsource_wrote;
+ goto eagain_loop;
+
+ case isc_usocketsource_connecting:
+ case isc_usocketsource_connected:
+ buf[0] = 1;
+ buf[1] = ndesired;
+ if ((n = sendto(fd, buf, 2, 0, NULL, 0)) < 0) {
+ if (errno == EWOULDBLOCK || errno == EINTR ||
+ errno == ECONNRESET)
+ goto out;
+ goto err;
+ }
+ if (n == 1) {
+ source->sources.usocket.status =
+ isc_usocketsource_ndesired;
+ goto eagain_loop;
+ }
+ INSIST(n == 2);
+ source->sources.usocket.status =
+ isc_usocketsource_wrote;
+ /*FALLTHROUGH*/
+
+ case isc_usocketsource_wrote:
+ if (recvfrom(fd, buf, 1, 0, NULL, NULL) != 1) {
+ if (errno == EAGAIN) {
+ /*
+ * The problem of EAGAIN (try again
+ * later) is a major issue on HP-UX.
+ * Solaris actually tries the recvfrom
+ * call again, while HP-UX just dies.
+ * This code is an attempt to let the
+ * entropy pool fill back up (at least
+ * that's what I think the problem is.)
+ * We go to eagain_loop because if we
+ * just "break", then the "desired"
+ * amount gets borked.
+ */
+ usleep(1000);
+ goto eagain_loop;
+ }
+ if (errno == EWOULDBLOCK || errno == EINTR)
+ goto out;
+ goto err;
+ }
+ source->sources.usocket.status =
+ isc_usocketsource_reading;
+ sz_to_recv = buf[0];
+ source->sources.usocket.sz_to_recv = sz_to_recv;
+ if (sz_to_recv > sizeof(buf))
+ goto err;
+ /*FALLTHROUGH*/
+
+ case isc_usocketsource_reading:
+ if (sz_to_recv != 0U) {
+ n = recv(fd, buf, sz_to_recv, 0);
+ if (n < 0) {
+ if (errno == EWOULDBLOCK ||
+ errno == EINTR)
+ goto out;
+ goto err;
+ }
+ } else
+ n = 0;
+ break;
+
+ default:
+ goto err;
+ }
+
+ if ((size_t)n != sz_to_recv)
+ source->sources.usocket.sz_to_recv -= n;
+ else
+ source->sources.usocket.status =
+ isc_usocketsource_connected;
+
+ if (n == 0)
+ goto out;
+
+ entropypool_adddata(ent, buf, n, n * 8);
+ added += n * 8;
+ desired -= n;
+ }
+ goto out;
+
+ err:
+ close(fd);
+ source->bad = ISC_TRUE;
+ source->sources.usocket.status = isc_usocketsource_disconnected;
+ source->sources.usocket.handle = -1;
+
+ out:
+ return (added);
+}
+
+/*
+ * Poll each source, trying to get data from it to stuff into the entropy
+ * pool.
+ */
+static void
+fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
+ unsigned int added;
+ unsigned int remaining;
+ unsigned int needed;
+ unsigned int nsource;
+ isc_entropysource_t *source;
+
+ REQUIRE(VALID_ENTROPY(ent));
+
+ needed = desired;
+
+ /*
+ * This logic is a little strange, so an explanation is in order.
+ *
+ * If needed is 0, it means we are being asked to "fill to whatever
+ * we think is best." This means that if we have at least a
+ * partially full pool (say, > 1/4th of the pool) we probably don't
+ * need to add anything.
+ *
+ * Also, we will check to see if the "pseudo" count is too high.
+ * If it is, try to mix in better data. Too high is currently
+ * defined as 1/4th of the pool.
+ *
+ * Next, if we are asked to add a specific bit of entropy, make
+ * certain that we will do so. Clamp how much we try to add to
+ * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
+ *
+ * Note that if we are in a blocking mode, we will only try to
+ * get as much data as we need, not as much as we might want
+ * to build up.
+ */
+ if (needed == 0) {
+ REQUIRE(!blocking);
+
+ if ((ent->pool.entropy >= RND_POOLBITS / 4)
+ && (ent->pool.pseudo <= RND_POOLBITS / 4))
+ return;
+
+ needed = THRESHOLD_BITS * 4;
+ } else {
+ needed = ISC_MAX(needed, THRESHOLD_BITS);
+ needed = ISC_MIN(needed, RND_POOLBITS);
+ }
+
+ /*
+ * In any case, clamp how much we need to how much we can add.
+ */
+ needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
+
+ /*
+ * But wait! If we're not yet initialized, we need at least
+ * THRESHOLD_BITS
+ * of randomness.
+ */
+ if (ent->initialized < THRESHOLD_BITS)
+ needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
+
+ /*
+ * Poll each file source to see if we can read anything useful from
+ * it. XXXMLG When where are multiple sources, we should keep a
+ * record of which one we last used so we can start from it (or the
+ * next one) to avoid letting some sources build up entropy while
+ * others are always drained.
+ */
+
+ added = 0;
+ remaining = needed;
+ if (ent->nextsource == NULL) {
+ ent->nextsource = ISC_LIST_HEAD(ent->sources);
+ if (ent->nextsource == NULL)
+ return;
+ }
+ source = ent->nextsource;
+ again_file:
+ for (nsource = 0; nsource < ent->nsources; nsource++) {
+ unsigned int got;
+
+ if (remaining == 0)
+ break;
+
+ got = 0;
+
+ switch ( source->type ) {
+ case ENTROPY_SOURCETYPE_FILE:
+ got = get_from_filesource(source, remaining);
+ break;
+
+ case ENTROPY_SOURCETYPE_USOCKET:
+ got = get_from_usocketsource(source, remaining);
+ break;
+ }
+
+ added += got;
+
+ remaining -= ISC_MIN(remaining, got);
+
+ source = ISC_LIST_NEXT(source, link);
+ if (source == NULL)
+ source = ISC_LIST_HEAD(ent->sources);
+ }
+ ent->nextsource = source;
+
+ if (blocking && remaining != 0) {
+ int fds;
+
+ fds = wait_for_sources(ent);
+ if (fds > 0)
+ goto again_file;
+ }
+
+ /*
+ * Here, if there are bits remaining to be had and we can block,
+ * check to see if we have a callback source. If so, call them.
+ */
+ source = ISC_LIST_HEAD(ent->sources);
+ while ((remaining != 0) && (source != NULL)) {
+ unsigned int got;
+
+ got = 0;
+
+ if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
+ got = get_from_callback(source, remaining, blocking);
+
+ added += got;
+ remaining -= ISC_MIN(remaining, got);
+
+ if (added >= needed)
+ break;
+
+ source = ISC_LIST_NEXT(source, link);
+ }
+
+ /*
+ * Mark as initialized if we've added enough data.
+ */
+ if (ent->initialized < THRESHOLD_BITS)
+ ent->initialized += added;
+}
+
+static int
+wait_for_sources(isc_entropy_t *ent) {
+ isc_entropysource_t *source;
+ int maxfd, fd;
+ int cc;
+ fd_set reads;
+ fd_set writes;
+
+ maxfd = -1;
+ FD_ZERO(&reads);
+ FD_ZERO(&writes);
+
+ source = ISC_LIST_HEAD(ent->sources);
+ while (source != NULL) {
+ if (source->type == ENTROPY_SOURCETYPE_FILE) {
+ fd = source->sources.file.handle;
+ if (fd >= 0) {
+ maxfd = ISC_MAX(maxfd, fd);
+ FD_SET(fd, &reads);
+ }
+ }
+ if (source->type == ENTROPY_SOURCETYPE_USOCKET) {
+ fd = source->sources.usocket.handle;
+ if (fd >= 0) {
+ switch (source->sources.usocket.status) {
+ case isc_usocketsource_disconnected:
+ break;
+ case isc_usocketsource_connecting:
+ case isc_usocketsource_connected:
+ case isc_usocketsource_ndesired:
+ maxfd = ISC_MAX(maxfd, fd);
+ FD_SET(fd, &writes);
+ break;
+ case isc_usocketsource_wrote:
+ case isc_usocketsource_reading:
+ maxfd = ISC_MAX(maxfd, fd);
+ FD_SET(fd, &reads);
+ break;
+ }
+ }
+ }
+ source = ISC_LIST_NEXT(source, link);
+ }
+
+ if (maxfd < 0)
+ return (-1);
+
+ cc = select(maxfd + 1, &reads, &writes, NULL, NULL);
+ if (cc < 0)
+ return (-1);
+
+ return (cc);
+}
+
+static void
+destroyfilesource(isc_entropyfilesource_t *source) {
+ (void)close(source->handle);
+}
+
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source) {
+ close(source->handle);
+}
+
+/*
+ * Make a fd non-blocking
+ */
+static isc_result_t
+make_nonblock(int fd) {
+ int ret;
+ int flags;
+ char strbuf[ISC_STRERRORSIZE];
+#ifdef USE_FIONBIO_IOCTL
+ int on = 1;
+
+ ret = ioctl(fd, FIONBIO, (char *)&on);
+#else
+ flags = fcntl(fd, F_GETFL, 0);
+ flags |= PORT_NONBLOCK;
+ ret = fcntl(fd, F_SETFL, flags);
+#endif
+
+ if (ret == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+#ifdef USE_FIONBIO_IOCTL
+ "ioctl(%d, FIONBIO, &on): %s", fd,
+#else
+ "fcntl(%d, F_SETFL, %d): %s", fd, flags,
+#endif
+ strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
+ int fd;
+ struct stat _stat;
+ isc_boolean_t is_usocket = ISC_FALSE;
+ isc_boolean_t is_connected = ISC_FALSE;
+ isc_result_t ret;
+ isc_entropysource_t *source;
+
+ REQUIRE(VALID_ENTROPY(ent));
+ REQUIRE(fname != NULL);
+
+ LOCK(&ent->lock);
+
+ if (stat(fname, &_stat) < 0) {
+ ret = isc__errno2result(errno);
+ goto errout;
+ }
+ /*
+ * Solaris 2.5.1 does not have support for sockets (S_IFSOCK),
+ * but it does return type S_IFIFO (the OS believes that
+ * the socket is a fifo). This may be an issue if we tell
+ * the program to look at an actual FIFO as its source of
+ * entropy.
+ */
+#if defined(S_ISSOCK)
+ if (S_ISSOCK(_stat.st_mode))
+ is_usocket = ISC_TRUE;
+#endif
+#if defined(S_ISFIFO) && defined(sun)
+ if (S_ISFIFO(_stat.st_mode))
+ is_usocket = ISC_TRUE;
+#endif
+ if (is_usocket)
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ else
+ fd = open(fname, O_RDONLY | PORT_NONBLOCK, 0);
+
+ if (fd < 0) {
+ ret = isc__errno2result(errno);
+ goto errout;
+ }
+
+ ret = make_nonblock(fd);
+ if (ret != ISC_R_SUCCESS)
+ goto closefd;
+
+ if (is_usocket) {
+ struct sockaddr_un sname;
+
+ memset(&sname, 0, sizeof(sname));
+ sname.sun_family = AF_UNIX;
+ strncpy(sname.sun_path, fname, sizeof(sname.sun_path));
+ sname.sun_path[sizeof(sname.sun_path)-1] = '0';
+#ifdef ISC_PLATFORM_HAVESALEN
+#if !defined(SUN_LEN)
+#define SUN_LEN(su) \
+ (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
+ sname.sun_len = SUN_LEN(&sname);
+#endif
+
+ if (connect(fd, (struct sockaddr *) &sname,
+ sizeof(struct sockaddr_un)) < 0) {
+ if (errno != EINPROGRESS) {
+ ret = isc__errno2result(errno);
+ goto closefd;
+ }
+ } else
+ is_connected = ISC_TRUE;
+ }
+
+ source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
+ if (source == NULL) {
+ ret = ISC_R_NOMEMORY;
+ goto closefd;
+ }
+
+ /*
+ * From here down, no failures can occur.
+ */
+ source->magic = SOURCE_MAGIC;
+ source->ent = ent;
+ source->total = 0;
+ source->bad = ISC_FALSE;
+ memset(source->name, 0, sizeof(source->name));
+ ISC_LINK_INIT(source, link);
+ if (is_usocket) {
+ source->sources.usocket.handle = fd;
+ if (is_connected)
+ source->sources.usocket.status =
+ isc_usocketsource_connected;
+ else
+ source->sources.usocket.status =
+ isc_usocketsource_connecting;
+ source->sources.usocket.sz_to_recv = 0;
+ source->type = ENTROPY_SOURCETYPE_USOCKET;
+ } else {
+ source->sources.file.handle = fd;
+ source->type = ENTROPY_SOURCETYPE_FILE;
+ }
+
+ /*
+ * Hook it into the entropy system.
+ */
+ ISC_LIST_APPEND(ent->sources, source, link);
+ ent->nsources++;
+
+ UNLOCK(&ent->lock);
+ return (ISC_R_SUCCESS);
+
+ closefd:
+ (void)close(fd);
+
+ errout:
+ UNLOCK(&ent->lock);
+
+ return (ret);
+}
diff --git a/lib/isc/unix/errno2result.c b/lib/isc/unix/errno2result.c
new file mode 100644
index 0000000..d4b188f
--- /dev/null
+++ b/lib/isc/unix/errno2result.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2004, 2005 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: errno2result.c,v 1.13.18.2 2005/04/29 00:17:07 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/result.h>
+#include <isc/strerror.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+/*%
+ * Convert a POSIX errno value into an isc_result_t. The
+ * list of supported errno values is not complete; new users
+ * of this function should add any expected errors that are
+ * not already there.
+ */
+isc_result_t
+isc__errno2result(int posixerrno) {
+ char strbuf[ISC_STRERRORSIZE];
+
+ switch (posixerrno) {
+ case ENOTDIR:
+ case ELOOP:
+ case EINVAL: /* XXX sometimes this is not for files */
+ case ENAMETOOLONG:
+ case EBADF:
+ return (ISC_R_INVALIDFILE);
+ case ENOENT:
+ return (ISC_R_FILENOTFOUND);
+ case EACCES:
+ case EPERM:
+ return (ISC_R_NOPERM);
+ case EEXIST:
+ return (ISC_R_FILEEXISTS);
+ case EIO:
+ return (ISC_R_IOERROR);
+ case ENOMEM:
+ return (ISC_R_NOMEMORY);
+ case ENFILE:
+ case EMFILE:
+ return (ISC_R_TOOMANYOPENFILES);
+ case EPIPE:
+#ifdef ECONNRESET
+ case ECONNRESET:
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED:
+#endif
+ return (ISC_R_CONNECTIONRESET);
+#ifdef ENOTCONN
+ case ENOTCONN:
+ return (ISC_R_NOTCONNECTED);
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT:
+ return (ISC_R_TIMEDOUT);
+#endif
+#ifdef ENOBUFS
+ case ENOBUFS:
+ return (ISC_R_NORESOURCES);
+#endif
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT:
+ return (ISC_R_FAMILYNOSUPPORT);
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN:
+ return (ISC_R_NETDOWN);
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN:
+ return (ISC_R_HOSTDOWN);
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH:
+ return (ISC_R_NETUNREACH);
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH:
+ return (ISC_R_HOSTUNREACH);
+#endif
+#ifdef EADDRINUSE
+ case EADDRINUSE:
+ return (ISC_R_ADDRINUSE);
+#endif
+ case EADDRNOTAVAIL:
+ return (ISC_R_ADDRNOTAVAIL);
+ case ECONNREFUSED:
+ return (ISC_R_CONNREFUSED);
+ default:
+ isc__strerror(posixerrno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "unable to convert errno "
+ "to isc_result: %d: %s",
+ posixerrno, strbuf);
+ /*
+ * XXXDCL would be nice if perhaps this function could
+ * return the system's error string, so the caller
+ * might have something more descriptive than "unexpected
+ * error" to log with.
+ */
+ return (ISC_R_UNEXPECTED);
+ }
+}
diff --git a/lib/isc/unix/errno2result.h b/lib/isc/unix/errno2result.h
new file mode 100644
index 0000000..5e36116
--- /dev/null
+++ b/lib/isc/unix/errno2result.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2004, 2005 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: errno2result.h,v 1.8.18.2 2005/04/29 00:17:07 marka Exp $ */
+
+#ifndef UNIX_ERRNO2RESULT_H
+#define UNIX_ERRNO2RESULT_H 1
+
+/*! \file */
+
+/* XXXDCL this should be moved to lib/isc/include/isc/errno2result.h. */
+
+#include <errno.h> /* Provides errno. */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc__errno2result(int posixerrno);
+
+ISC_LANG_ENDDECLS
+
+#endif /* UNIX_ERRNO2RESULT_H */
diff --git a/lib/isc/unix/file.c b/lib/isc/unix/file.c
new file mode 100644
index 0000000..e45e0fe
--- /dev/null
+++ b/lib/isc/unix/file.c
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2004, 2005 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.
+ */
+
+/*
+ * Portions 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.
+ */
+
+/* $Id: file.c,v 1.47.18.2 2005/04/29 00:17:07 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <time.h> /* Required for utimes on some platforms. */
+#include <unistd.h> /* Required for mkstemp on NetBSD. */
+
+
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <isc/dir.h>
+#include <isc/file.h>
+#include <isc/random.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+/*
+ * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
+ * it might be good to provide a mechanism that allows for the results
+ * of a previous stat() to be used again without having to do another stat,
+ * such as perl's mechanism of using "_" in place of a file name to indicate
+ * that the results of the last stat should be used. But then you get into
+ * annoying MP issues. BTW, Win32 has stat().
+ */
+static isc_result_t
+file_stats(const char *file, struct stat *stats) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(file != NULL);
+ REQUIRE(stats != NULL);
+
+ if (stat(file, stats) != 0)
+ result = isc__errno2result(errno);
+
+ return (result);
+}
+
+isc_result_t
+isc_file_getmodtime(const char *file, isc_time_t *time) {
+ isc_result_t result;
+ struct stat stats;
+
+ REQUIRE(file != NULL);
+ REQUIRE(time != NULL);
+
+ result = file_stats(file, &stats);
+
+ if (result == ISC_R_SUCCESS)
+ /*
+ * XXXDCL some operating systems provide nanoseconds, too,
+ * such as BSD/OS via st_mtimespec.
+ */
+ isc_time_set(time, stats.st_mtime, 0);
+
+ return (result);
+}
+
+isc_result_t
+isc_file_settime(const char *file, isc_time_t *time) {
+ struct timeval times[2];
+
+ REQUIRE(file != NULL && time != NULL);
+
+ /*
+ * tv_sec is at least a 32 bit quantity on all platforms we're
+ * dealing with, but it is signed on most (all?) of them,
+ * so we need to make sure the high bit isn't set. This unfortunately
+ * loses when either:
+ * * tv_sec becomes a signed 64 bit integer but long is 32 bits
+ * and isc_time_seconds > LONG_MAX, or
+ * * isc_time_seconds is changed to be > 32 bits but long is 32 bits
+ * and isc_time_seconds has at least 33 significant bits.
+ */
+ times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(time);
+
+ /*
+ * Here is the real check for the high bit being set.
+ */
+ if ((times[0].tv_sec &
+ (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0)
+ return (ISC_R_RANGE);
+
+ /*
+ * isc_time_nanoseconds guarantees a value that divided by 1000 will
+ * fit into the minimum possible size tv_usec field. Unfortunately,
+ * we don't know what that type is so can't cast directly ... but
+ * we can at least cast to signed so the IRIX compiler shuts up.
+ */
+ times[0].tv_usec = times[1].tv_usec =
+ (isc_int32_t)(isc_time_nanoseconds(time) / 1000);
+
+ if (utimes(file, times) < 0)
+ return (isc__errno2result(errno));
+
+ return (ISC_R_SUCCESS);
+}
+
+#undef TEMPLATE
+#define TEMPLATE "tmp-XXXXXXXXXX" /*%< 14 characters. */
+
+isc_result_t
+isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
+ return (isc_file_template(path, TEMPLATE, buf, buflen));
+}
+
+isc_result_t
+isc_file_template(const char *path, const char *templet, char *buf,
+ size_t buflen) {
+ char *s;
+
+ REQUIRE(path != NULL);
+ REQUIRE(templet != NULL);
+ REQUIRE(buf != NULL);
+
+ s = strrchr(templet, '/');
+ if (s != NULL)
+ templet = s + 1;
+
+ s = strrchr(path, '/');
+
+ if (s != NULL) {
+ if ((s - path + 1 + strlen(templet) + 1) > buflen)
+ return (ISC_R_NOSPACE);
+
+ strncpy(buf, path, s - path + 1);
+ buf[s - path + 1] = '\0';
+ strcat(buf, templet);
+ } else {
+ if ((strlen(templet) + 1) > buflen)
+ return (ISC_R_NOSPACE);
+
+ strcpy(buf, templet);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static char alphnum[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+isc_result_t
+isc_file_renameunique(const char *file, char *templet) {
+ char *x;
+ char *cp;
+ isc_uint32_t which;
+
+ REQUIRE(file != NULL);
+ REQUIRE(templet != NULL);
+
+ cp = templet;
+ while (*cp != '\0')
+ cp++;
+ if (cp == templet)
+ return (ISC_R_FAILURE);
+
+ x = cp--;
+ while (cp >= templet && *cp == 'X') {
+ isc_random_get(&which);
+ *cp = alphnum[which % (sizeof(alphnum) - 1)];
+ x = cp--;
+ }
+ while (link(file, templet) == -1) {
+ if (errno != EEXIST)
+ return (isc__errno2result(errno));
+ for (cp = x;;) {
+ char *t;
+ if (*cp == '\0')
+ return (ISC_R_FAILURE);
+ t = strchr(alphnum, *cp);
+ if (t == NULL || *++t == '\0')
+ *cp++ = alphnum[0];
+ else {
+ *cp = *t;
+ break;
+ }
+ }
+ }
+ (void)unlink(file);
+ return (ISC_R_SUCCESS);
+}
+
+
+isc_result_t
+isc_file_openunique(char *templet, FILE **fp) {
+ int fd;
+ FILE *f;
+ isc_result_t result = ISC_R_SUCCESS;
+ char *x;
+ char *cp;
+ isc_uint32_t which;
+ int mode;
+
+ REQUIRE(templet != NULL);
+ REQUIRE(fp != NULL && *fp == NULL);
+
+ cp = templet;
+ while (*cp != '\0')
+ cp++;
+ if (cp == templet)
+ return (ISC_R_FAILURE);
+
+ x = cp--;
+ while (cp >= templet && *cp == 'X') {
+ isc_random_get(&which);
+ *cp = alphnum[which % (sizeof(alphnum) - 1)];
+ x = cp--;
+ }
+
+ mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+
+ while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) {
+ if (errno != EEXIST)
+ return (isc__errno2result(errno));
+ for (cp = x;;) {
+ char *t;
+ if (*cp == '\0')
+ return (ISC_R_FAILURE);
+ t = strchr(alphnum, *cp);
+ if (t == NULL || *++t == '\0')
+ *cp++ = alphnum[0];
+ else {
+ *cp = *t;
+ break;
+ }
+ }
+ }
+ f = fdopen(fd, "w+");
+ if (f == NULL) {
+ result = isc__errno2result(errno);
+ (void)remove(templet);
+ (void)close(fd);
+ } else
+ *fp = f;
+
+ return (result);
+}
+
+isc_result_t
+isc_file_remove(const char *filename) {
+ int r;
+
+ REQUIRE(filename != NULL);
+
+ r = unlink(filename);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_file_rename(const char *oldname, const char *newname) {
+ int r;
+
+ REQUIRE(oldname != NULL);
+ REQUIRE(newname != NULL);
+
+ r = rename(oldname, newname);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_boolean_t
+isc_file_exists(const char *pathname) {
+ struct stat stats;
+
+ REQUIRE(pathname != NULL);
+
+ return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
+}
+
+isc_boolean_t
+isc_file_isabsolute(const char *filename) {
+ REQUIRE(filename != NULL);
+ return (ISC_TF(filename[0] == '/'));
+}
+
+isc_boolean_t
+isc_file_iscurrentdir(const char *filename) {
+ REQUIRE(filename != NULL);
+ return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
+}
+
+isc_boolean_t
+isc_file_ischdiridempotent(const char *filename) {
+ REQUIRE(filename != NULL);
+ if (isc_file_isabsolute(filename))
+ return (ISC_TRUE);
+ if (isc_file_iscurrentdir(filename))
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+const char *
+isc_file_basename(const char *filename) {
+ char *s;
+
+ REQUIRE(filename != NULL);
+
+ s = strrchr(filename, '/');
+ if (s == NULL)
+ return (filename);
+
+ return (s + 1);
+}
+
+isc_result_t
+isc_file_progname(const char *filename, char *buf, size_t buflen) {
+ const char *base;
+ size_t len;
+
+ REQUIRE(filename != NULL);
+ REQUIRE(buf != NULL);
+
+ base = isc_file_basename(filename);
+ len = strlen(base) + 1;
+
+ if (len > buflen)
+ return (ISC_R_NOSPACE);
+ memcpy(buf, base, len);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Put the absolute name of the current directory into 'dirname', which is
+ * a buffer of at least 'length' characters. End the string with the
+ * appropriate path separator, such that the final product could be
+ * concatenated with a relative pathname to make a valid pathname string.
+ */
+static isc_result_t
+dir_current(char *dirname, size_t length) {
+ char *cwd;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(dirname != NULL);
+ REQUIRE(length > 0U);
+
+ cwd = getcwd(dirname, length);
+
+ if (cwd == NULL) {
+ if (errno == ERANGE)
+ result = ISC_R_NOSPACE;
+ else
+ result = isc__errno2result(errno);
+ } else {
+ if (strlen(dirname) + 1 == length)
+ result = ISC_R_NOSPACE;
+ else if (dirname[1] != '\0')
+ strcat(dirname, "/");
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
+ isc_result_t result;
+ result = dir_current(path, pathlen);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (strlen(path) + strlen(filename) + 1 > pathlen)
+ return (ISC_R_NOSPACE);
+ strcat(path, filename);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_truncate(const char *filename, isc_offset_t size) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ if (truncate(filename, size) < 0)
+ result = isc__errno2result(errno);
+ return (result);
+}
diff --git a/lib/isc/unix/fsaccess.c b/lib/isc/unix/fsaccess.c
new file mode 100644
index 0000000..f3ed60f
--- /dev/null
+++ b/lib/isc/unix/fsaccess.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2004-2006 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: fsaccess.c,v 1.7.18.4 2006/08/25 05:25:51 marka Exp $ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+
+#include "errno2result.h"
+
+/*! \file
+ * \brief
+ * The OS-independent part of the API is in lib/isc.
+ */
+#include "../fsaccess.c"
+
+isc_result_t
+isc_fsaccess_set(const char *path, isc_fsaccess_t access) {
+ struct stat statb;
+ mode_t mode;
+ isc_boolean_t is_dir = ISC_FALSE;
+ isc_fsaccess_t bits;
+ isc_result_t result;
+
+ if (stat(path, &statb) != 0)
+ return (isc__errno2result(errno));
+
+ if ((statb.st_mode & S_IFDIR) != 0)
+ is_dir = ISC_TRUE;
+ else if ((statb.st_mode & S_IFREG) == 0)
+ return (ISC_R_INVALIDFILE);
+
+ result = check_bad_bits(access, is_dir);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Done with checking bad bits. Set mode_t.
+ */
+ mode = 0;
+
+#define SET_AND_CLEAR1(modebit) \
+ if ((access & bits) != 0) { \
+ mode |= modebit; \
+ access &= ~bits; \
+ }
+#define SET_AND_CLEAR(user, group, other) \
+ SET_AND_CLEAR1(user); \
+ bits <<= STEP; \
+ SET_AND_CLEAR1(group); \
+ bits <<= STEP; \
+ SET_AND_CLEAR1(other);
+
+ bits = ISC_FSACCESS_READ | ISC_FSACCESS_LISTDIRECTORY;
+
+ SET_AND_CLEAR(S_IRUSR, S_IRGRP, S_IROTH);
+
+ bits = ISC_FSACCESS_WRITE |
+ ISC_FSACCESS_CREATECHILD |
+ ISC_FSACCESS_DELETECHILD;
+
+ SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH);
+
+ bits = ISC_FSACCESS_EXECUTE |
+ ISC_FSACCESS_ACCESSCHILD;
+
+ SET_AND_CLEAR(S_IXUSR, S_IXGRP, S_IXOTH);
+
+ INSIST(access == 0);
+
+ if (chmod(path, mode) < 0)
+ return (isc__errno2result(errno));
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/unix/ifiter_getifaddrs.c b/lib/isc/unix/ifiter_getifaddrs.c
new file mode 100644
index 0000000..3599a89
--- /dev/null
+++ b/lib/isc/unix/ifiter_getifaddrs.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ifiter_getifaddrs.c,v 1.4.18.5 2007/08/28 07:20:06 tbox Exp $ */
+
+/*! \file
+ * \brief
+ * Obtain the list of network interfaces using the getifaddrs(3) library.
+ */
+
+#include <ifaddrs.h>
+
+/*% Iterator Magic */
+#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'G')
+/*% Valid Iterator */
+#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
+
+/*% Iterator structure */
+struct isc_interfaceiter {
+ unsigned int magic; /*%< Magic number. */
+ isc_mem_t *mctx;
+ void *buf; /*%< (unused) */
+ unsigned int bufsize; /*%< (always 0) */
+ struct ifaddrs *ifaddrs; /*%< List of ifaddrs */
+ struct ifaddrs *pos; /*%< Ptr to current ifaddr */
+ isc_interface_t current; /*%< Current interface data. */
+ isc_result_t result; /*%< Last result code. */
+};
+
+
+isc_result_t
+isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
+ isc_interfaceiter_t *iter;
+ isc_result_t result;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(iterp != NULL);
+ REQUIRE(*iterp == NULL);
+
+ iter = isc_mem_get(mctx, sizeof(*iter));
+ if (iter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ iter->mctx = mctx;
+ iter->buf = NULL;
+ iter->bufsize = 0;
+ iter->ifaddrs = NULL;
+
+ if (getifaddrs(&iter->ifaddrs) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERGETIFADDRS,
+ ISC_MSG_GETIFADDRS,
+ "getting interface "
+ "addresses: getifaddrs: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto failure;
+ }
+
+ /*
+ * A newly created iterator has an undefined position
+ * until isc_interfaceiter_first() is called.
+ */
+ iter->pos = NULL;
+ iter->result = ISC_R_FAILURE;
+
+ iter->magic = IFITER_MAGIC;
+ *iterp = iter;
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (iter->ifaddrs != NULL) /* just in case */
+ freeifaddrs(iter->ifaddrs);
+ isc_mem_put(mctx, iter, sizeof(*iter));
+ return (result);
+}
+
+/*
+ * Get information about the current interface to iter->current.
+ * If successful, return ISC_R_SUCCESS.
+ * If the interface has an unsupported address family,
+ * return ISC_R_IGNORE.
+ */
+
+static isc_result_t
+internal_current(isc_interfaceiter_t *iter) {
+ struct ifaddrs *ifa;
+ int family;
+ unsigned int namelen;
+
+ REQUIRE(VALID_IFITER(iter));
+
+ ifa = iter->pos;
+
+ INSIST(ifa != NULL);
+ INSIST(ifa->ifa_name != NULL);
+
+ if (ifa->ifa_addr == NULL)
+ return (ISC_R_IGNORE);
+
+ family = ifa->ifa_addr->sa_family;
+ if (family != AF_INET && family != AF_INET6)
+ return (ISC_R_IGNORE);
+
+ memset(&iter->current, 0, sizeof(iter->current));
+
+ namelen = strlen(ifa->ifa_name);
+ if (namelen > sizeof(iter->current.name) - 1)
+ namelen = sizeof(iter->current.name) - 1;
+
+ memset(iter->current.name, 0, sizeof(iter->current.name));
+ memcpy(iter->current.name, ifa->ifa_name, namelen);
+
+ iter->current.flags = 0;
+
+ if ((ifa->ifa_flags & IFF_UP) != 0)
+ iter->current.flags |= INTERFACE_F_UP;
+
+ if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
+ iter->current.flags |= INTERFACE_F_POINTTOPOINT;
+
+ if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
+ iter->current.flags |= INTERFACE_F_LOOPBACK;
+
+ iter->current.af = family;
+
+ get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
+
+ if (ifa->ifa_netmask != NULL)
+ get_addr(family, &iter->current.netmask, ifa->ifa_netmask,
+ ifa->ifa_name);
+
+ if (ifa->ifa_dstaddr != NULL &&
+ (iter->current.flags & IFF_POINTOPOINT) != 0)
+ get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
+ ifa->ifa_name);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Step the iterator to the next interface. Unlike
+ * isc_interfaceiter_next(), this may leave the iterator
+ * positioned on an interface that will ultimately
+ * be ignored. Return ISC_R_NOMORE if there are no more
+ * interfaces, otherwise ISC_R_SUCCESS.
+ */
+static isc_result_t
+internal_next(isc_interfaceiter_t *iter) {
+ iter->pos = iter->pos->ifa_next;
+
+ if (iter->pos == NULL)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+internal_destroy(isc_interfaceiter_t *iter) {
+ if (iter->ifaddrs)
+ freeifaddrs(iter->ifaddrs);
+ iter->ifaddrs = NULL;
+}
+
+static
+void internal_first(isc_interfaceiter_t *iter) {
+ iter->pos = iter->ifaddrs;
+}
diff --git a/lib/isc/unix/ifiter_ioctl.c b/lib/isc/unix/ifiter_ioctl.c
new file mode 100644
index 0000000..ce63de7
--- /dev/null
+++ b/lib/isc/unix/ifiter_ioctl.c
@@ -0,0 +1,1029 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ifiter_ioctl.c,v 1.44.18.13 2007/08/31 23:46:25 tbox Exp $ */
+
+/*! \file
+ * \brief
+ * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
+ * See netintro(4).
+ */
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
+#define lifc_len iflc_len
+#define lifc_buf iflc_buf
+#define lifc_req iflc_req
+#define LIFCONF if_laddrconf
+#else
+#define ISC_HAVE_LIFC_FAMILY 1
+#define ISC_HAVE_LIFC_FLAGS 1
+#define LIFCONF lifconf
+#endif
+
+#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
+#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
+#endif
+
+#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'T')
+#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
+
+#define ISC_IF_INET6_SZ \
+ sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
+
+struct isc_interfaceiter {
+ unsigned int magic; /* Magic number. */
+ isc_mem_t *mctx;
+ int mode;
+ int socket;
+ struct ifconf ifc;
+ void *buf; /* Buffer for sysctl data. */
+ unsigned int bufsize; /* Bytes allocated. */
+ unsigned int pos; /* Current offset in
+ SIOCGIFCONF data */
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ int socket6;
+ struct LIFCONF lifc;
+ void *buf6; /* Buffer for sysctl data. */
+ unsigned int bufsize6; /* Bytes allocated. */
+ unsigned int pos6; /* Current offset in
+ SIOCGLIFCONF data */
+ isc_result_t result6; /* Last result code. */
+ isc_boolean_t first6;
+#endif
+#ifdef HAVE_TRUCLUSTER
+ int clua_context; /* Cluster alias context */
+ isc_boolean_t clua_done;
+ struct sockaddr clua_sa;
+#endif
+#ifdef __linux
+ FILE * proc;
+ char entry[ISC_IF_INET6_SZ];
+ isc_result_t valid;
+ isc_boolean_t first;
+#endif
+ isc_interface_t current; /* Current interface data. */
+ isc_result_t result; /* Last result code. */
+};
+
+#ifdef HAVE_TRUCLUSTER
+#include <clua/clua.h>
+#include <sys/socket.h>
+#endif
+
+
+/*%
+ * Size of buffer for SIOCGLIFCONF, in bytes. We assume no sane system
+ * will have more than a megabyte of interface configuration data.
+ */
+#define IFCONF_BUFSIZE_INITIAL 4096
+#define IFCONF_BUFSIZE_MAX 1048576
+
+#ifdef __linux
+#ifndef IF_NAMESIZE
+# ifdef IFNAMSIZ
+# define IF_NAMESIZE IFNAMSIZ
+# else
+# define IF_NAMESIZE 16
+# endif
+#endif
+#endif
+
+static isc_result_t
+getbuf4(isc_interfaceiter_t *iter) {
+ char strbuf[ISC_STRERRORSIZE];
+
+ iter->bufsize = IFCONF_BUFSIZE_INITIAL;
+
+ for (;;) {
+ iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
+ if (iter->buf == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
+ iter->ifc.ifc_len = iter->bufsize;
+ iter->ifc.ifc_buf = iter->buf;
+ /*
+ * Ignore the HP/UX warning about "interger overflow during
+ * conversion". It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
+ == -1) {
+ if (errno != EINVAL) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETIFCONFIG,
+ "get interface "
+ "configuration: %s"),
+ strbuf);
+ goto unexpected;
+ }
+ /*
+ * EINVAL. Retry with a bigger buffer.
+ */
+ } else {
+ /*
+ * The ioctl succeeded.
+ * 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.lifc_len is too near to the end of the
+ * buffer we will grow it just in case and
+ * retry.
+ */
+ if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
+ < iter->bufsize)
+ break;
+ }
+ if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_BUFFERMAX,
+ "get interface "
+ "configuration: "
+ "maximum buffer "
+ "size exceeded"));
+ goto unexpected;
+ }
+ isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
+
+ iter->bufsize *= 2;
+ }
+ return (ISC_R_SUCCESS);
+
+ unexpected:
+ isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
+ iter->buf = NULL;
+ return (ISC_R_UNEXPECTED);
+}
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+static isc_result_t
+getbuf6(isc_interfaceiter_t *iter) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc_result_t result;
+
+ iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
+
+ for (;;) {
+ iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
+ if (iter->buf6 == NULL)
+ return (ISC_R_NOMEMORY);
+
+ memset(&iter->lifc, 0, sizeof(iter->lifc));
+#ifdef ISC_HAVE_LIFC_FAMILY
+ iter->lifc.lifc_family = AF_INET6;
+#endif
+#ifdef ISC_HAVE_LIFC_FLAGS
+ iter->lifc.lifc_flags = 0;
+#endif
+ iter->lifc.lifc_len = iter->bufsize6;
+ iter->lifc.lifc_buf = iter->buf6;
+ /*
+ * Ignore the HP/UX warning about "interger overflow during
+ * conversion". It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
+ == -1) {
+#ifdef __hpux
+ /*
+ * IPv6 interface scanning is not available on all
+ * kernels w/ IPv6 sockets.
+ */
+ if (errno == ENOENT) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_INTERFACE,
+ ISC_LOG_DEBUG(1),
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETIFCONFIG,
+ "get interface "
+ "configuration: %s"),
+ strbuf);
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+#endif
+ if (errno != EINVAL) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETIFCONFIG,
+ "get interface "
+ "configuration: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+ /*
+ * EINVAL. Retry with a bigger buffer.
+ */
+ } else {
+ /*
+ * The ioctl succeeded.
+ * 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 (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
+ < iter->bufsize6)
+ break;
+ }
+ if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_BUFFERMAX,
+ "get interface "
+ "configuration: "
+ "maximum buffer "
+ "size exceeded"));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+ isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
+
+ iter->bufsize6 *= 2;
+ }
+
+ if (iter->lifc.lifc_len != 0)
+ iter->mode = 6;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
+ iter->buf6 = NULL;
+ return (result);
+}
+#endif
+
+isc_result_t
+isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
+ isc_interfaceiter_t *iter;
+ isc_result_t result;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(iterp != NULL);
+ REQUIRE(*iterp == NULL);
+
+ iter = isc_mem_get(mctx, sizeof(*iter));
+ if (iter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ iter->mctx = mctx;
+ iter->mode = 4;
+ iter->buf = NULL;
+ iter->pos = (unsigned int) -1;
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ iter->buf6 = NULL;
+ iter->pos6 = (unsigned int) -1;
+ iter->result6 = ISC_R_NOMORE;
+ iter->socket6 = -1;
+ iter->first6 = ISC_FALSE;
+#endif
+
+ /*
+ * Get the interface configuration, allocating more memory if
+ * necessary.
+ */
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ result = isc_net_probeipv6();
+ if (result == ISC_R_SUCCESS) {
+ /*
+ * Create an unbound datagram socket to do the SIOCGLIFCONF
+ * ioctl on. HP/UX requires an AF_INET6 socket for
+ * SIOCGLIFCONF to get IPv6 addresses.
+ */
+ if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_MAKESCANSOCKET,
+ "making interface "
+ "scan socket: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto socket6_failure;
+ }
+ result = iter->result6 = getbuf6(iter);
+ if (result != ISC_R_NOTIMPLEMENTED && result != ISC_R_SUCCESS)
+ goto ioctl6_failure;
+ }
+#endif
+ if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_MAKESCANSOCKET,
+ "making interface "
+ "scan socket: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto socket_failure;
+ }
+ result = getbuf4(iter);
+ if (result != ISC_R_SUCCESS)
+ goto ioctl_failure;
+
+ /*
+ * A newly created iterator has an undefined position
+ * until isc_interfaceiter_first() is called.
+ */
+#ifdef HAVE_TRUCLUSTER
+ iter->clua_context = -1;
+ iter->clua_done = ISC_TRUE;
+#endif
+#ifdef __linux
+ iter->proc = fopen("/proc/net/if_inet6", "r");
+ iter->valid = ISC_R_FAILURE;
+ iter->first = ISC_FALSE;
+#endif
+ iter->result = ISC_R_FAILURE;
+
+ iter->magic = IFITER_MAGIC;
+ *iterp = iter;
+ return (ISC_R_SUCCESS);
+
+ ioctl_failure:
+ if (iter->buf != NULL)
+ isc_mem_put(mctx, iter->buf, iter->bufsize);
+ (void) close(iter->socket);
+
+ socket_failure:
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ if (iter->buf6 != NULL)
+ isc_mem_put(mctx, iter->buf6, iter->bufsize6);
+ ioctl6_failure:
+ if (iter->socket6 != -1)
+ (void) close(iter->socket6);
+ socket6_failure:
+#endif
+
+ isc_mem_put(mctx, iter, sizeof(*iter));
+ return (result);
+}
+
+#ifdef HAVE_TRUCLUSTER
+static void
+get_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
+ dst->family = AF_INET;
+ memcpy(&dst->type.in, src, sizeof(struct in_addr));
+}
+
+static isc_result_t
+internal_current_clusteralias(isc_interfaceiter_t *iter) {
+ struct clua_info ci;
+ if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
+ return (ISC_R_IGNORE);
+ memset(&iter->current, 0, sizeof(iter->current));
+ iter->current.af = iter->clua_sa.sa_family;
+ memset(iter->current.name, 0, sizeof(iter->current.name));
+ sprintf(iter->current.name, "clua%d", ci.aliasid);
+ iter->current.flags = INTERFACE_F_UP;
+ get_inaddr(&iter->current.address, &ci.addr);
+ get_inaddr(&iter->current.netmask, &ci.netmask);
+ return (ISC_R_SUCCESS);
+}
+#endif
+
+#ifdef __linux
+static isc_result_t
+linux_if_inet6_next(isc_interfaceiter_t *iter) {
+ if (iter->proc != NULL &&
+ fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
+ iter->valid = ISC_R_SUCCESS;
+ else
+ iter->valid = ISC_R_NOMORE;
+ return (iter->valid);
+}
+
+static void
+linux_if_inet6_first(isc_interfaceiter_t *iter) {
+ if (iter->proc != NULL) {
+ rewind(iter->proc);
+ (void)linux_if_inet6_next(iter);
+ } else
+ iter->valid = ISC_R_NOMORE;
+ iter->first = ISC_FALSE;
+}
+
+static isc_result_t
+linux_if_inet6_current(isc_interfaceiter_t *iter) {
+ char address[33];
+ char name[IF_NAMESIZE+1];
+ struct in6_addr addr6;
+ int ifindex, prefix, flag3, flag4;
+ int res;
+ unsigned int i;
+
+ if (iter->valid != ISC_R_SUCCESS)
+ return (iter->valid);
+ if (iter->proc == NULL) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
+ "/proc/net/if_inet6:iter->proc == NULL");
+ return (ISC_R_FAILURE);
+ }
+
+ res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
+ address, &ifindex, &prefix, &flag3, &flag4, name);
+ if (res != 6) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
+ "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
+ res);
+ return (ISC_R_FAILURE);
+ }
+ if (strlen(address) != 32) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
+ "/proc/net/if_inet6:strlen(%s) != 32", address);
+ return (ISC_R_FAILURE);
+ }
+ for (i = 0; i < 16; i++) {
+ unsigned char byte;
+ static const char hex[] = "0123456789abcdef";
+ byte = ((index(hex, address[i * 2]) - hex) << 4) |
+ (index(hex, address[i * 2 + 1]) - hex);
+ addr6.s6_addr[i] = byte;
+ }
+ iter->current.af = AF_INET6;
+ iter->current.flags = INTERFACE_F_UP;
+ isc_netaddr_fromin6(&iter->current.address, &addr6);
+ if (isc_netaddr_islinklocal(&iter->current.address)) {
+ isc_netaddr_setzone(&iter->current.address,
+ (isc_uint32_t)ifindex);
+ }
+ for (i = 0; i < 16; i++) {
+ if (prefix > 8) {
+ addr6.s6_addr[i] = 0xff;
+ prefix -= 8;
+ } else {
+ addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
+ prefix = 0;
+ }
+ }
+ isc_netaddr_fromin6(&iter->current.netmask, &addr6);
+ strncpy(iter->current.name, name, sizeof(iter->current.name));
+ return (ISC_R_SUCCESS);
+}
+#endif
+
+/*
+ * Get information about the current interface to iter->current.
+ * If successful, return ISC_R_SUCCESS.
+ * If the interface has an unsupported address family, or if
+ * some operation on it fails, return ISC_R_IGNORE to make
+ * the higher-level iterator code ignore it.
+ */
+
+static isc_result_t
+internal_current4(isc_interfaceiter_t *iter) {
+ struct ifreq *ifrp;
+ struct ifreq ifreq;
+ int family;
+ char strbuf[ISC_STRERRORSIZE];
+#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
+ struct lifreq lifreq;
+#else
+ char sabuf[256];
+#endif
+ int i, bits, prefixlen;
+#ifdef __linux
+ isc_result_t result;
+#endif
+
+ REQUIRE(VALID_IFITER(iter));
+ REQUIRE(iter->ifc.ifc_len == 0 ||
+ iter->pos < (unsigned int) iter->ifc.ifc_len);
+
+#ifdef __linux
+ result = linux_if_inet6_current(iter);
+ if (result != ISC_R_NOMORE)
+ return (result);
+ iter->first = ISC_TRUE;
+#endif
+
+ if (iter->ifc.ifc_len == 0)
+ return (ISC_R_NOMORE);
+
+ ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
+
+ memset(&ifreq, 0, sizeof(ifreq));
+ memcpy(&ifreq, ifrp, sizeof(ifreq));
+
+ family = ifreq.ifr_addr.sa_family;
+#if defined(ISC_PLATFORM_HAVEIPV6)
+ if (family != AF_INET && family != AF_INET6)
+#else
+ if (family != AF_INET)
+#endif
+ return (ISC_R_IGNORE);
+
+ memset(&iter->current, 0, sizeof(iter->current));
+ iter->current.af = family;
+
+ INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
+ memset(iter->current.name, 0, sizeof(iter->current.name));
+ memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
+
+ get_addr(family, &iter->current.address,
+ (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
+
+ /*
+ * If the interface does not have a address ignore it.
+ */
+ switch (family) {
+ case AF_INET:
+ if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
+ return (ISC_R_IGNORE);
+ break;
+ case AF_INET6:
+ if (memcmp(&iter->current.address.type.in6, &in6addr_any,
+ sizeof(in6addr_any)) == 0)
+ return (ISC_R_IGNORE);
+ break;
+ }
+
+ /*
+ * Get interface flags.
+ */
+
+ iter->current.flags = 0;
+
+ /*
+ * Ignore the HP/UX warning about "interger overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s: getting interface flags: %s",
+ ifreq.ifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+
+ if ((ifreq.ifr_flags & IFF_UP) != 0)
+ iter->current.flags |= INTERFACE_F_UP;
+
+#ifdef IFF_POINTOPOINT
+ if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
+ iter->current.flags |= INTERFACE_F_POINTTOPOINT;
+#endif
+
+ if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
+ iter->current.flags |= INTERFACE_F_LOOPBACK;
+
+ if (family == AF_INET)
+ goto inet;
+
+#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
+ memset(&lifreq, 0, sizeof(lifreq));
+ memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
+ memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6,
+ sizeof(iter->current.address.type.in6));
+
+ if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s: getting interface address: %s",
+ ifreq.ifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+ prefixlen = lifreq.lifr_addrlen;
+#else
+ isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_INTERFACE,
+ ISC_LOG_INFO,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETIFCONFIG,
+ "prefix length for %s is unknown "
+ "(assume 128)"), sabuf);
+ prefixlen = 128;
+#endif
+
+ /*
+ * Netmask already zeroed.
+ */
+ iter->current.netmask.family = family;
+ for (i = 0; i < 16; i++) {
+ if (prefixlen > 8) {
+ bits = 0;
+ prefixlen -= 8;
+ } else {
+ bits = 8 - prefixlen;
+ prefixlen = 0;
+ }
+ iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
+ }
+ return (ISC_R_SUCCESS);
+
+ inet:
+ if (family != AF_INET)
+ return (ISC_R_IGNORE);
+#ifdef IFF_POINTOPOINT
+ /*
+ * If the interface is point-to-point, get the destination address.
+ */
+ if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
+ /*
+ * Ignore the HP/UX warning about "interger overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
+ < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETDESTADDR,
+ "%s: getting "
+ "destination address: %s"),
+ ifreq.ifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+ get_addr(family, &iter->current.dstaddress,
+ (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
+ }
+#endif
+
+ /*
+ * Get the network mask.
+ */
+ memset(&ifreq, 0, sizeof(ifreq));
+ memcpy(&ifreq, ifrp, sizeof(ifreq));
+ /*
+ * Ignore the HP/UX warning about "interger overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETNETMASK,
+ "%s: getting netmask: %s"),
+ ifreq.ifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+ get_addr(family, &iter->current.netmask,
+ (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
+ return (ISC_R_SUCCESS);
+}
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+static isc_result_t
+internal_current6(isc_interfaceiter_t *iter) {
+ struct LIFREQ *ifrp;
+ struct LIFREQ lifreq;
+ int family;
+ char strbuf[ISC_STRERRORSIZE];
+ int fd;
+
+ REQUIRE(VALID_IFITER(iter));
+ if (iter->result6 != ISC_R_SUCCESS)
+ return (iter->result6);
+ REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
+
+ ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
+
+ memset(&lifreq, 0, sizeof(lifreq));
+ memcpy(&lifreq, ifrp, sizeof(lifreq));
+
+ family = lifreq.lifr_addr.ss_family;
+#ifdef ISC_PLATFORM_HAVEIPV6
+ if (family != AF_INET && family != AF_INET6)
+#else
+ if (family != AF_INET)
+#endif
+ return (ISC_R_IGNORE);
+
+ memset(&iter->current, 0, sizeof(iter->current));
+ iter->current.af = family;
+
+ INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
+ memset(iter->current.name, 0, sizeof(iter->current.name));
+ memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
+
+ get_addr(family, &iter->current.address,
+ (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
+
+ /*
+ * If the interface does not have a address ignore it.
+ */
+ switch (family) {
+ case AF_INET:
+ if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
+ return (ISC_R_IGNORE);
+ break;
+ case AF_INET6:
+ if (memcmp(&iter->current.address.type.in6, &in6addr_any,
+ sizeof(in6addr_any)) == 0)
+ return (ISC_R_IGNORE);
+ break;
+ }
+
+ /*
+ * Get interface flags.
+ */
+
+ iter->current.flags = 0;
+
+ if (family == AF_INET6)
+ fd = iter->socket6;
+ else
+ fd = iter->socket;
+
+ /*
+ * Ignore the HP/UX warning about "interger overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s: getting interface flags: %s",
+ lifreq.lifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+
+ if ((lifreq.lifr_flags & IFF_UP) != 0)
+ iter->current.flags |= INTERFACE_F_UP;
+
+#ifdef IFF_POINTOPOINT
+ if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
+ iter->current.flags |= INTERFACE_F_POINTTOPOINT;
+#endif
+
+ if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
+ iter->current.flags |= INTERFACE_F_LOOPBACK;
+
+#ifdef IFF_POINTOPOINT
+ /*
+ * If the interface is point-to-point, get the destination address.
+ */
+ if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
+ /*
+ * Ignore the HP/UX warning about "interger overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
+ < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETDESTADDR,
+ "%s: getting "
+ "destination address: %s"),
+ lifreq.lifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+ get_addr(family, &iter->current.dstaddress,
+ (struct sockaddr *)&lifreq.lifr_dstaddr,
+ lifreq.lifr_name);
+ }
+#endif
+
+ /*
+ * Get the network mask. Netmask already zeroed.
+ */
+ memset(&lifreq, 0, sizeof(lifreq));
+ memcpy(&lifreq, ifrp, sizeof(lifreq));
+
+#ifdef lifr_addrlen
+ /*
+ * Special case: if the system provides lifr_addrlen member, the
+ * netmask of an IPv6 address can be derived from the length, since
+ * an IPv6 address always has a contiguous mask.
+ */
+ if (family == AF_INET6) {
+ int i, bits;
+
+ iter->current.netmask.family = family;
+ for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
+ bits = lifreq.lifr_addrlen - i;
+ bits = (bits < 8) ? (8 - bits) : 0;
+ iter->current.netmask.type.in6.s6_addr[i / 8] =
+ (~0 << bits) & 0xff;
+ }
+
+ return (ISC_R_SUCCESS);
+ }
+#endif
+
+ /*
+ * Ignore the HP/UX warning about "interger overflow during
+ * conversion. It comes from its own macro definition,
+ * and is really hard to shut up.
+ */
+ if (ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERIOCTL,
+ ISC_MSG_GETNETMASK,
+ "%s: getting netmask: %s"),
+ lifreq.lifr_name, strbuf);
+ return (ISC_R_IGNORE);
+ }
+ get_addr(family, &iter->current.netmask,
+ (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
+
+ return (ISC_R_SUCCESS);
+}
+#endif
+
+static isc_result_t
+internal_current(isc_interfaceiter_t *iter) {
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ if (iter->mode == 6) {
+ iter->result6 = internal_current6(iter);
+ if (iter->result6 != ISC_R_NOMORE)
+ return (iter->result6);
+ }
+#endif
+#ifdef HAVE_TRUCLUSTER
+ if (!iter->clua_done)
+ return(internal_current_clusteralias(iter));
+#endif
+ return (internal_current4(iter));
+}
+
+/*
+ * Step the iterator to the next interface. Unlike
+ * isc_interfaceiter_next(), this may leave the iterator
+ * positioned on an interface that will ultimately
+ * be ignored. Return ISC_R_NOMORE if there are no more
+ * interfaces, otherwise ISC_R_SUCCESS.
+ */
+static isc_result_t
+internal_next4(isc_interfaceiter_t *iter) {
+#ifdef ISC_PLATFORM_HAVESALEN
+ struct ifreq *ifrp;
+#endif
+
+ REQUIRE(iter->ifc.ifc_len == 0 ||
+ iter->pos < (unsigned int) iter->ifc.ifc_len);
+
+#ifdef __linux
+ if (linux_if_inet6_next(iter) == ISC_R_SUCCESS)
+ return (ISC_R_SUCCESS);
+ if (!iter->first)
+ return (ISC_R_SUCCESS);
+#endif
+
+ if (iter->ifc.ifc_len == 0)
+ return (ISC_R_NOMORE);
+
+#ifdef ISC_PLATFORM_HAVESALEN
+ ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
+
+ if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
+ iter->pos += sizeof(ifrp->ifr_name) + ifrp->ifr_addr.sa_len;
+ else
+#endif
+ iter->pos += sizeof(struct ifreq);
+
+ if (iter->pos >= (unsigned int) iter->ifc.ifc_len)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+static isc_result_t
+internal_next6(isc_interfaceiter_t *iter) {
+#ifdef ISC_PLATFORM_HAVESALEN
+ struct LIFREQ *ifrp;
+#endif
+
+ if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
+ return (iter->result6);
+
+ REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
+
+#ifdef ISC_PLATFORM_HAVESALEN
+ ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
+
+ if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
+ iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
+ else
+#endif
+ iter->pos6 += sizeof(struct LIFREQ);
+
+ if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+#endif
+
+static isc_result_t
+internal_next(isc_interfaceiter_t *iter) {
+#ifdef HAVE_TRUCLUSTER
+ int clua_result;
+#endif
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ if (iter->mode == 6) {
+ iter->result6 = internal_next6(iter);
+ if (iter->result6 != ISC_R_NOMORE)
+ return (iter->result6);
+ if (iter->first6) {
+ iter->first6 = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+ }
+ }
+#endif
+#ifdef HAVE_TRUCLUSTER
+ if (!iter->clua_done) {
+ clua_result = clua_getaliasaddress(&iter->clua_sa,
+ &iter->clua_context);
+ if (clua_result != CLUA_SUCCESS)
+ iter->clua_done = ISC_TRUE;
+ return (ISC_R_SUCCESS);
+ }
+#endif
+ return (internal_next4(iter));
+}
+
+static void
+internal_destroy(isc_interfaceiter_t *iter) {
+ (void) close(iter->socket);
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ if (iter->socket6 != -1)
+ (void) close(iter->socket6);
+ if (iter->buf6 != NULL) {
+ isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
+ }
+#endif
+#ifdef __linux
+ if (iter->proc != NULL)
+ fclose(iter->proc);
+#endif
+}
+
+static
+void internal_first(isc_interfaceiter_t *iter) {
+#ifdef HAVE_TRUCLUSTER
+ int clua_result;
+#endif
+ iter->pos = 0;
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
+ iter->pos6 = 0;
+ if (iter->result6 == ISC_R_NOMORE)
+ iter->result6 = ISC_R_SUCCESS;
+ iter->first6 = ISC_TRUE;
+#endif
+#ifdef HAVE_TRUCLUSTER
+ iter->clua_context = 0;
+ clua_result = clua_getaliasaddress(&iter->clua_sa,
+ &iter->clua_context);
+ iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);
+#endif
+#ifdef __linux
+ linux_if_inet6_first(iter);
+#endif
+}
diff --git a/lib/isc/unix/ifiter_sysctl.c b/lib/isc/unix/ifiter_sysctl.c
new file mode 100644
index 0000000..212a478
--- /dev/null
+++ b/lib/isc/unix/ifiter_sysctl.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2004, 2005 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: ifiter_sysctl.c,v 1.20.18.3 2005/04/27 05:02:35 sra Exp $ */
+
+/*! \file
+ * \brief
+ * Obtain the list of network interfaces using sysctl.
+ * See TCP/IP Illustrated Volume 2, sections 19.8, 19.14,
+ * and 19.16.
+ */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#include <net/if_dl.h>
+
+/* XXX what about Alpha? */
+#ifdef sgi
+#define ROUNDUP(a) ((a) > 0 ? \
+ (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) : \
+ sizeof(__uint64_t))
+#else
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
+ : sizeof(long))
+#endif
+
+#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'S')
+#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
+
+struct isc_interfaceiter {
+ unsigned int magic; /* Magic number. */
+ isc_mem_t *mctx;
+ void *buf; /* Buffer for sysctl data. */
+ unsigned int bufsize; /* Bytes allocated. */
+ unsigned int bufused; /* Bytes used. */
+ unsigned int pos; /* Current offset in
+ sysctl data. */
+ isc_interface_t current; /* Current interface data. */
+ isc_result_t result; /* Last result code. */
+};
+
+static int mib[6] = {
+ CTL_NET,
+ PF_ROUTE,
+ 0,
+ 0, /* Any address family. */
+ NET_RT_IFLIST,
+ 0 /* Flags. */
+};
+
+isc_result_t
+isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
+ isc_interfaceiter_t *iter;
+ isc_result_t result;
+ size_t bufsize;
+ size_t bufused;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(iterp != NULL);
+ REQUIRE(*iterp == NULL);
+
+ iter = isc_mem_get(mctx, sizeof(*iter));
+ if (iter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ iter->mctx = mctx;
+ iter->buf = 0;
+
+ /*
+ * Determine the amount of memory needed.
+ */
+ bufsize = 0;
+ if (sysctl(mib, 6, NULL, &bufsize, NULL, (size_t) 0) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERSYSCTL,
+ ISC_MSG_GETIFLISTSIZE,
+ "getting interface "
+ "list size: sysctl: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto failure;
+ }
+ iter->bufsize = bufsize;
+
+ iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
+ if (iter->buf == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto failure;
+ }
+
+ bufused = bufsize;
+ if (sysctl(mib, 6, iter->buf, &bufused, NULL, (size_t) 0) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_IFITERSYSCTL,
+ ISC_MSG_GETIFLIST,
+ "getting interface list: "
+ "sysctl: %s"),
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto failure;
+ }
+ iter->bufused = bufused;
+ INSIST(iter->bufused <= iter->bufsize);
+
+ /*
+ * A newly created iterator has an undefined position
+ * until isc_interfaceiter_first() is called.
+ */
+ iter->pos = (unsigned int) -1;
+ iter->result = ISC_R_FAILURE;
+
+ iter->magic = IFITER_MAGIC;
+ *iterp = iter;
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (iter->buf != NULL)
+ isc_mem_put(mctx, iter->buf, iter->bufsize);
+ isc_mem_put(mctx, iter, sizeof(*iter));
+ return (result);
+}
+
+/*
+ * Get information about the current interface to iter->current.
+ * If successful, return ISC_R_SUCCESS.
+ * If the interface has an unsupported address family,
+ * return ISC_R_IGNORE. In case of other failure,
+ * return ISC_R_UNEXPECTED.
+ */
+
+static isc_result_t
+internal_current(isc_interfaceiter_t *iter) {
+ struct ifa_msghdr *ifam, *ifam_end;
+
+ REQUIRE(VALID_IFITER(iter));
+ REQUIRE (iter->pos < (unsigned int) iter->bufused);
+
+ ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
+ ifam_end = (struct ifa_msghdr *) ((char *) iter->buf + iter->bufused);
+
+ if (ifam->ifam_type == RTM_IFINFO) {
+ struct if_msghdr *ifm = (struct if_msghdr *) ifam;
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *) (ifm + 1);
+ unsigned int namelen;
+
+ memset(&iter->current, 0, sizeof(iter->current));
+
+ namelen = sdl->sdl_nlen;
+ if (namelen > sizeof(iter->current.name) - 1)
+ namelen = sizeof(iter->current.name) - 1;
+
+ memset(iter->current.name, 0, sizeof(iter->current.name));
+ memcpy(iter->current.name, sdl->sdl_data, namelen);
+
+ iter->current.flags = 0;
+
+ if ((ifam->ifam_flags & IFF_UP) != 0)
+ iter->current.flags |= INTERFACE_F_UP;
+
+ if ((ifam->ifam_flags & IFF_POINTOPOINT) != 0)
+ iter->current.flags |= INTERFACE_F_POINTTOPOINT;
+
+ if ((ifam->ifam_flags & IFF_LOOPBACK) != 0)
+ iter->current.flags |= INTERFACE_F_LOOPBACK;
+
+ /*
+ * This is not an interface address.
+ * Force another iteration.
+ */
+ return (ISC_R_IGNORE);
+ } else if (ifam->ifam_type == RTM_NEWADDR) {
+ int i;
+ int family;
+ struct sockaddr *mask_sa = NULL;
+ struct sockaddr *addr_sa = NULL;
+ struct sockaddr *dst_sa = NULL;
+
+ struct sockaddr *sa = (struct sockaddr *)(ifam + 1);
+ family = sa->sa_family;
+
+ for (i = 0; i < RTAX_MAX; i++)
+ {
+ if ((ifam->ifam_addrs & (1 << i)) == 0)
+ continue;
+
+ INSIST(sa < (struct sockaddr *) ifam_end);
+
+ switch (i) {
+ case RTAX_NETMASK: /* Netmask */
+ mask_sa = sa;
+ break;
+ case RTAX_IFA: /* Interface address */
+ addr_sa = sa;
+ break;
+ case RTAX_BRD: /* Broadcast or destination address */
+ dst_sa = sa;
+ break;
+ }
+#ifdef ISC_PLATFORM_HAVESALEN
+ sa = (struct sockaddr *)((char*)(sa)
+ + ROUNDUP(sa->sa_len));
+#else
+#ifdef sgi
+ /*
+ * Do as the contributed SGI code does.
+ */
+ sa = (struct sockaddr *)((char*)(sa)
+ + ROUNDUP(_FAKE_SA_LEN_DST(sa)));
+#else
+ /* XXX untested. */
+ sa = (struct sockaddr *)((char*)(sa)
+ + ROUNDUP(sizeof(struct sockaddr)));
+#endif
+#endif
+ }
+
+ if (addr_sa == NULL)
+ return (ISC_R_IGNORE);
+
+ family = addr_sa->sa_family;
+ if (family != AF_INET && family != AF_INET6)
+ return (ISC_R_IGNORE);
+
+ iter->current.af = family;
+
+ get_addr(family, &iter->current.address, addr_sa,
+ iter->current.name);
+
+ if (mask_sa != NULL)
+ get_addr(family, &iter->current.netmask, mask_sa,
+ iter->current.name);
+
+ if (dst_sa != NULL &&
+ (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
+ get_addr(family, &iter->current.dstaddress, dst_sa,
+ iter->current.name);
+
+ return (ISC_R_SUCCESS);
+ } else {
+ printf(isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERSYSCTL,
+ ISC_MSG_UNEXPECTEDTYPE,
+ "warning: unexpected interface list "
+ "message type\n"));
+ return (ISC_R_IGNORE);
+ }
+}
+
+/*
+ * Step the iterator to the next interface. Unlike
+ * isc_interfaceiter_next(), this may leave the iterator
+ * positioned on an interface that will ultimately
+ * be ignored. Return ISC_R_NOMORE if there are no more
+ * interfaces, otherwise ISC_R_SUCCESS.
+ */
+static isc_result_t
+internal_next(isc_interfaceiter_t *iter) {
+ struct ifa_msghdr *ifam;
+ REQUIRE (iter->pos < (unsigned int) iter->bufused);
+
+ ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
+
+ iter->pos += ifam->ifam_msglen;
+
+ if (iter->pos >= iter->bufused)
+ return (ISC_R_NOMORE);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+internal_destroy(isc_interfaceiter_t *iter) {
+ UNUSED(iter); /* Unused. */
+ /*
+ * Do nothing.
+ */
+}
+
+static
+void internal_first(isc_interfaceiter_t *iter) {
+ iter->pos = 0;
+}
diff --git a/lib/isc/unix/include/Makefile.in b/lib/isc/unix/include/Makefile.in
new file mode 100644
index 0000000..78eba44
--- /dev/null
+++ b/lib/isc/unix/include/Makefile.in
@@ -0,0 +1,25 @@
+# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-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: Makefile.in,v 1.12 2004/03/05 05:11:50 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/unix/include/isc/Makefile.in b/lib/isc/unix/include/isc/Makefile.in
new file mode 100644
index 0000000..9599f7c
--- /dev/null
+++ b/lib/isc/unix/include/isc/Makefile.in
@@ -0,0 +1,38 @@
+# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 1998-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: Makefile.in,v 1.28 2004/03/05 05:11:52 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = dir.h int.h net.h netdb.h offset.h stdtime.h \
+ syslog.h time.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc ; \
+ done
diff --git a/lib/isc/unix/include/isc/dir.h b/lib/isc/unix/include/isc/dir.h
new file mode 100644
index 0000000..cc85706
--- /dev/null
+++ b/lib/isc/unix/include/isc/dir.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2004, 2005 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: dir.h,v 1.17.18.2 2005/04/29 00:17:09 marka Exp $ */
+
+/* Principal Authors: DCL */
+
+#ifndef ISC_DIR_H
+#define ISC_DIR_H 1
+
+/*! \file */
+
+#include <sys/types.h> /* Required on some systems. */
+#include <dirent.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+#define ISC_DIR_NAMEMAX 256
+#define ISC_DIR_PATHMAX 1024
+
+/*% Directory Entry */
+typedef struct isc_direntry {
+ /*!
+ * Ideally, this should be NAME_MAX, but AIX does not define it by
+ * default and dynamically allocating the space based on pathconf()
+ * complicates things undesirably, as does adding special conditionals
+ * just for AIX. So a comfortably sized buffer is chosen instead.
+ */
+ char name[ISC_DIR_NAMEMAX];
+ unsigned int length;
+} isc_direntry_t;
+
+/*% Directory */
+typedef struct isc_dir {
+ unsigned int magic;
+ /*!
+ * As with isc_direntry_t->name, making this "right" for all systems
+ * is slightly problematic because AIX does not define PATH_MAX.
+ */
+ char dirname[ISC_DIR_PATHMAX];
+ isc_direntry_t entry;
+ DIR * handle;
+} isc_dir_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_dir_init(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_open(isc_dir_t *dir, const char *dirname);
+
+isc_result_t
+isc_dir_read(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_reset(isc_dir_t *dir);
+
+void
+isc_dir_close(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_chdir(const char *dirname);
+
+isc_result_t
+isc_dir_chroot(const char *dirname);
+
+isc_result_t
+isc_dir_createunique(char *templet);
+/*!<
+ * Use a templet (such as from isc_file_mktemplate()) to create a uniquely
+ * named, empty directory. The templet string is modified in place.
+ * If result == ISC_R_SUCCESS, it is the name of the directory that was
+ * created.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_DIR_H */
diff --git a/lib/isc/unix/include/isc/int.h b/lib/isc/unix/include/isc/int.h
new file mode 100644
index 0000000..1e1de7b
--- /dev/null
+++ b/lib/isc/unix/include/isc/int.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2004, 2005 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: int.h,v 1.12.18.2 2005/04/29 00:17:09 marka Exp $ */
+
+#ifndef ISC_INT_H
+#define ISC_INT_H 1
+
+/*! \file */
+
+typedef char isc_int8_t;
+typedef unsigned char isc_uint8_t;
+typedef short isc_int16_t;
+typedef unsigned short isc_uint16_t;
+typedef int isc_int32_t;
+typedef unsigned int isc_uint32_t;
+typedef long long isc_int64_t;
+typedef unsigned long long isc_uint64_t;
+
+#define ISC_INT8_MIN -128
+#define ISC_INT8_MAX 127
+#define ISC_UINT8_MAX 255
+
+#define ISC_INT16_MIN -32768
+#define ISC_INT16_MAX 32767
+#define ISC_UINT16_MAX 65535
+
+/*%
+ * Note that "int" is 32 bits on all currently supported Unix-like operating
+ * systems, but "long" can be either 32 bits or 64 bits, thus the 32 bit
+ * constants are not qualified with "L".
+ */
+#define ISC_INT32_MIN -2147483648
+#define ISC_INT32_MAX 2147483647
+#define ISC_UINT32_MAX 4294967295U
+
+#define ISC_INT64_MIN -9223372036854775808LL
+#define ISC_INT64_MAX 9223372036854775807LL
+#define ISC_UINT64_MAX 18446744073709551615ULL
+
+#endif /* ISC_INT_H */
diff --git a/lib/isc/unix/include/isc/keyboard.h b/lib/isc/unix/include/isc/keyboard.h
new file mode 100644
index 0000000..4b28cc0
--- /dev/null
+++ b/lib/isc/unix/include/isc/keyboard.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2004, 2005 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: keyboard.h,v 1.7.18.2 2005/04/29 00:17:09 marka Exp $ */
+
+#ifndef ISC_KEYBOARD_H
+#define ISC_KEYBOARD_H 1
+
+/*! \file */
+
+#include <termios.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef struct {
+ int fd;
+ struct termios saved_mode;
+ isc_result_t result;
+} isc_keyboard_t;
+
+isc_result_t
+isc_keyboard_open(isc_keyboard_t *keyboard);
+
+isc_result_t
+isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleepseconds);
+
+isc_result_t
+isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp);
+
+isc_boolean_t
+isc_keyboard_canceled(isc_keyboard_t *keyboard);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_KEYBOARD_H */
diff --git a/lib/isc/unix/include/isc/net.h b/lib/isc/unix/include/isc/net.h
new file mode 100644
index 0000000..bdd8c14
--- /dev/null
+++ b/lib/isc/unix/include/isc/net.h
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2004, 2005 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: net.h,v 1.39.18.4 2005/04/27 05:02:37 sra Exp $ */
+
+#ifndef ISC_NET_H
+#define ISC_NET_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Basic Networking Types
+ *
+ * This module is responsible for defining the following basic networking
+ * types:
+ *
+ *\li struct in_addr
+ *\li struct in6_addr
+ *\li struct in6_pktinfo
+ *\li struct sockaddr
+ *\li struct sockaddr_in
+ *\li struct sockaddr_in6
+ *\li in_port_t
+ *
+ * It ensures that the AF_ and PF_ macros are defined.
+ *
+ * It declares ntoh[sl]() and hton[sl]().
+ *
+ * It declares inet_aton(), inet_ntop(), and inet_pton().
+ *
+ * It ensures that #INADDR_LOOPBACK, #INADDR_ANY, #IN6ADDR_ANY_INIT,
+ * in6addr_any, and in6addr_loopback are available.
+ *
+ * It ensures that IN_MULTICAST() is available to check for multicast
+ * addresses.
+ *
+ * MP:
+ *\li No impact.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li N/A.
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li BSD Socket API
+ *\li RFC2553
+ */
+
+/***
+ *** Imports.
+ ***/
+#include <isc/platform.h>
+
+#include <sys/types.h>
+#include <sys/socket.h> /* Contractual promise. */
+
+#include <net/if.h>
+
+#include <netinet/in.h> /* Contractual promise. */
+#include <arpa/inet.h> /* Contractual promise. */
+#ifdef ISC_PLATFORM_NEEDNETINETIN6H
+#include <netinet/in6.h> /* Required on UnixWare. */
+#endif
+#ifdef ISC_PLATFORM_NEEDNETINET6IN6H
+#include <netinet6/in6.h> /* Required on BSD/OS for in6_pktinfo. */
+#endif
+
+#ifndef ISC_PLATFORM_HAVEIPV6
+#include <isc/ipv6.h> /* Contractual promise. */
+#endif
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_HAVEINADDR6
+#define in6_addr in_addr6 /*%< Required for pre RFC2133 implementations. */
+#endif
+
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifndef IN6ADDR_ANY_INIT
+#ifdef s6_addr
+/*%
+ * Required for some pre RFC2133 implementations.
+ * IN6ADDR_ANY_INIT and IN6ADDR_LOOPBACK_INIT were added in
+ * draft-ietf-ipngwg-bsd-api-04.txt or draft-ietf-ipngwg-bsd-api-05.txt.
+ * If 's6_addr' is defined then assume that there is a union and three
+ * levels otherwise assume two levels required.
+ */
+#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
+#else
+#define IN6ADDR_ANY_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }
+#endif
+#endif
+
+#ifndef IN6ADDR_LOOPBACK_INIT
+#ifdef s6_addr
+/*% IPv6 address loopback init */
+#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
+#else
+#define IN6ADDR_LOOPBACK_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } }
+#endif
+#endif
+
+#ifndef IN6_IS_ADDR_V4MAPPED
+/*% Is IPv6 address V4 mapped? */
+#define IN6_IS_ADDR_V4MAPPED(x) \
+ (memcmp((x)->s6_addr, in6addr_any.s6_addr, 10) == 0 && \
+ (x)->s6_addr[10] == 0xff && (x)->s6_addr[11] == 0xff)
+#endif
+
+#ifndef IN6_IS_ADDR_V4COMPAT
+/*% Is IPv6 address V4 compatible? */
+#define IN6_IS_ADDR_V4COMPAT(x) \
+ (memcmp((x)->s6_addr, in6addr_any.s6_addr, 12) == 0 && \
+ ((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_MULTICAST
+/*% Is IPv6 address multicast? */
+#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff)
+#endif
+
+#ifndef IN6_IS_ADDR_LINKLOCAL
+/*% Is IPv6 address linklocal? */
+#define IN6_IS_ADDR_LINKLOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
+#endif
+
+#ifndef IN6_IS_ADDR_SITELOCAL
+/*% is IPv6 address sitelocal? */
+#define IN6_IS_ADDR_SITELOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
+#endif
+
+
+#ifndef IN6_IS_ADDR_LOOPBACK
+/*% is IPv6 address loopback? */
+#define IN6_IS_ADDR_LOOPBACK(x) \
+ (memcmp((x)->s6_addr, in6addr_loopback.s6_addr, 16) == 0)
+#endif
+#endif
+
+#ifndef AF_INET6
+/*% IPv6 */
+#define AF_INET6 99
+#endif
+
+#ifndef PF_INET6
+/*% IPv6 */
+#define PF_INET6 AF_INET6
+#endif
+
+#ifndef INADDR_LOOPBACK
+/*% inaddr loopback */
+#define INADDR_LOOPBACK 0x7f000001UL
+#endif
+
+#ifndef ISC_PLATFORM_HAVEIN6PKTINFO
+/*% IPv6 packet info */
+struct in6_pktinfo {
+ struct in6_addr ipi6_addr; /*%< src/dst IPv6 address */
+ unsigned int ipi6_ifindex; /*%< send/recv interface index */
+};
+#endif
+
+#if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRANY)
+extern const struct in6_addr isc_net_in6addrany;
+/*%
+ * Cope with a missing in6addr_any and in6addr_loopback.
+ */
+#define in6addr_any isc_net_in6addrany
+#endif
+
+#if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
+extern const struct in6_addr isc_net_in6addrloop;
+#define in6addr_loopback isc_net_in6addrloop
+#endif
+
+#ifdef ISC_PLATFORM_FIXIN6ISADDR
+#undef IN6_IS_ADDR_GEOGRAPHIC
+/*!
+ * \brief
+ * Fix UnixWare 7.1.1's broken IN6_IS_ADDR_* definitions.
+ */
+#define IN6_IS_ADDR_GEOGRAPHIC(a) (((a)->S6_un.S6_l[0] & 0xE0) == 0x80)
+#undef IN6_IS_ADDR_IPX
+#define IN6_IS_ADDR_IPX(a) (((a)->S6_un.S6_l[0] & 0xFE) == 0x04)
+#undef IN6_IS_ADDR_LINKLOCAL
+#define IN6_IS_ADDR_LINKLOCAL(a) (((a)->S6_un.S6_l[0] & 0xC0FF) == 0x80FE)
+#undef IN6_IS_ADDR_MULTICAST
+#define IN6_IS_ADDR_MULTICAST(a) (((a)->S6_un.S6_l[0] & 0xFF) == 0xFF)
+#undef IN6_IS_ADDR_NSAP
+#define IN6_IS_ADDR_NSAP(a) (((a)->S6_un.S6_l[0] & 0xFE) == 0x02)
+#undef IN6_IS_ADDR_PROVIDER
+#define IN6_IS_ADDR_PROVIDER(a) (((a)->S6_un.S6_l[0] & 0xE0) == 0x40)
+#undef IN6_IS_ADDR_SITELOCAL
+#define IN6_IS_ADDR_SITELOCAL(a) (((a)->S6_un.S6_l[0] & 0xC0FF) == 0xC0FE)
+#endif /* ISC_PLATFORM_FIXIN6ISADDR */
+
+#ifdef ISC_PLATFORM_NEEDPORTT
+/*%
+ * Ensure type in_port_t is defined.
+ */
+typedef isc_uint16_t in_port_t;
+#endif
+
+#ifndef MSG_TRUNC
+/*%
+ * If this system does not have MSG_TRUNC (as returned from recvmsg())
+ * ISC_PLATFORM_RECVOVERFLOW will be defined. This will enable the MSG_TRUNC
+ * faking code in socket.c.
+ */
+#define ISC_PLATFORM_RECVOVERFLOW
+#endif
+
+/*% IP address. */
+#define ISC__IPADDR(x) ((isc_uint32_t)htonl((isc_uint32_t)(x)))
+
+/*% Is IP address multicast? */
+#define ISC_IPADDR_ISMULTICAST(i) \
+ (((isc_uint32_t)(i) & ISC__IPADDR(0xf0000000)) \
+ == ISC__IPADDR(0xe0000000))
+
+#define ISC_IPADDR_ISEXPERIMENTAL(i) \
+ (((isc_uint32_t)(i) & ISC__IPADDR(0xf0000000)) \
+ == ISC__IPADDR(0xf0000000))
+
+/***
+ *** Functions.
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_net_probeipv4(void);
+/*%<
+ * Check if the system's kernel supports IPv4.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS IPv4 is supported.
+ *\li #ISC_R_NOTFOUND IPv4 is not supported.
+ *\li #ISC_R_DISABLED IPv4 is disabled.
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probeipv6(void);
+/*%<
+ * Check if the system's kernel supports IPv6.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS IPv6 is supported.
+ *\li #ISC_R_NOTFOUND IPv6 is not supported.
+ *\li #ISC_R_DISABLED IPv6 is disabled.
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probe_ipv6only(void);
+/*%<
+ * Check if the system's kernel supports the IPV6_V6ONLY socket option.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS the option is supported for both TCP and UDP.
+ *\li #ISC_R_NOTFOUND IPv6 itself or the option is not supported.
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probe_ipv6pktinfo(void);
+/*
+ * Check if the system's kernel supports the IPV6_(RECV)PKTINFO socket option
+ * for UDP sockets.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS the option is supported.
+ * \li #ISC_R_NOTFOUND IPv6 itself or the option is not supported.
+ * \li #ISC_R_UNEXPECTED
+ */
+
+void
+isc_net_disableipv4(void);
+
+void
+isc_net_disableipv6(void);
+
+void
+isc_net_enableipv4(void);
+
+void
+isc_net_enableipv6(void);
+
+isc_result_t
+isc_net_probeunix(void);
+/*
+ * Returns whether UNIX domain sockets are supported.
+ */
+
+#ifdef ISC_PLATFORM_NEEDNTOP
+const char *
+isc_net_ntop(int af, const void *src, char *dst, size_t size);
+#define inet_ntop isc_net_ntop
+#endif
+
+#ifdef ISC_PLATFORM_NEEDPTON
+int
+isc_net_pton(int af, const char *src, void *dst);
+#undef inet_pton
+#define inet_pton isc_net_pton
+#endif
+
+#ifdef ISC_PLATFORM_NEEDATON
+int
+isc_net_aton(const char *cp, struct in_addr *addr);
+#define inet_aton isc_net_aton
+#endif
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NET_H */
diff --git a/lib/isc/unix/include/isc/netdb.h b/lib/isc/unix/include/isc/netdb.h
new file mode 100644
index 0000000..428f087
--- /dev/null
+++ b/lib/isc/unix/include/isc/netdb.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2004, 2005 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: netdb.h,v 1.7.18.2 2005/04/29 00:17:10 marka Exp $ */
+
+#ifndef ISC_NETDB_H
+#define ISC_NETDB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Portable netdb.h support.
+ *
+ * This module is responsible for defining the get<x>by<y> APIs.
+ *
+ * MP:
+ *\li No impact.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li N/A.
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li BSD API
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/net.h>
+
+#include <netdb.h>
+
+#endif /* ISC_NETDB_H */
diff --git a/lib/isc/unix/include/isc/offset.h b/lib/isc/unix/include/isc/offset.h
new file mode 100644
index 0000000..15fbad4
--- /dev/null
+++ b/lib/isc/unix/include/isc/offset.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2005 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: offset.h,v 1.11.18.2 2005/04/29 00:17:10 marka Exp $ */
+
+#ifndef ISC_OFFSET_H
+#define ISC_OFFSET_H 1
+
+/*! \file
+ * \brief
+ * File offsets are operating-system dependent.
+ */
+#include <limits.h> /* Required for CHAR_BIT. */
+#include <sys/types.h>
+
+typedef off_t isc_offset_t;
+
+/*%
+ * POSIX says "Additionally, blkcnt_t and off_t are extended signed integral
+ * types", so the maximum value is all 1s except for the high bit.
+ * This definition is more complex than it really needs to be because it was
+ * crafted to keep both the SunOS 5.6 and the HP/UX 11 compilers quiet about
+ * integer overflow. For example, though this is equivalent to just left
+ * shifting 1 to the high bit and then inverting the bits, the SunOS compiler
+ * is unhappy about shifting a positive "1" to negative in a signed integer.
+ */
+#define ISC_OFFSET_MAXIMUM \
+ (~(((off_t)-1 >> (sizeof(off_t) * CHAR_BIT - 1)) \
+ << (sizeof(off_t) * CHAR_BIT - 1)))
+
+#endif /* ISC_OFFSET_H */
diff --git a/lib/isc/unix/include/isc/stat.h b/lib/isc/unix/include/isc/stat.h
new file mode 100644
index 0000000..d1b2489
--- /dev/null
+++ b/lib/isc/unix/include/isc/stat.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: stat.h,v 1.2.18.1 2004/08/19 04:42:54 marka Exp $ */
+
+#ifndef ISC_STAT_H
+#define ISC_STAT_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * Portable netdb.h support.
+ *
+ * This module is responsible for defining S_IS??? macros.
+ *
+ * MP:
+ * No impact.
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ * N/A.
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#endif /* ISC_STAT_H */
diff --git a/lib/isc/unix/include/isc/stdtime.h b/lib/isc/unix/include/isc/stdtime.h
new file mode 100644
index 0000000..24a91d2
--- /dev/null
+++ b/lib/isc/unix/include/isc/stdtime.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2004, 2005 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: stdtime.h,v 1.9.18.3 2005/06/04 06:23:45 jinmei Exp $ */
+
+#ifndef ISC_STDTIME_H
+#define ISC_STDTIME_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/int.h>
+
+/*%
+ * It's public information that 'isc_stdtime_t' is an unsigned integral type.
+ * Applications that want maximum portability should not assume anything
+ * about its size.
+ */
+typedef isc_uint32_t isc_stdtime_t;
+/*
+ * isc_stdtime32_t is a 32-bit version of isc_stdtime_t. A variable of this
+ * type should only be used as an opaque integer (e.g.,) to compare two
+ * time values.
+ */
+typedef isc_uint32_t isc_stdtime32_t;
+
+ISC_LANG_BEGINDECLS
+/* */
+void
+isc_stdtime_get(isc_stdtime_t *t);
+/*%<
+ * Set 't' to the number of seconds since 00:00:00 UTC, January 1, 1970.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+#define isc_stdtime_convert32(t, t32p) (*(t32p) = t)
+/*
+ * Convert the standard time to its 32-bit version.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STDTIME_H */
diff --git a/lib/isc/unix/include/isc/strerror.h b/lib/isc/unix/include/isc/strerror.h
new file mode 100644
index 0000000..fb2e8a4
--- /dev/null
+++ b/lib/isc/unix/include/isc/strerror.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2005 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: strerror.h,v 1.4.18.2 2005/04/29 00:17:10 marka Exp $ */
+
+#ifndef ISC_STRERROR_H
+#define ISC_STRERROR_H
+
+/*! \file */
+
+#include <sys/types.h>
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% String Error Size */
+#define ISC_STRERRORSIZE 128
+
+/*%
+ * Provide a thread safe wrapper to strerrror().
+ *
+ * Requires:
+ * 'buf' to be non NULL.
+ */
+void
+isc__strerror(int num, char *buf, size_t bufsize);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STRERROR_H */
diff --git a/lib/isc/unix/include/isc/syslog.h b/lib/isc/unix/include/isc/syslog.h
new file mode 100644
index 0000000..08adca1
--- /dev/null
+++ b/lib/isc/unix/include/isc/syslog.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2004, 2005 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: syslog.h,v 1.3.18.2 2005/04/29 00:17:10 marka Exp $ */
+
+#ifndef ISC_SYSLOG_H
+#define ISC_SYSLOG_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp);
+/*%<
+ * Convert 'str' to the appropriate syslog facility constant.
+ *
+ * Requires:
+ *
+ *\li 'str' is not NULL
+ *\li 'facilityp' is not NULL
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SYSLOG_H */
diff --git a/lib/isc/unix/include/isc/time.h b/lib/isc/unix/include/isc/time.h
new file mode 100644
index 0000000..6579439
--- /dev/null
+++ b/lib/isc/unix/include/isc/time.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: time.h,v 1.30.18.2 2005/04/29 00:17:10 marka Exp $ */
+
+#ifndef ISC_TIME_H
+#define ISC_TIME_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/***
+ *** Intervals
+ ***/
+
+/*!
+ * \brief
+ * The contents of this structure are private, and MUST NOT be accessed
+ * directly by callers.
+ *
+ * The contents are exposed only to allow callers to avoid dynamic allocation.
+ */
+struct isc_interval {
+ unsigned int seconds;
+ unsigned int nanoseconds;
+};
+
+extern isc_interval_t *isc_interval_zero;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_interval_set(isc_interval_t *i,
+ unsigned int seconds, unsigned int nanoseconds);
+/*%<
+ * Set 'i' to a value representing an interval of 'seconds' seconds and
+ * 'nanoseconds' nanoseconds, suitable for use in isc_time_add() and
+ * isc_time_subtract().
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ *\li nanoseconds < 1000000000.
+ */
+
+isc_boolean_t
+isc_interval_iszero(const isc_interval_t *i);
+/*%<
+ * Returns ISC_TRUE iff. 'i' is the zero interval.
+ *
+ * Requires:
+ *
+ *\li 'i' is a valid pointer.
+ */
+
+/***
+ *** Absolute Times
+ ***/
+
+/*%
+ * The contents of this structure are private, and MUST NOT be accessed
+ * directly by callers.
+ *
+ * The contents are exposed only to allow callers to avoid dynamic allocation.
+ */
+
+struct isc_time {
+ unsigned int seconds;
+ unsigned int nanoseconds;
+};
+
+extern isc_time_t *isc_time_epoch;
+
+void
+isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds);
+/*%<
+ * Set 't' to a particular number of seconds + nanoseconds since the epoch.
+ *
+ * Notes:
+ *\li This call is equivalent to:
+ *\code
+ * isc_time_settoepoch(t);
+ * isc_interval_set(i, seconds, nanoseconds);
+ * isc_time_add(t, i, t);
+ *\endcode
+ * Requires:
+ *\li 't' is a valid pointer.
+ *\li nanoseconds < 1000000000.
+ */
+
+void
+isc_time_settoepoch(isc_time_t *t);
+/*%<
+ * Set 't' to the time of the epoch.
+ *
+ * Notes:
+ * \li The date of the epoch is platform-dependent.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+isc_boolean_t
+isc_time_isepoch(const isc_time_t *t);
+/*%<
+ * Returns ISC_TRUE iff. 't' is the epoch ("time zero").
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+isc_result_t
+isc_time_now(isc_time_t *t);
+/*%<
+ * Set 't' to the current absolute time.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li Unexpected error
+ * Getting the time from the system failed.
+ *\li Out of range
+ * The time from the system is too large to be represented
+ * in the current definition of isc_time_t.
+ */
+
+isc_result_t
+isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i);
+/*%<
+ * Set *t to the current absolute time + i.
+ *
+ * Note:
+ *\li This call is equivalent to:
+ *
+ *\code
+ * isc_time_now(t);
+ * isc_time_add(t, i, t);
+ *\endcode
+ *
+ * Requires:
+ *
+ *\li 't' and 'i' are valid pointers.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li Unexpected error
+ * Getting the time from the system failed.
+ *\li Out of range
+ * The interval added to the time from the system is too large to
+ * be represented in the current definition of isc_time_t.
+ */
+
+int
+isc_time_compare(const isc_time_t *t1, const isc_time_t *t2);
+/*%<
+ * Compare the times referenced by 't1' and 't2'
+ *
+ * Requires:
+ *
+ *\li 't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ *
+ *\li -1 t1 < t2 (comparing times, not pointers)
+ *\li 0 t1 = t2
+ *\li 1 t1 > t2
+ */
+
+isc_result_t
+isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result);
+/*%<
+ * Add 'i' to 't', storing the result in 'result'.
+ *
+ * Requires:
+ *
+ *\li 't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ * \li Success
+ *\li Out of range
+ * The interval added to the time is too large to
+ * be represented in the current definition of isc_time_t.
+ */
+
+isc_result_t
+isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
+ isc_time_t *result);
+/*%<
+ * Subtract 'i' from 't', storing the result in 'result'.
+ *
+ * Requires:
+ *
+ *\li 't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ *\li Success
+ *\li Out of range
+ * The interval is larger than the time since the epoch.
+ */
+
+isc_uint64_t
+isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2);
+/*%<
+ * Find the difference in microseconds between time t1 and time t2.
+ * t2 is the subtrahend of t1; ie, difference = t1 - t2.
+ *
+ * Requires:
+ *
+ *\li 't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ *\li The difference of t1 - t2, or 0 if t1 <= t2.
+ */
+
+isc_uint32_t
+isc_time_seconds(const isc_time_t *t);
+/*%<
+ * Return the number of seconds since the epoch stored in a time structure.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+isc_result_t
+isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp);
+/*%<
+ * Ensure the number of seconds in an isc_time_t is representable by a time_t.
+ *
+ * Notes:
+ *\li The number of seconds stored in an isc_time_t might be larger
+ * than the number of seconds a time_t is able to handle. Since
+ * time_t is mostly opaque according to the ANSI/ISO standard
+ * (essentially, all you can be sure of is that it is an arithmetic type,
+ * not even necessarily integral), it can be tricky to ensure that
+ * the isc_time_t is in the range a time_t can handle. Use this
+ * function in place of isc_time_seconds() any time you need to set a
+ * time_t from an isc_time_t.
+ *
+ * Requires:
+ *\li 't' is a valid pointer.
+ *
+ * Returns:
+ *\li Success
+ *\li Out of range
+ */
+
+isc_uint32_t
+isc_time_nanoseconds(const isc_time_t *t);
+/*%<
+ * Return the number of nanoseconds stored in a time structure.
+ *
+ * Notes:
+ *\li This is the number of nanoseconds in excess of the the number
+ * of seconds since the epoch; it will always be less than one
+ * full second.
+ *
+ * Requires:
+ *\li 't' is a valid pointer.
+ *
+ * Ensures:
+ *\li The returned value is less than 1*10^9.
+ */
+
+void
+isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using a format like "30-Aug-2000 04:06:47.997" and the local time zone.
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ * \li 'buf' points to an array of at least len chars
+ *
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TIME_H */
diff --git a/lib/isc/unix/interfaceiter.c b/lib/isc/unix/interfaceiter.c
new file mode 100644
index 0000000..72ecdd2
--- /dev/null
+++ b/lib/isc/unix/interfaceiter.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2004, 2005 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: interfaceiter.c,v 1.35.18.5 2005/04/29 00:17:08 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h> /* Required for ifiter_ioctl.c. */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <isc/interfaceiter.h>
+#include <isc/log.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/net.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+/* Must follow <isc/net.h>. */
+#ifdef HAVE_NET_IF6_H
+#include <net/if6.h>
+#endif
+#include <net/if.h>
+
+/* Common utility functions */
+
+/*%
+ * Extract the network address part from a "struct sockaddr".
+ * \brief
+ * The address family is given explicitly
+ * instead of using src->sa_family, because the latter does not work
+ * for copying a network mask obtained by SIOCGIFNETMASK (it does
+ * not have a valid address family).
+ */
+
+static void
+get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
+ char *ifname)
+{
+ struct sockaddr_in6 *sa6;
+
+#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \
+ !defined(ISC_PLATFORM_HAVESCOPEID)
+ UNUSED(ifname);
+#endif
+
+ /* clear any remaining value for safety */
+ memset(dst, 0, sizeof(*dst));
+
+ dst->family = family;
+ switch (family) {
+ case AF_INET:
+ memcpy(&dst->type.in,
+ &((struct sockaddr_in *) src)->sin_addr,
+ sizeof(struct in_addr));
+ break;
+ case AF_INET6:
+ sa6 = (struct sockaddr_in6 *)src;
+ memcpy(&dst->type.in6, &sa6->sin6_addr,
+ sizeof(struct in6_addr));
+#ifdef ISC_PLATFORM_HAVESCOPEID
+ if (sa6->sin6_scope_id != 0)
+ isc_netaddr_setzone(dst, sa6->sin6_scope_id);
+ else {
+ /*
+ * BSD variants embed scope zone IDs in the 128bit
+ * address as a kernel internal form. Unfortunately,
+ * the embedded IDs are not hidden from applications
+ * when getting access to them by sysctl or ioctl.
+ * We convert the internal format to the pure address
+ * part and the zone ID part.
+ * Since multicast addresses should not appear here
+ * and they cannot be distinguished from netmasks,
+ * we only consider unicast link-local addresses.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
+ isc_uint16_t zone16;
+
+ memcpy(&zone16, &sa6->sin6_addr.s6_addr[2],
+ sizeof(zone16));
+ zone16 = ntohs(zone16);
+ if (zone16 != 0) {
+ /* the zone ID is embedded */
+ isc_netaddr_setzone(dst,
+ (isc_uint32_t)zone16);
+ dst->type.in6.s6_addr[2] = 0;
+ dst->type.in6.s6_addr[3] = 0;
+#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
+ } else if (ifname != NULL) {
+ unsigned int zone;
+
+ /*
+ * sin6_scope_id is still not provided,
+ * but the corresponding interface name
+ * is know. Use the interface ID as
+ * the link ID.
+ */
+ zone = if_nametoindex(ifname);
+ if (zone != 0) {
+ isc_netaddr_setzone(dst,
+ (isc_uint32_t)zone);
+ }
+#endif
+ }
+ }
+ }
+#endif
+ break;
+ default:
+ INSIST(0);
+ break;
+ }
+}
+
+/*
+ * Include system-dependent code.
+ */
+
+#if HAVE_GETIFADDRS
+#include "ifiter_getifaddrs.c"
+#elif HAVE_IFLIST_SYSCTL
+#include "ifiter_sysctl.c"
+#else
+#include "ifiter_ioctl.c"
+#endif
+
+/*
+ * The remaining code is common to the sysctl and ioctl case.
+ */
+
+isc_result_t
+isc_interfaceiter_current(isc_interfaceiter_t *iter,
+ isc_interface_t *ifdata)
+{
+ REQUIRE(iter->result == ISC_R_SUCCESS);
+ memcpy(ifdata, &iter->current, sizeof(*ifdata));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_interfaceiter_first(isc_interfaceiter_t *iter) {
+ isc_result_t result;
+
+ REQUIRE(VALID_IFITER(iter));
+
+ internal_first(iter);
+ for (;;) {
+ result = internal_current(iter);
+ if (result != ISC_R_IGNORE)
+ break;
+ result = internal_next(iter);
+ if (result != ISC_R_SUCCESS)
+ break;
+ }
+ iter->result = result;
+ return (result);
+}
+
+isc_result_t
+isc_interfaceiter_next(isc_interfaceiter_t *iter) {
+ isc_result_t result;
+
+ REQUIRE(VALID_IFITER(iter));
+ REQUIRE(iter->result == ISC_R_SUCCESS);
+
+ for (;;) {
+ result = internal_next(iter);
+ if (result != ISC_R_SUCCESS)
+ break;
+ result = internal_current(iter);
+ if (result != ISC_R_IGNORE)
+ break;
+ }
+ iter->result = result;
+ return (result);
+}
+
+void
+isc_interfaceiter_destroy(isc_interfaceiter_t **iterp)
+{
+ isc_interfaceiter_t *iter;
+ REQUIRE(iterp != NULL);
+ iter = *iterp;
+ REQUIRE(VALID_IFITER(iter));
+
+ internal_destroy(iter);
+ if (iter->buf != NULL)
+ isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
+
+ iter->magic = 0;
+ isc_mem_put(iter->mctx, iter, sizeof(*iter));
+ *iterp = NULL;
+}
diff --git a/lib/isc/unix/ipv6.c b/lib/isc/unix/ipv6.c
new file mode 100644
index 0000000..3066e0c
--- /dev/null
+++ b/lib/isc/unix/ipv6.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2004-2006 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: ipv6.c,v 1.8.18.4 2006/08/25 05:25:51 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/ipv6.h>
+
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
diff --git a/lib/isc/unix/keyboard.c b/lib/isc/unix/keyboard.c
new file mode 100644
index 0000000..db56b3c
--- /dev/null
+++ b/lib/isc/unix/keyboard.c
@@ -0,0 +1,126 @@
+/*
+ * 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: keyboard.c,v 1.11 2004/03/05 05:11:46 marka Exp $ */
+
+#include <config.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <isc/keyboard.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_keyboard_open(isc_keyboard_t *keyboard) {
+ int fd;
+ isc_result_t ret;
+ struct termios current_mode;
+
+ REQUIRE(keyboard != NULL);
+
+ fd = open("/dev/tty", O_RDONLY, 0);
+ if (fd < 0)
+ return (ISC_R_IOERROR);
+
+ keyboard->fd = fd;
+
+ if (tcgetattr(fd, &keyboard->saved_mode) < 0) {
+ ret = ISC_R_IOERROR;
+ goto errout;
+ }
+
+ current_mode = keyboard->saved_mode;
+
+ current_mode.c_iflag &=
+ ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+ current_mode.c_oflag &= ~OPOST;
+ current_mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+ current_mode.c_cflag &= ~(CSIZE|PARENB);
+ current_mode.c_cflag |= CS8;
+
+ current_mode.c_cc[VMIN] = 1;
+ current_mode.c_cc[VTIME] = 0;
+ if (tcsetattr(fd, TCSAFLUSH, &current_mode) < 0) {
+ ret = ISC_R_IOERROR;
+ goto errout;
+ }
+
+ keyboard->result = ISC_R_SUCCESS;
+
+ return (ISC_R_SUCCESS);
+
+ errout:
+ close (fd);
+
+ return (ret);
+}
+
+isc_result_t
+isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleeptime) {
+ REQUIRE(keyboard != NULL);
+
+ if (sleeptime > 0 && keyboard->result != ISC_R_CANCELED)
+ (void)sleep(sleeptime);
+
+ (void)tcsetattr(keyboard->fd, TCSAFLUSH, &keyboard->saved_mode);
+ (void)close(keyboard->fd);
+
+ keyboard->fd = -1;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp) {
+ ssize_t cc;
+ unsigned char c;
+ cc_t *controlchars;
+
+ REQUIRE(keyboard != NULL);
+ REQUIRE(cp != NULL);
+
+ cc = read(keyboard->fd, &c, 1);
+ if (cc < 0) {
+ keyboard->result = ISC_R_IOERROR;
+ return (keyboard->result);
+ }
+
+ controlchars = keyboard->saved_mode.c_cc;
+ if (c == controlchars[VINTR] || c == controlchars[VQUIT]) {
+ keyboard->result = ISC_R_CANCELED;
+ return (keyboard->result);
+ }
+
+ *cp = c;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_boolean_t
+isc_keyboard_canceled(isc_keyboard_t *keyboard) {
+ return (ISC_TF(keyboard->result == ISC_R_CANCELED));
+}
diff --git a/lib/isc/unix/net.c b/lib/isc/unix/net.c
new file mode 100644
index 0000000..1de6b32
--- /dev/null
+++ b/lib/isc/unix/net.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: net.c,v 1.29.18.6 2007/09/13 23:46:26 tbox Exp $ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <isc/log.h>
+#include <isc/msgs.h>
+#include <isc/net.h>
+#include <isc/once.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#if defined(ISC_PLATFORM_HAVEIPV6)
+# if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
+const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
+# endif
+
+# if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
+const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
+# endif
+
+# if defined(WANT_IPV6)
+static isc_once_t once_ipv6only = ISC_ONCE_INIT;
+# endif
+
+# if defined(ISC_PLATFORM_HAVEIN6PKTINFO)
+static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
+# endif
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+
+static isc_once_t once = ISC_ONCE_INIT;
+
+static isc_result_t ipv4_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6_result = ISC_R_NOTFOUND;
+static isc_result_t unix_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
+
+static isc_result_t
+try_proto(int domain) {
+ int s;
+ isc_result_t result = ISC_R_SUCCESS;
+ char strbuf[ISC_STRERRORSIZE];
+
+ s = socket(domain, SOCK_STREAM, 0);
+ if (s == -1) {
+ switch (errno) {
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT:
+#endif
+#ifdef EPROTONOSUPPORT
+ case EPROTONOSUPPORT:
+#endif
+#ifdef EINVAL
+ case EINVAL:
+#endif
+ return (ISC_R_NOTFOUND);
+ default:
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+ if (domain == PF_INET6) {
+ struct sockaddr_in6 sin6;
+ unsigned int len;
+
+ /*
+ * Check to see if IPv6 is broken, as is common on Linux.
+ */
+ len = sizeof(sin6);
+ if (getsockname(s, (struct sockaddr *)&sin6, (void *)&len) < 0)
+ {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "retrieving the address of an IPv6 "
+ "socket from the kernel failed.");
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "IPv6 is not supported.");
+ result = ISC_R_NOTFOUND;
+ } else {
+ if (len == sizeof(struct sockaddr_in6))
+ result = ISC_R_SUCCESS;
+ else {
+ isc_log_write(isc_lctx,
+ ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET,
+ ISC_LOG_ERROR,
+ "IPv6 structures in kernel and "
+ "user space do not match.");
+ isc_log_write(isc_lctx,
+ ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET,
+ ISC_LOG_ERROR,
+ "IPv6 is not supported.");
+ result = ISC_R_NOTFOUND;
+ }
+ }
+ }
+#endif
+#endif
+#endif
+
+ (void)close(s);
+
+ return (result);
+}
+
+static void
+initialize_action(void) {
+ ipv4_result = try_proto(PF_INET);
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+ ipv6_result = try_proto(PF_INET6);
+#endif
+#endif
+#endif
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ unix_result = try_proto(PF_UNIX);
+#endif
+}
+
+static void
+initialize(void) {
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_net_probeipv4(void) {
+ initialize();
+ return (ipv4_result);
+}
+
+isc_result_t
+isc_net_probeipv6(void) {
+ initialize();
+ return (ipv6_result);
+}
+
+isc_result_t
+isc_net_probeunix(void) {
+ initialize();
+ return (unix_result);
+}
+
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+static void
+try_ipv6only(void) {
+#ifdef IPV6_V6ONLY
+ int s, on;
+ char strbuf[ISC_STRERRORSIZE];
+#endif
+ isc_result_t result;
+
+ result = isc_net_probeipv6();
+ if (result != ISC_R_SUCCESS) {
+ ipv6only_result = result;
+ return;
+ }
+
+#ifndef IPV6_V6ONLY
+ ipv6only_result = ISC_R_NOTFOUND;
+ return;
+#else
+ /* check for TCP sockets */
+ s = socket(PF_INET6, SOCK_STREAM, 0);
+ if (s == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ ipv6only_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
+ ipv6only_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ close(s);
+
+ /* check for UDP sockets */
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ ipv6only_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
+ ipv6only_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ close(s);
+
+ ipv6only_result = ISC_R_SUCCESS;
+
+close:
+ close(s);
+ return;
+#endif /* IPV6_V6ONLY */
+}
+
+static void
+initialize_ipv6only(void) {
+ RUNTIME_CHECK(isc_once_do(&once_ipv6only,
+ try_ipv6only) == ISC_R_SUCCESS);
+}
+#endif /* WANT_IPV6 */
+
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+static void
+try_ipv6pktinfo(void) {
+ int s, on;
+ char strbuf[ISC_STRERRORSIZE];
+ isc_result_t result;
+ int optname;
+
+ result = isc_net_probeipv6();
+ if (result != ISC_R_SUCCESS) {
+ ipv6pktinfo_result = result;
+ return;
+ }
+
+ /* we only use this for UDP sockets */
+ s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ ipv6pktinfo_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+#ifdef IPV6_RECVPKTINFO
+ optname = IPV6_RECVPKTINFO;
+#else
+ optname = IPV6_PKTINFO;
+#endif
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
+ ipv6pktinfo_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ close(s);
+ ipv6pktinfo_result = ISC_R_SUCCESS;
+
+close:
+ close(s);
+ return;
+}
+
+static void
+initialize_ipv6pktinfo(void) {
+ RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
+ try_ipv6pktinfo) == ISC_R_SUCCESS);
+}
+#endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+
+isc_result_t
+isc_net_probe_ipv6only(void) {
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+ initialize_ipv6only();
+#else
+ ipv6only_result = ISC_R_NOTFOUND;
+#endif
+#endif
+ return (ipv6only_result);
+}
+
+isc_result_t
+isc_net_probe_ipv6pktinfo(void) {
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+#ifdef WANT_IPV6
+ initialize_ipv6pktinfo();
+#else
+ ipv6pktinfo_result = ISC_R_NOTFOUND;
+#endif
+#endif
+#endif
+ return (ipv6pktinfo_result);
+}
+
+void
+isc_net_disableipv4(void) {
+ initialize();
+ if (ipv4_result == ISC_R_SUCCESS)
+ ipv4_result = ISC_R_DISABLED;
+}
+
+void
+isc_net_disableipv6(void) {
+ initialize();
+ if (ipv6_result == ISC_R_SUCCESS)
+ ipv6_result = ISC_R_DISABLED;
+}
+
+void
+isc_net_enableipv4(void) {
+ initialize();
+ if (ipv4_result == ISC_R_DISABLED)
+ ipv4_result = ISC_R_SUCCESS;
+}
+
+void
+isc_net_enableipv6(void) {
+ initialize();
+ if (ipv6_result == ISC_R_DISABLED)
+ ipv6_result = ISC_R_SUCCESS;
+}
diff --git a/lib/isc/unix/os.c b/lib/isc/unix/os.c
new file mode 100644
index 0000000..6bbf059
--- /dev/null
+++ b/lib/isc/unix/os.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2004, 2005 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: os.c,v 1.13.18.3 2005/10/14 02:13:08 marka Exp $ */
+
+#include <config.h>
+
+#include <isc/os.h>
+
+
+#ifdef HAVE_SYSCONF
+
+#include <unistd.h>
+
+#ifndef __hpux
+static inline long
+sysconf_ncpus(void) {
+#if defined(_SC_NPROCESSORS_ONLN)
+ return sysconf((_SC_NPROCESSORS_ONLN));
+#elif defined(_SC_NPROC_ONLN)
+ return sysconf((_SC_NPROC_ONLN));
+#else
+ return (0);
+#endif
+}
+#endif
+#endif /* HAVE_SYSCONF */
+
+
+#ifdef __hpux
+
+#include <sys/pstat.h>
+
+static inline int
+hpux_ncpus(void) {
+ struct pst_dynamic psd;
+ if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) != -1)
+ return (psd.psd_proc_cnt);
+ else
+ return (0);
+}
+
+#endif /* __hpux */
+
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)
+#include <sys/types.h> /* for FreeBSD */
+#include <sys/param.h> /* for NetBSD */
+#include <sys/sysctl.h>
+
+static int
+sysctl_ncpus(void) {
+ int ncpu, result;
+ size_t len;
+
+ len = sizeof(ncpu);
+ result = sysctlbyname("hw.ncpu", &ncpu, &len , 0, 0);
+ if (result != -1)
+ return (ncpu);
+ return (0);
+}
+#endif
+
+unsigned int
+isc_os_ncpus(void) {
+ long ncpus = 0;
+
+#ifdef __hpux
+ ncpus = hpux_ncpus();
+#elif defined(HAVE_SYSCONF)
+ ncpus = sysconf_ncpus();
+#endif
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)
+ if (ncpus <= 0)
+ ncpus = sysctl_ncpus();
+#endif
+ if (ncpus <= 0)
+ ncpus = 1;
+
+ return ((unsigned int)ncpus);
+}
diff --git a/lib/isc/unix/resource.c b/lib/isc/unix/resource.c
new file mode 100644
index 0000000..703ec27
--- /dev/null
+++ b/lib/isc/unix/resource.c
@@ -0,0 +1,204 @@
+/*
+ * 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: resource.c,v 1.12 2004/03/05 05:11:46 marka Exp $ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/time.h> /* Required on some systems for <sys/resource.h>. */
+#include <sys/resource.h>
+
+#include <isc/platform.h>
+#include <isc/resource.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+static isc_result_t
+resource2rlim(isc_resource_t resource, int *rlim_resource) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ switch (resource) {
+ case isc_resource_coresize:
+ *rlim_resource = RLIMIT_CORE;
+ break;
+ case isc_resource_cputime:
+ *rlim_resource = RLIMIT_CPU;
+ break;
+ case isc_resource_datasize:
+ *rlim_resource = RLIMIT_DATA;
+ break;
+ case isc_resource_filesize:
+ *rlim_resource = RLIMIT_FSIZE;
+ break;
+ case isc_resource_lockedmemory:
+#ifdef RLIMIT_MEMLOCK
+ *rlim_resource = RLIMIT_MEMLOCK;
+#else
+ result = ISC_R_NOTIMPLEMENTED;
+#endif
+ break;
+ case isc_resource_openfiles:
+#ifdef RLIMIT_NOFILE
+ *rlim_resource = RLIMIT_NOFILE;
+#else
+ result = ISC_R_NOTIMPLEMENTED;
+#endif
+ break;
+ case isc_resource_processes:
+#ifdef RLIMIT_NPROC
+ *rlim_resource = RLIMIT_NPROC;
+#else
+ result = ISC_R_NOTIMPLEMENTED;
+#endif
+ break;
+ case isc_resource_residentsize:
+#ifdef RLIMIT_RSS
+ *rlim_resource = RLIMIT_RSS;
+#else
+ result = ISC_R_NOTIMPLEMENTED;
+#endif
+ break;
+ case isc_resource_stacksize:
+ *rlim_resource = RLIMIT_STACK;
+ break;
+ default:
+ /*
+ * This test is not very robust if isc_resource_t
+ * changes, but generates a clear assertion message.
+ */
+ REQUIRE(resource >= isc_resource_coresize &&
+ resource <= isc_resource_stacksize);
+
+ result = ISC_R_RANGE;
+ break;
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
+ struct rlimit rl;
+ ISC_PLATFORM_RLIMITTYPE rlim_value;
+ int unixresult;
+ int unixresource;
+ isc_result_t result;
+
+ result = resource2rlim(resource, &unixresource);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (value == ISC_RESOURCE_UNLIMITED)
+ rlim_value = RLIM_INFINITY;
+
+ else {
+ /*
+ * isc_resourcevalue_t was chosen as an unsigned 64 bit
+ * integer so that it could contain the maximum range of
+ * reasonable values. Unfortunately, this exceeds the typical
+ * range on Unix systems. Ensure the range of
+ * ISC_PLATFORM_RLIMITTYPE is not overflowed.
+ */
+ isc_resourcevalue_t rlim_max;
+ isc_boolean_t rlim_t_is_signed =
+ ISC_TF(((double)(ISC_PLATFORM_RLIMITTYPE)-1) < 0);
+
+ if (rlim_t_is_signed)
+ rlim_max = ~((ISC_PLATFORM_RLIMITTYPE)1 <<
+ (sizeof(ISC_PLATFORM_RLIMITTYPE) * 8 - 1));
+ else
+ rlim_max = (ISC_PLATFORM_RLIMITTYPE)-1;
+
+ if (value > rlim_max)
+ value = rlim_max;
+
+ rlim_value = value;
+ }
+
+ /*
+ * The BIND 8 documentation reports:
+ *
+ * Note: on some operating systems the server cannot set an
+ * unlimited value and cannot determine the maximum number of
+ * open files the kernel can support. On such systems, choosing
+ * unlimited will cause the server to use the larger of the
+ * rlim_max for RLIMIT_NOFILE and the value returned by
+ * sysconf(_SC_OPEN_MAX). If the actual kernel limit is larger
+ * than this value, use limit files to specify the limit
+ * explicitly.
+ *
+ * The CHANGES for 8.1.2-T3A also mention:
+ *
+ * 352. [bug] Because of problems with setting an infinite
+ * rlim_max for RLIMIT_NOFILE on some systems, previous versions
+ * of the server implemented "limit files unlimited" by setting
+ * the limit to the value returned by sysconf(_SC_OPEN_MAX). The
+ * server will now use RLIM_INFINITY on systems which allow it.
+ *
+ * At some point the BIND 8 server stopped using SC_OPEN_MAX for this
+ * purpose at all, but it isn't clear to me when or why, as my access
+ * to the CVS archive is limited at the time of this writing. What
+ * BIND 8 *does* do is to set RLIMIT_NOFILE to either RLIMIT_INFINITY
+ * on a half dozen operating systems or to FD_SETSIZE on the rest,
+ * the latter of which is probably fewer than the real limit. (Note
+ * that libisc's socket module will have problems with any fd over
+ * FD_SETSIZE. This should be fixed in the socket module, not a
+ * limitation here. BIND 8's eventlib also has a problem, making
+ * its RLIMIT_INFINITY setting useless, because it closes and ignores
+ * any fd over FD_SETSIZE.)
+ *
+ * More troubling is the reference to some operating systems not being
+ * able to set an unlimited value for the number of open files. I'd
+ * hate to put in code that is really only there to support archaic
+ * systems that the rest of libisc won't work on anyway. So what this
+ * extremely verbose comment is here to say is the following:
+ *
+ * I'm aware there might be an issue with not limiting the value
+ * for RLIMIT_NOFILE on some systems, but since I don't know yet
+ * what those systems are and what the best workaround is (use
+ * sysconf()? rlim_max from getrlimit()? FD_SETSIZE?) so nothing
+ * is currently being done to clamp the value for open files.
+ */
+
+ rl.rlim_cur = rl.rlim_max = rlim_value;
+ unixresult = setrlimit(unixresource, &rl);
+
+ if (unixresult == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
+ int unixresult;
+ int unixresource;
+ struct rlimit rl;
+ isc_result_t result;
+
+ result = resource2rlim(resource, &unixresource);
+ if (result == ISC_R_SUCCESS) {
+ unixresult = getrlimit(unixresource, &rl);
+ INSIST(unixresult == 0);
+ *value = rl.rlim_max;
+ }
+
+ return (result);
+}
diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c
new file mode 100644
index 0000000..e0b9021
--- /dev/null
+++ b/lib/isc/unix/socket.c
@@ -0,0 +1,3836 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: socket.c,v 1.237.18.29 2007/08/28 07:20:06 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#ifdef ISC_PLATFORM_HAVESYSUNH
+#include <sys/un.h>
+#endif
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/buffer.h>
+#include <isc/bufferlist.h>
+#include <isc/condition.h>
+#include <isc/formatcheck.h>
+#include <isc/list.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/once.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/socket.h>
+#include <isc/strerror.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+#ifndef ISC_PLATFORM_USETHREADS
+#include "socket_p.h"
+#endif /* ISC_PLATFORM_USETHREADS */
+
+/*%
+ * Some systems define the socket length argument as an int, some as size_t,
+ * some as socklen_t. This is here so it can be easily changed if needed.
+ */
+#ifndef ISC_SOCKADDR_LEN_T
+#define ISC_SOCKADDR_LEN_T unsigned int
+#endif
+
+
+#if defined(SO_BSDCOMPAT) && defined(__linux__)
+#include <sys/utsname.h>
+#endif
+
+/*%
+ * Define what the possible "soft" errors can be. These are non-fatal returns
+ * of various network related functions, like recv() and so on.
+ *
+ * For some reason, BSDI (and perhaps others) will sometimes return <0
+ * from recv() but will have errno==0. This is broken, but we have to
+ * work around it here.
+ */
+#define SOFT_ERROR(e) ((e) == EAGAIN || \
+ (e) == EWOULDBLOCK || \
+ (e) == EINTR || \
+ (e) == 0)
+
+#define DLVL(x) ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(x)
+
+/*!<
+ * DLVL(90) -- Function entry/exit and other tracing.
+ * DLVL(70) -- Socket "correctness" -- including returning of events, etc.
+ * DLVL(60) -- Socket data send/receive
+ * DLVL(50) -- Event tracing, including receiving/sending completion events.
+ * DLVL(20) -- Socket creation/destruction.
+ */
+#define TRACE_LEVEL 90
+#define CORRECTNESS_LEVEL 70
+#define IOEVENT_LEVEL 60
+#define EVENT_LEVEL 50
+#define CREATION_LEVEL 20
+
+#define TRACE DLVL(TRACE_LEVEL)
+#define CORRECTNESS DLVL(CORRECTNESS_LEVEL)
+#define IOEVENT DLVL(IOEVENT_LEVEL)
+#define EVENT DLVL(EVENT_LEVEL)
+#define CREATION DLVL(CREATION_LEVEL)
+
+typedef isc_event_t intev_t;
+
+#define SOCKET_MAGIC ISC_MAGIC('I', 'O', 'i', 'o')
+#define VALID_SOCKET(t) ISC_MAGIC_VALID(t, SOCKET_MAGIC)
+
+/*!
+ * IPv6 control information. If the socket is an IPv6 socket we want
+ * to collect the destination address and interface so the client can
+ * set them on outgoing packets.
+ */
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+#ifndef USE_CMSG
+#define USE_CMSG 1
+#endif
+#endif
+
+/*%
+ * NetBSD and FreeBSD can timestamp packets. XXXMLG Should we have
+ * a setsockopt() like interface to request timestamps, and if the OS
+ * doesn't do it for us, call gettimeofday() on every UDP receive?
+ */
+#ifdef SO_TIMESTAMP
+#ifndef USE_CMSG
+#define USE_CMSG 1
+#endif
+#endif
+
+/*%
+ * The size to raise the recieve buffer to (from BIND 8).
+ */
+#define RCVBUFSIZE (32*1024)
+
+/*%
+ * The number of times a send operation is repeated if the result is EINTR.
+ */
+#define NRETRIES 10
+
+struct isc_socket {
+ /* Not locked. */
+ unsigned int magic;
+ isc_socketmgr_t *manager;
+ isc_mutex_t lock;
+ isc_sockettype_t type;
+
+ /* Locked by socket lock. */
+ ISC_LINK(isc_socket_t) link;
+ unsigned int references;
+ int fd;
+ int pf;
+
+ ISC_LIST(isc_socketevent_t) send_list;
+ ISC_LIST(isc_socketevent_t) recv_list;
+ ISC_LIST(isc_socket_newconnev_t) accept_list;
+ isc_socket_connev_t *connect_ev;
+
+ /*
+ * Internal events. Posted when a descriptor is readable or
+ * writable. These are statically allocated and never freed.
+ * They will be set to non-purgable before use.
+ */
+ intev_t readable_ev;
+ intev_t writable_ev;
+
+ isc_sockaddr_t address; /* remote address */
+
+ unsigned int pending_recv : 1,
+ pending_send : 1,
+ pending_accept : 1,
+ listener : 1, /* listener socket */
+ connected : 1,
+ connecting : 1, /* connect pending */
+ bound : 1; /* bound to local addr */
+
+#ifdef ISC_NET_RECVOVERFLOW
+ unsigned char overflow; /* used for MSG_TRUNC fake */
+#endif
+
+ char *recvcmsgbuf;
+ ISC_SOCKADDR_LEN_T recvcmsgbuflen;
+ char *sendcmsgbuf;
+ ISC_SOCKADDR_LEN_T sendcmsgbuflen;
+};
+
+#define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g')
+#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC)
+
+struct isc_socketmgr {
+ /* Not locked. */
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ /* Locked by manager lock. */
+ ISC_LIST(isc_socket_t) socklist;
+ fd_set read_fds;
+ fd_set write_fds;
+ isc_socket_t *fds[FD_SETSIZE];
+ int fdstate[FD_SETSIZE];
+ int maxfd;
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_thread_t watcher;
+ isc_condition_t shutdown_ok;
+ int pipe_fds[2];
+#else /* ISC_PLATFORM_USETHREADS */
+ unsigned int refs;
+#endif /* ISC_PLATFORM_USETHREADS */
+};
+
+#ifndef ISC_PLATFORM_USETHREADS
+static isc_socketmgr_t *socketmgr = NULL;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#define CLOSED 0 /* this one must be zero */
+#define MANAGED 1
+#define CLOSE_PENDING 2
+
+/*
+ * send() and recv() iovec counts
+ */
+#define MAXSCATTERGATHER_SEND (ISC_SOCKET_MAXSCATTERGATHER)
+#ifdef ISC_NET_RECVOVERFLOW
+# define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER + 1)
+#else
+# define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER)
+#endif
+
+static void send_recvdone_event(isc_socket_t *, isc_socketevent_t **);
+static void send_senddone_event(isc_socket_t *, isc_socketevent_t **);
+static void free_socket(isc_socket_t **);
+static isc_result_t allocate_socket(isc_socketmgr_t *, isc_sockettype_t,
+ isc_socket_t **);
+static void destroy(isc_socket_t **);
+static void internal_accept(isc_task_t *, isc_event_t *);
+static void internal_connect(isc_task_t *, isc_event_t *);
+static void internal_recv(isc_task_t *, isc_event_t *);
+static void internal_send(isc_task_t *, isc_event_t *);
+static void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *);
+static void build_msghdr_send(isc_socket_t *, isc_socketevent_t *,
+ struct msghdr *, struct iovec *, size_t *);
+static void build_msghdr_recv(isc_socket_t *, isc_socketevent_t *,
+ struct msghdr *, struct iovec *, size_t *);
+
+#define SELECT_POKE_SHUTDOWN (-1)
+#define SELECT_POKE_NOTHING (-2)
+#define SELECT_POKE_READ (-3)
+#define SELECT_POKE_ACCEPT (-3) /*%< Same as _READ */
+#define SELECT_POKE_WRITE (-4)
+#define SELECT_POKE_CONNECT (-4) /*%< Same as _WRITE */
+#define SELECT_POKE_CLOSE (-5)
+
+#define SOCK_DEAD(s) ((s)->references == 0)
+
+static void
+manager_log(isc_socketmgr_t *sockmgr,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6);
+static void
+manager_log(isc_socketmgr_t *sockmgr,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ const char *fmt, ...)
+{
+ char msgbuf[2048];
+ va_list ap;
+
+ if (! isc_log_wouldlog(isc_lctx, level))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ isc_log_write(isc_lctx, category, module, level,
+ "sockmgr %p: %s", sockmgr, msgbuf);
+}
+
+static void
+socket_log(isc_socket_t *sock, isc_sockaddr_t *address,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10);
+static void
+socket_log(isc_socket_t *sock, isc_sockaddr_t *address,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ isc_msgcat_t *msgcat, int msgset, int message,
+ const char *fmt, ...)
+{
+ char msgbuf[2048];
+ char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+ va_list ap;
+
+ if (! isc_log_wouldlog(isc_lctx, level))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ if (address == NULL) {
+ isc_log_iwrite(isc_lctx, category, module, level,
+ msgcat, msgset, message,
+ "socket %p: %s", sock, msgbuf);
+ } else {
+ isc_sockaddr_format(address, peerbuf, sizeof(peerbuf));
+ isc_log_iwrite(isc_lctx, category, module, level,
+ msgcat, msgset, message,
+ "socket %p %s: %s", sock, peerbuf, msgbuf);
+ }
+}
+
+static void
+wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) {
+ isc_socket_t *sock;
+
+ /*
+ * This is a wakeup on a socket. If the socket is not in the
+ * process of being closed, start watching it for either reads
+ * or writes.
+ */
+
+ INSIST(fd >= 0 && fd < (int)FD_SETSIZE);
+
+ if (manager->fdstate[fd] == CLOSE_PENDING) {
+ manager->fdstate[fd] = CLOSED;
+ FD_CLR(fd, &manager->read_fds);
+ FD_CLR(fd, &manager->write_fds);
+ (void)close(fd);
+ return;
+ }
+ if (manager->fdstate[fd] != MANAGED)
+ return;
+
+ sock = manager->fds[fd];
+
+ /*
+ * Set requested bit.
+ */
+ if (msg == SELECT_POKE_READ)
+ FD_SET(sock->fd, &manager->read_fds);
+ if (msg == SELECT_POKE_WRITE)
+ FD_SET(sock->fd, &manager->write_fds);
+}
+
+#ifdef ISC_PLATFORM_USETHREADS
+/*
+ * Poke the select loop when there is something for us to do.
+ * The write is required (by POSIX) to complete. That is, we
+ * will not get partial writes.
+ */
+static void
+select_poke(isc_socketmgr_t *mgr, int fd, int msg) {
+ int cc;
+ int buf[2];
+ char strbuf[ISC_STRERRORSIZE];
+
+ buf[0] = fd;
+ buf[1] = msg;
+
+ do {
+ cc = write(mgr->pipe_fds[1], buf, sizeof(buf));
+#ifdef ENOSR
+ /*
+ * Treat ENOSR as EAGAIN but loop slowly as it is
+ * unlikely to clear fast.
+ */
+ if (cc < 0 && errno == ENOSR) {
+ sleep(1);
+ errno = EAGAIN;
+ }
+#endif
+ } while (cc < 0 && SOFT_ERROR(errno));
+
+ if (cc < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_WRITEFAILED,
+ "write() failed "
+ "during watcher poke: %s"),
+ strbuf);
+ }
+
+ INSIST(cc == sizeof(buf));
+}
+
+/*
+ * Read a message on the internal fd.
+ */
+static void
+select_readmsg(isc_socketmgr_t *mgr, int *fd, int *msg) {
+ int buf[2];
+ int cc;
+ char strbuf[ISC_STRERRORSIZE];
+
+ cc = read(mgr->pipe_fds[0], buf, sizeof(buf));
+ if (cc < 0) {
+ *msg = SELECT_POKE_NOTHING;
+ *fd = -1; /* Silence compiler. */
+ if (SOFT_ERROR(errno))
+ return;
+
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_READFAILED,
+ "read() failed "
+ "during watcher poke: %s"),
+ strbuf);
+
+ return;
+ }
+ INSIST(cc == sizeof(buf));
+
+ *fd = buf[0];
+ *msg = buf[1];
+}
+#else /* ISC_PLATFORM_USETHREADS */
+/*
+ * Update the state of the socketmgr when something changes.
+ */
+static void
+select_poke(isc_socketmgr_t *manager, int fd, int msg) {
+ if (msg == SELECT_POKE_SHUTDOWN)
+ return;
+ else if (fd >= 0)
+ wakeup_socket(manager, fd, msg);
+ return;
+}
+#endif /* ISC_PLATFORM_USETHREADS */
+
+/*
+ * Make a fd non-blocking.
+ */
+static isc_result_t
+make_nonblock(int fd) {
+ int ret;
+ int flags;
+ char strbuf[ISC_STRERRORSIZE];
+#ifdef USE_FIONBIO_IOCTL
+ int on = 1;
+
+ ret = ioctl(fd, FIONBIO, (char *)&on);
+#else
+ flags = fcntl(fd, F_GETFL, 0);
+ flags |= PORT_NONBLOCK;
+ ret = fcntl(fd, F_SETFL, flags);
+#endif
+
+ if (ret == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+#ifdef USE_FIONBIO_IOCTL
+ "ioctl(%d, FIONBIO, &on): %s", fd,
+#else
+ "fcntl(%d, F_SETFL, %d): %s", fd, flags,
+#endif
+ strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+#ifdef USE_CMSG
+/*
+ * Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE.
+ * In order to ensure as much portability as possible, we provide wrapper
+ * functions of these macros.
+ * Note that cmsg_space() could run slow on OSes that do not have
+ * CMSG_SPACE.
+ */
+static inline ISC_SOCKADDR_LEN_T
+cmsg_len(ISC_SOCKADDR_LEN_T len) {
+#ifdef CMSG_LEN
+ return (CMSG_LEN(len));
+#else
+ ISC_SOCKADDR_LEN_T hdrlen;
+
+ /*
+ * Cast NULL so that any pointer arithmetic performed by CMSG_DATA
+ * is correct.
+ */
+ hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(((struct cmsghdr *)NULL));
+ return (hdrlen + len);
+#endif
+}
+
+static inline ISC_SOCKADDR_LEN_T
+cmsg_space(ISC_SOCKADDR_LEN_T len) {
+#ifdef CMSG_SPACE
+ return (CMSG_SPACE(len));
+#else
+ struct msghdr msg;
+ struct cmsghdr *cmsgp;
+ /*
+ * XXX: The buffer length is an ad-hoc value, but should be enough
+ * in a practical sense.
+ */
+ char dummybuf[sizeof(struct cmsghdr) + 1024];
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_control = dummybuf;
+ msg.msg_controllen = sizeof(dummybuf);
+
+ cmsgp = (struct cmsghdr *)dummybuf;
+ cmsgp->cmsg_len = cmsg_len(len);
+
+ cmsgp = CMSG_NXTHDR(&msg, cmsgp);
+ if (cmsgp != NULL)
+ return ((char *)cmsgp - (char *)msg.msg_control);
+ else
+ return (0);
+#endif
+}
+#endif /* USE_CMSG */
+
+/*
+ * Process control messages received on a socket.
+ */
+static void
+process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) {
+#ifdef USE_CMSG
+ struct cmsghdr *cmsgp;
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+ struct in6_pktinfo *pktinfop;
+#endif
+#ifdef SO_TIMESTAMP
+ struct timeval *timevalp;
+#endif
+#endif
+
+ /*
+ * sock is used only when ISC_NET_BSD44MSGHDR and USE_CMSG are defined.
+ * msg and dev are used only when ISC_NET_BSD44MSGHDR is defined.
+ * They are all here, outside of the CPP tests, because it is
+ * more consistent with the usual ISC coding style.
+ */
+ UNUSED(sock);
+ UNUSED(msg);
+ UNUSED(dev);
+
+#ifdef ISC_NET_BSD44MSGHDR
+
+#ifdef MSG_TRUNC
+ if ((msg->msg_flags & MSG_TRUNC) == MSG_TRUNC)
+ dev->attributes |= ISC_SOCKEVENTATTR_TRUNC;
+#endif
+
+#ifdef MSG_CTRUNC
+ if ((msg->msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
+ dev->attributes |= ISC_SOCKEVENTATTR_CTRUNC;
+#endif
+
+#ifndef USE_CMSG
+ return;
+#else
+ if (msg->msg_controllen == 0U || msg->msg_control == NULL)
+ return;
+
+#ifdef SO_TIMESTAMP
+ timevalp = NULL;
+#endif
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+ pktinfop = NULL;
+#endif
+
+ cmsgp = CMSG_FIRSTHDR(msg);
+ while (cmsgp != NULL) {
+ socket_log(sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PROCESSCMSG,
+ "processing cmsg %p", cmsgp);
+
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+ if (cmsgp->cmsg_level == IPPROTO_IPV6
+ && cmsgp->cmsg_type == IPV6_PKTINFO) {
+
+ pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
+ memcpy(&dev->pktinfo, pktinfop,
+ sizeof(struct in6_pktinfo));
+ dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
+ socket_log(sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_IFRECEIVED,
+ "interface received on ifindex %u",
+ dev->pktinfo.ipi6_ifindex);
+ if (IN6_IS_ADDR_MULTICAST(&pktinfop->ipi6_addr))
+ dev->attributes |= ISC_SOCKEVENTATTR_MULTICAST;
+ goto next;
+ }
+#endif
+
+#ifdef SO_TIMESTAMP
+ if (cmsgp->cmsg_level == SOL_SOCKET
+ && cmsgp->cmsg_type == SCM_TIMESTAMP) {
+ timevalp = (struct timeval *)CMSG_DATA(cmsgp);
+ dev->timestamp.seconds = timevalp->tv_sec;
+ dev->timestamp.nanoseconds = timevalp->tv_usec * 1000;
+ dev->attributes |= ISC_SOCKEVENTATTR_TIMESTAMP;
+ goto next;
+ }
+#endif
+
+ next:
+ cmsgp = CMSG_NXTHDR(msg, cmsgp);
+ }
+#endif /* USE_CMSG */
+
+#endif /* ISC_NET_BSD44MSGHDR */
+}
+
+/*
+ * Construct an iov array and attach it to the msghdr passed in. This is
+ * the SEND constructor, which will use the used region of the buffer
+ * (if using a buffer list) or will use the internal region (if a single
+ * buffer I/O is requested).
+ *
+ * Nothing can be NULL, and the done event must list at least one buffer
+ * on the buffer linked list for this function to be meaningful.
+ *
+ * If write_countp != NULL, *write_countp will hold the number of bytes
+ * this transaction can send.
+ */
+static void
+build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
+ struct msghdr *msg, struct iovec *iov, size_t *write_countp)
+{
+ unsigned int iovcount;
+ isc_buffer_t *buffer;
+ isc_region_t used;
+ size_t write_count;
+ size_t skip_count;
+
+ memset(msg, 0, sizeof(*msg));
+
+ if (sock->type == isc_sockettype_udp) {
+ msg->msg_name = (void *)&dev->address.type.sa;
+ msg->msg_namelen = dev->address.length;
+ } else {
+ msg->msg_name = NULL;
+ msg->msg_namelen = 0;
+ }
+
+ buffer = ISC_LIST_HEAD(dev->bufferlist);
+ write_count = 0;
+ iovcount = 0;
+
+ /*
+ * Single buffer I/O? Skip what we've done so far in this region.
+ */
+ if (buffer == NULL) {
+ write_count = dev->region.length - dev->n;
+ iov[0].iov_base = (void *)(dev->region.base + dev->n);
+ iov[0].iov_len = write_count;
+ iovcount = 1;
+
+ goto config;
+ }
+
+ /*
+ * Multibuffer I/O.
+ * Skip the data in the buffer list that we have already written.
+ */
+ skip_count = dev->n;
+ while (buffer != NULL) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ if (skip_count < isc_buffer_usedlength(buffer))
+ break;
+ skip_count -= isc_buffer_usedlength(buffer);
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ while (buffer != NULL) {
+ INSIST(iovcount < MAXSCATTERGATHER_SEND);
+
+ isc_buffer_usedregion(buffer, &used);
+
+ if (used.length > 0) {
+ iov[iovcount].iov_base = (void *)(used.base
+ + skip_count);
+ iov[iovcount].iov_len = used.length - skip_count;
+ write_count += (used.length - skip_count);
+ skip_count = 0;
+ iovcount++;
+ }
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ INSIST(skip_count == 0U);
+
+ config:
+ msg->msg_iov = iov;
+ msg->msg_iovlen = iovcount;
+
+#ifdef ISC_NET_BSD44MSGHDR
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+ msg->msg_flags = 0;
+#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
+ if ((sock->type == isc_sockettype_udp)
+ && ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0)) {
+ struct cmsghdr *cmsgp;
+ struct in6_pktinfo *pktinfop;
+
+ socket_log(sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_SENDTODATA,
+ "sendto pktinfo data, ifindex %u",
+ dev->pktinfo.ipi6_ifindex);
+
+ msg->msg_controllen = cmsg_space(sizeof(struct in6_pktinfo));
+ INSIST(msg->msg_controllen <= sock->sendcmsgbuflen);
+ msg->msg_control = (void *)sock->sendcmsgbuf;
+
+ cmsgp = (struct cmsghdr *)sock->sendcmsgbuf;
+ cmsgp->cmsg_level = IPPROTO_IPV6;
+ cmsgp->cmsg_type = IPV6_PKTINFO;
+ cmsgp->cmsg_len = cmsg_len(sizeof(struct in6_pktinfo));
+ pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
+ memcpy(pktinfop, &dev->pktinfo, sizeof(struct in6_pktinfo));
+ }
+#endif /* USE_CMSG && ISC_PLATFORM_HAVEIPV6 */
+#else /* ISC_NET_BSD44MSGHDR */
+ msg->msg_accrights = NULL;
+ msg->msg_accrightslen = 0;
+#endif /* ISC_NET_BSD44MSGHDR */
+
+ if (write_countp != NULL)
+ *write_countp = write_count;
+}
+
+/*
+ * Construct an iov array and attach it to the msghdr passed in. This is
+ * the RECV constructor, which will use the avialable region of the buffer
+ * (if using a buffer list) or will use the internal region (if a single
+ * buffer I/O is requested).
+ *
+ * Nothing can be NULL, and the done event must list at least one buffer
+ * on the buffer linked list for this function to be meaningful.
+ *
+ * If read_countp != NULL, *read_countp will hold the number of bytes
+ * this transaction can receive.
+ */
+static void
+build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
+ struct msghdr *msg, struct iovec *iov, size_t *read_countp)
+{
+ unsigned int iovcount;
+ isc_buffer_t *buffer;
+ isc_region_t available;
+ size_t read_count;
+
+ memset(msg, 0, sizeof(struct msghdr));
+
+ if (sock->type == isc_sockettype_udp) {
+ memset(&dev->address, 0, sizeof(dev->address));
+#ifdef BROKEN_RECVMSG
+ if (sock->pf == AF_INET) {
+ msg->msg_name = (void *)&dev->address.type.sin;
+ msg->msg_namelen = sizeof(dev->address.type.sin6);
+ } else if (sock->pf == AF_INET6) {
+ msg->msg_name = (void *)&dev->address.type.sin6;
+ msg->msg_namelen = sizeof(dev->address.type.sin6);
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ } else if (sock->pf == AF_UNIX) {
+ msg->msg_name = (void *)&dev->address.type.sunix;
+ msg->msg_namelen = sizeof(dev->address.type.sunix);
+#endif
+ } else {
+ msg->msg_name = (void *)&dev->address.type.sa;
+ msg->msg_namelen = sizeof(dev->address.type);
+ }
+#else
+ msg->msg_name = (void *)&dev->address.type.sa;
+ msg->msg_namelen = sizeof(dev->address.type);
+#endif
+#ifdef ISC_NET_RECVOVERFLOW
+ /* If needed, steal one iovec for overflow detection. */
+ maxiov--;
+#endif
+ } else { /* TCP */
+ msg->msg_name = NULL;
+ msg->msg_namelen = 0;
+ dev->address = sock->address;
+ }
+
+ buffer = ISC_LIST_HEAD(dev->bufferlist);
+ read_count = 0;
+
+ /*
+ * Single buffer I/O? Skip what we've done so far in this region.
+ */
+ if (buffer == NULL) {
+ read_count = dev->region.length - dev->n;
+ iov[0].iov_base = (void *)(dev->region.base + dev->n);
+ iov[0].iov_len = read_count;
+ iovcount = 1;
+
+ goto config;
+ }
+
+ /*
+ * Multibuffer I/O.
+ * Skip empty buffers.
+ */
+ while (buffer != NULL) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ if (isc_buffer_availablelength(buffer) != 0)
+ break;
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ iovcount = 0;
+ while (buffer != NULL) {
+ INSIST(iovcount < MAXSCATTERGATHER_RECV);
+
+ isc_buffer_availableregion(buffer, &available);
+
+ if (available.length > 0) {
+ iov[iovcount].iov_base = (void *)(available.base);
+ iov[iovcount].iov_len = available.length;
+ read_count += available.length;
+ iovcount++;
+ }
+ buffer = ISC_LIST_NEXT(buffer, link);
+ }
+
+ config:
+
+ /*
+ * If needed, set up to receive that one extra byte. Note that
+ * we know there is at least one iov left, since we stole it
+ * at the top of this function.
+ */
+#ifdef ISC_NET_RECVOVERFLOW
+ if (sock->type == isc_sockettype_udp) {
+ iov[iovcount].iov_base = (void *)(&sock->overflow);
+ iov[iovcount].iov_len = 1;
+ iovcount++;
+ }
+#endif
+
+ msg->msg_iov = iov;
+ msg->msg_iovlen = iovcount;
+
+#ifdef ISC_NET_BSD44MSGHDR
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+ msg->msg_flags = 0;
+#if defined(USE_CMSG)
+ if (sock->type == isc_sockettype_udp) {
+ msg->msg_control = sock->recvcmsgbuf;
+ msg->msg_controllen = sock->recvcmsgbuflen;
+ }
+#endif /* USE_CMSG */
+#else /* ISC_NET_BSD44MSGHDR */
+ msg->msg_accrights = NULL;
+ msg->msg_accrightslen = 0;
+#endif /* ISC_NET_BSD44MSGHDR */
+
+ if (read_countp != NULL)
+ *read_countp = read_count;
+}
+
+static void
+set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock,
+ isc_socketevent_t *dev)
+{
+ if (sock->type == isc_sockettype_udp) {
+ if (address != NULL)
+ dev->address = *address;
+ else
+ dev->address = sock->address;
+ } else if (sock->type == isc_sockettype_tcp) {
+ INSIST(address == NULL);
+ dev->address = sock->address;
+ }
+}
+
+static void
+destroy_socketevent(isc_event_t *event) {
+ isc_socketevent_t *ev = (isc_socketevent_t *)event;
+
+ INSIST(ISC_LIST_EMPTY(ev->bufferlist));
+
+ (ev->destroy)(event);
+}
+
+static isc_socketevent_t *
+allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype,
+ isc_taskaction_t action, const void *arg)
+{
+ isc_socketevent_t *ev;
+
+ ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx,
+ sock, eventtype,
+ action, arg,
+ sizeof(*ev));
+
+ if (ev == NULL)
+ return (NULL);
+
+ ev->result = ISC_R_UNEXPECTED;
+ ISC_LINK_INIT(ev, ev_link);
+ ISC_LIST_INIT(ev->bufferlist);
+ ev->region.base = NULL;
+ ev->n = 0;
+ ev->offset = 0;
+ ev->attributes = 0;
+ ev->destroy = ev->ev_destroy;
+ ev->ev_destroy = destroy_socketevent;
+
+ return (ev);
+}
+
+#if defined(ISC_SOCKET_DEBUG)
+static void
+dump_msg(struct msghdr *msg) {
+ unsigned int i;
+
+ printf("MSGHDR %p\n", msg);
+ printf("\tname %p, namelen %d\n", msg->msg_name, msg->msg_namelen);
+ printf("\tiov %p, iovlen %d\n", msg->msg_iov, msg->msg_iovlen);
+ for (i = 0; i < (unsigned int)msg->msg_iovlen; i++)
+ printf("\t\t%d\tbase %p, len %d\n", i,
+ msg->msg_iov[i].iov_base,
+ msg->msg_iov[i].iov_len);
+#ifdef ISC_NET_BSD44MSGHDR
+ printf("\tcontrol %p, controllen %d\n", msg->msg_control,
+ msg->msg_controllen);
+#endif
+}
+#endif
+
+#define DOIO_SUCCESS 0 /* i/o ok, event sent */
+#define DOIO_SOFT 1 /* i/o ok, soft error, no event sent */
+#define DOIO_HARD 2 /* i/o error, event sent */
+#define DOIO_EOF 3 /* EOF, no event sent */
+
+static int
+doio_recv(isc_socket_t *sock, isc_socketevent_t *dev) {
+ int cc;
+ struct iovec iov[MAXSCATTERGATHER_RECV];
+ size_t read_count;
+ size_t actual_count;
+ struct msghdr msghdr;
+ isc_buffer_t *buffer;
+ int recv_errno;
+ char strbuf[ISC_STRERRORSIZE];
+
+ build_msghdr_recv(sock, dev, &msghdr, iov, &read_count);
+
+#if defined(ISC_SOCKET_DEBUG)
+ dump_msg(&msghdr);
+#endif
+
+ cc = recvmsg(sock->fd, &msghdr, 0);
+ recv_errno = errno;
+
+#if defined(ISC_SOCKET_DEBUG)
+ dump_msg(&msghdr);
+#endif
+
+ if (cc < 0) {
+ if (SOFT_ERROR(recv_errno))
+ return (DOIO_SOFT);
+
+ if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+ isc__strerror(recv_errno, strbuf, sizeof(strbuf));
+ socket_log(sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_DOIORECV,
+ "doio_recv: recvmsg(%d) %d bytes, err %d/%s",
+ sock->fd, cc, recv_errno, strbuf);
+ }
+
+#define SOFT_OR_HARD(_system, _isc) \
+ if (recv_errno == _system) { \
+ if (sock->connected) { \
+ dev->result = _isc; \
+ return (DOIO_HARD); \
+ } \
+ return (DOIO_SOFT); \
+ }
+#define ALWAYS_HARD(_system, _isc) \
+ if (recv_errno == _system) { \
+ dev->result = _isc; \
+ return (DOIO_HARD); \
+ }
+
+ SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
+ SOFT_OR_HARD(ENETUNREACH, ISC_R_NETUNREACH);
+ SOFT_OR_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+ SOFT_OR_HARD(EHOSTDOWN, ISC_R_HOSTDOWN);
+ /* HPUX 11.11 can return EADDRNOTAVAIL. */
+ SOFT_OR_HARD(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+ ALWAYS_HARD(ENOBUFS, ISC_R_NORESOURCES);
+
+#undef SOFT_OR_HARD
+#undef ALWAYS_HARD
+
+ dev->result = isc__errno2result(recv_errno);
+ return (DOIO_HARD);
+ }
+
+ /*
+ * On TCP, zero length reads indicate EOF, while on
+ * UDP, zero length reads are perfectly valid, although
+ * strange.
+ */
+ if ((sock->type == isc_sockettype_tcp) && (cc == 0))
+ return (DOIO_EOF);
+
+ if (sock->type == isc_sockettype_udp) {
+ dev->address.length = msghdr.msg_namelen;
+ if (isc_sockaddr_getport(&dev->address) == 0) {
+ if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+ socket_log(sock, &dev->address, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_ZEROPORT,
+ "dropping source port zero packet");
+ }
+ return (DOIO_SOFT);
+ }
+ }
+
+ socket_log(sock, &dev->address, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PKTRECV,
+ "packet received correctly");
+
+ /*
+ * Overflow bit detection. If we received MORE bytes than we should,
+ * this indicates an overflow situation. Set the flag in the
+ * dev entry and adjust how much we read by one.
+ */
+#ifdef ISC_NET_RECVOVERFLOW
+ if ((sock->type == isc_sockettype_udp) && ((size_t)cc > read_count)) {
+ dev->attributes |= ISC_SOCKEVENTATTR_TRUNC;
+ cc--;
+ }
+#endif
+
+ /*
+ * If there are control messages attached, run through them and pull
+ * out the interesting bits.
+ */
+ if (sock->type == isc_sockettype_udp)
+ process_cmsg(sock, &msghdr, dev);
+
+ /*
+ * update the buffers (if any) and the i/o count
+ */
+ dev->n += cc;
+ actual_count = cc;
+ buffer = ISC_LIST_HEAD(dev->bufferlist);
+ while (buffer != NULL && actual_count > 0U) {
+ REQUIRE(ISC_BUFFER_VALID(buffer));
+ if (isc_buffer_availablelength(buffer) <= actual_count) {
+ actual_count -= isc_buffer_availablelength(buffer);
+ isc_buffer_add(buffer,
+ isc_buffer_availablelength(buffer));
+ } else {
+ isc_buffer_add(buffer, actual_count);
+ actual_count = 0;
+ break;
+ }
+ buffer = ISC_LIST_NEXT(buffer, link);
+ if (buffer == NULL) {
+ INSIST(actual_count == 0U);
+ }
+ }
+
+ /*
+ * If we read less than we expected, update counters,
+ * and let the upper layer poke the descriptor.
+ */
+ if (((size_t)cc != read_count) && (dev->n < dev->minimum))
+ return (DOIO_SOFT);
+
+ /*
+ * Full reads are posted, or partials if partials are ok.
+ */
+ dev->result = ISC_R_SUCCESS;
+ return (DOIO_SUCCESS);
+}
+
+/*
+ * Returns:
+ * DOIO_SUCCESS The operation succeeded. dev->result contains
+ * ISC_R_SUCCESS.
+ *
+ * DOIO_HARD A hard or unexpected I/O error was encountered.
+ * dev->result contains the appropriate error.
+ *
+ * DOIO_SOFT A soft I/O error was encountered. No senddone
+ * event was sent. The operation should be retried.
+ *
+ * No other return values are possible.
+ */
+static int
+doio_send(isc_socket_t *sock, isc_socketevent_t *dev) {
+ int cc;
+ struct iovec iov[MAXSCATTERGATHER_SEND];
+ size_t write_count;
+ struct msghdr msghdr;
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+ int attempts = 0;
+ int send_errno;
+ char strbuf[ISC_STRERRORSIZE];
+
+ build_msghdr_send(sock, dev, &msghdr, iov, &write_count);
+
+ resend:
+ cc = sendmsg(sock->fd, &msghdr, 0);
+ send_errno = errno;
+
+ /*
+ * Check for error or block condition.
+ */
+ if (cc < 0) {
+ if (send_errno == EINTR && ++attempts < NRETRIES)
+ goto resend;
+
+ if (SOFT_ERROR(send_errno))
+ return (DOIO_SOFT);
+
+#define SOFT_OR_HARD(_system, _isc) \
+ if (send_errno == _system) { \
+ if (sock->connected) { \
+ dev->result = _isc; \
+ return (DOIO_HARD); \
+ } \
+ return (DOIO_SOFT); \
+ }
+#define ALWAYS_HARD(_system, _isc) \
+ if (send_errno == _system) { \
+ dev->result = _isc; \
+ return (DOIO_HARD); \
+ }
+
+ SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
+ ALWAYS_HARD(EACCES, ISC_R_NOPERM);
+ ALWAYS_HARD(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+ ALWAYS_HARD(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+ ALWAYS_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+#ifdef EHOSTDOWN
+ ALWAYS_HARD(EHOSTDOWN, ISC_R_HOSTUNREACH);
+#endif
+ ALWAYS_HARD(ENETUNREACH, ISC_R_NETUNREACH);
+ ALWAYS_HARD(ENOBUFS, ISC_R_NORESOURCES);
+ ALWAYS_HARD(EPERM, ISC_R_HOSTUNREACH);
+ ALWAYS_HARD(EPIPE, ISC_R_NOTCONNECTED);
+ ALWAYS_HARD(ECONNRESET, ISC_R_CONNECTIONRESET);
+
+#undef SOFT_OR_HARD
+#undef ALWAYS_HARD
+
+ /*
+ * The other error types depend on whether or not the
+ * socket is UDP or TCP. If it is UDP, some errors
+ * that we expect to be fatal under TCP are merely
+ * annoying, and are really soft errors.
+ *
+ * However, these soft errors are still returned as
+ * a status.
+ */
+ isc_sockaddr_format(&dev->address, addrbuf, sizeof(addrbuf));
+ isc__strerror(send_errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "internal_send: %s: %s",
+ addrbuf, strbuf);
+ dev->result = isc__errno2result(send_errno);
+ return (DOIO_HARD);
+ }
+
+ if (cc == 0)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "internal_send: send() %s 0",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_RETURNED, "returned"));
+
+ /*
+ * If we write less than we expected, update counters, poke.
+ */
+ dev->n += cc;
+ if ((size_t)cc != write_count)
+ return (DOIO_SOFT);
+
+ /*
+ * Exactly what we wanted to write. We're done with this
+ * entry. Post its completion event.
+ */
+ dev->result = ISC_R_SUCCESS;
+ return (DOIO_SUCCESS);
+}
+
+/*
+ * Kill.
+ *
+ * Caller must ensure that the socket is not locked and no external
+ * references exist.
+ */
+static void
+destroy(isc_socket_t **sockp) {
+ isc_socket_t *sock = *sockp;
+ isc_socketmgr_t *manager = sock->manager;
+
+ socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_DESTROYING, "destroying");
+
+ INSIST(ISC_LIST_EMPTY(sock->accept_list));
+ INSIST(ISC_LIST_EMPTY(sock->recv_list));
+ INSIST(ISC_LIST_EMPTY(sock->send_list));
+ INSIST(sock->connect_ev == NULL);
+ REQUIRE(sock->fd >= 0 && sock->fd < (int)FD_SETSIZE);
+
+ LOCK(&manager->lock);
+
+ /*
+ * No one has this socket open, so the watcher doesn't have to be
+ * poked, and the socket doesn't have to be locked.
+ */
+ manager->fds[sock->fd] = NULL;
+ manager->fdstate[sock->fd] = CLOSE_PENDING;
+ select_poke(manager, sock->fd, SELECT_POKE_CLOSE);
+ ISC_LIST_UNLINK(manager->socklist, sock, link);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ if (ISC_LIST_EMPTY(manager->socklist))
+ SIGNAL(&manager->shutdown_ok);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /*
+ * XXX should reset manager->maxfd here
+ */
+
+ UNLOCK(&manager->lock);
+
+ free_socket(sockp);
+}
+
+static isc_result_t
+allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
+ isc_socket_t **socketp)
+{
+ isc_socket_t *sock;
+ isc_result_t result;
+ ISC_SOCKADDR_LEN_T cmsgbuflen;
+
+ sock = isc_mem_get(manager->mctx, sizeof(*sock));
+
+ if (sock == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = ISC_R_UNEXPECTED;
+
+ sock->magic = 0;
+ sock->references = 0;
+
+ sock->manager = manager;
+ sock->type = type;
+ sock->fd = -1;
+
+ ISC_LINK_INIT(sock, link);
+
+ sock->recvcmsgbuf = NULL;
+ sock->sendcmsgbuf = NULL;
+
+ /*
+ * set up cmsg buffers
+ */
+ cmsgbuflen = 0;
+#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
+ cmsgbuflen = cmsg_space(sizeof(struct in6_pktinfo));
+#endif
+#if defined(USE_CMSG) && defined(SO_TIMESTAMP)
+ cmsgbuflen += cmsg_space(sizeof(struct timeval));
+#endif
+ sock->recvcmsgbuflen = cmsgbuflen;
+ if (sock->recvcmsgbuflen != 0U) {
+ sock->recvcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen);
+ if (sock->recvcmsgbuf == NULL)
+ goto error;
+ }
+
+ cmsgbuflen = 0;
+#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
+ cmsgbuflen = cmsg_space(sizeof(struct in6_pktinfo));
+#endif
+ sock->sendcmsgbuflen = cmsgbuflen;
+ if (sock->sendcmsgbuflen != 0U) {
+ sock->sendcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen);
+ if (sock->sendcmsgbuf == NULL)
+ goto error;
+ }
+
+ /*
+ * set up list of readers and writers to be initially empty
+ */
+ ISC_LIST_INIT(sock->recv_list);
+ ISC_LIST_INIT(sock->send_list);
+ ISC_LIST_INIT(sock->accept_list);
+ sock->connect_ev = NULL;
+ sock->pending_recv = 0;
+ sock->pending_send = 0;
+ sock->pending_accept = 0;
+ sock->listener = 0;
+ sock->connected = 0;
+ sock->connecting = 0;
+ sock->bound = 0;
+
+ /*
+ * initialize the lock
+ */
+ result = isc_mutex_init(&sock->lock);
+ if (result != ISC_R_SUCCESS) {
+ sock->magic = 0;
+ goto error;
+ }
+
+ /*
+ * Initialize readable and writable events
+ */
+ ISC_EVENT_INIT(&sock->readable_ev, sizeof(intev_t),
+ ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTR,
+ NULL, sock, sock, NULL, NULL);
+ ISC_EVENT_INIT(&sock->writable_ev, sizeof(intev_t),
+ ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTW,
+ NULL, sock, sock, NULL, NULL);
+
+ sock->magic = SOCKET_MAGIC;
+ *socketp = sock;
+
+ return (ISC_R_SUCCESS);
+
+ error:
+ if (sock->recvcmsgbuf != NULL)
+ isc_mem_put(manager->mctx, sock->recvcmsgbuf,
+ sock->recvcmsgbuflen);
+ if (sock->sendcmsgbuf != NULL)
+ isc_mem_put(manager->mctx, sock->sendcmsgbuf,
+ sock->sendcmsgbuflen);
+ isc_mem_put(manager->mctx, sock, sizeof(*sock));
+
+ return (result);
+}
+
+/*
+ * This event requires that the various lists be empty, that the reference
+ * count be 1, and that the magic number is valid. The other socket bits,
+ * like the lock, must be initialized as well. The fd associated must be
+ * marked as closed, by setting it to -1 on close, or this routine will
+ * also close the socket.
+ */
+static void
+free_socket(isc_socket_t **socketp) {
+ isc_socket_t *sock = *socketp;
+
+ INSIST(sock->references == 0);
+ INSIST(VALID_SOCKET(sock));
+ INSIST(!sock->connecting);
+ INSIST(!sock->pending_recv);
+ INSIST(!sock->pending_send);
+ INSIST(!sock->pending_accept);
+ INSIST(ISC_LIST_EMPTY(sock->recv_list));
+ INSIST(ISC_LIST_EMPTY(sock->send_list));
+ INSIST(ISC_LIST_EMPTY(sock->accept_list));
+ INSIST(!ISC_LINK_LINKED(sock, link));
+
+ if (sock->recvcmsgbuf != NULL)
+ isc_mem_put(sock->manager->mctx, sock->recvcmsgbuf,
+ sock->recvcmsgbuflen);
+ if (sock->sendcmsgbuf != NULL)
+ isc_mem_put(sock->manager->mctx, sock->sendcmsgbuf,
+ sock->sendcmsgbuflen);
+
+ sock->magic = 0;
+
+ DESTROYLOCK(&sock->lock);
+
+ isc_mem_put(sock->manager->mctx, sock, sizeof(*sock));
+
+ *socketp = NULL;
+}
+
+#ifdef SO_BSDCOMPAT
+/*
+ * This really should not be necessary to do. Having to workout
+ * which kernel version we are on at run time so that we don't cause
+ * the kernel to issue a warning about us using a deprecated socket option.
+ * Such warnings should *never* be on by default in production kernels.
+ *
+ * We can't do this a build time because executables are moved between
+ * machines and hence kernels.
+ *
+ * We can't just not set SO_BSDCOMAT because some kernels require it.
+ */
+
+static isc_once_t bsdcompat_once = ISC_ONCE_INIT;
+isc_boolean_t bsdcompat = ISC_TRUE;
+
+static void
+clear_bsdcompat(void) {
+#ifdef __linux__
+ struct utsname buf;
+ char *endp;
+ long int major;
+ long int minor;
+
+ uname(&buf); /* Can only fail if buf is bad in Linux. */
+
+ /* Paranoia in parsing can be increased, but we trust uname(). */
+ major = strtol(buf.release, &endp, 10);
+ if (*endp == '.') {
+ minor = strtol(endp+1, &endp, 10);
+ if ((major > 2) || ((major == 2) && (minor >= 4))) {
+ bsdcompat = ISC_FALSE;
+ }
+ }
+#endif /* __linux __ */
+}
+#endif
+
+/*%
+ * Create a new 'type' socket managed by 'manager'. Events
+ * will be posted to 'task' and when dispatched 'action' will be
+ * called with 'arg' as the arg value. The new socket is returned
+ * in 'socketp'.
+ */
+isc_result_t
+isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
+ isc_socket_t **socketp)
+{
+ isc_socket_t *sock = NULL;
+ isc_result_t result;
+#if defined(USE_CMSG) || defined(SO_BSDCOMPAT)
+ int on = 1;
+#endif
+#if defined(SO_RCVBUF)
+ ISC_SOCKADDR_LEN_T optlen;
+ int size;
+#endif
+ char strbuf[ISC_STRERRORSIZE];
+ const char *err = "socket";
+ int try = 0;
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+ result = allocate_socket(manager, type, &sock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ sock->pf = pf;
+ again:
+ switch (type) {
+ case isc_sockettype_udp:
+ sock->fd = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
+ break;
+ case isc_sockettype_tcp:
+ sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP);
+ break;
+ case isc_sockettype_unix:
+ sock->fd = socket(pf, SOCK_STREAM, 0);
+ break;
+ }
+ if (sock->fd == -1 && errno == EINTR && try++ < 42)
+ goto again;
+
+#ifdef F_DUPFD
+ /*
+ * Leave a space for stdio to work in.
+ */
+ if (sock->fd >= 0 && sock->fd < 20) {
+ int new, tmp;
+ new = fcntl(sock->fd, F_DUPFD, 20);
+ tmp = errno;
+ (void)close(sock->fd);
+ errno = tmp;
+ sock->fd = new;
+ err = "isc_socket_create: fcntl";
+ }
+#endif
+
+ if (sock->fd >= (int)FD_SETSIZE) {
+ (void)close(sock->fd);
+ isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_TOOMANYFDS,
+ "%s: too many open file descriptors", "socket");
+ free_socket(&sock);
+ return (ISC_R_NORESOURCES);
+ }
+
+ if (sock->fd < 0) {
+ free_socket(&sock);
+
+ switch (errno) {
+ case EMFILE:
+ case ENFILE:
+ case ENOBUFS:
+ return (ISC_R_NORESOURCES);
+
+ case EPROTONOSUPPORT:
+ case EPFNOSUPPORT:
+ case EAFNOSUPPORT:
+ /*
+ * Linux 2.2 (and maybe others) return EINVAL instead of
+ * EAFNOSUPPORT.
+ */
+ case EINVAL:
+ return (ISC_R_FAMILYNOSUPPORT);
+
+ default:
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "%s() %s: %s", err,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+ if (make_nonblock(sock->fd) != ISC_R_SUCCESS) {
+ (void)close(sock->fd);
+ free_socket(&sock);
+ return (ISC_R_UNEXPECTED);
+ }
+
+#ifdef SO_BSDCOMPAT
+ RUNTIME_CHECK(isc_once_do(&bsdcompat_once,
+ clear_bsdcompat) == ISC_R_SUCCESS);
+ if (type != isc_sockettype_unix && bsdcompat &&
+ setsockopt(sock->fd, SOL_SOCKET, SO_BSDCOMPAT,
+ (void *)&on, sizeof(on)) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, SO_BSDCOMPAT) %s: %s",
+ sock->fd,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ strbuf);
+ /* Press on... */
+ }
+#endif
+
+#if defined(USE_CMSG) || defined(SO_RCVBUF)
+ if (type == isc_sockettype_udp) {
+
+#if defined(USE_CMSG)
+#if defined(SO_TIMESTAMP)
+ if (setsockopt(sock->fd, SOL_SOCKET, SO_TIMESTAMP,
+ (void *)&on, sizeof(on)) < 0
+ && errno != ENOPROTOOPT) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, SO_TIMESTAMP) %s: %s",
+ sock->fd,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ /* Press on... */
+ }
+#endif /* SO_TIMESTAMP */
+
+#if defined(ISC_PLATFORM_HAVEIPV6)
+ if (pf == AF_INET6 && sock->recvcmsgbuflen == 0U) {
+ /*
+ * Warn explicitly because this anomaly can be hidden
+ * in usual operation (and unexpectedly appear later).
+ */
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "No buffer available to receive "
+ "IPv6 destination");
+ }
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+#ifdef IPV6_RECVPKTINFO
+ /* RFC 3542 */
+ if ((pf == AF_INET6)
+ && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ (void *)&on, sizeof(on)) < 0)) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_RECVPKTINFO) "
+ "%s: %s", sock->fd,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+#else
+ /* RFC 2292 */
+ if ((pf == AF_INET6)
+ && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO,
+ (void *)&on, sizeof(on)) < 0)) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_PKTINFO) %s: %s",
+ sock->fd,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+#endif /* IPV6_RECVPKTINFO */
+#endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
+#ifdef IPV6_USE_MIN_MTU /* RFC 3542, not too common yet*/
+ /* use minimum MTU */
+ if (pf == AF_INET6) {
+ (void)setsockopt(sock->fd, IPPROTO_IPV6,
+ IPV6_USE_MIN_MTU,
+ (void *)&on, sizeof(on));
+ }
+#endif
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+#endif /* defined(USE_CMSG) */
+
+#if defined(SO_RCVBUF)
+ optlen = sizeof(size);
+ if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
+ (void *)&size, &optlen) >= 0 &&
+ size < RCVBUFSIZE) {
+ size = RCVBUFSIZE;
+ if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
+ (void *)&size, sizeof(size)) == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, SO_RCVBUF, %d) %s: %s",
+ sock->fd, size,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+ }
+#endif
+ }
+#endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */
+
+ sock->references = 1;
+ *socketp = sock;
+
+ LOCK(&manager->lock);
+
+ /*
+ * Note we don't have to lock the socket like we normally would because
+ * there are no external references to it yet.
+ */
+
+ manager->fds[sock->fd] = sock;
+ manager->fdstate[sock->fd] = MANAGED;
+ ISC_LIST_APPEND(manager->socklist, sock, link);
+ if (manager->maxfd < sock->fd)
+ manager->maxfd = sock->fd;
+
+ UNLOCK(&manager->lock);
+
+ socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_CREATED, "created");
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Attach to a socket. Caller must explicitly detach when it is done.
+ */
+void
+isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) {
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+ LOCK(&sock->lock);
+ sock->references++;
+ UNLOCK(&sock->lock);
+
+ *socketp = sock;
+}
+
+/*
+ * Dereference a socket. If this is the last reference to it, clean things
+ * up by destroying the socket.
+ */
+void
+isc_socket_detach(isc_socket_t **socketp) {
+ isc_socket_t *sock;
+ isc_boolean_t kill_socket = ISC_FALSE;
+
+ REQUIRE(socketp != NULL);
+ sock = *socketp;
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ REQUIRE(sock->references > 0);
+ sock->references--;
+ if (sock->references == 0)
+ kill_socket = ISC_TRUE;
+ UNLOCK(&sock->lock);
+
+ if (kill_socket)
+ destroy(&sock);
+
+ *socketp = NULL;
+}
+
+/*
+ * I/O is possible on a given socket. Schedule an event to this task that
+ * will call an internal function to do the I/O. This will charge the
+ * task with the I/O operation and let our select loop handler get back
+ * to doing something real as fast as possible.
+ *
+ * The socket and manager must be locked before calling this function.
+ */
+static void
+dispatch_recv(isc_socket_t *sock) {
+ intev_t *iev;
+ isc_socketevent_t *ev;
+
+ INSIST(!sock->pending_recv);
+
+ ev = ISC_LIST_HEAD(sock->recv_list);
+ if (ev == NULL)
+ return;
+
+ sock->pending_recv = 1;
+ iev = &sock->readable_ev;
+
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "dispatch_recv: event %p -> task %p", ev, ev->ev_sender);
+
+ sock->references++;
+ iev->ev_sender = sock;
+ iev->ev_action = internal_recv;
+ iev->ev_arg = sock;
+
+ isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
+}
+
+static void
+dispatch_send(isc_socket_t *sock) {
+ intev_t *iev;
+ isc_socketevent_t *ev;
+
+ INSIST(!sock->pending_send);
+
+ ev = ISC_LIST_HEAD(sock->send_list);
+ if (ev == NULL)
+ return;
+
+ sock->pending_send = 1;
+ iev = &sock->writable_ev;
+
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "dispatch_send: event %p -> task %p", ev, ev->ev_sender);
+
+ sock->references++;
+ iev->ev_sender = sock;
+ iev->ev_action = internal_send;
+ iev->ev_arg = sock;
+
+ isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
+}
+
+/*
+ * Dispatch an internal accept event.
+ */
+static void
+dispatch_accept(isc_socket_t *sock) {
+ intev_t *iev;
+ isc_socket_newconnev_t *ev;
+
+ INSIST(!sock->pending_accept);
+
+ /*
+ * Are there any done events left, or were they all canceled
+ * before the manager got the socket lock?
+ */
+ ev = ISC_LIST_HEAD(sock->accept_list);
+ if (ev == NULL)
+ return;
+
+ sock->pending_accept = 1;
+ iev = &sock->readable_ev;
+
+ sock->references++; /* keep socket around for this internal event */
+ iev->ev_sender = sock;
+ iev->ev_action = internal_accept;
+ iev->ev_arg = sock;
+
+ isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
+}
+
+static void
+dispatch_connect(isc_socket_t *sock) {
+ intev_t *iev;
+ isc_socket_connev_t *ev;
+
+ iev = &sock->writable_ev;
+
+ ev = sock->connect_ev;
+ INSIST(ev != NULL); /* XXX */
+
+ INSIST(sock->connecting);
+
+ sock->references++; /* keep socket around for this internal event */
+ iev->ev_sender = sock;
+ iev->ev_action = internal_connect;
+ iev->ev_arg = sock;
+
+ isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
+}
+
+/*
+ * Dequeue an item off the given socket's read queue, set the result code
+ * in the done event to the one provided, and send it to the task it was
+ * destined for.
+ *
+ * If the event to be sent is on a list, remove it before sending. If
+ * asked to, send and detach from the socket as well.
+ *
+ * Caller must have the socket locked if the event is attached to the socket.
+ */
+static void
+send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
+ isc_task_t *task;
+
+ task = (*dev)->ev_sender;
+
+ (*dev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*dev, ev_link))
+ ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link);
+
+ if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
+ == ISC_SOCKEVENTATTR_ATTACHED)
+ isc_task_sendanddetach(&task, (isc_event_t **)dev);
+ else
+ isc_task_send(task, (isc_event_t **)dev);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ *
+ * Caller must have the socket locked if the event is attached to the socket.
+ */
+static void
+send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
+ isc_task_t *task;
+
+ INSIST(dev != NULL && *dev != NULL);
+
+ task = (*dev)->ev_sender;
+ (*dev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*dev, ev_link))
+ ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link);
+
+ if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
+ == ISC_SOCKEVENTATTR_ATTACHED)
+ isc_task_sendanddetach(&task, (isc_event_t **)dev);
+ else
+ isc_task_send(task, (isc_event_t **)dev);
+}
+
+/*
+ * Call accept() on a socket, to get the new file descriptor. The listen
+ * socket is used as a prototype to create a new isc_socket_t. The new
+ * socket has one outstanding reference. The task receiving the event
+ * will be detached from just after the event is delivered.
+ *
+ * On entry to this function, the event delivered is the internal
+ * readable event, and the first item on the accept_list should be
+ * the done event we want to send. If the list is empty, this is a no-op,
+ * so just unlock and return.
+ */
+static void
+internal_accept(isc_task_t *me, isc_event_t *ev) {
+ isc_socket_t *sock;
+ isc_socketmgr_t *manager;
+ isc_socket_newconnev_t *dev;
+ isc_task_t *task;
+ ISC_SOCKADDR_LEN_T addrlen;
+ int fd;
+ isc_result_t result = ISC_R_SUCCESS;
+ char strbuf[ISC_STRERRORSIZE];
+ const char *err = "accept";
+
+ UNUSED(me);
+
+ sock = ev->ev_sender;
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ socket_log(sock, NULL, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+ "internal_accept called, locked socket");
+
+ manager = sock->manager;
+ INSIST(VALID_MANAGER(manager));
+
+ INSIST(sock->listener);
+ INSIST(sock->pending_accept == 1);
+ sock->pending_accept = 0;
+
+ INSIST(sock->references > 0);
+ sock->references--; /* the internal event is done with this socket */
+ if (sock->references == 0) {
+ UNLOCK(&sock->lock);
+ destroy(&sock);
+ return;
+ }
+
+ /*
+ * Get the first item off the accept list.
+ * If it is empty, unlock the socket and return.
+ */
+ dev = ISC_LIST_HEAD(sock->accept_list);
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return;
+ }
+
+ /*
+ * Try to accept the new connection. If the accept fails with
+ * EAGAIN or EINTR, simply poke the watcher to watch this socket
+ * again. Also ignore ECONNRESET, which has been reported to
+ * be spuriously returned on Linux 2.2.19 although it is not
+ * a documented error for accept(). ECONNABORTED has been
+ * reported for Solaris 8. The rest are thrown in not because
+ * we have seen them but because they are ignored by other
+ * deamons such as BIND 8 and Apache.
+ */
+
+ addrlen = sizeof(dev->newsocket->address.type);
+ memset(&dev->newsocket->address.type.sa, 0, addrlen);
+ fd = accept(sock->fd, &dev->newsocket->address.type.sa,
+ (void *)&addrlen);
+
+#ifdef F_DUPFD
+ /*
+ * Leave a space for stdio to work in.
+ */
+ if (fd >= 0 && fd < 20) {
+ int new, tmp;
+ new = fcntl(fd, F_DUPFD, 20);
+ tmp = errno;
+ (void)close(fd);
+ errno = tmp;
+ fd = new;
+ err = "fcntl";
+ }
+#endif
+
+ if (fd < 0) {
+ if (SOFT_ERROR(errno))
+ goto soft_error;
+ switch (errno) {
+ case ENOBUFS:
+ case ENFILE:
+ case ENOMEM:
+ case ECONNRESET:
+ case ECONNABORTED:
+ case EHOSTUNREACH:
+ case EHOSTDOWN:
+ case ENETUNREACH:
+ case ENETDOWN:
+ case ECONNREFUSED:
+#ifdef EPROTO
+ case EPROTO:
+#endif
+#ifdef ENONET
+ case ENONET:
+#endif
+ goto soft_error;
+ default:
+ break;
+ }
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "internal_accept: %s() %s: %s", err,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ fd = -1;
+ result = ISC_R_UNEXPECTED;
+ } else {
+ if (addrlen == 0U) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "internal_accept(): "
+ "accept() failed to return "
+ "remote address");
+
+ (void)close(fd);
+ goto soft_error;
+ } else if (dev->newsocket->address.type.sa.sa_family !=
+ sock->pf)
+ {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "internal_accept(): "
+ "accept() returned peer address "
+ "family %u (expected %u)",
+ dev->newsocket->address.
+ type.sa.sa_family,
+ sock->pf);
+ (void)close(fd);
+ goto soft_error;
+ } else if (fd >= (int)FD_SETSIZE) {
+ isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_TOOMANYFDS,
+ "%s: too many open file descriptors",
+ "accept");
+ (void)close(fd);
+ goto soft_error;
+ }
+ }
+
+ if (fd != -1) {
+ dev->newsocket->address.length = addrlen;
+ dev->newsocket->pf = sock->pf;
+ }
+
+ /*
+ * Pull off the done event.
+ */
+ ISC_LIST_UNLINK(sock->accept_list, dev, ev_link);
+
+ /*
+ * Poke watcher if there are more pending accepts.
+ */
+ if (!ISC_LIST_EMPTY(sock->accept_list))
+ select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT);
+
+ UNLOCK(&sock->lock);
+
+ if (fd != -1 && (make_nonblock(fd) != ISC_R_SUCCESS)) {
+ (void)close(fd);
+ fd = -1;
+ result = ISC_R_UNEXPECTED;
+ }
+
+ /*
+ * -1 means the new socket didn't happen.
+ */
+ if (fd != -1) {
+ LOCK(&manager->lock);
+ ISC_LIST_APPEND(manager->socklist, dev->newsocket, link);
+
+ dev->newsocket->fd = fd;
+ dev->newsocket->bound = 1;
+ dev->newsocket->connected = 1;
+
+ /*
+ * Save away the remote address
+ */
+ dev->address = dev->newsocket->address;
+
+ manager->fds[fd] = dev->newsocket;
+ manager->fdstate[fd] = MANAGED;
+ if (manager->maxfd < fd)
+ manager->maxfd = fd;
+
+ socket_log(sock, &dev->newsocket->address, CREATION,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
+ "accepted connection, new socket %p",
+ dev->newsocket);
+
+ UNLOCK(&manager->lock);
+ } else {
+ dev->newsocket->references--;
+ free_socket(&dev->newsocket);
+ }
+
+ /*
+ * Fill in the done event details and send it off.
+ */
+ dev->result = result;
+ task = dev->ev_sender;
+ dev->ev_sender = sock;
+
+ isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev));
+ return;
+
+ soft_error:
+ select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT);
+ UNLOCK(&sock->lock);
+ return;
+}
+
+static void
+internal_recv(isc_task_t *me, isc_event_t *ev) {
+ isc_socketevent_t *dev;
+ isc_socket_t *sock;
+
+ INSIST(ev->ev_type == ISC_SOCKEVENT_INTR);
+
+ sock = ev->ev_sender;
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ socket_log(sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
+ "internal_recv: task %p got event %p", me, ev);
+
+ INSIST(sock->pending_recv == 1);
+ sock->pending_recv = 0;
+
+ INSIST(sock->references > 0);
+ sock->references--; /* the internal event is done with this socket */
+ if (sock->references == 0) {
+ UNLOCK(&sock->lock);
+ destroy(&sock);
+ return;
+ }
+
+ /*
+ * Try to do as much I/O as possible on this socket. There are no
+ * limits here, currently.
+ */
+ dev = ISC_LIST_HEAD(sock->recv_list);
+ while (dev != NULL) {
+ switch (doio_recv(sock, dev)) {
+ case DOIO_SOFT:
+ goto poke;
+
+ case DOIO_EOF:
+ /*
+ * read of 0 means the remote end was closed.
+ * Run through the event queue and dispatch all
+ * the events with an EOF result code.
+ */
+ do {
+ dev->result = ISC_R_EOF;
+ send_recvdone_event(sock, &dev);
+ dev = ISC_LIST_HEAD(sock->recv_list);
+ } while (dev != NULL);
+ goto poke;
+
+ case DOIO_SUCCESS:
+ case DOIO_HARD:
+ send_recvdone_event(sock, &dev);
+ break;
+ }
+
+ dev = ISC_LIST_HEAD(sock->recv_list);
+ }
+
+ poke:
+ if (!ISC_LIST_EMPTY(sock->recv_list))
+ select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+
+ UNLOCK(&sock->lock);
+}
+
+static void
+internal_send(isc_task_t *me, isc_event_t *ev) {
+ isc_socketevent_t *dev;
+ isc_socket_t *sock;
+
+ INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
+
+ /*
+ * Find out what socket this is and lock it.
+ */
+ sock = (isc_socket_t *)ev->ev_sender;
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ socket_log(sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
+ "internal_send: task %p got event %p", me, ev);
+
+ INSIST(sock->pending_send == 1);
+ sock->pending_send = 0;
+
+ INSIST(sock->references > 0);
+ sock->references--; /* the internal event is done with this socket */
+ if (sock->references == 0) {
+ UNLOCK(&sock->lock);
+ destroy(&sock);
+ return;
+ }
+
+ /*
+ * Try to do as much I/O as possible on this socket. There are no
+ * limits here, currently.
+ */
+ dev = ISC_LIST_HEAD(sock->send_list);
+ while (dev != NULL) {
+ switch (doio_send(sock, dev)) {
+ case DOIO_SOFT:
+ goto poke;
+
+ case DOIO_HARD:
+ case DOIO_SUCCESS:
+ send_senddone_event(sock, &dev);
+ break;
+ }
+
+ dev = ISC_LIST_HEAD(sock->send_list);
+ }
+
+ poke:
+ if (!ISC_LIST_EMPTY(sock->send_list))
+ select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
+
+ UNLOCK(&sock->lock);
+}
+
+static void
+process_fds(isc_socketmgr_t *manager, int maxfd,
+ fd_set *readfds, fd_set *writefds)
+{
+ int i;
+ isc_socket_t *sock;
+ isc_boolean_t unlock_sock;
+
+ REQUIRE(maxfd <= (int)FD_SETSIZE);
+
+ /*
+ * Process read/writes on other fds here. Avoid locking
+ * and unlocking twice if both reads and writes are possible.
+ */
+ for (i = 0; i < maxfd; i++) {
+#ifdef ISC_PLATFORM_USETHREADS
+ if (i == manager->pipe_fds[0] || i == manager->pipe_fds[1])
+ continue;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ if (manager->fdstate[i] == CLOSE_PENDING) {
+ manager->fdstate[i] = CLOSED;
+ FD_CLR(i, &manager->read_fds);
+ FD_CLR(i, &manager->write_fds);
+
+ (void)close(i);
+
+ continue;
+ }
+
+ sock = manager->fds[i];
+ unlock_sock = ISC_FALSE;
+ if (FD_ISSET(i, readfds)) {
+ if (sock == NULL) {
+ FD_CLR(i, &manager->read_fds);
+ goto check_write;
+ }
+ unlock_sock = ISC_TRUE;
+ LOCK(&sock->lock);
+ if (!SOCK_DEAD(sock)) {
+ if (sock->listener)
+ dispatch_accept(sock);
+ else
+ dispatch_recv(sock);
+ }
+ FD_CLR(i, &manager->read_fds);
+ }
+ check_write:
+ if (FD_ISSET(i, writefds)) {
+ if (sock == NULL) {
+ FD_CLR(i, &manager->write_fds);
+ continue;
+ }
+ if (!unlock_sock) {
+ unlock_sock = ISC_TRUE;
+ LOCK(&sock->lock);
+ }
+ if (!SOCK_DEAD(sock)) {
+ if (sock->connecting)
+ dispatch_connect(sock);
+ else
+ dispatch_send(sock);
+ }
+ FD_CLR(i, &manager->write_fds);
+ }
+ if (unlock_sock)
+ UNLOCK(&sock->lock);
+ }
+}
+
+#ifdef ISC_PLATFORM_USETHREADS
+/*
+ * This is the thread that will loop forever, always in a select or poll
+ * call.
+ *
+ * When select returns something to do, track down what thread gets to do
+ * this I/O and post the event to it.
+ */
+static isc_threadresult_t
+watcher(void *uap) {
+ isc_socketmgr_t *manager = uap;
+ isc_boolean_t done;
+ int ctlfd;
+ int cc;
+ fd_set readfds;
+ fd_set writefds;
+ int msg, fd;
+ int maxfd;
+ char strbuf[ISC_STRERRORSIZE];
+
+ /*
+ * Get the control fd here. This will never change.
+ */
+ LOCK(&manager->lock);
+ ctlfd = manager->pipe_fds[0];
+
+ done = ISC_FALSE;
+ while (!done) {
+ do {
+ readfds = manager->read_fds;
+ writefds = manager->write_fds;
+ maxfd = manager->maxfd + 1;
+
+ UNLOCK(&manager->lock);
+
+ cc = select(maxfd, &readfds, &writefds, NULL, NULL);
+ if (cc < 0) {
+ if (!SOFT_ERROR(errno)) {
+ isc__strerror(errno, strbuf,
+ sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ "select() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
+ }
+
+ LOCK(&manager->lock);
+ } while (cc < 0);
+
+
+ /*
+ * Process reads on internal, control fd.
+ */
+ if (FD_ISSET(ctlfd, &readfds)) {
+ for (;;) {
+ select_readmsg(manager, &fd, &msg);
+
+ manager_log(manager, IOEVENT,
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_SOCKET,
+ ISC_MSG_WATCHERMSG,
+ "watcher got message %d"),
+ msg);
+
+ /*
+ * Nothing to read?
+ */
+ if (msg == SELECT_POKE_NOTHING)
+ break;
+
+ /*
+ * Handle shutdown message. We really should
+ * jump out of this loop right away, but
+ * it doesn't matter if we have to do a little
+ * more work first.
+ */
+ if (msg == SELECT_POKE_SHUTDOWN) {
+ done = ISC_TRUE;
+
+ break;
+ }
+
+ /*
+ * This is a wakeup on a socket. Look
+ * at the event queue for both read and write,
+ * and decide if we need to watch on it now
+ * or not.
+ */
+ wakeup_socket(manager, fd, msg);
+ }
+ }
+
+ process_fds(manager, maxfd, &readfds, &writefds);
+ }
+
+ manager_log(manager, TRACE,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_EXITING, "watcher exiting"));
+
+ UNLOCK(&manager->lock);
+ return ((isc_threadresult_t)0);
+}
+#endif /* ISC_PLATFORM_USETHREADS */
+
+/*
+ * Create a new socket manager.
+ */
+isc_result_t
+isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) {
+ isc_socketmgr_t *manager;
+#ifdef ISC_PLATFORM_USETHREADS
+ char strbuf[ISC_STRERRORSIZE];
+#endif
+ isc_result_t result;
+
+ REQUIRE(managerp != NULL && *managerp == NULL);
+
+#ifndef ISC_PLATFORM_USETHREADS
+ if (socketmgr != NULL) {
+ socketmgr->refs++;
+ *managerp = socketmgr;
+ return (ISC_R_SUCCESS);
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ manager = isc_mem_get(mctx, sizeof(*manager));
+ if (manager == NULL)
+ return (ISC_R_NOMEMORY);
+
+ manager->magic = SOCKET_MANAGER_MAGIC;
+ manager->mctx = NULL;
+ memset(manager->fds, 0, sizeof(manager->fds));
+ ISC_LIST_INIT(manager->socklist);
+ result = isc_mutex_init(&manager->lock);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ return (result);
+ }
+#ifdef ISC_PLATFORM_USETHREADS
+ if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) {
+ DESTROYLOCK(&manager->lock);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ return (ISC_R_UNEXPECTED);
+ }
+
+ /*
+ * Create the special fds that will be used to wake up the
+ * select/poll loop when something internal needs to be done.
+ */
+ if (pipe(manager->pipe_fds) != 0) {
+ DESTROYLOCK(&manager->lock);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "pipe() %s: %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"),
+ strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+ RUNTIME_CHECK(make_nonblock(manager->pipe_fds[0]) == ISC_R_SUCCESS);
+#if 0
+ RUNTIME_CHECK(make_nonblock(manager->pipe_fds[1]) == ISC_R_SUCCESS);
+#endif
+#else /* ISC_PLATFORM_USETHREADS */
+ manager->refs = 1;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /*
+ * Set up initial state for the select loop
+ */
+ FD_ZERO(&manager->read_fds);
+ FD_ZERO(&manager->write_fds);
+#ifdef ISC_PLATFORM_USETHREADS
+ FD_SET(manager->pipe_fds[0], &manager->read_fds);
+ manager->maxfd = manager->pipe_fds[0];
+#else /* ISC_PLATFORM_USETHREADS */
+ manager->maxfd = 0;
+#endif /* ISC_PLATFORM_USETHREADS */
+ memset(manager->fdstate, 0, sizeof(manager->fdstate));
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Start up the select/poll thread.
+ */
+ if (isc_thread_create(watcher, manager, &manager->watcher) !=
+ ISC_R_SUCCESS) {
+ (void)close(manager->pipe_fds[0]);
+ (void)close(manager->pipe_fds[1]);
+ DESTROYLOCK(&manager->lock);
+ isc_mem_put(mctx, manager, sizeof(*manager));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_thread_create() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ return (ISC_R_UNEXPECTED);
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+ isc_mem_attach(mctx, &manager->mctx);
+
+#ifndef ISC_PLATFORM_USETHREADS
+ socketmgr = manager;
+#endif /* ISC_PLATFORM_USETHREADS */
+ *managerp = manager;
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_socketmgr_destroy(isc_socketmgr_t **managerp) {
+ isc_socketmgr_t *manager;
+ int i;
+ isc_mem_t *mctx;
+
+ /*
+ * Destroy a socket manager.
+ */
+
+ REQUIRE(managerp != NULL);
+ manager = *managerp;
+ REQUIRE(VALID_MANAGER(manager));
+
+#ifndef ISC_PLATFORM_USETHREADS
+ if (manager->refs > 1) {
+ manager->refs--;
+ *managerp = NULL;
+ return;
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ LOCK(&manager->lock);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Wait for all sockets to be destroyed.
+ */
+ while (!ISC_LIST_EMPTY(manager->socklist)) {
+ manager_log(manager, CREATION,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_SOCKETSREMAIN,
+ "sockets exist"));
+ WAIT(&manager->shutdown_ok, &manager->lock);
+ }
+#else /* ISC_PLATFORM_USETHREADS */
+ /*
+ * Hope all sockets have been destroyed.
+ */
+ if (!ISC_LIST_EMPTY(manager->socklist)) {
+ manager_log(manager, CREATION,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_SOCKETSREMAIN,
+ "sockets exist"));
+ INSIST(0);
+ }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ UNLOCK(&manager->lock);
+
+ /*
+ * Here, poke our select/poll thread. Do this by closing the write
+ * half of the pipe, which will send EOF to the read half.
+ * This is currently a no-op in the non-threaded case.
+ */
+ select_poke(manager, 0, SELECT_POKE_SHUTDOWN);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Wait for thread to exit.
+ */
+ if (isc_thread_join(manager->watcher, NULL) != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_thread_join() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /*
+ * Clean up.
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+ (void)close(manager->pipe_fds[0]);
+ (void)close(manager->pipe_fds[1]);
+ (void)isc_condition_destroy(&manager->shutdown_ok);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ for (i = 0; i < (int)FD_SETSIZE; i++)
+ if (manager->fdstate[i] == CLOSE_PENDING)
+ (void)close(i);
+
+ DESTROYLOCK(&manager->lock);
+ manager->magic = 0;
+ mctx= manager->mctx;
+ isc_mem_put(mctx, manager, sizeof(*manager));
+
+ isc_mem_detach(&mctx);
+
+ *managerp = NULL;
+}
+
+static isc_result_t
+socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+ unsigned int flags)
+{
+ int io_state;
+ isc_boolean_t have_lock = ISC_FALSE;
+ isc_task_t *ntask = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ dev->ev_sender = task;
+
+ if (sock->type == isc_sockettype_udp) {
+ io_state = doio_recv(sock, dev);
+ } else {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
+
+ if (ISC_LIST_EMPTY(sock->recv_list))
+ io_state = doio_recv(sock, dev);
+ else
+ io_state = DOIO_SOFT;
+ }
+
+ switch (io_state) {
+ case DOIO_SOFT:
+ /*
+ * We couldn't read all or part of the request right now, so
+ * queue it.
+ *
+ * Attach to socket and to task
+ */
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ if (!have_lock) {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
+ }
+
+ /*
+ * Enqueue the request. If the socket was previously not being
+ * watched, poke the watcher to start paying attention to it.
+ */
+ if (ISC_LIST_EMPTY(sock->recv_list))
+ select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+ ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
+
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "socket_recv: event %p -> task %p",
+ dev, ntask);
+
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
+ result = ISC_R_INPROGRESS;
+ break;
+
+ case DOIO_EOF:
+ dev->result = ISC_R_EOF;
+ /* fallthrough */
+
+ case DOIO_HARD:
+ case DOIO_SUCCESS:
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
+ send_recvdone_event(sock, &dev);
+ break;
+ }
+
+ if (have_lock)
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ unsigned int minimum, isc_task_t *task,
+ isc_taskaction_t action, const void *arg)
+{
+ isc_socketevent_t *dev;
+ isc_socketmgr_t *manager;
+ unsigned int iocount;
+ isc_buffer_t *buffer;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(buflist != NULL);
+ REQUIRE(!ISC_LIST_EMPTY(*buflist));
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ iocount = isc_bufferlist_availablecount(buflist);
+ REQUIRE(iocount > 0);
+
+ INSIST(sock->bound);
+
+ dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
+ if (dev == NULL) {
+ return (ISC_R_NOMEMORY);
+ }
+
+ /*
+ * UDP sockets are always partial read
+ */
+ if (sock->type == isc_sockettype_udp)
+ dev->minimum = 1;
+ else {
+ if (minimum == 0)
+ dev->minimum = iocount;
+ else
+ dev->minimum = minimum;
+ }
+
+ /*
+ * Move each buffer from the passed in list to our internal one.
+ */
+ buffer = ISC_LIST_HEAD(*buflist);
+ while (buffer != NULL) {
+ ISC_LIST_DEQUEUE(*buflist, buffer, link);
+ ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
+ buffer = ISC_LIST_HEAD(*buflist);
+ }
+
+ return (socket_recv(sock, dev, task, 0));
+}
+
+isc_result_t
+isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
+ isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+ isc_socketevent_t *dev;
+ isc_socketmgr_t *manager;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ INSIST(sock->bound);
+
+ dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
+ if (dev == NULL)
+ return (ISC_R_NOMEMORY);
+
+ return (isc_socket_recv2(sock, region, minimum, task, dev, 0));
+}
+
+isc_result_t
+isc_socket_recv2(isc_socket_t *sock, isc_region_t *region,
+ unsigned int minimum, isc_task_t *task,
+ isc_socketevent_t *event, unsigned int flags)
+{
+ event->ev_sender = sock;
+ event->result = ISC_R_UNEXPECTED;
+ ISC_LIST_INIT(event->bufferlist);
+ event->region = *region;
+ event->n = 0;
+ event->offset = 0;
+ event->attributes = 0;
+
+ /*
+ * UDP sockets are always partial read.
+ */
+ if (sock->type == isc_sockettype_udp)
+ event->minimum = 1;
+ else {
+ if (minimum == 0)
+ event->minimum = region->length;
+ else
+ event->minimum = minimum;
+ }
+
+ return (socket_recv(sock, event, task, flags));
+}
+
+static isc_result_t
+socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ unsigned int flags)
+{
+ int io_state;
+ isc_boolean_t have_lock = ISC_FALSE;
+ isc_task_t *ntask = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ dev->ev_sender = task;
+
+ set_dev_address(address, sock, dev);
+ if (pktinfo != NULL) {
+ dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
+ dev->pktinfo = *pktinfo;
+
+ if (!isc_sockaddr_issitelocal(&dev->address) &&
+ !isc_sockaddr_islinklocal(&dev->address)) {
+ socket_log(sock, NULL, TRACE, isc_msgcat,
+ ISC_MSGSET_SOCKET, ISC_MSG_PKTINFOPROVIDED,
+ "pktinfo structure provided, ifindex %u "
+ "(set to 0)", pktinfo->ipi6_ifindex);
+
+ /*
+ * Set the pktinfo index to 0 here, to let the
+ * kernel decide what interface it should send on.
+ */
+ dev->pktinfo.ipi6_ifindex = 0;
+ }
+ }
+
+ if (sock->type == isc_sockettype_udp)
+ io_state = doio_send(sock, dev);
+ else {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
+
+ if (ISC_LIST_EMPTY(sock->send_list))
+ io_state = doio_send(sock, dev);
+ else
+ io_state = DOIO_SOFT;
+ }
+
+ switch (io_state) {
+ case DOIO_SOFT:
+ /*
+ * We couldn't send all or part of the request right now, so
+ * queue it unless ISC_SOCKFLAG_NORETRY is set.
+ */
+ if ((flags & ISC_SOCKFLAG_NORETRY) == 0) {
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ if (!have_lock) {
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
+ }
+
+ /*
+ * Enqueue the request. If the socket was previously
+ * not being watched, poke the watcher to start
+ * paying attention to it.
+ */
+ if (ISC_LIST_EMPTY(sock->send_list))
+ select_poke(sock->manager, sock->fd,
+ SELECT_POKE_WRITE);
+ ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
+
+ socket_log(sock, NULL, EVENT, NULL, 0, 0,
+ "socket_send: event %p -> task %p",
+ dev, ntask);
+
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
+ result = ISC_R_INPROGRESS;
+ break;
+ }
+
+ case DOIO_HARD:
+ case DOIO_SUCCESS:
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
+ send_senddone_event(sock, &dev);
+ break;
+ }
+
+ if (have_lock)
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc_socket_send(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+ /*
+ * REQUIRE() checking is performed in isc_socket_sendto().
+ */
+ return (isc_socket_sendto(sock, region, task, action, arg, NULL,
+ NULL));
+}
+
+isc_result_t
+isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task, isc_taskaction_t action, const void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+ isc_socketevent_t *dev;
+ isc_socketmgr_t *manager;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(region != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ INSIST(sock->bound);
+
+ dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
+ if (dev == NULL) {
+ return (ISC_R_NOMEMORY);
+ }
+
+ dev->region = *region;
+
+ return (socket_send(sock, dev, task, address, pktinfo, 0));
+}
+
+isc_result_t
+isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+ return (isc_socket_sendtov(sock, buflist, task, action, arg, NULL,
+ NULL));
+}
+
+isc_result_t
+isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
+ isc_task_t *task, isc_taskaction_t action, const void *arg,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+ isc_socketevent_t *dev;
+ isc_socketmgr_t *manager;
+ unsigned int iocount;
+ isc_buffer_t *buffer;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(buflist != NULL);
+ REQUIRE(!ISC_LIST_EMPTY(*buflist));
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ iocount = isc_bufferlist_usedcount(buflist);
+ REQUIRE(iocount > 0);
+
+ dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
+ if (dev == NULL) {
+ return (ISC_R_NOMEMORY);
+ }
+
+ /*
+ * Move each buffer from the passed in list to our internal one.
+ */
+ buffer = ISC_LIST_HEAD(*buflist);
+ while (buffer != NULL) {
+ ISC_LIST_DEQUEUE(*buflist, buffer, link);
+ ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
+ buffer = ISC_LIST_HEAD(*buflist);
+ }
+
+ return (socket_send(sock, dev, task, address, pktinfo, 0));
+}
+
+isc_result_t
+isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region,
+ isc_task_t *task,
+ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ isc_socketevent_t *event, unsigned int flags)
+{
+ REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0);
+ if ((flags & ISC_SOCKFLAG_NORETRY) != 0)
+ REQUIRE(sock->type == isc_sockettype_udp);
+ event->ev_sender = sock;
+ event->result = ISC_R_UNEXPECTED;
+ ISC_LIST_INIT(event->bufferlist);
+ event->region = *region;
+ event->n = 0;
+ event->offset = 0;
+ event->attributes = 0;
+
+ return (socket_send(sock, event, task, address, pktinfo, flags));
+}
+
+void
+isc_socket_cleanunix(isc_sockaddr_t *sockaddr, isc_boolean_t active) {
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ int s;
+ struct stat sb;
+ char strbuf[ISC_STRERRORSIZE];
+
+ if (sockaddr->type.sa.sa_family != AF_UNIX)
+ return;
+
+#ifndef S_ISSOCK
+#if defined(S_IFMT) && defined(S_IFSOCK)
+#define S_ISSOCK(mode) ((mode & S_IFMT)==S_IFSOCK)
+#elif defined(_S_IFMT) && defined(S_IFSOCK)
+#define S_ISSOCK(mode) ((mode & _S_IFMT)==S_IFSOCK)
+#endif
+#endif
+
+#ifndef S_ISFIFO
+#if defined(S_IFMT) && defined(S_IFIFO)
+#define S_ISFIFO(mode) ((mode & S_IFMT)==S_IFIFO)
+#elif defined(_S_IFMT) && defined(S_IFIFO)
+#define S_ISFIFO(mode) ((mode & _S_IFMT)==S_IFIFO)
+#endif
+#endif
+
+#if !defined(S_ISFIFO) && !defined(S_ISSOCK)
+#error You need to define S_ISFIFO and S_ISSOCK as appropriate for your platform. See <sys/stat.h>.
+#endif
+
+#ifndef S_ISFIFO
+#define S_ISFIFO(mode) 0
+#endif
+
+#ifndef S_ISSOCK
+#define S_ISSOCK(mode) 0
+#endif
+
+ if (active) {
+ if (stat(sockaddr->type.sunix.sun_path, &sb) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "isc_socket_cleanunix: stat(%s): %s",
+ sockaddr->type.sunix.sun_path, strbuf);
+ return;
+ }
+ if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "isc_socket_cleanunix: %s: not a socket",
+ sockaddr->type.sunix.sun_path);
+ return;
+ }
+ if (unlink(sockaddr->type.sunix.sun_path) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "isc_socket_cleanunix: unlink(%s): %s",
+ sockaddr->type.sunix.sun_path, strbuf);
+ }
+ return;
+ }
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+ "isc_socket_cleanunix: socket(%s): %s",
+ sockaddr->type.sunix.sun_path, strbuf);
+ return;
+ }
+
+ if (stat(sockaddr->type.sunix.sun_path, &sb) < 0) {
+ switch (errno) {
+ case ENOENT: /* We exited cleanly last time */
+ break;
+ default:
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+ "isc_socket_cleanunix: stat(%s): %s",
+ sockaddr->type.sunix.sun_path, strbuf);
+ break;
+ }
+ goto cleanup;
+ }
+
+ if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) {
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+ "isc_socket_cleanunix: %s: not a socket",
+ sockaddr->type.sunix.sun_path);
+ goto cleanup;
+ }
+
+ if (connect(s, (struct sockaddr *)&sockaddr->type.sunix,
+ sizeof(sockaddr->type.sunix)) < 0) {
+ switch (errno) {
+ case ECONNREFUSED:
+ case ECONNRESET:
+ if (unlink(sockaddr->type.sunix.sun_path) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET,
+ ISC_LOG_WARNING,
+ "isc_socket_cleanunix: "
+ "unlink(%s): %s",
+ sockaddr->type.sunix.sun_path,
+ strbuf);
+ }
+ break;
+ default:
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+ "isc_socket_cleanunix: connect(%s): %s",
+ sockaddr->type.sunix.sun_path, strbuf);
+ break;
+ }
+ }
+ cleanup:
+ close(s);
+#else
+ UNUSED(sockaddr);
+ UNUSED(active);
+#endif
+}
+
+isc_result_t
+isc_socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm,
+ isc_uint32_t owner, isc_uint32_t group)
+{
+#ifdef ISC_PLATFORM_HAVESYSUNH
+ isc_result_t result = ISC_R_SUCCESS;
+ char strbuf[ISC_STRERRORSIZE];
+ char path[sizeof(sockaddr->type.sunix.sun_path)];
+#ifdef NEED_SECURE_DIRECTORY
+ char *slash;
+#endif
+
+ REQUIRE(sockaddr->type.sa.sa_family == AF_UNIX);
+ INSIST(strlen(sockaddr->type.sunix.sun_path) < sizeof(path));
+ strcpy(path, sockaddr->type.sunix.sun_path);
+
+#ifdef NEED_SECURE_DIRECTORY
+ slash = strrchr(path, '/');
+ if (slash != NULL) {
+ if (slash != path)
+ *slash = '\0';
+ else
+ strcpy(path, "/");
+ } else
+ strcpy(path, ".");
+#endif
+
+ if (chmod(path, perm) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "isc_socket_permunix: chmod(%s, %d): %s",
+ path, perm, strbuf);
+ result = ISC_R_FAILURE;
+ }
+ if (chown(path, owner, group) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "isc_socket_permunix: chown(%s, %d, %d): %s",
+ path, owner, group,
+ strbuf);
+ result = ISC_R_FAILURE;
+ }
+ return (result);
+#else
+ UNUSED(sockaddr);
+ UNUSED(perm);
+ UNUSED(owner);
+ UNUSED(group);
+ return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+isc_result_t
+isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr) {
+ char strbuf[ISC_STRERRORSIZE];
+ int on = 1;
+
+ LOCK(&sock->lock);
+
+ INSIST(!sock->bound);
+
+ if (sock->pf != sockaddr->type.sa.sa_family) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_FAMILYMISMATCH);
+ }
+ /*
+ * Only set SO_REUSEADDR when we want a specific port.
+ */
+#ifdef AF_UNIX
+ if (sock->pf == AF_UNIX)
+ goto bind_socket;
+#endif
+ if (isc_sockaddr_getport(sockaddr) != (in_port_t)0 &&
+ setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
+ sizeof(on)) < 0) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d) %s", sock->fd,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ /* Press on... */
+ }
+#ifdef AF_UNIX
+ bind_socket:
+#endif
+ if (bind(sock->fd, &sockaddr->type.sa, sockaddr->length) < 0) {
+ UNLOCK(&sock->lock);
+ switch (errno) {
+ case EACCES:
+ return (ISC_R_NOPERM);
+ case EADDRNOTAVAIL:
+ return (ISC_R_ADDRNOTAVAIL);
+ case EADDRINUSE:
+ return (ISC_R_ADDRINUSE);
+ case EINVAL:
+ return (ISC_R_BOUND);
+ default:
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+ socket_log(sock, sockaddr, TRACE,
+ isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "bound");
+ sock->bound = 1;
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_filter(isc_socket_t *sock, const char *filter) {
+#ifdef SO_ACCEPTFILTER
+ char strbuf[ISC_STRERRORSIZE];
+ struct accept_filter_arg afa;
+#else
+ UNUSED(sock);
+ UNUSED(filter);
+#endif
+
+ REQUIRE(VALID_SOCKET(sock));
+
+#ifdef SO_ACCEPTFILTER
+ bzero(&afa, sizeof(afa));
+ strncpy(afa.af_name, filter, sizeof(afa.af_name));
+ if (setsockopt(sock->fd, SOL_SOCKET, SO_ACCEPTFILTER,
+ &afa, sizeof(afa)) == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FILTER, "setsockopt(SO_ACCEPTFILTER): %s",
+ strbuf);
+ return (ISC_R_FAILURE);
+ }
+ return (ISC_R_SUCCESS);
+#else
+ return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+/*
+ * Set up to listen on a given socket. We do this by creating an internal
+ * event that will be dispatched when the socket has read activity. The
+ * watcher will send the internal event to the task when there is a new
+ * connection.
+ *
+ * Unlike in read, we don't preallocate a done event here. Every time there
+ * is a new connection we'll have to allocate a new one anyway, so we might
+ * as well keep things simple rather than having to track them.
+ */
+isc_result_t
+isc_socket_listen(isc_socket_t *sock, unsigned int backlog) {
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+
+ REQUIRE(!sock->listener);
+ REQUIRE(sock->bound);
+ REQUIRE(sock->type == isc_sockettype_tcp ||
+ sock->type == isc_sockettype_unix);
+
+ if (backlog == 0)
+ backlog = SOMAXCONN;
+
+ if (listen(sock->fd, (int)backlog) < 0) {
+ UNLOCK(&sock->lock);
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s", strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+ sock->listener = 1;
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This should try to do agressive accept() XXXMLG
+ */
+isc_result_t
+isc_socket_accept(isc_socket_t *sock,
+ isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+ isc_socket_newconnev_t *dev;
+ isc_socketmgr_t *manager;
+ isc_task_t *ntask = NULL;
+ isc_socket_t *nsock;
+ isc_result_t result;
+ isc_boolean_t do_poke = ISC_FALSE;
+
+ REQUIRE(VALID_SOCKET(sock));
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ LOCK(&sock->lock);
+
+ REQUIRE(sock->listener);
+
+ /*
+ * Sender field is overloaded here with the task we will be sending
+ * this event to. Just before the actual event is delivered the
+ * actual ev_sender will be touched up to be the socket.
+ */
+ dev = (isc_socket_newconnev_t *)
+ isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN,
+ action, arg, sizeof(*dev));
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+ ISC_LINK_INIT(dev, ev_link);
+
+ result = allocate_socket(manager, sock->type, &nsock);
+ if (result != ISC_R_SUCCESS) {
+ isc_event_free(ISC_EVENT_PTR(&dev));
+ UNLOCK(&sock->lock);
+ return (result);
+ }
+
+ /*
+ * Attach to socket and to task.
+ */
+ isc_task_attach(task, &ntask);
+ nsock->references++;
+
+ dev->ev_sender = ntask;
+ dev->newsocket = nsock;
+
+ /*
+ * Poke watcher here. We still have the socket locked, so there
+ * is no race condition. We will keep the lock for such a short
+ * bit of time waking it up now or later won't matter all that much.
+ */
+ if (ISC_LIST_EMPTY(sock->accept_list))
+ do_poke = ISC_TRUE;
+
+ ISC_LIST_ENQUEUE(sock->accept_list, dev, ev_link);
+
+ if (do_poke)
+ select_poke(manager, sock->fd, SELECT_POKE_ACCEPT);
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr,
+ isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+ isc_socket_connev_t *dev;
+ isc_task_t *ntask = NULL;
+ isc_socketmgr_t *manager;
+ int cc;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addr != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(addr != NULL);
+
+ if (isc_sockaddr_ismulticast(addr))
+ return (ISC_R_MULTICAST);
+
+ LOCK(&sock->lock);
+
+ REQUIRE(!sock->connecting);
+
+ dev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock,
+ ISC_SOCKEVENT_CONNECT,
+ action, arg,
+ sizeof(*dev));
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+ ISC_LINK_INIT(dev, ev_link);
+
+ /*
+ * Try to do the connect right away, as there can be only one
+ * outstanding, and it might happen to complete.
+ */
+ sock->address = *addr;
+ cc = connect(sock->fd, &addr->type.sa, addr->length);
+ if (cc < 0) {
+ if (SOFT_ERROR(errno) || errno == EINPROGRESS)
+ goto queue;
+
+ switch (errno) {
+#define ERROR_MATCH(a, b) case a: dev->result = b; goto err_exit;
+ ERROR_MATCH(EACCES, ISC_R_NOPERM);
+ ERROR_MATCH(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(ECONNREFUSED, ISC_R_CONNREFUSED);
+ ERROR_MATCH(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+#ifdef EHOSTDOWN
+ ERROR_MATCH(EHOSTDOWN, ISC_R_HOSTUNREACH);
+#endif
+ ERROR_MATCH(ENETUNREACH, ISC_R_NETUNREACH);
+ ERROR_MATCH(ENOBUFS, ISC_R_NORESOURCES);
+ ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH);
+ ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED);
+ ERROR_MATCH(ECONNRESET, ISC_R_CONNECTIONRESET);
+#undef ERROR_MATCH
+ }
+
+ sock->connected = 0;
+
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "%d/%s", errno, strbuf);
+
+ UNLOCK(&sock->lock);
+ isc_event_free(ISC_EVENT_PTR(&dev));
+ return (ISC_R_UNEXPECTED);
+
+ err_exit:
+ sock->connected = 0;
+ isc_task_send(task, ISC_EVENT_PTR(&dev));
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * If connect completed, fire off the done event.
+ */
+ if (cc == 0) {
+ sock->connected = 1;
+ sock->bound = 1;
+ dev->result = ISC_R_SUCCESS;
+ isc_task_send(task, ISC_EVENT_PTR(&dev));
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+ }
+
+ queue:
+
+ /*
+ * Attach to task.
+ */
+ isc_task_attach(task, &ntask);
+
+ sock->connecting = 1;
+
+ dev->ev_sender = ntask;
+
+ /*
+ * Poke watcher here. We still have the socket locked, so there
+ * is no race condition. We will keep the lock for such a short
+ * bit of time waking it up now or later won't matter all that much.
+ */
+ if (sock->connect_ev == NULL)
+ select_poke(manager, sock->fd, SELECT_POKE_CONNECT);
+
+ sock->connect_ev = dev;
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Called when a socket with a pending connect() finishes.
+ */
+static void
+internal_connect(isc_task_t *me, isc_event_t *ev) {
+ isc_socket_t *sock;
+ isc_socket_connev_t *dev;
+ isc_task_t *task;
+ int cc;
+ ISC_SOCKADDR_LEN_T optlen;
+ char strbuf[ISC_STRERRORSIZE];
+ char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+
+ UNUSED(me);
+ INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
+
+ sock = ev->ev_sender;
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+
+ /*
+ * When the internal event was sent the reference count was bumped
+ * to keep the socket around for us. Decrement the count here.
+ */
+ INSIST(sock->references > 0);
+ sock->references--;
+ if (sock->references == 0) {
+ UNLOCK(&sock->lock);
+ destroy(&sock);
+ return;
+ }
+
+ /*
+ * Has this event been canceled?
+ */
+ dev = sock->connect_ev;
+ if (dev == NULL) {
+ INSIST(!sock->connecting);
+ UNLOCK(&sock->lock);
+ return;
+ }
+
+ INSIST(sock->connecting);
+ sock->connecting = 0;
+
+ /*
+ * Get any possible error status here.
+ */
+ optlen = sizeof(cc);
+ if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR,
+ (void *)&cc, (void *)&optlen) < 0)
+ cc = errno;
+ else
+ errno = cc;
+
+ if (errno != 0) {
+ /*
+ * If the error is EAGAIN, just re-select on this
+ * fd and pretend nothing strange happened.
+ */
+ if (SOFT_ERROR(errno) || errno == EINPROGRESS) {
+ sock->connecting = 1;
+ select_poke(sock->manager, sock->fd,
+ SELECT_POKE_CONNECT);
+ UNLOCK(&sock->lock);
+
+ return;
+ }
+
+ /*
+ * Translate other errors into ISC_R_* flavors.
+ */
+ switch (errno) {
+#define ERROR_MATCH(a, b) case a: dev->result = b; break;
+ ERROR_MATCH(EACCES, ISC_R_NOPERM);
+ ERROR_MATCH(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(ECONNREFUSED, ISC_R_CONNREFUSED);
+ ERROR_MATCH(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+#ifdef EHOSTDOWN
+ ERROR_MATCH(EHOSTDOWN, ISC_R_HOSTUNREACH);
+#endif
+ ERROR_MATCH(ENETUNREACH, ISC_R_NETUNREACH);
+ ERROR_MATCH(ENOBUFS, ISC_R_NORESOURCES);
+ ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH);
+ ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED);
+ ERROR_MATCH(ETIMEDOUT, ISC_R_TIMEDOUT);
+ ERROR_MATCH(ECONNRESET, ISC_R_CONNECTIONRESET);
+#undef ERROR_MATCH
+ default:
+ dev->result = ISC_R_UNEXPECTED;
+ isc_sockaddr_format(&sock->address, peerbuf,
+ sizeof(peerbuf));
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "internal_connect: connect(%s) %s",
+ peerbuf, strbuf);
+ }
+ } else {
+ dev->result = ISC_R_SUCCESS;
+ sock->connected = 1;
+ sock->bound = 1;
+ }
+
+ sock->connect_ev = NULL;
+
+ UNLOCK(&sock->lock);
+
+ task = dev->ev_sender;
+ dev->ev_sender = sock;
+ isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev));
+}
+
+isc_result_t
+isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+ isc_result_t result;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addressp != NULL);
+
+ LOCK(&sock->lock);
+
+ if (sock->connected) {
+ *addressp = sock->address;
+ result = ISC_R_SUCCESS;
+ } else {
+ result = ISC_R_NOTCONNECTED;
+ }
+
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+ ISC_SOCKADDR_LEN_T len;
+ isc_result_t result;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addressp != NULL);
+
+ LOCK(&sock->lock);
+
+ if (!sock->bound) {
+ result = ISC_R_NOTBOUND;
+ goto out;
+ }
+
+ result = ISC_R_SUCCESS;
+
+ len = sizeof(addressp->type);
+ if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto out;
+ }
+ addressp->length = (unsigned int)len;
+
+ out:
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+/*
+ * Run through the list of events on this socket, and cancel the ones
+ * queued for task "task" of type "how". "how" is a bitmask.
+ */
+void
+isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ /*
+ * Quick exit if there is nothing to do. Don't even bother locking
+ * in this case.
+ */
+ if (how == 0)
+ return;
+
+ LOCK(&sock->lock);
+
+ /*
+ * All of these do the same thing, more or less.
+ * Each will:
+ * o If the internal event is marked as "posted" try to
+ * remove it from the task's queue. If this fails, mark it
+ * as canceled instead, and let the task clean it up later.
+ * o For each I/O request for that task of that type, post
+ * its done event with status of "ISC_R_CANCELED".
+ * o Reset any state needed.
+ */
+ if (((how & ISC_SOCKCANCEL_RECV) == ISC_SOCKCANCEL_RECV)
+ && !ISC_LIST_EMPTY(sock->recv_list)) {
+ isc_socketevent_t *dev;
+ isc_socketevent_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->recv_list);
+
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_recvdone_event(sock, &dev);
+ }
+ dev = next;
+ }
+ }
+
+ if (((how & ISC_SOCKCANCEL_SEND) == ISC_SOCKCANCEL_SEND)
+ && !ISC_LIST_EMPTY(sock->send_list)) {
+ isc_socketevent_t *dev;
+ isc_socketevent_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->send_list);
+
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_senddone_event(sock, &dev);
+ }
+ dev = next;
+ }
+ }
+
+ if (((how & ISC_SOCKCANCEL_ACCEPT) == ISC_SOCKCANCEL_ACCEPT)
+ && !ISC_LIST_EMPTY(sock->accept_list)) {
+ isc_socket_newconnev_t *dev;
+ isc_socket_newconnev_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->accept_list);
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+
+ if ((task == NULL) || (task == current_task)) {
+
+ ISC_LIST_UNLINK(sock->accept_list, dev,
+ ev_link);
+
+ dev->newsocket->references--;
+ free_socket(&dev->newsocket);
+
+ dev->result = ISC_R_CANCELED;
+ dev->ev_sender = sock;
+ isc_task_sendanddetach(&current_task,
+ ISC_EVENT_PTR(&dev));
+ }
+
+ dev = next;
+ }
+ }
+
+ /*
+ * Connecting is not a list.
+ */
+ if (((how & ISC_SOCKCANCEL_CONNECT) == ISC_SOCKCANCEL_CONNECT)
+ && sock->connect_ev != NULL) {
+ isc_socket_connev_t *dev;
+ isc_task_t *current_task;
+
+ INSIST(sock->connecting);
+ sock->connecting = 0;
+
+ dev = sock->connect_ev;
+ current_task = dev->ev_sender;
+
+ if ((task == NULL) || (task == current_task)) {
+ sock->connect_ev = NULL;
+
+ dev->result = ISC_R_CANCELED;
+ dev->ev_sender = sock;
+ isc_task_sendanddetach(&current_task,
+ ISC_EVENT_PTR(&dev));
+ }
+ }
+
+ UNLOCK(&sock->lock);
+}
+
+isc_sockettype_t
+isc_socket_gettype(isc_socket_t *sock) {
+ REQUIRE(VALID_SOCKET(sock));
+
+ return (sock->type);
+}
+
+isc_boolean_t
+isc_socket_isbound(isc_socket_t *sock) {
+ isc_boolean_t val;
+
+ LOCK(&sock->lock);
+ val = ((sock->bound) ? ISC_TRUE : ISC_FALSE);
+ UNLOCK(&sock->lock);
+
+ return (val);
+}
+
+void
+isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) {
+#if defined(IPV6_V6ONLY)
+ int onoff = yes ? 1 : 0;
+#else
+ UNUSED(yes);
+ UNUSED(sock);
+#endif
+
+ REQUIRE(VALID_SOCKET(sock));
+
+#ifdef IPV6_V6ONLY
+ if (sock->pf == AF_INET6) {
+ (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (void *)&onoff, sizeof(onoff));
+ }
+#endif
+}
+
+#ifndef ISC_PLATFORM_USETHREADS
+void
+isc__socketmgr_getfdsets(fd_set *readset, fd_set *writeset, int *maxfd) {
+ if (socketmgr == NULL)
+ *maxfd = 0;
+ else {
+ *readset = socketmgr->read_fds;
+ *writeset = socketmgr->write_fds;
+ *maxfd = socketmgr->maxfd + 1;
+ }
+}
+
+isc_result_t
+isc__socketmgr_dispatch(fd_set *readset, fd_set *writeset, int maxfd) {
+ isc_socketmgr_t *manager = socketmgr;
+
+ if (manager == NULL)
+ return (ISC_R_NOTFOUND);
+
+ process_fds(manager, maxfd, readset, writeset);
+ return (ISC_R_SUCCESS);
+}
+#endif /* ISC_PLATFORM_USETHREADS */
diff --git a/lib/isc/unix/socket_p.h b/lib/isc/unix/socket_p.h
new file mode 100644
index 0000000..c260bbc
--- /dev/null
+++ b/lib/isc/unix/socket_p.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2004, 2005 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: socket_p.h,v 1.7.18.2 2005/04/29 00:17:08 marka Exp $ */
+
+#ifndef ISC_SOCKET_P_H
+#define ISC_SOCKET_P_H
+
+/*! \file */
+
+#ifdef ISC_PLATFORM_NEEDSYSSELECTH
+#include <sys/select.h>
+#endif
+
+void
+isc__socketmgr_getfdsets(fd_set *readset, fd_set *writeset, int *maxfd);
+
+isc_result_t
+isc__socketmgr_dispatch(fd_set *readset, fd_set *writeset, int maxfd);
+
+#endif /* ISC_SOCKET_P_H */
diff --git a/lib/isc/unix/stdio.c b/lib/isc/unix/stdio.c
new file mode 100644
index 0000000..64db925
--- /dev/null
+++ b/lib/isc/unix/stdio.c
@@ -0,0 +1,117 @@
+/*
+ * 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: stdio.c,v 1.6 2004/03/05 05:11:47 marka Exp $ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <isc/stdio.h>
+
+#include "errno2result.h"
+
+isc_result_t
+isc_stdio_open(const char *filename, const char *mode, FILE **fp) {
+ FILE *f;
+
+ f = fopen(filename, mode);
+ if (f == NULL)
+ return (isc__errno2result(errno));
+ *fp = f;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_stdio_close(FILE *f) {
+ int r;
+
+ r = fclose(f);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_seek(FILE *f, long offset, int whence) {
+ int r;
+
+ r = fseek(f, offset, whence);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f, size_t *nret) {
+ isc_result_t result = ISC_R_SUCCESS;
+ size_t r;
+
+ clearerr(f);
+ r = fread(ptr, size, nmemb, f);
+ if (r != nmemb) {
+ if (feof(f))
+ result = ISC_R_EOF;
+ else
+ result = isc__errno2result(errno);
+ }
+ if (nret != NULL)
+ *nret = r;
+ return (result);
+}
+
+isc_result_t
+isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f,
+ size_t *nret)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ size_t r;
+
+ clearerr(f);
+ r = fwrite(ptr, size, nmemb, f);
+ if (r != nmemb)
+ result = isc__errno2result(errno);
+ if (nret != NULL)
+ *nret = r;
+ return (result);
+}
+
+isc_result_t
+isc_stdio_flush(FILE *f) {
+ int r;
+
+ r = fflush(f);
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_sync(FILE *f) {
+ int r;
+
+ r = fsync(fileno(f));
+ if (r == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (isc__errno2result(errno));
+}
+
diff --git a/lib/isc/unix/stdtime.c b/lib/isc/unix/stdtime.c
new file mode 100644
index 0000000..3f240b7
--- /dev/null
+++ b/lib/isc/unix/stdtime.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2004, 2005 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: stdtime.c,v 1.14.18.3 2005/06/08 02:07:57 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h> /* NULL */
+#include <stdlib.h> /* NULL */
+#include <syslog.h>
+
+#include <sys/time.h>
+
+#include <isc/stdtime.h>
+#include <isc/util.h>
+
+#ifndef ISC_FIX_TV_USEC
+#define ISC_FIX_TV_USEC 1
+#endif
+
+#define US_PER_S 1000000
+
+#if ISC_FIX_TV_USEC
+static inline void
+fix_tv_usec(struct timeval *tv) {
+ isc_boolean_t fixed = ISC_FALSE;
+
+ if (tv->tv_usec < 0) {
+ fixed = ISC_TRUE;
+ do {
+ tv->tv_sec -= 1;
+ tv->tv_usec += US_PER_S;
+ } while (tv->tv_usec < 0);
+ } else if (tv->tv_usec >= US_PER_S) {
+ fixed = ISC_TRUE;
+ do {
+ tv->tv_sec += 1;
+ tv->tv_usec -= US_PER_S;
+ } while (tv->tv_usec >=US_PER_S);
+ }
+ /*
+ * Call syslog directly as we are called from the logging functions.
+ */
+ if (fixed)
+ (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected");
+}
+#endif
+
+void
+isc_stdtime_get(isc_stdtime_t *t) {
+ struct timeval tv;
+
+ /*
+ * Set 't' to the number of seconds since 00:00:00 UTC, January 1,
+ * 1970.
+ */
+
+ REQUIRE(t != NULL);
+
+ RUNTIME_CHECK(gettimeofday(&tv, NULL) != -1);
+
+#if ISC_FIX_TV_USEC
+ fix_tv_usec(&tv);
+ INSIST(tv.tv_usec >= 0);
+#else
+ INSIST(tv.tv_usec >= 0 && tv.tv_usec < US_PER_S);
+#endif
+
+ *t = (unsigned int)tv.tv_sec;
+}
diff --git a/lib/isc/unix/strerror.c b/lib/isc/unix/strerror.c
new file mode 100644
index 0000000..18cc367
--- /dev/null
+++ b/lib/isc/unix/strerror.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2004, 2005 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: strerror.c,v 1.4.18.2 2005/04/29 00:17:08 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/strerror.h>
+#include <isc/util.h>
+
+#ifdef HAVE_STRERROR
+/*%
+ * We need to do this this way for profiled locks.
+ */
+static isc_mutex_t isc_strerror_lock;
+static void init_lock(void) {
+ RUNTIME_CHECK(isc_mutex_init(&isc_strerror_lock) == ISC_R_SUCCESS);
+}
+#else
+extern const char * const sys_errlist[];
+extern const int sys_nerr;
+#endif
+
+void
+isc__strerror(int num, char *buf, size_t size) {
+#ifdef HAVE_STRERROR
+ char *msg;
+ unsigned int unum = num;
+ static isc_once_t once = ISC_ONCE_INIT;
+
+ REQUIRE(buf != NULL);
+
+ RUNTIME_CHECK(isc_once_do(&once, init_lock) == ISC_R_SUCCESS);
+
+ LOCK(&isc_strerror_lock);
+ msg = strerror(num);
+ if (msg != NULL)
+ snprintf(buf, size, "%s", msg);
+ else
+ snprintf(buf, size, "Unknown error: %u", unum);
+ UNLOCK(&isc_strerror_lock);
+#else
+ unsigned int unum = num;
+
+ REQUIRE(buf != NULL);
+
+ if (num >= 0 && num < sys_nerr)
+ snprintf(buf, size, "%s", sys_errlist[num]);
+ else
+ snprintf(buf, size, "Unknown error: %u", unum);
+#endif
+}
diff --git a/lib/isc/unix/syslog.c b/lib/isc/unix/syslog.c
new file mode 100644
index 0000000..ae67399
--- /dev/null
+++ b/lib/isc/unix/syslog.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: syslog.c,v 1.3.18.4 2007/09/13 23:46:26 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <syslog.h>
+
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/syslog.h>
+#include <isc/util.h>
+
+static struct dsn_c_pvt_sfnt {
+ int val;
+ const char *strval;
+} facilities[] = {
+ { LOG_KERN, "kern" },
+ { LOG_USER, "user" },
+ { LOG_MAIL, "mail" },
+ { LOG_DAEMON, "daemon" },
+ { LOG_AUTH, "auth" },
+ { LOG_SYSLOG, "syslog" },
+ { LOG_LPR, "lpr" },
+#ifdef LOG_NEWS
+ { LOG_NEWS, "news" },
+#endif
+#ifdef LOG_UUCP
+ { LOG_UUCP, "uucp" },
+#endif
+#ifdef LOG_CRON
+ { LOG_CRON, "cron" },
+#endif
+#ifdef LOG_AUTHPRIV
+ { LOG_AUTHPRIV, "authpriv" },
+#endif
+#ifdef LOG_FTP
+ { LOG_FTP, "ftp" },
+#endif
+ { LOG_LOCAL0, "local0"},
+ { LOG_LOCAL1, "local1"},
+ { LOG_LOCAL2, "local2"},
+ { LOG_LOCAL3, "local3"},
+ { LOG_LOCAL4, "local4"},
+ { LOG_LOCAL5, "local5"},
+ { LOG_LOCAL6, "local6"},
+ { LOG_LOCAL7, "local7"},
+ { 0, NULL }
+};
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp) {
+ int i;
+
+ REQUIRE(str != NULL);
+ REQUIRE(facilityp != NULL);
+
+ for (i = 0; facilities[i].strval != NULL; i++) {
+ if (strcasecmp(facilities[i].strval, str) == 0) {
+ *facilityp = facilities[i].val;
+ return (ISC_R_SUCCESS);
+ }
+ }
+ return (ISC_R_NOTFOUND);
+
+}
diff --git a/lib/isc/unix/time.c b/lib/isc/unix/time.c
new file mode 100644
index 0000000..bac24d7
--- /dev/null
+++ b/lib/isc/unix/time.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2004, 2005 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: time.c,v 1.47.18.2 2005/04/29 00:17:09 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <sys/time.h> /* Required for struct timeval on some platforms. */
+
+#include <isc/log.h>
+#include <isc/print.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#define NS_PER_S 1000000000 /*%< Nanoseconds per second. */
+#define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */
+#define US_PER_S 1000000 /*%< Microseconds per second. */
+
+/*
+ * All of the INSIST()s checks of nanoseconds < NS_PER_S are for
+ * consistency checking of the type. In lieu of magic numbers, it
+ * is the best we've got. The check is only performed on functions which
+ * need an initialized type.
+ */
+
+#ifndef ISC_FIX_TV_USEC
+#define ISC_FIX_TV_USEC 1
+#endif
+
+/*%
+ *** Intervals
+ ***/
+
+static isc_interval_t zero_interval = { 0, 0 };
+isc_interval_t *isc_interval_zero = &zero_interval;
+
+#if ISC_FIX_TV_USEC
+static inline void
+fix_tv_usec(struct timeval *tv) {
+ isc_boolean_t fixed = ISC_FALSE;
+
+ if (tv->tv_usec < 0) {
+ fixed = ISC_TRUE;
+ do {
+ tv->tv_sec -= 1;
+ tv->tv_usec += US_PER_S;
+ } while (tv->tv_usec < 0);
+ } else if (tv->tv_usec >= US_PER_S) {
+ fixed = ISC_TRUE;
+ do {
+ tv->tv_sec += 1;
+ tv->tv_usec -= US_PER_S;
+ } while (tv->tv_usec >=US_PER_S);
+ }
+ /*
+ * Call syslog directly as was are called from the logging functions.
+ */
+ if (fixed)
+ (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected");
+}
+#endif
+
+void
+isc_interval_set(isc_interval_t *i,
+ unsigned int seconds, unsigned int nanoseconds)
+{
+ REQUIRE(i != NULL);
+ REQUIRE(nanoseconds < NS_PER_S);
+
+ i->seconds = seconds;
+ i->nanoseconds = nanoseconds;
+}
+
+isc_boolean_t
+isc_interval_iszero(const isc_interval_t *i) {
+ REQUIRE(i != NULL);
+ INSIST(i->nanoseconds < NS_PER_S);
+
+ if (i->seconds == 0 && i->nanoseconds == 0)
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+}
+
+
+/***
+ *** Absolute Times
+ ***/
+
+static isc_time_t epoch = { 0, 0 };
+isc_time_t *isc_time_epoch = &epoch;
+
+void
+isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
+ REQUIRE(t != NULL);
+ REQUIRE(nanoseconds < NS_PER_S);
+
+ t->seconds = seconds;
+ t->nanoseconds = nanoseconds;
+}
+
+void
+isc_time_settoepoch(isc_time_t *t) {
+ REQUIRE(t != NULL);
+
+ t->seconds = 0;
+ t->nanoseconds = 0;
+}
+
+isc_boolean_t
+isc_time_isepoch(const isc_time_t *t) {
+ REQUIRE(t != NULL);
+ INSIST(t->nanoseconds < NS_PER_S);
+
+ if (t->seconds == 0 && t->nanoseconds == 0)
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+}
+
+
+isc_result_t
+isc_time_now(isc_time_t *t) {
+ struct timeval tv;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(t != NULL);
+
+ if (gettimeofday(&tv, NULL) == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ /*
+ * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not,
+ * then this test will generate warnings for platforms on which it is
+ * unsigned. In any event, the chances of any of these problems
+ * happening are pretty much zero, but since the libisc library ensures
+ * certain things to be true ...
+ */
+#if ISC_FIX_TV_USEC
+ fix_tv_usec(&tv);
+ if (tv.tv_sec < 0)
+ return (ISC_R_UNEXPECTED);
+#else
+ if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
+ return (ISC_R_UNEXPECTED);
+#endif
+
+ /*
+ * Ensure the tv_sec value fits in t->seconds.
+ */
+ if (sizeof(tv.tv_sec) > sizeof(t->seconds) &&
+ ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U)
+ return (ISC_R_RANGE);
+
+ t->seconds = tv.tv_sec;
+ t->nanoseconds = tv.tv_usec * NS_PER_US;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
+ struct timeval tv;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(t != NULL);
+ REQUIRE(i != NULL);
+ INSIST(i->nanoseconds < NS_PER_S);
+
+ if (gettimeofday(&tv, NULL) == -1) {
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ /*
+ * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not,
+ * then this test will generate warnings for platforms on which it is
+ * unsigned. In any event, the chances of any of these problems
+ * happening are pretty much zero, but since the libisc library ensures
+ * certain things to be true ...
+ */
+#if ISC_FIX_TV_USEC
+ fix_tv_usec(&tv);
+ if (tv.tv_sec < 0)
+ return (ISC_R_UNEXPECTED);
+#else
+ if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
+ return (ISC_R_UNEXPECTED);
+#endif
+
+ /*
+ * Ensure the resulting seconds value fits in the size of an
+ * unsigned int. (It is written this way as a slight optimization;
+ * note that even if both values == INT_MAX, then when added
+ * and getting another 1 added below the result is UINT_MAX.)
+ */
+ if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) &&
+ ((long long)tv.tv_sec + i->seconds > UINT_MAX))
+ return (ISC_R_RANGE);
+
+ t->seconds = tv.tv_sec + i->seconds;
+ t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds;
+ if (t->nanoseconds > NS_PER_S) {
+ t->seconds++;
+ t->nanoseconds -= NS_PER_S;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+int
+isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
+ REQUIRE(t1 != NULL && t2 != NULL);
+ INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
+
+ if (t1->seconds < t2->seconds)
+ return (-1);
+ if (t1->seconds > t2->seconds)
+ return (1);
+ if (t1->nanoseconds < t2->nanoseconds)
+ return (-1);
+ if (t1->nanoseconds > t2->nanoseconds)
+ return (1);
+ return (0);
+}
+
+isc_result_t
+isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result)
+{
+ REQUIRE(t != NULL && i != NULL && result != NULL);
+ INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
+
+ /*
+ * Ensure the resulting seconds value fits in the size of an
+ * unsigned int. (It is written this way as a slight optimization;
+ * note that even if both values == INT_MAX, then when added
+ * and getting another 1 added below the result is UINT_MAX.)
+ */
+ if ((t->seconds > INT_MAX || i->seconds > INT_MAX) &&
+ ((long long)t->seconds + i->seconds > UINT_MAX))
+ return (ISC_R_RANGE);
+
+ result->seconds = t->seconds + i->seconds;
+ result->nanoseconds = t->nanoseconds + i->nanoseconds;
+ if (result->nanoseconds >= NS_PER_S) {
+ result->seconds++;
+ result->nanoseconds -= NS_PER_S;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
+ isc_time_t *result)
+{
+ REQUIRE(t != NULL && i != NULL && result != NULL);
+ INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
+
+ if ((unsigned int)t->seconds < i->seconds ||
+ ((unsigned int)t->seconds == i->seconds &&
+ t->nanoseconds < i->nanoseconds))
+ return (ISC_R_RANGE);
+
+ result->seconds = t->seconds - i->seconds;
+ if (t->nanoseconds >= i->nanoseconds)
+ result->nanoseconds = t->nanoseconds - i->nanoseconds;
+ else {
+ result->nanoseconds = NS_PER_S - i->nanoseconds +
+ t->nanoseconds;
+ result->seconds--;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_uint64_t
+isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
+ isc_uint64_t i1, i2, i3;
+
+ REQUIRE(t1 != NULL && t2 != NULL);
+ INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
+
+ i1 = (isc_uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds;
+ i2 = (isc_uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds;
+
+ if (i1 <= i2)
+ return (0);
+
+ i3 = i1 - i2;
+
+ /*
+ * Convert to microseconds.
+ */
+ i3 = (i1 - i2) / NS_PER_US;
+
+ return (i3);
+}
+
+isc_uint32_t
+isc_time_seconds(const isc_time_t *t) {
+ REQUIRE(t != NULL);
+ INSIST(t->nanoseconds < NS_PER_S);
+
+ return ((isc_uint32_t)t->seconds);
+}
+
+isc_result_t
+isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
+ isc_uint64_t i;
+ time_t seconds;
+
+ REQUIRE(t != NULL);
+ INSIST(t->nanoseconds < NS_PER_S);
+
+ /*
+ * Ensure that the number of seconds represented by t->seconds
+ * can be represented by a time_t. Since t->seconds is an unsigned
+ * int and since time_t is mostly opaque, this is trickier than
+ * it seems. (This standardized opaqueness of time_t is *very*
+ * frustrating; time_t is not even limited to being an integral
+ * type.)
+ *
+ * The mission, then, is to avoid generating any kind of warning
+ * about "signed versus unsigned" while trying to determine if the
+ * the unsigned int t->seconds is out range for tv_sec, which is
+ * pretty much only true if time_t is a signed integer of the same
+ * size as the return value of isc_time_seconds.
+ *
+ * The use of the 64 bit integer ``i'' takes advantage of C's
+ * conversion rules to either zero fill or sign extend the widened
+ * type.
+ *
+ * Solaris 5.6 gives this warning about the left shift:
+ * warning: integer overflow detected: op "<<"
+ * if the U(nsigned) qualifier is not on the 1.
+ */
+ seconds = (time_t)t->seconds;
+
+ INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t));
+ INSIST(sizeof(time_t) >= sizeof(isc_uint32_t));
+
+ if (sizeof(time_t) == sizeof(isc_uint32_t) && /* Same size. */
+ (time_t)0.5 != 0.5 && /* Not a floating point type. */
+ (i = (time_t)-1) != 4294967295u && /* Is signed. */
+ (seconds &
+ (1U << (sizeof(time_t) * CHAR_BIT - 1))) != 0U) { /* Negative. */
+ /*
+ * This UNUSED() is here to shut up the IRIX compiler:
+ * variable "i" was set but never used
+ * when the value of i *was* used in the third test.
+ * (Let's hope the compiler got the actual test right.)
+ */
+ UNUSED(i);
+ return (ISC_R_RANGE);
+ }
+
+ *secondsp = seconds;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_uint32_t
+isc_time_nanoseconds(const isc_time_t *t) {
+ REQUIRE(t != NULL);
+
+ ENSURE(t->nanoseconds < NS_PER_S);
+
+ return ((isc_uint32_t)t->nanoseconds);
+}
+
+void
+isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
+ time_t now;
+ unsigned int flen;
+
+ REQUIRE(len > 0);
+
+ now = (time_t) t->seconds;
+ flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now));
+ INSIST(flen < len);
+ if (flen != 0)
+ snprintf(buf + flen, len - flen,
+ ".%03u", t->nanoseconds / 1000000);
+ else
+ snprintf(buf, len, "99-Bad-9999 99:99:99.999");
+}
diff --git a/lib/isc/version.c b/lib/isc/version.c
new file mode 100644
index 0000000..6d3b3d2
--- /dev/null
+++ b/lib/isc/version.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: version.c,v 1.11.18.2 2005/04/29 00:16:51 marka Exp $ */
+
+/*! \file */
+
+#include <isc/version.h>
+
+const char isc_version[] = VERSION;
+
+const unsigned int isc_libinterface = LIBINTERFACE;
+const unsigned int isc_librevision = LIBREVISION;
+const unsigned int isc_libage = LIBAGE;
diff --git a/lib/isc/x86_32/Makefile.in b/lib/isc/x86_32/Makefile.in
new file mode 100644
index 0000000..c8e77e4
--- /dev/null
+++ b/lib/isc/x86_32/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:38 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/x86_32/include/Makefile.in b/lib/isc/x86_32/include/Makefile.in
new file mode 100644
index 0000000..b68a765
--- /dev/null
+++ b/lib/isc/x86_32/include/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:39 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/x86_32/include/isc/Makefile.in b/lib/isc/x86_32/include/isc/Makefile.in
new file mode 100644
index 0000000..4ce057a
--- /dev/null
+++ b/lib/isc/x86_32/include/isc/Makefile.in
@@ -0,0 +1,36 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:39 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc ; \
+ done
diff --git a/lib/isc/x86_32/include/isc/atomic.h b/lib/isc/x86_32/include/isc/atomic.h
new file mode 100644
index 0000000..f3136d9
--- /dev/null
+++ b/lib/isc/x86_32/include/isc/atomic.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.2.2.3 2005/07/27 04:23:33 marka Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ */
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+ isc_int32_t prev = val;
+
+ __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xadd %0, %1"
+ :"=q"(prev)
+ :"m"(*p), "0"(prev)
+ :"memory", "cc");
+
+ return (prev);
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+ __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * xchg should automatically lock memory, but we add it
+ * explicitly just in case (it at least doesn't harm)
+ */
+ "lock;"
+#endif
+
+ "xchgl %1, %0"
+ :
+ : "r"(val), "m"(*p)
+ : "memory");
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'. The original value is returned in any
+ * case.
+ */
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+ __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "cmpxchgl %1, %2"
+ : "=a"(cmpval)
+ : "r"(val), "m"(*p), "a"(cmpval)
+ : "memory");
+
+ return (cmpval);
+}
+
+#elif defined(ISC_PLATFORM_USESTDASM)
+/*
+ * The followings are "generic" assembly code which implements the same
+ * functionality in case the gcc extension cannot be used. It should be
+ * better to avoid inlining below, since we directly refer to specific
+ * positions of the stack frame, which would not actually point to the
+ * intended address in the embedded mnemonic.
+ */
+#include <isc/util.h> /* for 'UNUSED' macro */
+
+static isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+ UNUSED(p);
+ UNUSED(val);
+
+ __asm (
+ "movl 8(%ebp), %ecx\n"
+ "movl 12(%ebp), %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xadd %edx, (%ecx)\n"
+
+ /*
+ * set the return value directly in the register so that we
+ * can avoid guessing the correct position in the stack for a
+ * local variable.
+ */
+ "movl %edx, %eax"
+ );
+}
+
+static void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+ UNUSED(p);
+ UNUSED(val);
+
+ __asm (
+ "movl 8(%ebp), %ecx\n"
+ "movl 12(%ebp), %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xchgl (%ecx), %edx\n"
+ );
+}
+
+static isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+ UNUSED(p);
+ UNUSED(cmpval);
+ UNUSED(val);
+
+ __asm (
+ "movl 8(%ebp), %ecx\n"
+ "movl 12(%ebp), %eax\n" /* must be %eax for cmpxchgl */
+ "movl 16(%ebp), %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+
+ /*
+ * If (%ecx) == %eax then (%ecx) := %edx.
+ % %eax is set to old (%ecx), which will be the return value.
+ */
+ "cmpxchgl %edx, (%ecx)"
+ );
+}
+#else /* !ISC_PLATFORM_USEGCCASM && !ISC_PLATFORM_USESTDASM */
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/x86_64/Makefile.in b/lib/isc/x86_64/Makefile.in
new file mode 100644
index 0000000..de577a9
--- /dev/null
+++ b/lib/isc/x86_64/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:39 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/x86_64/include/Makefile.in b/lib/isc/x86_64/include/Makefile.in
new file mode 100644
index 0000000..b68a765
--- /dev/null
+++ b/lib/isc/x86_64/include/Makefile.in
@@ -0,0 +1,24 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:39 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/x86_64/include/isc/Makefile.in b/lib/isc/x86_64/include/isc/Makefile.in
new file mode 100644
index 0000000..4ce057a
--- /dev/null
+++ b/lib/isc/x86_64/include/isc/Makefile.in
@@ -0,0 +1,36 @@
+# Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.2.2.1 2007/09/14 04:26:39 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+HEADERS = atomic.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/isc ; \
+ done
diff --git a/lib/isc/x86_64/include/isc/atomic.h b/lib/isc/x86_64/include/isc/atomic.h
new file mode 100644
index 0000000..0752d8f
--- /dev/null
+++ b/lib/isc/x86_64/include/isc/atomic.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.2.20.1 2005/09/02 13:27:12 marka Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+
+/* We share the gcc-version with x86_32 */
+#error "impossible case. check build configuration"
+
+#elif defined(ISC_PLATFORM_USESTDASM)
+/*
+ * The followings are "generic" assembly code which implements the same
+ * functionality in case the gcc extension cannot be used. It should be
+ * better to avoid inlining below, since we directly refer to specific
+ * registers for arguments, which would not actually correspond to the
+ * intended address or value in the embedded mnemonic.
+ */
+#include <isc/util.h> /* for 'UNUSED' macro */
+
+static isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+ UNUSED(p);
+ UNUSED(val);
+
+ __asm (
+ "movq %rdi, %rdx\n"
+ "movl %esi, %eax\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xadd %eax, (%rdx)\n"
+
+ /*
+ * set the return value directly in the register so that we
+ * can avoid guessing the correct position in the stack for a
+ * local variable.
+ */
+ );
+}
+
+static void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+ UNUSED(p);
+ UNUSED(val);
+
+ __asm (
+ "movq %rdi, %rax\n"
+ "movl %esi, %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ "xchgl (%rax), %edx\n"
+ );
+}
+
+static isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+ UNUSED(p);
+ UNUSED(cmpval);
+ UNUSED(val);
+
+ __asm (
+ "movl %edx, %ecx\n"
+ "movl %esi, %eax\n"
+ "movq %rdi, %rdx\n"
+
+#ifdef ISC_PLATFORM_USETHREADS
+ "lock;"
+#endif
+ /*
+ * If (%rdi) == %eax then (%rdi) := %edx.
+ % %eax is set to old (%ecx), which will be the return value.
+ */
+ "cmpxchgl %ecx, (%rdx)"
+ );
+}
+
+#else /* !ISC_PLATFORM_USEGCCASM && !ISC_PLATFORM_USESTDASM */
+
+#error "unsupported compiler. disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isccc/Makefile.in b/lib/isccc/Makefile.in
new file mode 100644
index 0000000..cb41681
--- /dev/null
+++ b/lib/isccc/Makefile.in
@@ -0,0 +1,86 @@
+# 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: Makefile.in,v 1.6.18.1 2004/07/20 07:03:29 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+@LIBISCCC_API@
+
+@BIND9_MAKE_INCLUDES@
+
+CINCLUDES = -I. ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCC_INCLUDES}
+
+CDEFINES =
+CWARNINGS =
+
+ISCLIBS = ../../lib/isc/libisc.@A@
+ISCCCLIBS = ../../lib/isccc/libisccc.@A@
+
+ISCDEPLIBS = ../../lib/isc/libisc.@A@
+ISCCCDEPLIBS = libisccc.@A@
+
+LIBS = @LIBS@
+
+SUBDIRS = include
+
+# Alphabetically
+OBJS = alist.@O@ base64.@O@ cc.@O@ ccmsg.@O@ \
+ lib.@O@ \
+ result.@O@ sexpr.@O@ symtab.@O@ version.@O@
+
+# Alphabetically
+SRCS = alist.c base64.c cc.c ccmsg.c \
+ lib.c \
+ result.c sexpr.c symtab.c version.c
+
+
+TARGETS = timestamp
+
+@BIND9_MAKE_RULES@
+
+version.@O@: version.c
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \
+ -DVERSION=\"${VERSION}\" \
+ -DLIBINTERFACE=${LIBINTERFACE} \
+ -DLIBREVISION=${LIBREVISION} \
+ -DLIBAGE=${LIBAGE} \
+ -c ${srcdir}/version.c
+
+libisccc.@SA@: ${OBJS}
+ ${AR} ${ARFLAGS} $@ ${OBJS}
+ ${RANLIB} $@
+
+libisccc.la: ${OBJS}
+ ${LIBTOOL_MODE_LINK} \
+ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisccc.la -rpath ${libdir} \
+ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ ${OBJS} ${LIBS} ${ISCLIBS}
+
+timestamp: libisccc.@A@
+ touch timestamp
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+
+install:: timestamp installdirs
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libisccc.@A@ ${DESTDIR}${libdir}
+
+clean distclean::
+ rm -f libisccc.@A@ timestamp
diff --git a/lib/isccc/alist.c b/lib/isccc/alist.c
new file mode 100644
index 0000000..a8335c8
--- /dev/null
+++ b/lib/isccc/alist.c
@@ -0,0 +1,299 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: alist.c,v 1.3.18.2 2005/04/29 00:17:11 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <isccc/alist.h>
+#include <isc/assertions.h>
+#include <isccc/result.h>
+#include <isccc/sexpr.h>
+#include <isccc/util.h>
+
+#define CAR(s) (s)->value.as_dottedpair.car
+#define CDR(s) (s)->value.as_dottedpair.cdr
+
+#define ALIST_TAG "*alist*"
+#define MAX_INDENT 64
+
+static char spaces[MAX_INDENT + 1] =
+ " ";
+
+isccc_sexpr_t *
+isccc_alist_create(void)
+{
+ isccc_sexpr_t *alist, *tag;
+
+ tag = isccc_sexpr_fromstring(ALIST_TAG);
+ if (tag == NULL)
+ return (NULL);
+ alist = isccc_sexpr_cons(tag, NULL);
+ if (alist == NULL) {
+ isccc_sexpr_free(&tag);
+ return (NULL);
+ }
+
+ return (alist);
+}
+
+isc_boolean_t
+isccc_alist_alistp(isccc_sexpr_t *alist)
+{
+ isccc_sexpr_t *car;
+
+ if (alist == NULL || alist->type != ISCCC_SEXPRTYPE_DOTTEDPAIR)
+ return (ISC_FALSE);
+ car = CAR(alist);
+ if (car == NULL || car->type != ISCCC_SEXPRTYPE_STRING)
+ return (ISC_FALSE);
+ if (strcmp(car->value.as_string, ALIST_TAG) != 0)
+ return (ISC_FALSE);
+ return (ISC_TRUE);
+}
+
+isc_boolean_t
+isccc_alist_emptyp(isccc_sexpr_t *alist)
+{
+ REQUIRE(isccc_alist_alistp(alist));
+
+ if (CDR(alist) == NULL)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isccc_sexpr_t *
+isccc_alist_first(isccc_sexpr_t *alist)
+{
+ REQUIRE(isccc_alist_alistp(alist));
+
+ return (CDR(alist));
+}
+
+isccc_sexpr_t *
+isccc_alist_assq(isccc_sexpr_t *alist, const char *key)
+{
+ isccc_sexpr_t *car, *caar;
+
+ REQUIRE(isccc_alist_alistp(alist));
+
+ /*
+ * Skip alist type tag.
+ */
+ alist = CDR(alist);
+
+ while (alist != NULL) {
+ INSIST(alist->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+ car = CAR(alist);
+ INSIST(car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+ caar = CAR(car);
+ if (caar->type == ISCCC_SEXPRTYPE_STRING &&
+ strcmp(caar->value.as_string, key) == 0)
+ return (car);
+ alist = CDR(alist);
+ }
+
+ return (NULL);
+}
+
+void
+isccc_alist_delete(isccc_sexpr_t *alist, const char *key)
+{
+ isccc_sexpr_t *car, *caar, *rest, *prev;
+
+ REQUIRE(isccc_alist_alistp(alist));
+
+ prev = alist;
+ rest = CDR(alist);
+ while (rest != NULL) {
+ INSIST(rest->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+ car = CAR(rest);
+ INSIST(car != NULL && car->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+ caar = CAR(car);
+ if (caar->type == ISCCC_SEXPRTYPE_STRING &&
+ strcmp(caar->value.as_string, key) == 0) {
+ CDR(prev) = CDR(rest);
+ CDR(rest) = NULL;
+ isccc_sexpr_free(&rest);
+ break;
+ }
+ prev = rest;
+ rest = CDR(rest);
+ }
+}
+
+isccc_sexpr_t *
+isccc_alist_define(isccc_sexpr_t *alist, const char *key, isccc_sexpr_t *value)
+{
+ isccc_sexpr_t *kv, *k, *elt;
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv == NULL) {
+ /*
+ * New association.
+ */
+ k = isccc_sexpr_fromstring(key);
+ if (k == NULL)
+ return (NULL);
+ kv = isccc_sexpr_cons(k, value);
+ if (kv == NULL) {
+ isccc_sexpr_free(&kv);
+ return (NULL);
+ }
+ elt = isccc_sexpr_addtolist(&alist, kv);
+ if (elt == NULL) {
+ isccc_sexpr_free(&kv);
+ return (NULL);
+ }
+ } else {
+ /*
+ * We've already got an entry for this key. Replace it.
+ */
+ isccc_sexpr_free(&CDR(kv));
+ CDR(kv) = value;
+ }
+
+ return (kv);
+}
+
+isccc_sexpr_t *
+isccc_alist_definestring(isccc_sexpr_t *alist, const char *key, const char *str)
+{
+ isccc_sexpr_t *v, *kv;
+
+ v = isccc_sexpr_fromstring(str);
+ if (v == NULL)
+ return (NULL);
+ kv = isccc_alist_define(alist, key, v);
+ if (kv == NULL)
+ isccc_sexpr_free(&v);
+
+ return (kv);
+}
+
+isccc_sexpr_t *
+isccc_alist_definebinary(isccc_sexpr_t *alist, const char *key, isccc_region_t *r)
+{
+ isccc_sexpr_t *v, *kv;
+
+ v = isccc_sexpr_frombinary(r);
+ if (v == NULL)
+ return (NULL);
+ kv = isccc_alist_define(alist, key, v);
+ if (kv == NULL)
+ isccc_sexpr_free(&v);
+
+ return (kv);
+}
+
+isccc_sexpr_t *
+isccc_alist_lookup(isccc_sexpr_t *alist, const char *key)
+{
+ isccc_sexpr_t *kv;
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv != NULL)
+ return (CDR(kv));
+ return (NULL);
+}
+
+isc_result_t
+isccc_alist_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp)
+{
+ isccc_sexpr_t *kv, *v;
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv != NULL) {
+ v = CDR(kv);
+ if (isccc_sexpr_stringp(v)) {
+ if (strp != NULL)
+ *strp = isccc_sexpr_tostring(v);
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_EXISTS);
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+isc_result_t
+isccc_alist_lookupbinary(isccc_sexpr_t *alist, const char *key, isccc_region_t **r)
+{
+ isccc_sexpr_t *kv, *v;
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv != NULL) {
+ v = CDR(kv);
+ if (isccc_sexpr_binaryp(v)) {
+ if (r != NULL)
+ *r = isccc_sexpr_tobinary(v);
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_EXISTS);
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+void
+isccc_alist_prettyprint(isccc_sexpr_t *sexpr, unsigned int indent, FILE *stream)
+{
+ isccc_sexpr_t *elt, *kv, *k, *v;
+
+ if (isccc_alist_alistp(sexpr)) {
+ fprintf(stream, "{\n");
+ indent += 4;
+ for (elt = isccc_alist_first(sexpr);
+ elt != NULL;
+ elt = CDR(elt)) {
+ kv = CAR(elt);
+ INSIST(isccc_sexpr_listp(kv));
+ k = CAR(kv);
+ v = CDR(kv);
+ INSIST(isccc_sexpr_stringp(k));
+ fprintf(stream, "%.*s%s => ", (int)indent, spaces,
+ isccc_sexpr_tostring(k));
+ isccc_alist_prettyprint(v, indent, stream);
+ if (CDR(elt) != NULL)
+ fprintf(stream, ",");
+ fprintf(stream, "\n");
+ }
+ indent -= 4;
+ fprintf(stream, "%.*s}", (int)indent, spaces);
+ } else if (isccc_sexpr_listp(sexpr)) {
+ fprintf(stream, "(\n");
+ indent += 4;
+ for (elt = sexpr;
+ elt != NULL;
+ elt = CDR(elt)) {
+ fprintf(stream, "%.*s", (int)indent, spaces);
+ isccc_alist_prettyprint(CAR(elt), indent, stream);
+ if (CDR(elt) != NULL)
+ fprintf(stream, ",");
+ fprintf(stream, "\n");
+ }
+ indent -= 4;
+ fprintf(stream, "%.*s)", (int)indent, spaces);
+ } else
+ isccc_sexpr_print(sexpr, stream);
+}
diff --git a/lib/isccc/api b/lib/isccc/api
new file mode 100644
index 0000000..cd8c055
--- /dev/null
+++ b/lib/isccc/api
@@ -0,0 +1,3 @@
+LIBINTERFACE = 30
+LIBREVISION = 1
+LIBAGE = 0
diff --git a/lib/isccc/base64.c b/lib/isccc/base64.c
new file mode 100644
index 0000000..e723cf2
--- /dev/null
+++ b/lib/isccc/base64.c
@@ -0,0 +1,65 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: base64.c,v 1.3.18.2 2005/04/29 00:17:11 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/base64.h>
+#include <isc/buffer.h>
+#include <isc/region.h>
+#include <isc/result.h>
+
+#include <isccc/base64.h>
+#include <isccc/result.h>
+#include <isccc/util.h>
+
+isc_result_t
+isccc_base64_encode(isccc_region_t *source, int wordlength,
+ const char *wordbreak, isccc_region_t *target)
+{
+ isc_region_t sr;
+ isc_buffer_t tb;
+ isc_result_t result;
+
+ sr.base = source->rstart;
+ sr.length = source->rend - source->rstart;
+ isc_buffer_init(&tb, target->rstart, target->rend - target->rstart);
+
+ result = isc_base64_totext(&sr, wordlength, wordbreak, &tb);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ source->rstart = source->rend;
+ target->rstart = isc_buffer_used(&tb);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isccc_base64_decode(const char *cstr, isccc_region_t *target) {
+ isc_buffer_t b;
+ isc_result_t result;
+
+ isc_buffer_init(&b, target->rstart, target->rend - target->rstart);
+ result = isc_base64_decodestring(cstr, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ target->rstart = isc_buffer_used(&b);
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isccc/cc.c b/lib/isccc/cc.c
new file mode 100644
index 0000000..e65349e
--- /dev/null
+++ b/lib/isccc/cc.c
@@ -0,0 +1,818 @@
+/*
+ * Portions Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001-2003 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: cc.c,v 1.10.18.5 2006/12/07 23:57:58 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <isc/assertions.h>
+#include <isc/hmacmd5.h>
+#include <isc/print.h>
+#include <isc/stdlib.h>
+
+#include <isccc/alist.h>
+#include <isccc/base64.h>
+#include <isccc/cc.h>
+#include <isccc/result.h>
+#include <isccc/sexpr.h>
+#include <isccc/symtab.h>
+#include <isccc/symtype.h>
+#include <isccc/util.h>
+
+#define MAX_TAGS 256
+#define DUP_LIFETIME 900
+
+typedef isccc_sexpr_t *sexpr_ptr;
+
+static unsigned char auth_hmd5[] = {
+ 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
+ ISCCC_CCMSGTYPE_TABLE, /*%< message type */
+ 0x00, 0x00, 0x00, 0x20, /*%< length == 32 */
+ 0x04, 0x68, 0x6d, 0x64, 0x35, /*%< len + hmd5 */
+ ISCCC_CCMSGTYPE_BINARYDATA, /*%< message type */
+ 0x00, 0x00, 0x00, 0x16, /*%< length == 22 */
+ /*
+ * The base64 encoding of one of our HMAC-MD5 signatures is
+ * 22 bytes.
+ */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#define HMD5_OFFSET 21 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 */
+#define HMD5_LENGTH 22
+
+static isc_result_t
+table_towire(isccc_sexpr_t *alist, isccc_region_t *target);
+
+static isc_result_t
+list_towire(isccc_sexpr_t *alist, isccc_region_t *target);
+
+static isc_result_t
+value_towire(isccc_sexpr_t *elt, isccc_region_t *target)
+{
+ size_t len;
+ unsigned char *lenp;
+ isccc_region_t *vr;
+ isc_result_t result;
+
+ if (isccc_sexpr_binaryp(elt)) {
+ vr = isccc_sexpr_tobinary(elt);
+ len = REGION_SIZE(*vr);
+ if (REGION_SIZE(*target) < 1 + 4 + len)
+ return (ISC_R_NOSPACE);
+ PUT8(ISCCC_CCMSGTYPE_BINARYDATA, target->rstart);
+ PUT32(len, target->rstart);
+ if (REGION_SIZE(*target) < len)
+ return (ISC_R_NOSPACE);
+ PUT_MEM(vr->rstart, len, target->rstart);
+ } else if (isccc_alist_alistp(elt)) {
+ if (REGION_SIZE(*target) < 1 + 4)
+ return (ISC_R_NOSPACE);
+ PUT8(ISCCC_CCMSGTYPE_TABLE, target->rstart);
+ /*
+ * Emit a placeholder length.
+ */
+ lenp = target->rstart;
+ PUT32(0, target->rstart);
+ /*
+ * Emit the table.
+ */
+ result = table_towire(elt, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ len = (size_t)(target->rstart - lenp);
+ /*
+ * 'len' is 4 bytes too big, since it counts
+ * the placeholder length too. Adjust and
+ * emit.
+ */
+ INSIST(len >= 4U);
+ len -= 4;
+ PUT32(len, lenp);
+ } else if (isccc_sexpr_listp(elt)) {
+ if (REGION_SIZE(*target) < 1 + 4)
+ return (ISC_R_NOSPACE);
+ PUT8(ISCCC_CCMSGTYPE_LIST, target->rstart);
+ /*
+ * Emit a placeholder length and count.
+ */
+ lenp = target->rstart;
+ PUT32(0, target->rstart);
+ /*
+ * Emit the list.
+ */
+ result = list_towire(elt, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ len = (size_t)(target->rstart - lenp);
+ /*
+ * 'len' is 4 bytes too big, since it counts
+ * the placeholder length. Adjust and emit.
+ */
+ INSIST(len >= 4U);
+ len -= 4;
+ PUT32(len, lenp);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+table_towire(isccc_sexpr_t *alist, isccc_region_t *target)
+{
+ isccc_sexpr_t *kv, *elt, *k, *v;
+ char *ks;
+ isc_result_t result;
+ size_t len;
+
+ for (elt = isccc_alist_first(alist);
+ elt != NULL;
+ elt = ISCCC_SEXPR_CDR(elt)) {
+ kv = ISCCC_SEXPR_CAR(elt);
+ k = ISCCC_SEXPR_CAR(kv);
+ ks = isccc_sexpr_tostring(k);
+ v = ISCCC_SEXPR_CDR(kv);
+ len = strlen(ks);
+ INSIST(len <= 255U);
+ /*
+ * Emit the key name.
+ */
+ if (REGION_SIZE(*target) < 1 + len)
+ return (ISC_R_NOSPACE);
+ PUT8(len, target->rstart);
+ PUT_MEM(ks, len, target->rstart);
+ /*
+ * Emit the value.
+ */
+ result = value_towire(v, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+list_towire(isccc_sexpr_t *list, isccc_region_t *target)
+{
+ isc_result_t result;
+
+ while (list != NULL) {
+ result = value_towire(ISCCC_SEXPR_CAR(list), target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ list = ISCCC_SEXPR_CDR(list);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+sign(unsigned char *data, unsigned int length, unsigned char *hmd5,
+ isccc_region_t *secret)
+{
+ isc_hmacmd5_t ctx;
+ isc_result_t result;
+ isccc_region_t source, target;
+ unsigned char digest[ISC_MD5_DIGESTLENGTH];
+ unsigned char digestb64[ISC_MD5_DIGESTLENGTH * 4];
+
+ isc_hmacmd5_init(&ctx, secret->rstart, REGION_SIZE(*secret));
+ isc_hmacmd5_update(&ctx, data, length);
+ isc_hmacmd5_sign(&ctx, digest);
+ source.rstart = digest;
+ source.rend = digest + ISC_MD5_DIGESTLENGTH;
+ target.rstart = digestb64;
+ target.rend = digestb64 + ISC_MD5_DIGESTLENGTH * 4;
+ result = isccc_base64_encode(&source, 64, "", &target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ PUT_MEM(digestb64, HMD5_LENGTH, hmd5);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target,
+ isccc_region_t *secret)
+{
+ unsigned char *hmd5_rstart, *signed_rstart;
+ isc_result_t result;
+
+ if (REGION_SIZE(*target) < 4 + sizeof(auth_hmd5))
+ return (ISC_R_NOSPACE);
+ /*
+ * Emit protocol version.
+ */
+ PUT32(1, target->rstart);
+ if (secret != NULL) {
+ /*
+ * Emit _auth section with zeroed HMAC-MD5 signature.
+ * We'll replace the zeros with the real signature once
+ * we know what it is.
+ */
+ hmd5_rstart = target->rstart + HMD5_OFFSET;
+ PUT_MEM(auth_hmd5, sizeof(auth_hmd5), target->rstart);
+ } else
+ hmd5_rstart = NULL;
+ signed_rstart = target->rstart;
+ /*
+ * Delete any existing _auth section so that we don't try
+ * to encode it.
+ */
+ isccc_alist_delete(alist, "_auth");
+ /*
+ * Emit the message.
+ */
+ result = table_towire(alist, target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (secret != NULL)
+ return (sign(signed_rstart, (target->rstart - signed_rstart),
+ hmd5_rstart, secret));
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
+ isccc_region_t *secret)
+{
+ isc_hmacmd5_t ctx;
+ isccc_region_t source;
+ isccc_region_t target;
+ isc_result_t result;
+ isccc_sexpr_t *_auth, *hmd5;
+ unsigned char digest[ISC_MD5_DIGESTLENGTH];
+ unsigned char digestb64[ISC_MD5_DIGESTLENGTH * 4];
+
+ /*
+ * Extract digest.
+ */
+ _auth = isccc_alist_lookup(alist, "_auth");
+ if (_auth == NULL)
+ return (ISC_R_FAILURE);
+ hmd5 = isccc_alist_lookup(_auth, "hmd5");
+ if (hmd5 == NULL)
+ return (ISC_R_FAILURE);
+ /*
+ * Compute digest.
+ */
+ isc_hmacmd5_init(&ctx, secret->rstart, REGION_SIZE(*secret));
+ isc_hmacmd5_update(&ctx, data, length);
+ isc_hmacmd5_sign(&ctx, digest);
+ source.rstart = digest;
+ source.rend = digest + ISC_MD5_DIGESTLENGTH;
+ target.rstart = digestb64;
+ target.rend = digestb64 + ISC_MD5_DIGESTLENGTH * 4;
+ result = isccc_base64_encode(&source, 64, "", &target);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ /*
+ * Strip trailing == and NUL terminate target.
+ */
+ target.rstart -= 2;
+ *target.rstart++ = '\0';
+ /*
+ * Verify.
+ */
+ if (strcmp((char *)digestb64, isccc_sexpr_tostring(hmd5)) != 0)
+ return (ISCCC_R_BADAUTH);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+table_fromwire(isccc_region_t *source, isccc_region_t *secret,
+ isccc_sexpr_t **alistp);
+
+static isc_result_t
+list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp);
+
+static isc_result_t
+value_fromwire(isccc_region_t *source, isccc_sexpr_t **valuep)
+{
+ unsigned int msgtype;
+ isc_uint32_t len;
+ isccc_sexpr_t *value;
+ isccc_region_t active;
+ isc_result_t result;
+
+ if (REGION_SIZE(*source) < 1 + 4)
+ return (ISC_R_UNEXPECTEDEND);
+ GET8(msgtype, source->rstart);
+ GET32(len, source->rstart);
+ if (REGION_SIZE(*source) < len)
+ return (ISC_R_UNEXPECTEDEND);
+ active.rstart = source->rstart;
+ active.rend = active.rstart + len;
+ source->rstart = active.rend;
+ if (msgtype == ISCCC_CCMSGTYPE_BINARYDATA) {
+ value = isccc_sexpr_frombinary(&active);
+ if (value != NULL) {
+ *valuep = value;
+ result = ISC_R_SUCCESS;
+ } else
+ result = ISC_R_NOMEMORY;
+ } else if (msgtype == ISCCC_CCMSGTYPE_TABLE)
+ result = table_fromwire(&active, NULL, valuep);
+ else if (msgtype == ISCCC_CCMSGTYPE_LIST)
+ result = list_fromwire(&active, valuep);
+ else
+ result = ISCCC_R_SYNTAX;
+
+ return (result);
+}
+
+static isc_result_t
+table_fromwire(isccc_region_t *source, isccc_region_t *secret,
+ isccc_sexpr_t **alistp)
+{
+ char key[256];
+ isc_uint32_t len;
+ isc_result_t result;
+ isccc_sexpr_t *alist, *value;
+ isc_boolean_t first_tag;
+ unsigned char *checksum_rstart;
+
+ REQUIRE(alistp != NULL && *alistp == NULL);
+
+ checksum_rstart = NULL;
+ first_tag = ISC_TRUE;
+ alist = isccc_alist_create();
+ if (alist == NULL)
+ return (ISC_R_NOMEMORY);
+
+ while (!REGION_EMPTY(*source)) {
+ GET8(len, source->rstart);
+ if (REGION_SIZE(*source) < len) {
+ result = ISC_R_UNEXPECTEDEND;
+ goto bad;
+ }
+ GET_MEM(key, len, source->rstart);
+ key[len] = '\0'; /* Ensure NUL termination. */
+ value = NULL;
+ result = value_fromwire(source, &value);
+ if (result != ISC_R_SUCCESS)
+ goto bad;
+ if (isccc_alist_define(alist, key, value) == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto bad;
+ }
+ if (first_tag && secret != NULL && strcmp(key, "_auth") == 0)
+ checksum_rstart = source->rstart;
+ first_tag = ISC_FALSE;
+ }
+
+ *alistp = alist;
+
+ if (secret != NULL) {
+ if (checksum_rstart != NULL)
+ return (verify(alist, checksum_rstart,
+ (source->rend - checksum_rstart),
+ secret));
+ return (ISCCC_R_BADAUTH);
+ }
+
+ return (ISC_R_SUCCESS);
+
+ bad:
+ isccc_sexpr_free(&alist);
+
+ return (result);
+}
+
+static isc_result_t
+list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp)
+{
+ isccc_sexpr_t *list, *value;
+ isc_result_t result;
+
+ list = NULL;
+ while (!REGION_EMPTY(*source)) {
+ value = NULL;
+ result = value_fromwire(source, &value);
+ if (result != ISC_R_SUCCESS) {
+ isccc_sexpr_free(&list);
+ return (result);
+ }
+ if (isccc_sexpr_addtolist(&list, value) == NULL) {
+ isccc_sexpr_free(&value);
+ isccc_sexpr_free(&list);
+ return (result);
+ }
+ }
+
+ *listp = list;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isccc_cc_fromwire(isccc_region_t *source, isccc_sexpr_t **alistp,
+ isccc_region_t *secret)
+{
+ unsigned int size;
+ isc_uint32_t version;
+
+ size = REGION_SIZE(*source);
+ if (size < 4)
+ return (ISC_R_UNEXPECTEDEND);
+ GET32(version, source->rstart);
+ if (version != 1)
+ return (ISCCC_R_UNKNOWNVERSION);
+
+ return (table_fromwire(source, secret, alistp));
+}
+
+static isc_result_t
+createmessage(isc_uint32_t version, const char *from, const char *to,
+ isc_uint32_t serial, isccc_time_t now,
+ isccc_time_t expires, isccc_sexpr_t **alistp,
+ isc_boolean_t want_expires)
+{
+ isccc_sexpr_t *alist, *_ctrl, *_data;
+ isc_result_t result;
+
+ REQUIRE(alistp != NULL && *alistp == NULL);
+
+ if (version != 1)
+ return (ISCCC_R_UNKNOWNVERSION);
+
+ alist = isccc_alist_create();
+ if (alist == NULL)
+ return (ISC_R_NOMEMORY);
+
+ result = ISC_R_NOMEMORY;
+
+ _ctrl = isccc_alist_create();
+ if (_ctrl == NULL)
+ goto bad;
+ if (isccc_alist_define(alist, "_ctrl", _ctrl) == NULL) {
+ isccc_sexpr_free(&_ctrl);
+ goto bad;
+ }
+
+ _data = isccc_alist_create();
+ if (_data == NULL)
+ goto bad;
+ if (isccc_alist_define(alist, "_data", _data) == NULL) {
+ isccc_sexpr_free(&_data);
+ goto bad;
+ }
+
+ if (isccc_cc_defineuint32(_ctrl, "_ser", serial) == NULL ||
+ isccc_cc_defineuint32(_ctrl, "_tim", now) == NULL ||
+ (want_expires &&
+ isccc_cc_defineuint32(_ctrl, "_exp", expires) == NULL))
+ goto bad;
+ if (from != NULL &&
+ isccc_cc_definestring(_ctrl, "_frm", from) == NULL)
+ goto bad;
+ if (to != NULL &&
+ isccc_cc_definestring(_ctrl, "_to", to) == NULL)
+ goto bad;
+
+ *alistp = alist;
+
+ return (ISC_R_SUCCESS);
+
+ bad:
+ isccc_sexpr_free(&alist);
+
+ return (result);
+}
+
+isc_result_t
+isccc_cc_createmessage(isc_uint32_t version, const char *from, const char *to,
+ isc_uint32_t serial, isccc_time_t now,
+ isccc_time_t expires, isccc_sexpr_t **alistp)
+{
+ return (createmessage(version, from, to, serial, now, expires,
+ alistp, ISC_TRUE));
+}
+
+isc_result_t
+isccc_cc_createack(isccc_sexpr_t *message, isc_boolean_t ok,
+ isccc_sexpr_t **ackp)
+{
+ char *_frm, *_to;
+ isc_uint32_t serial;
+ isccc_sexpr_t *ack, *_ctrl;
+ isc_result_t result;
+ isccc_time_t t;
+
+ REQUIRE(ackp != NULL && *ackp == NULL);
+
+ _ctrl = isccc_alist_lookup(message, "_ctrl");
+ if (_ctrl == NULL ||
+ isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
+ isccc_cc_lookupuint32(_ctrl, "_tim", &t) != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+ /*
+ * _frm and _to are optional.
+ */
+ _frm = NULL;
+ (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
+ _to = NULL;
+ (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
+ /*
+ * Create the ack.
+ */
+ ack = NULL;
+ result = createmessage(1, _to, _frm, serial, t, 0, &ack, ISC_FALSE);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ _ctrl = isccc_alist_lookup(ack, "_ctrl");
+ if (_ctrl == NULL)
+ return (ISC_R_FAILURE);
+ if (isccc_cc_definestring(ack, "_ack", (ok) ? "1" : "0") == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto bad;
+ }
+
+ *ackp = ack;
+
+ return (ISC_R_SUCCESS);
+
+ bad:
+ isccc_sexpr_free(&ack);
+
+ return (result);
+}
+
+isc_boolean_t
+isccc_cc_isack(isccc_sexpr_t *message)
+{
+ isccc_sexpr_t *_ctrl;
+
+ _ctrl = isccc_alist_lookup(message, "_ctrl");
+ if (_ctrl == NULL)
+ return (ISC_FALSE);
+ if (isccc_cc_lookupstring(_ctrl, "_ack", NULL) == ISC_R_SUCCESS)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+isccc_cc_isreply(isccc_sexpr_t *message)
+{
+ isccc_sexpr_t *_ctrl;
+
+ _ctrl = isccc_alist_lookup(message, "_ctrl");
+ if (_ctrl == NULL)
+ return (ISC_FALSE);
+ if (isccc_cc_lookupstring(_ctrl, "_rpl", NULL) == ISC_R_SUCCESS)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_result_t
+isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now,
+ isccc_time_t expires, isccc_sexpr_t **alistp)
+{
+ char *_frm, *_to, *type;
+ isc_uint32_t serial;
+ isccc_sexpr_t *alist, *_ctrl, *_data;
+ isc_result_t result;
+
+ REQUIRE(alistp != NULL && *alistp == NULL);
+
+ _ctrl = isccc_alist_lookup(message, "_ctrl");
+ _data = isccc_alist_lookup(message, "_data");
+ if (_ctrl == NULL ||
+ _data == NULL ||
+ isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
+ isccc_cc_lookupstring(_data, "type", &type) != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+ /*
+ * _frm and _to are optional.
+ */
+ _frm = NULL;
+ (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
+ _to = NULL;
+ (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
+ /*
+ * Create the response.
+ */
+ alist = NULL;
+ result = isccc_cc_createmessage(1, _to, _frm, serial, now, expires,
+ &alist);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ _ctrl = isccc_alist_lookup(alist, "_ctrl");
+ if (_ctrl == NULL)
+ return (ISC_R_FAILURE);
+ _data = isccc_alist_lookup(alist, "_data");
+ if (_data == NULL)
+ return (ISC_R_FAILURE);
+ if (isccc_cc_definestring(_ctrl, "_rpl", "1") == NULL ||
+ isccc_cc_definestring(_data, "type", type) == NULL) {
+ isccc_sexpr_free(&alist);
+ return (ISC_R_NOMEMORY);
+ }
+
+ *alistp = alist;
+
+ return (ISC_R_SUCCESS);
+}
+
+isccc_sexpr_t *
+isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str)
+{
+ size_t len;
+ isccc_region_t r;
+
+ len = strlen(str);
+ DE_CONST(str, r.rstart);
+ r.rend = r.rstart + len;
+
+ return (isccc_alist_definebinary(alist, key, &r));
+}
+
+isccc_sexpr_t *
+isccc_cc_defineuint32(isccc_sexpr_t *alist, const char *key, isc_uint32_t i)
+{
+ char b[100];
+ size_t len;
+ isccc_region_t r;
+
+ snprintf(b, sizeof(b), "%u", i);
+ len = strlen(b);
+ r.rstart = (unsigned char *)b;
+ r.rend = (unsigned char *)b + len;
+
+ return (isccc_alist_definebinary(alist, key, &r));
+}
+
+isc_result_t
+isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp)
+{
+ isccc_sexpr_t *kv, *v;
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv != NULL) {
+ v = ISCCC_SEXPR_CDR(kv);
+ if (isccc_sexpr_binaryp(v)) {
+ if (strp != NULL)
+ *strp = isccc_sexpr_tostring(v);
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_EXISTS);
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+isc_result_t
+isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key,
+ isc_uint32_t *uintp)
+{
+ isccc_sexpr_t *kv, *v;
+
+ kv = isccc_alist_assq(alist, key);
+ if (kv != NULL) {
+ v = ISCCC_SEXPR_CDR(kv);
+ if (isccc_sexpr_binaryp(v)) {
+ if (uintp != NULL)
+ *uintp = (isc_uint32_t)
+ strtoul(isccc_sexpr_tostring(v),
+ NULL, 10);
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_EXISTS);
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+static void
+symtab_undefine(char *key, unsigned int type, isccc_symvalue_t value,
+ void *arg)
+{
+ UNUSED(type);
+ UNUSED(value);
+ UNUSED(arg);
+
+ free(key);
+}
+
+static isc_boolean_t
+symtab_clean(char *key, unsigned int type, isccc_symvalue_t value,
+ void *arg)
+{
+ isccc_time_t *now;
+
+ UNUSED(key);
+ UNUSED(type);
+
+ now = arg;
+
+ if (*now < value.as_uinteger)
+ return (ISC_FALSE);
+ if ((*now - value.as_uinteger) < DUP_LIFETIME)
+ return (ISC_FALSE);
+ return (ISC_TRUE);
+}
+
+isc_result_t
+isccc_cc_createsymtab(isccc_symtab_t **symtabp)
+{
+ return (isccc_symtab_create(11897, symtab_undefine, NULL, ISC_FALSE,
+ symtabp));
+}
+
+void
+isccc_cc_cleansymtab(isccc_symtab_t *symtab, isccc_time_t now)
+{
+ isccc_symtab_foreach(symtab, symtab_clean, &now);
+}
+
+static isc_boolean_t
+has_whitespace(const char *str)
+{
+ char c;
+
+ if (str == NULL)
+ return (ISC_FALSE);
+ while ((c = *str++) != '\0') {
+ if (c == ' ' || c == '\t' || c == '\n')
+ return (ISC_TRUE);
+ }
+ return (ISC_FALSE);
+}
+
+isc_result_t
+isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message,
+ isccc_time_t now)
+{
+ const char *_frm;
+ const char *_to;
+ char *_ser, *_tim, *tmp;
+ isc_result_t result;
+ char *key;
+ size_t len;
+ isccc_symvalue_t value;
+ isccc_sexpr_t *_ctrl;
+
+ _ctrl = isccc_alist_lookup(message, "_ctrl");
+ if (_ctrl == NULL ||
+ isccc_cc_lookupstring(_ctrl, "_ser", &_ser) != ISC_R_SUCCESS ||
+ isccc_cc_lookupstring(_ctrl, "_tim", &_tim) != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+ /*
+ * _frm and _to are optional.
+ */
+ if (isccc_cc_lookupstring(_ctrl, "_frm", &tmp) != ISC_R_SUCCESS)
+ _frm = "";
+ else
+ _frm = tmp;
+ if (isccc_cc_lookupstring(_ctrl, "_to", &tmp) != ISC_R_SUCCESS)
+ _to = "";
+ else
+ _to = tmp;
+ /*
+ * Ensure there is no newline in any of the strings. This is so
+ * we can write them to a file later.
+ */
+ if (has_whitespace(_frm) || has_whitespace(_to) ||
+ has_whitespace(_ser) || has_whitespace(_tim))
+ return (ISC_R_FAILURE);
+ len = strlen(_frm) + strlen(_to) + strlen(_ser) + strlen(_tim) + 4;
+ key = malloc(len);
+ if (key == NULL)
+ return (ISC_R_NOMEMORY);
+ snprintf(key, len, "%s;%s;%s;%s", _frm, _to, _ser, _tim);
+ value.as_uinteger = now;
+ result = isccc_symtab_define(symtab, key, ISCCC_SYMTYPE_CCDUP, value,
+ isccc_symexists_reject);
+ if (result != ISC_R_SUCCESS) {
+ free(key);
+ return (result);
+ }
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isccc/ccmsg.c b/lib/isccc/ccmsg.c
new file mode 100644
index 0000000..d624c9b
--- /dev/null
+++ b/lib/isccc/ccmsg.c
@@ -0,0 +1,222 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ccmsg.c,v 1.5.18.2 2005/04/29 00:17:11 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/task.h>
+#include <isc/util.h>
+
+#include <isccc/events.h>
+#include <isccc/ccmsg.h>
+
+#define CCMSG_MAGIC ISC_MAGIC('C', 'C', 'm', 's')
+#define VALID_CCMSG(foo) ISC_MAGIC_VALID(foo, CCMSG_MAGIC)
+
+static void recv_length(isc_task_t *, isc_event_t *);
+static void recv_message(isc_task_t *, isc_event_t *);
+
+
+static void
+recv_length(isc_task_t *task, isc_event_t *ev_in) {
+ isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
+ isc_event_t *dev;
+ isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
+ isc_region_t region;
+ isc_result_t result;
+
+ INSIST(VALID_CCMSG(ccmsg));
+
+ dev = &ccmsg->event;
+
+ if (ev->result != ISC_R_SUCCESS) {
+ ccmsg->result = ev->result;
+ goto send_and_free;
+ }
+
+ /*
+ * Success.
+ */
+ ccmsg->size = ntohl(ccmsg->size);
+ if (ccmsg->size == 0) {
+ ccmsg->result = ISC_R_UNEXPECTEDEND;
+ goto send_and_free;
+ }
+ if (ccmsg->size > ccmsg->maxsize) {
+ ccmsg->result = ISC_R_RANGE;
+ goto send_and_free;
+ }
+
+ region.base = isc_mem_get(ccmsg->mctx, ccmsg->size);
+ region.length = ccmsg->size;
+ if (region.base == NULL) {
+ ccmsg->result = ISC_R_NOMEMORY;
+ goto send_and_free;
+ }
+
+ isc_buffer_init(&ccmsg->buffer, region.base, region.length);
+ result = isc_socket_recv(ccmsg->sock, &region, 0,
+ task, recv_message, ccmsg);
+ if (result != ISC_R_SUCCESS) {
+ ccmsg->result = result;
+ goto send_and_free;
+ }
+
+ isc_event_free(&ev_in);
+ return;
+
+ send_and_free:
+ isc_task_send(ccmsg->task, &dev);
+ ccmsg->task = NULL;
+ isc_event_free(&ev_in);
+ return;
+}
+
+static void
+recv_message(isc_task_t *task, isc_event_t *ev_in) {
+ isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
+ isc_event_t *dev;
+ isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
+
+ (void)task;
+
+ INSIST(VALID_CCMSG(ccmsg));
+
+ dev = &ccmsg->event;
+
+ if (ev->result != ISC_R_SUCCESS) {
+ ccmsg->result = ev->result;
+ goto send_and_free;
+ }
+
+ ccmsg->result = ISC_R_SUCCESS;
+ isc_buffer_add(&ccmsg->buffer, ev->n);
+ ccmsg->address = ev->address;
+
+ send_and_free:
+ isc_task_send(ccmsg->task, &dev);
+ ccmsg->task = NULL;
+ isc_event_free(&ev_in);
+}
+
+void
+isccc_ccmsg_init(isc_mem_t *mctx, isc_socket_t *sock, isccc_ccmsg_t *ccmsg) {
+ REQUIRE(mctx != NULL);
+ REQUIRE(sock != NULL);
+ REQUIRE(ccmsg != NULL);
+
+ ccmsg->magic = CCMSG_MAGIC;
+ ccmsg->size = 0;
+ ccmsg->buffer.base = NULL;
+ ccmsg->buffer.length = 0;
+ ccmsg->maxsize = 4294967295U; /* Largest message possible. */
+ ccmsg->mctx = mctx;
+ ccmsg->sock = sock;
+ ccmsg->task = NULL; /* None yet. */
+ ccmsg->result = ISC_R_UNEXPECTED; /* None yet. */
+ /*
+ * Should probably initialize the event here, but it can wait.
+ */
+}
+
+
+void
+isccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize) {
+ REQUIRE(VALID_CCMSG(ccmsg));
+
+ ccmsg->maxsize = maxsize;
+}
+
+
+isc_result_t
+isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg,
+ isc_task_t *task, isc_taskaction_t action, void *arg)
+{
+ isc_result_t result;
+ isc_region_t region;
+
+ REQUIRE(VALID_CCMSG(ccmsg));
+ REQUIRE(task != NULL);
+ REQUIRE(ccmsg->task == NULL); /* not currently in use */
+
+ if (ccmsg->buffer.base != NULL) {
+ isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
+ ccmsg->buffer.length);
+ ccmsg->buffer.base = NULL;
+ ccmsg->buffer.length = 0;
+ }
+
+ ccmsg->task = task;
+ ccmsg->action = action;
+ ccmsg->arg = arg;
+ ccmsg->result = ISC_R_UNEXPECTED; /* unknown right now */
+
+ ISC_EVENT_INIT(&ccmsg->event, sizeof(isc_event_t), 0, 0,
+ ISCCC_EVENT_CCMSG, action, arg, ccmsg,
+ NULL, NULL);
+
+ region.base = (unsigned char *)&ccmsg->size;
+ region.length = 4; /* isc_uint32_t */
+ result = isc_socket_recv(ccmsg->sock, &region, 0,
+ ccmsg->task, recv_length, ccmsg);
+
+ if (result != ISC_R_SUCCESS)
+ ccmsg->task = NULL;
+
+ return (result);
+}
+
+void
+isccc_ccmsg_cancelread(isccc_ccmsg_t *ccmsg) {
+ REQUIRE(VALID_CCMSG(ccmsg));
+
+ isc_socket_cancel(ccmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
+}
+
+#if 0
+void
+isccc_ccmsg_freebuffer(isccc_ccmsg_t *ccmsg) {
+ REQUIRE(VALID_CCMSG(ccmsg));
+
+ if (ccmsg->buffer.base == NULL)
+ return;
+
+ isc_mem_put(ccmsg->mctx, ccmsg->buffer.base, ccmsg->buffer.length);
+ ccmsg->buffer.base = NULL;
+ ccmsg->buffer.length = 0;
+}
+#endif
+
+void
+isccc_ccmsg_invalidate(isccc_ccmsg_t *ccmsg) {
+ REQUIRE(VALID_CCMSG(ccmsg));
+
+ ccmsg->magic = 0;
+
+ if (ccmsg->buffer.base != NULL) {
+ isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
+ ccmsg->buffer.length);
+ ccmsg->buffer.base = NULL;
+ ccmsg->buffer.length = 0;
+ }
+}
diff --git a/lib/isccc/include/Makefile.in b/lib/isccc/include/Makefile.in
new file mode 100644
index 0000000..f3d46ab
--- /dev/null
+++ b/lib/isccc/include/Makefile.in
@@ -0,0 +1,25 @@
+# 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: Makefile.in,v 1.3 2004/03/05 05:12:12 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isccc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isccc/include/isccc/Makefile.in b/lib/isccc/include/isccc/Makefile.in
new file mode 100644
index 0000000..b7b1d55
--- /dev/null
+++ b/lib/isccc/include/isccc/Makefile.in
@@ -0,0 +1,42 @@
+# 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: Makefile.in,v 1.5 2004/03/05 05:12:15 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+#
+# Only list headers that are to be installed and are not
+# machine generated. The latter are handled specially in the
+# install target below.
+#
+HEADERS = alist.h base64.h cc.h ccmsg.h events.h lib.h result.h \
+ sexpr.h symtab.h symtype.h types.h util.h version.h
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isccc
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/isccc ; \
+ done
diff --git a/lib/isccc/include/isccc/alist.h b/lib/isccc/include/isccc/alist.h
new file mode 100644
index 0000000..16b5ba2
--- /dev/null
+++ b/lib/isccc/include/isccc/alist.h
@@ -0,0 +1,74 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: alist.h,v 1.3.18.2 2005/04/29 00:17:12 marka Exp $ */
+
+#ifndef ISCCC_ALIST_H
+#define ISCCC_ALIST_H 1
+
+/*! \file */
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isccc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isccc_sexpr_t *
+isccc_alist_create(void);
+
+isc_boolean_t
+isccc_alist_alistp(isccc_sexpr_t *alist);
+
+isc_boolean_t
+isccc_alist_emptyp(isccc_sexpr_t *alist);
+
+isccc_sexpr_t *
+isccc_alist_first(isccc_sexpr_t *alist);
+
+isccc_sexpr_t *
+isccc_alist_assq(isccc_sexpr_t *alist, const char *key);
+
+void
+isccc_alist_delete(isccc_sexpr_t *alist, const char *key);
+
+isccc_sexpr_t *
+isccc_alist_define(isccc_sexpr_t *alist, const char *key, isccc_sexpr_t *value);
+
+isccc_sexpr_t *
+isccc_alist_definestring(isccc_sexpr_t *alist, const char *key, const char *str);
+
+isccc_sexpr_t *
+isccc_alist_definebinary(isccc_sexpr_t *alist, const char *key, isccc_region_t *r);
+
+isccc_sexpr_t *
+isccc_alist_lookup(isccc_sexpr_t *alist, const char *key);
+
+isc_result_t
+isccc_alist_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp);
+
+isc_result_t
+isccc_alist_lookupbinary(isccc_sexpr_t *alist, const char *key, isccc_region_t **r);
+
+void
+isccc_alist_prettyprint(isccc_sexpr_t *sexpr, unsigned int indent, FILE *stream);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_ALIST_H */
diff --git a/lib/isccc/include/isccc/base64.h b/lib/isccc/include/isccc/base64.h
new file mode 100644
index 0000000..dd70e8d
--- /dev/null
+++ b/lib/isccc/include/isccc/base64.h
@@ -0,0 +1,72 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: base64.h,v 1.3.18.2 2005/04/29 00:17:13 marka Exp $ */
+
+#ifndef ISCCC_BASE64_H
+#define ISCCC_BASE64_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isccc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isccc_base64_encode(isccc_region_t *source, int wordlength,
+ const char *wordbreak, isccc_region_t *target);
+/*%<
+ * Convert data into base64 encoded text.
+ *
+ * Notes:
+ *\li The base64 encoded text in 'target' will be divided into
+ * words of at most 'wordlength' characters, separated by
+ * the 'wordbreak' string. No parentheses will surround
+ * the text.
+ *
+ * Requires:
+ *\li 'source' is a region containing binary data.
+ *\li 'target' is a text region containing available space.
+ *\li 'wordbreak' points to a null-terminated string of
+ * zero or more whitespace characters.
+ */
+
+isc_result_t
+isccc_base64_decode(const char *cstr, isccc_region_t *target);
+/*%<
+ * Decode a null-terminated base64 string.
+ *
+ * Requires:
+ *\li 'cstr' is non-null.
+ *\li 'target' is a valid region.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADBASE64 -- 'cstr' is not a valid base64 encoding.
+ *\li #ISC_R_NOSPACE -- 'target' is not big enough.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_BASE64_H */
diff --git a/lib/isccc/include/isccc/cc.h b/lib/isccc/include/isccc/cc.h
new file mode 100644
index 0000000..2e291ea
--- /dev/null
+++ b/lib/isccc/include/isccc/cc.h
@@ -0,0 +1,109 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: cc.h,v 1.4.18.2 2005/04/29 00:17:13 marka Exp $ */
+
+#ifndef ISCCC_CC_H
+#define ISCCC_CC_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isccc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% Maximum Datagram Package */
+#define ISCCC_CC_MAXDGRAMPACKET 4096
+
+/*% Message Type String */
+#define ISCCC_CCMSGTYPE_STRING 0x00
+/*% Message Type Binary Data */
+#define ISCCC_CCMSGTYPE_BINARYDATA 0x01
+/*% Message Type Table */
+#define ISCCC_CCMSGTYPE_TABLE 0x02
+/*% Message Type List */
+#define ISCCC_CCMSGTYPE_LIST 0x03
+
+/*% Send to Wire */
+isc_result_t
+isccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target,
+ isccc_region_t *secret);
+
+/*% Get From Wire */
+isc_result_t
+isccc_cc_fromwire(isccc_region_t *source, isccc_sexpr_t **alistp,
+ isccc_region_t *secret);
+
+/*% Create Message */
+isc_result_t
+isccc_cc_createmessage(isc_uint32_t version, const char *from, const char *to,
+ isc_uint32_t serial, isccc_time_t now,
+ isccc_time_t expires, isccc_sexpr_t **alistp);
+
+/*% Create Acknowledgment */
+isc_result_t
+isccc_cc_createack(isccc_sexpr_t *message, isc_boolean_t ok,
+ isccc_sexpr_t **ackp);
+
+/*% Is Ack? */
+isc_boolean_t
+isccc_cc_isack(isccc_sexpr_t *message);
+
+/*% Is Reply? */
+isc_boolean_t
+isccc_cc_isreply(isccc_sexpr_t *message);
+
+/*% Create Response */
+isc_result_t
+isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now,
+ isccc_time_t expires, isccc_sexpr_t **alistp);
+
+/*% Define String */
+isccc_sexpr_t *
+isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str);
+
+/*% Define uint 32 */
+isccc_sexpr_t *
+isccc_cc_defineuint32(isccc_sexpr_t *alist, const char *key, isc_uint32_t i);
+
+/*% Lookup String */
+isc_result_t
+isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp);
+
+/*% Lookup uint 32 */
+isc_result_t
+isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key,
+ isc_uint32_t *uintp);
+
+/*% Create Symbol Table */
+isc_result_t
+isccc_cc_createsymtab(isccc_symtab_t **symtabp);
+
+/*% Clean up Symbol Table */
+void
+isccc_cc_cleansymtab(isccc_symtab_t *symtab, isccc_time_t now);
+
+/*% Check for Duplicates */
+isc_result_t
+isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message,
+ isccc_time_t now);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_CC_H */
diff --git a/lib/isccc/include/isccc/ccmsg.h b/lib/isccc/include/isccc/ccmsg.h
new file mode 100644
index 0000000..372047d
--- /dev/null
+++ b/lib/isccc/include/isccc/ccmsg.h
@@ -0,0 +1,135 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ccmsg.h,v 1.4.18.2 2005/04/29 00:17:13 marka Exp $ */
+
+#ifndef ISCCC_CCMSG_H
+#define ISCCC_CCMSG_H 1
+
+/*! \file */
+
+#include <isc/buffer.h>
+#include <isc/lang.h>
+#include <isc/socket.h>
+
+/*% ISCCC Message Structure */
+typedef struct isccc_ccmsg {
+ /* private (don't touch!) */
+ unsigned int magic;
+ isc_uint32_t size;
+ isc_buffer_t buffer;
+ unsigned int maxsize;
+ isc_mem_t *mctx;
+ isc_socket_t *sock;
+ isc_task_t *task;
+ isc_taskaction_t action;
+ void *arg;
+ isc_event_t event;
+ /* public (read-only) */
+ isc_result_t result;
+ isc_sockaddr_t address;
+} isccc_ccmsg_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isccc_ccmsg_init(isc_mem_t *mctx, isc_socket_t *sock, isccc_ccmsg_t *ccmsg);
+/*%
+ * Associate a cc message state with a given memory context and
+ * TCP socket.
+ *
+ * Requires:
+ *
+ *\li "mctx" and "sock" be non-NULL and valid types.
+ *
+ *\li "sock" be a read/write TCP socket.
+ *
+ *\li "ccmsg" be non-NULL and an uninitialized or invalidated structure.
+ *
+ * Ensures:
+ *
+ *\li "ccmsg" is a valid structure.
+ */
+
+void
+isccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize);
+/*%
+ * Set the maximum packet size to "maxsize"
+ *
+ * Requires:
+ *
+ *\li "ccmsg" be valid.
+ *
+ *\li 512 <= "maxsize" <= 4294967296
+ */
+
+isc_result_t
+isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg,
+ isc_task_t *task, isc_taskaction_t action, void *arg);
+/*%
+ * Schedule an event to be delivered when a command channel message is
+ * readable, or when an error occurs on the socket.
+ *
+ * Requires:
+ *
+ *\li "ccmsg" be valid.
+ *
+ *\li "task", "taskaction", and "arg" be valid.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS -- no error
+ *\li Anything that the isc_socket_recv() call can return. XXXMLG
+ *
+ * Notes:
+ *
+ *\li The event delivered is a fully generic event. It will contain no
+ * actual data. The sender will be a pointer to the isccc_ccmsg_t.
+ * The result code inside that structure should be checked to see
+ * what the final result was.
+ */
+
+void
+isccc_ccmsg_cancelread(isccc_ccmsg_t *ccmsg);
+/*%
+ * Cancel a readmessage() call. The event will still be posted with a
+ * CANCELED result code.
+ *
+ * Requires:
+ *
+ *\li "ccmsg" be valid.
+ */
+
+void
+isccc_ccmsg_invalidate(isccc_ccmsg_t *ccmsg);
+/*%
+ * Clean up all allocated state, and invalidate the structure.
+ *
+ * Requires:
+ *
+ *\li "ccmsg" be valid.
+ *
+ * Ensures:
+ *
+ *\li "ccmsg" is invalidated and disassociated with all memory contexts,
+ * sockets, etc.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_CCMSG_H */
diff --git a/lib/isccc/include/isccc/events.h b/lib/isccc/include/isccc/events.h
new file mode 100644
index 0000000..0ac365f
--- /dev/null
+++ b/lib/isccc/include/isccc/events.h
@@ -0,0 +1,37 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: events.h,v 1.3.18.2 2005/04/29 00:17:13 marka Exp $ */
+
+#ifndef ISCCC_EVENTS_H
+#define ISCCC_EVENTS_H 1
+
+/*! \file */
+
+#include <isc/eventclass.h>
+
+/*%
+ * Registry of ISCCC event numbers.
+ */
+
+#define ISCCC_EVENT_CCMSG (ISC_EVENTCLASS_ISCCC + 0)
+
+#define ISCCC_EVENT_FIRSTEVENT (ISC_EVENTCLASS_ISCCC + 0)
+#define ISCCC_EVENT_LASTEVENT (ISC_EVENTCLASS_ISCCC + 65535)
+
+#endif /* ISCCC_EVENTS_H */
diff --git a/lib/isccc/include/isccc/lib.h b/lib/isccc/include/isccc/lib.h
new file mode 100644
index 0000000..247267c
--- /dev/null
+++ b/lib/isccc/include/isccc/lib.h
@@ -0,0 +1,42 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lib.h,v 1.4.18.2 2005/04/29 00:17:13 marka Exp $ */
+
+#ifndef ISCCC_LIB_H
+#define ISCCC_LIB_H 1
+
+/*! \file */
+
+#include <isc/types.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+LIBISCCC_EXTERNAL_DATA extern isc_msgcat_t *isccc_msgcat;
+
+void
+isccc_lib_initmsgcat(void);
+/*%
+ * Initialize the ISCCC library's message catalog, isccc_msgcat, if it
+ * has not already been initialized.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_LIB_H */
diff --git a/lib/isccc/include/isccc/result.h b/lib/isccc/include/isccc/result.h
new file mode 100644
index 0000000..6fbc298
--- /dev/null
+++ b/lib/isccc/include/isccc/result.h
@@ -0,0 +1,60 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001, 2003 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: result.h,v 1.5.18.2 2005/04/29 00:17:14 marka Exp $ */
+
+#ifndef ISCCC_RESULT_H
+#define ISCCC_RESULT_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/resultclass.h>
+#include <isc/result.h>
+
+#include <isccc/types.h>
+
+/*% Unknown Version */
+#define ISCCC_R_UNKNOWNVERSION (ISC_RESULTCLASS_ISCCC + 0)
+/*% Syntax Error */
+#define ISCCC_R_SYNTAX (ISC_RESULTCLASS_ISCCC + 1)
+/*% Bad Authorization */
+#define ISCCC_R_BADAUTH (ISC_RESULTCLASS_ISCCC + 2)
+/*% Expired */
+#define ISCCC_R_EXPIRED (ISC_RESULTCLASS_ISCCC + 3)
+/*% Clock Skew */
+#define ISCCC_R_CLOCKSKEW (ISC_RESULTCLASS_ISCCC + 4)
+/*% Duplicate */
+#define ISCCC_R_DUPLICATE (ISC_RESULTCLASS_ISCCC + 5)
+
+#define ISCCC_R_NRESULTS 6 /*%< Number of results */
+
+ISC_LANG_BEGINDECLS
+
+const char *
+isccc_result_totext(isc_result_t result);
+/*%
+ * Convert a isccc_result_t into a string message describing the result.
+ */
+
+void
+isccc_result_register(void);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_RESULT_H */
diff --git a/lib/isccc/include/isccc/sexpr.h b/lib/isccc/include/isccc/sexpr.h
new file mode 100644
index 0000000..cb1d297
--- /dev/null
+++ b/lib/isccc/include/isccc/sexpr.h
@@ -0,0 +1,111 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: sexpr.h,v 1.4.18.2 2005/04/29 00:17:14 marka Exp $ */
+
+#ifndef ISCCC_SEXPR_H
+#define ISCCC_SEXPR_H 1
+
+/*! \file */
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isccc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% dotted pair structure */
+struct isccc_dottedpair {
+ isccc_sexpr_t *car;
+ isccc_sexpr_t *cdr;
+};
+
+/*% iscc_sexpr structure */
+struct isccc_sexpr {
+ unsigned int type;
+ union {
+ char * as_string;
+ isccc_dottedpair_t as_dottedpair;
+ isccc_region_t as_region;
+ } value;
+};
+
+#define ISCCC_SEXPRTYPE_NONE 0x00 /*%< Illegal. */
+#define ISCCC_SEXPRTYPE_T 0x01
+#define ISCCC_SEXPRTYPE_STRING 0x02
+#define ISCCC_SEXPRTYPE_DOTTEDPAIR 0x03
+#define ISCCC_SEXPRTYPE_BINARY 0x04
+
+#define ISCCC_SEXPR_CAR(s) (s)->value.as_dottedpair.car
+#define ISCCC_SEXPR_CDR(s) (s)->value.as_dottedpair.cdr
+
+isccc_sexpr_t *
+isccc_sexpr_cons(isccc_sexpr_t *car, isccc_sexpr_t *cdr);
+
+isccc_sexpr_t *
+isccc_sexpr_tconst(void);
+
+isccc_sexpr_t *
+isccc_sexpr_fromstring(const char *str);
+
+isccc_sexpr_t *
+isccc_sexpr_frombinary(const isccc_region_t *region);
+
+void
+isccc_sexpr_free(isccc_sexpr_t **sexprp);
+
+void
+isccc_sexpr_print(isccc_sexpr_t *sexpr, FILE *stream);
+
+isccc_sexpr_t *
+isccc_sexpr_car(isccc_sexpr_t *list);
+
+isccc_sexpr_t *
+isccc_sexpr_cdr(isccc_sexpr_t *list);
+
+void
+isccc_sexpr_setcar(isccc_sexpr_t *pair, isccc_sexpr_t *car);
+
+void
+isccc_sexpr_setcdr(isccc_sexpr_t *pair, isccc_sexpr_t *cdr);
+
+isccc_sexpr_t *
+isccc_sexpr_addtolist(isccc_sexpr_t **l1p, isccc_sexpr_t *l2);
+
+isc_boolean_t
+isccc_sexpr_listp(isccc_sexpr_t *sexpr);
+
+isc_boolean_t
+isccc_sexpr_emptyp(isccc_sexpr_t *sexpr);
+
+isc_boolean_t
+isccc_sexpr_stringp(isccc_sexpr_t *sexpr);
+
+isc_boolean_t
+isccc_sexpr_binaryp(isccc_sexpr_t *sexpr);
+
+char *
+isccc_sexpr_tostring(isccc_sexpr_t *sexpr);
+
+isccc_region_t *
+isccc_sexpr_tobinary(isccc_sexpr_t *sexpr);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_SEXPR_H */
diff --git a/lib/isccc/include/isccc/symtab.h b/lib/isccc/include/isccc/symtab.h
new file mode 100644
index 0000000..5b11a01
--- /dev/null
+++ b/lib/isccc/include/isccc/symtab.h
@@ -0,0 +1,122 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: symtab.h,v 1.3.18.2 2005/04/29 00:17:14 marka Exp $ */
+
+#ifndef ISCCC_SYMTAB_H
+#define ISCCC_SYMTAB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Provides a simple memory-based symbol table.
+ *
+ * Keys are C strings. A type may be specified when looking up,
+ * defining, or undefining. A type value of 0 means "match any type";
+ * any other value will only match the given type.
+ *
+ * It's possible that a client will attempt to define a <key, type,
+ * value> tuple when a tuple with the given key and type already
+ * exists in the table. What to do in this case is specified by the
+ * client. Possible policies are:
+ *
+ *\li isccc_symexists_reject Disallow the define, returning #ISC_R_EXISTS
+ *\li isccc_symexists_replace Replace the old value with the new. The
+ * undefine action (if provided) will be called
+ * with the old <key, type, value> tuple.
+ *\li isccc_symexists_add Add the new tuple, leaving the old tuple in
+ * the table. Subsequent lookups will retrieve
+ * the most-recently-defined tuple.
+ *
+ * A lookup of a key using type 0 will return the most-recently
+ * defined symbol with that key. An undefine of a key using type 0
+ * will undefine the most-recently defined symbol with that key.
+ * Trying to define a key with type 0 is illegal.
+ *
+ * The symbol table library does not make a copy the key field, so the
+ * caller must ensure that any key it passes to isccc_symtab_define()
+ * will not change until it calls isccc_symtab_undefine() or
+ * isccc_symtab_destroy().
+ *
+ * A user-specified action will be called (if provided) when a symbol
+ * is undefined. It can be used to free memory associated with keys
+ * and/or values.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isccc/types.h>
+
+/***
+ *** Symbol Tables.
+ ***/
+
+typedef union isccc_symvalue {
+ void * as_pointer;
+ int as_integer;
+ unsigned int as_uinteger;
+} isccc_symvalue_t;
+
+typedef void (*isccc_symtabundefaction_t)(char *key, unsigned int type,
+ isccc_symvalue_t value, void *userarg);
+
+typedef isc_boolean_t (*isccc_symtabforeachaction_t)(char *key,
+ unsigned int type,
+ isccc_symvalue_t value,
+ void *userarg);
+
+typedef enum {
+ isccc_symexists_reject = 0,
+ isccc_symexists_replace = 1,
+ isccc_symexists_add = 2
+} isccc_symexists_t;
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isccc_symtab_create(unsigned int size,
+ isccc_symtabundefaction_t undefine_action, void *undefine_arg,
+ isc_boolean_t case_sensitive, isccc_symtab_t **symtabp);
+
+void
+isccc_symtab_destroy(isccc_symtab_t **symtabp);
+
+isc_result_t
+isccc_symtab_lookup(isccc_symtab_t *symtab, const char *key, unsigned int type,
+ isccc_symvalue_t *value);
+
+isc_result_t
+isccc_symtab_define(isccc_symtab_t *symtab, char *key, unsigned int type,
+ isccc_symvalue_t value, isccc_symexists_t exists_policy);
+
+isc_result_t
+isccc_symtab_undefine(isccc_symtab_t *symtab, const char *key, unsigned int type);
+
+void
+isccc_symtab_foreach(isccc_symtab_t *symtab, isccc_symtabforeachaction_t action,
+ void *arg);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCC_SYMTAB_H */
diff --git a/lib/isccc/include/isccc/symtype.h b/lib/isccc/include/isccc/symtype.h
new file mode 100644
index 0000000..e72ae92
--- /dev/null
+++ b/lib/isccc/include/isccc/symtype.h
@@ -0,0 +1,31 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: symtype.h,v 1.3.18.2 2005/04/29 00:17:14 marka Exp $ */
+
+#ifndef ISCCC_SYMTYPE_H
+#define ISCCC_SYMTYPE_H 1
+
+/*! \file */
+
+#define ISCCC_SYMTYPE_ZONESTATS 0x0001
+#define ISCCC_SYMTYPE_CCDUP 0x0002
+#define ISCCC_SYMTYPE_TELLSERVICE 0x0003
+#define ISCCC_SYMTYPE_TELLRESPONSE 0x0004
+
+#endif /* ISCCC_SYMTYPE_H */
diff --git a/lib/isccc/include/isccc/types.h b/lib/isccc/include/isccc/types.h
new file mode 100644
index 0000000..f46d257
--- /dev/null
+++ b/lib/isccc/include/isccc/types.h
@@ -0,0 +1,46 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: types.h,v 1.3.18.2 2005/04/29 00:17:14 marka Exp $ */
+
+#ifndef ISCCC_TYPES_H
+#define ISCCC_TYPES_H 1
+
+/*! \file */
+
+#include <isc/boolean.h>
+#include <isc/int.h>
+#include <isc/result.h>
+
+/*% isccc_time_t typedef */
+typedef isc_uint32_t isccc_time_t;
+
+/*% isccc_sexpr_t typedef */
+typedef struct isccc_sexpr isccc_sexpr_t;
+/*% isccc_dottedpair_t typedef */
+typedef struct isccc_dottedpair isccc_dottedpair_t;
+/*% isccc_symtab_t typedef */
+typedef struct isccc_symtab isccc_symtab_t;
+
+/*% iscc region structure */
+typedef struct isccc_region {
+ unsigned char * rstart;
+ unsigned char * rend;
+} isccc_region_t;
+
+#endif /* ISCCC_TYPES_H */
diff --git a/lib/isccc/include/isccc/util.h b/lib/isccc/include/isccc/util.h
new file mode 100644
index 0000000..7662483
--- /dev/null
+++ b/lib/isccc/include/isccc/util.h
@@ -0,0 +1,212 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 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.4.18.2 2005/04/29 00:17:14 marka Exp $ */
+
+#ifndef ISCCC_UTIL_H
+#define ISCCC_UTIL_H 1
+
+#include <isc/util.h>
+
+/*! \file
+ * \brief
+ * Macros for dealing with unaligned numbers.
+ *
+ * \note no side effects are allowed when invoking these macros!
+ */
+
+#define GET8(v, w) \
+ do { \
+ v = *w; \
+ w++; \
+ } while (0)
+
+#define GET16(v, w) \
+ do { \
+ v = (unsigned int)w[0] << 8; \
+ v |= (unsigned int)w[1]; \
+ w += 2; \
+ } while (0)
+
+#define GET24(v, w) \
+ do { \
+ v = (unsigned int)w[0] << 16; \
+ v |= (unsigned int)w[1] << 8; \
+ v |= (unsigned int)w[2]; \
+ w += 3; \
+ } while (0)
+
+#define GET32(v, w) \
+ do { \
+ v = (unsigned int)w[0] << 24; \
+ v |= (unsigned int)w[1] << 16; \
+ v |= (unsigned int)w[2] << 8; \
+ v |= (unsigned int)w[3]; \
+ w += 4; \
+ } while (0)
+
+#define GET64(v, w) \
+ do { \
+ v = (isc_uint64_t)w[0] << 56; \
+ v |= (isc_uint64_t)w[1] << 48; \
+ v |= (isc_uint64_t)w[2] << 40; \
+ v |= (isc_uint64_t)w[3] << 32; \
+ v |= (isc_uint64_t)w[4] << 24; \
+ v |= (isc_uint64_t)w[5] << 16; \
+ v |= (isc_uint64_t)w[6] << 8; \
+ v |= (isc_uint64_t)w[7]; \
+ w += 8; \
+ } while (0)
+
+#define GETC16(v, w, d) \
+ do { \
+ GET8(v, w); \
+ if (v == 0) \
+ d = ISCCC_TRUE; \
+ else { \
+ d = ISCCC_FALSE; \
+ if (v == 255) \
+ GET16(v, w); \
+ } \
+ } while (0)
+
+#define GETC32(v, w) \
+ do { \
+ GET24(v, w); \
+ if (v == 0xffffffu) \
+ GET32(v, w); \
+ } while (0)
+
+#define GET_OFFSET(v, w) GET32(v, w)
+
+#define GET_MEM(v, c, w) \
+ do { \
+ memcpy(v, w, c); \
+ w += c; \
+ } while (0)
+
+#define GET_TYPE(v, w) \
+ do { \
+ GET8(v, w); \
+ if (v > 127) { \
+ if (v < 255) \
+ v = ((v & 0x7f) << 16) | ISCCC_RDATATYPE_SIG; \
+ else \
+ GET32(v, w); \
+ } \
+ } while (0)
+
+#define PUT8(v, w) \
+ do { \
+ *w = (v & 0x000000ffU); \
+ w++; \
+ } while (0)
+
+#define PUT16(v, w) \
+ do { \
+ w[0] = (v & 0x0000ff00U) >> 8; \
+ w[1] = (v & 0x000000ffU); \
+ w += 2; \
+ } while (0)
+
+#define PUT24(v, w) \
+ do { \
+ w[0] = (v & 0x00ff0000U) >> 16; \
+ w[1] = (v & 0x0000ff00U) >> 8; \
+ w[2] = (v & 0x000000ffU); \
+ w += 3; \
+ } while (0)
+
+#define PUT32(v, w) \
+ do { \
+ w[0] = (v & 0xff000000U) >> 24; \
+ w[1] = (v & 0x00ff0000U) >> 16; \
+ w[2] = (v & 0x0000ff00U) >> 8; \
+ w[3] = (v & 0x000000ffU); \
+ w += 4; \
+ } while (0)
+
+#define PUT64(v, w) \
+ do { \
+ w[0] = (v & 0xff00000000000000ULL) >> 56; \
+ w[1] = (v & 0x00ff000000000000ULL) >> 48; \
+ w[2] = (v & 0x0000ff0000000000ULL) >> 40; \
+ w[3] = (v & 0x000000ff00000000ULL) >> 32; \
+ w[4] = (v & 0x00000000ff000000ULL) >> 24; \
+ w[5] = (v & 0x0000000000ff0000ULL) >> 16; \
+ w[6] = (v & 0x000000000000ff00ULL) >> 8; \
+ w[7] = (v & 0x00000000000000ffULL); \
+ w += 8; \
+ } while (0)
+
+#define PUTC16(v, w) \
+ do { \
+ if (v > 0 && v < 255) \
+ PUT8(v, w); \
+ else { \
+ PUT8(255, w); \
+ PUT16(v, w); \
+ } \
+ } while (0)
+
+#define PUTC32(v, w) \
+ do { \
+ if (v < 0xffffffU) \
+ PUT24(v, w); \
+ else { \
+ PUT24(0xffffffU, w); \
+ PUT32(v, w); \
+ } \
+ } while (0)
+
+#define PUT_OFFSET(v, w) PUT32(v, w)
+
+#include <string.h>
+
+#define PUT_MEM(s, c, w) \
+ do { \
+ memcpy(w, s, c); \
+ w += c; \
+ } while (0)
+
+/*
+ * Regions.
+ */
+#define REGION_SIZE(r) ((unsigned int)((r).rend - (r).rstart))
+#define REGION_EMPTY(r) ((r).rstart == (r).rend)
+#define REGION_FROMSTRING(r, s) do { \
+ (r).rstart = (unsigned char *)s; \
+ (r).rend = (r).rstart + strlen(s); \
+} while (0)
+
+/*%
+ * Use this to remove the const qualifier of a variable to assign it to
+ * a non-const variable or pass it as a non-const function argument ...
+ * but only when you are sure it won't then be changed!
+ * This is necessary to sometimes shut up some compilers
+ * (as with gcc -Wcast-qual) when there is just no other good way to avoid the
+ * situation.
+ */
+#define DE_CONST(konst, var) \
+ do { \
+ union { const void *k; void *v; } _u; \
+ _u.k = konst; \
+ var = _u.v; \
+ } while (0)
+
+#endif /* ISCCC_UTIL_H */
diff --git a/lib/isccc/include/isccc/version.h b/lib/isccc/include/isccc/version.h
new file mode 100644
index 0000000..b82ed8b
--- /dev/null
+++ b/lib/isccc/include/isccc/version.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005 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: version.h,v 1.3.18.2 2005/04/29 00:17:15 marka Exp $ */
+
+/*! \file */
+
+#include <isc/platform.h>
+
+LIBISCCC_EXTERNAL_DATA extern const char isccc_version[];
+
+LIBISCCC_EXTERNAL_DATA extern const unsigned int isccc_libinterface;
+LIBISCCC_EXTERNAL_DATA extern const unsigned int isccc_librevision;
+LIBISCCC_EXTERNAL_DATA extern const unsigned int isccc_libage;
diff --git a/lib/isccc/lib.c b/lib/isccc/lib.c
new file mode 100644
index 0000000..bef2d9a
--- /dev/null
+++ b/lib/isccc/lib.c
@@ -0,0 +1,65 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lib.c,v 1.4.18.2 2005/04/29 00:17:12 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/once.h>
+#include <isc/msgcat.h>
+#include <isc/util.h>
+
+#include <isccc/lib.h>
+
+/***
+ *** Globals
+ ***/
+
+LIBISCCC_EXTERNAL_DATA isc_msgcat_t * isccc_msgcat = NULL;
+
+
+/***
+ *** Private
+ ***/
+
+static isc_once_t msgcat_once = ISC_ONCE_INIT;
+
+
+/***
+ *** Functions
+ ***/
+
+static void
+open_msgcat(void) {
+ isc_msgcat_open("libisccc.cat", &isccc_msgcat);
+}
+
+void
+isccc_lib_initmsgcat(void) {
+
+ /*
+ * Initialize the DNS library's message catalog, isccc_msgcat, if it
+ * has not already been initialized.
+ */
+
+ RUNTIME_CHECK(isc_once_do(&msgcat_once, open_msgcat) == ISC_R_SUCCESS);
+}
diff --git a/lib/isccc/result.c b/lib/isccc/result.c
new file mode 100644
index 0000000..974e51b
--- /dev/null
+++ b/lib/isccc/result.c
@@ -0,0 +1,72 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001, 2003 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: result.c,v 1.5.18.2 2005/04/29 00:17:12 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/once.h>
+#include <isc/util.h>
+
+#include <isccc/result.h>
+#include <isccc/lib.h>
+
+static const char *text[ISCCC_R_NRESULTS] = {
+ "unknown version", /* 1 */
+ "syntax error", /* 2 */
+ "bad auth", /* 3 */
+ "expired", /* 4 */
+ "clock skew", /* 5 */
+ "duplicate" /* 6 */
+};
+
+#define ISCCC_RESULT_RESULTSET 2
+
+static isc_once_t once = ISC_ONCE_INIT;
+
+static void
+initialize_action(void) {
+ isc_result_t result;
+
+ result = isc_result_register(ISC_RESULTCLASS_ISCCC, ISCCC_R_NRESULTS,
+ text, isccc_msgcat,
+ ISCCC_RESULT_RESULTSET);
+ if (result != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_result_register() failed: %u", result);
+}
+
+static void
+initialize(void) {
+ isccc_lib_initmsgcat();
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+const char *
+isccc_result_totext(isc_result_t result) {
+ initialize();
+
+ return (isc_result_totext(result));
+}
+
+void
+isccc_result_register(void) {
+ initialize();
+}
diff --git a/lib/isccc/sexpr.c b/lib/isccc/sexpr.c
new file mode 100644
index 0000000..573a63c
--- /dev/null
+++ b/lib/isccc/sexpr.c
@@ -0,0 +1,312 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 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 ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: sexpr.c,v 1.4.18.2 2005/04/29 00:17:12 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/assertions.h>
+#include <isccc/sexpr.h>
+#include <isccc/util.h>
+
+static isccc_sexpr_t sexpr_t = { ISCCC_SEXPRTYPE_T, { NULL } };
+
+#define CAR(s) (s)->value.as_dottedpair.car
+#define CDR(s) (s)->value.as_dottedpair.cdr
+
+isccc_sexpr_t *
+isccc_sexpr_cons(isccc_sexpr_t *car, isccc_sexpr_t *cdr)
+{
+ isccc_sexpr_t *sexpr;
+
+ sexpr = malloc(sizeof(*sexpr));
+ if (sexpr == NULL)
+ return (NULL);
+ sexpr->type = ISCCC_SEXPRTYPE_DOTTEDPAIR;
+ CAR(sexpr) = car;
+ CDR(sexpr) = cdr;
+
+ return (sexpr);
+}
+
+isccc_sexpr_t *
+isccc_sexpr_tconst(void)
+{
+ return (&sexpr_t);
+}
+
+isccc_sexpr_t *
+isccc_sexpr_fromstring(const char *str)
+{
+ isccc_sexpr_t *sexpr;
+
+ sexpr = malloc(sizeof(*sexpr));
+ if (sexpr == NULL)
+ return (NULL);
+ sexpr->type = ISCCC_SEXPRTYPE_STRING;
+ sexpr->value.as_string = strdup(str);
+ if (sexpr->value.as_string == NULL) {
+ free(sexpr);
+ return (NULL);
+ }
+
+ return (sexpr);
+}
+
+isccc_sexpr_t *
+isccc_sexpr_frombinary(const isccc_region_t *region)
+{
+ isccc_sexpr_t *sexpr;
+ unsigned int region_size;
+
+ sexpr = malloc(sizeof(*sexpr));
+ if (sexpr == NULL)
+ return (NULL);
+ sexpr->type = ISCCC_SEXPRTYPE_BINARY;
+ region_size = REGION_SIZE(*region);
+ /*
+ * We add an extra byte when we malloc so we can NUL terminate
+ * the binary data. This allows the caller to use it as a C
+ * string. It's up to the caller to ensure this is safe. We don't
+ * add 1 to the length of the binary region, because the NUL is
+ * not part of the binary data.
+ */
+ sexpr->value.as_region.rstart = malloc(region_size + 1);
+ if (sexpr->value.as_region.rstart == NULL) {
+ free(sexpr);
+ return (NULL);
+ }
+ sexpr->value.as_region.rend = sexpr->value.as_region.rstart +
+ region_size;
+ memcpy(sexpr->value.as_region.rstart, region->rstart, region_size);
+ /*
+ * NUL terminate.
+ */
+ sexpr->value.as_region.rstart[region_size] = '\0';
+
+ return (sexpr);
+}
+
+void
+isccc_sexpr_free(isccc_sexpr_t **sexprp)
+{
+ isccc_sexpr_t *sexpr;
+ isccc_sexpr_t *item;
+
+ sexpr = *sexprp;
+ if (sexpr == NULL)
+ return;
+ switch (sexpr->type) {
+ case ISCCC_SEXPRTYPE_STRING:
+ free(sexpr->value.as_string);
+ break;
+ case ISCCC_SEXPRTYPE_DOTTEDPAIR:
+ item = CAR(sexpr);
+ if (item != NULL)
+ isccc_sexpr_free(&item);
+ item = CDR(sexpr);
+ if (item != NULL)
+ isccc_sexpr_free(&item);
+ break;
+ case ISCCC_SEXPRTYPE_BINARY:
+ free(sexpr->value.as_region.rstart);
+ break;
+ }
+ free(sexpr);
+
+ *sexprp = NULL;
+}
+
+static isc_boolean_t
+printable(isccc_region_t *r)
+{
+ unsigned char *curr;
+
+ curr = r->rstart;
+ while (curr != r->rend) {
+ if (!isprint(*curr))
+ return (ISC_FALSE);
+ curr++;
+ }
+
+ return (ISC_TRUE);
+}
+
+void
+isccc_sexpr_print(isccc_sexpr_t *sexpr, FILE *stream)
+{
+ isccc_sexpr_t *cdr;
+ unsigned int size, i;
+ unsigned char *curr;
+
+ if (sexpr == NULL) {
+ fprintf(stream, "nil");
+ return;
+ }
+
+ switch (sexpr->type) {
+ case ISCCC_SEXPRTYPE_T:
+ fprintf(stream, "t");
+ break;
+ case ISCCC_SEXPRTYPE_STRING:
+ fprintf(stream, "\"%s\"", sexpr->value.as_string);
+ break;
+ case ISCCC_SEXPRTYPE_DOTTEDPAIR:
+ fprintf(stream, "(");
+ do {
+ isccc_sexpr_print(CAR(sexpr), stream);
+ cdr = CDR(sexpr);
+ if (cdr != NULL) {
+ fprintf(stream, " ");
+ if (cdr->type != ISCCC_SEXPRTYPE_DOTTEDPAIR) {
+ fprintf(stream, ". ");
+ isccc_sexpr_print(cdr, stream);
+ cdr = NULL;
+ }
+ }
+ sexpr = cdr;
+ } while (sexpr != NULL);
+ fprintf(stream, ")");
+ break;
+ case ISCCC_SEXPRTYPE_BINARY:
+ size = REGION_SIZE(sexpr->value.as_region);
+ curr = sexpr->value.as_region.rstart;
+ if (printable(&sexpr->value.as_region)) {
+ fprintf(stream, "'%.*s'", (int)size, curr);
+ } else {
+ fprintf(stream, "0x");
+ for (i = 0; i < size; i++)
+ fprintf(stream, "%02x", *curr++);
+ }
+ break;
+ default:
+ INSIST(0);
+ }
+}
+
+isccc_sexpr_t *
+isccc_sexpr_car(isccc_sexpr_t *list)
+{
+ REQUIRE(list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+
+ return (CAR(list));
+}
+
+isccc_sexpr_t *
+isccc_sexpr_cdr(isccc_sexpr_t *list)
+{
+ REQUIRE(list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+
+ return (CDR(list));
+}
+
+void
+isccc_sexpr_setcar(isccc_sexpr_t *pair, isccc_sexpr_t *car)
+{
+ REQUIRE(pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+
+ CAR(pair) = car;
+}
+
+void
+isccc_sexpr_setcdr(isccc_sexpr_t *pair, isccc_sexpr_t *cdr)
+{
+ REQUIRE(pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+
+ CDR(pair) = cdr;
+}
+
+isccc_sexpr_t *
+isccc_sexpr_addtolist(isccc_sexpr_t **l1p, isccc_sexpr_t *l2)
+{
+ isccc_sexpr_t *last, *elt, *l1;
+
+ REQUIRE(l1p != NULL);
+ l1 = *l1p;
+ REQUIRE(l1 == NULL || l1->type == ISCCC_SEXPRTYPE_DOTTEDPAIR);
+
+ elt = isccc_sexpr_cons(l2, NULL);
+ if (elt == NULL)
+ return (NULL);
+ if (l1 == NULL) {
+ *l1p = elt;
+ return (elt);
+ }
+ for (last = l1; CDR(last) != NULL; last = CDR(last))
+ /* Nothing */;
+ CDR(last) = elt;
+
+ return (elt);
+}
+
+isc_boolean_t
+isccc_sexpr_listp(isccc_sexpr_t *sexpr)
+{
+ if (sexpr == NULL || sexpr->type == ISCCC_SEXPRTYPE_DOTTEDPAIR)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+isccc_sexpr_emptyp(isccc_sexpr_t *sexpr)
+{
+ if (sexpr == NULL)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+isccc_sexpr_stringp(isccc_sexpr_t *sexpr)
+{
+ if (sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_STRING)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+isc_boolean_t
+isccc_sexpr_binaryp(isccc_sexpr_t *sexpr)
+{
+ if (sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_BINARY)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+char *
+isccc_sexpr_tostring(isccc_sexpr_t *sexpr)
+{
+ REQUIRE(sexpr != NULL &&
+ (sexpr->type == ISCCC_SEXPRTYPE_STRING ||
+ sexpr->type == ISCCC_SEXPRTYPE_BINARY));
+
+ if (sexpr->type == ISCCC_SEXPRTYPE_BINARY)
+ return ((char *)sexpr->value.as_region.rstart);
+ return (sexpr->value.as_string);
+}
+
+isccc_region_t *
+isccc_sexpr_tobinary(isccc_sexpr_t *sexpr)
+{
+ REQUIRE(sexpr != NULL && sexpr->type == ISCCC_SEXPRTYPE_BINARY);
+ return (&sexpr->value.as_region);
+}
diff --git a/lib/isccc/symtab.c b/lib/isccc/symtab.c
new file mode 100644
index 0000000..7ec6d55
--- /dev/null
+++ b/lib/isccc/symtab.c
@@ -0,0 +1,280 @@
+/*
+ * Portions Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2001 Internet Software Consortium.
+ * Portions Copyright (C) 2001 Nominum, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: symtab.c,v 1.5.18.4 2007/09/13 23:46:26 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include <isc/assertions.h>
+#include <isc/magic.h>
+#include <isc/string.h>
+
+#include <isccc/result.h>
+#include <isccc/symtab.h>
+#include <isccc/util.h>
+
+typedef struct elt {
+ char * key;
+ unsigned int type;
+ isccc_symvalue_t value;
+ ISC_LINK(struct elt) link;
+} elt_t;
+
+typedef ISC_LIST(elt_t) eltlist_t;
+
+#define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T')
+#define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
+
+struct isccc_symtab {
+ unsigned int magic;
+ unsigned int size;
+ eltlist_t * table;
+ isccc_symtabundefaction_t undefine_action;
+ void * undefine_arg;
+ isc_boolean_t case_sensitive;
+};
+
+isc_result_t
+isccc_symtab_create(unsigned int size,
+ isccc_symtabundefaction_t undefine_action,
+ void *undefine_arg,
+ isc_boolean_t case_sensitive,
+ isccc_symtab_t **symtabp)
+{
+ isccc_symtab_t *symtab;
+ unsigned int i;
+
+ REQUIRE(symtabp != NULL && *symtabp == NULL);
+ REQUIRE(size > 0); /* Should be prime. */
+
+ symtab = malloc(sizeof(*symtab));
+ if (symtab == NULL)
+ return (ISC_R_NOMEMORY);
+ symtab->table = malloc(size * sizeof(eltlist_t));
+ if (symtab->table == NULL) {
+ free(symtab);
+ return (ISC_R_NOMEMORY);
+ }
+ for (i = 0; i < size; i++)
+ ISC_LIST_INIT(symtab->table[i]);
+ symtab->size = size;
+ symtab->undefine_action = undefine_action;
+ symtab->undefine_arg = undefine_arg;
+ symtab->case_sensitive = case_sensitive;
+ symtab->magic = SYMTAB_MAGIC;
+
+ *symtabp = symtab;
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+free_elt(isccc_symtab_t *symtab, unsigned int bucket, elt_t *elt) {
+ ISC_LIST_UNLINK(symtab->table[bucket], elt, link);
+ if (symtab->undefine_action != NULL)
+ (symtab->undefine_action)(elt->key, elt->type, elt->value,
+ symtab->undefine_arg);
+ free(elt);
+}
+
+void
+isccc_symtab_destroy(isccc_symtab_t **symtabp) {
+ isccc_symtab_t *symtab;
+ unsigned int i;
+ elt_t *elt, *nelt;
+
+ REQUIRE(symtabp != NULL);
+ symtab = *symtabp;
+ REQUIRE(VALID_SYMTAB(symtab));
+
+ for (i = 0; i < symtab->size; i++) {
+ for (elt = ISC_LIST_HEAD(symtab->table[i]);
+ elt != NULL;
+ elt = nelt) {
+ nelt = ISC_LIST_NEXT(elt, link);
+ free_elt(symtab, i, elt);
+ }
+ }
+ free(symtab->table);
+ symtab->magic = 0;
+ free(symtab);
+
+ *symtabp = NULL;
+}
+
+static inline unsigned int
+hash(const char *key, isc_boolean_t case_sensitive) {
+ const char *s;
+ unsigned int h = 0;
+ unsigned int g;
+ int c;
+
+ /*
+ * P. J. Weinberger's hash function, adapted from p. 436 of
+ * _Compilers: Principles, Techniques, and Tools_, Aho, Sethi
+ * and Ullman, Addison-Wesley, 1986, ISBN 0-201-10088-6.
+ */
+
+ if (case_sensitive) {
+ for (s = key; *s != '\0'; s++) {
+ h = ( h << 4 ) + *s;
+ if ((g = ( h & 0xf0000000 )) != 0) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ } else {
+ for (s = key; *s != '\0'; s++) {
+ c = *s;
+ c = tolower((unsigned char)c);
+ h = ( h << 4 ) + c;
+ if ((g = ( h & 0xf0000000 )) != 0) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ }
+
+ return (h);
+}
+
+#define FIND(s, k, t, b, e) \
+ b = hash((k), (s)->case_sensitive) % (s)->size; \
+ if ((s)->case_sensitive) { \
+ for (e = ISC_LIST_HEAD((s)->table[b]); \
+ e != NULL; \
+ e = ISC_LIST_NEXT(e, link)) { \
+ if (((t) == 0 || e->type == (t)) && \
+ strcmp(e->key, (k)) == 0) \
+ break; \
+ } \
+ } else { \
+ for (e = ISC_LIST_HEAD((s)->table[b]); \
+ e != NULL; \
+ e = ISC_LIST_NEXT(e, link)) { \
+ if (((t) == 0 || e->type == (t)) && \
+ strcasecmp(e->key, (k)) == 0) \
+ break; \
+ } \
+ }
+
+isc_result_t
+isccc_symtab_lookup(isccc_symtab_t *symtab, const char *key, unsigned int type,
+ isccc_symvalue_t *value)
+{
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (elt == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (value != NULL)
+ *value = elt->value;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isccc_symtab_define(isccc_symtab_t *symtab, char *key, unsigned int type,
+ isccc_symvalue_t value, isccc_symexists_t exists_policy)
+{
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+ REQUIRE(type != 0);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (exists_policy != isccc_symexists_add && elt != NULL) {
+ if (exists_policy == isccc_symexists_reject)
+ return (ISC_R_EXISTS);
+ INSIST(exists_policy == isccc_symexists_replace);
+ ISC_LIST_UNLINK(symtab->table[bucket], elt, link);
+ if (symtab->undefine_action != NULL)
+ (symtab->undefine_action)(elt->key, elt->type,
+ elt->value,
+ symtab->undefine_arg);
+ } else {
+ elt = malloc(sizeof(*elt));
+ if (elt == NULL)
+ return (ISC_R_NOMEMORY);
+ ISC_LINK_INIT(elt, link);
+ }
+
+ elt->key = key;
+ elt->type = type;
+ elt->value = value;
+
+ /*
+ * We prepend so that the most recent definition will be found.
+ */
+ ISC_LIST_PREPEND(symtab->table[bucket], elt, link);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isccc_symtab_undefine(isccc_symtab_t *symtab, const char *key, unsigned int type) {
+ unsigned int bucket;
+ elt_t *elt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(key != NULL);
+
+ FIND(symtab, key, type, bucket, elt);
+
+ if (elt == NULL)
+ return (ISC_R_NOTFOUND);
+
+ free_elt(symtab, bucket, elt);
+
+ return (ISC_R_SUCCESS);
+}
+
+void
+isccc_symtab_foreach(isccc_symtab_t *symtab, isccc_symtabforeachaction_t action,
+ void *arg)
+{
+ unsigned int i;
+ elt_t *elt, *nelt;
+
+ REQUIRE(VALID_SYMTAB(symtab));
+ REQUIRE(action != NULL);
+
+ for (i = 0; i < symtab->size; i++) {
+ for (elt = ISC_LIST_HEAD(symtab->table[i]);
+ elt != NULL;
+ elt = nelt) {
+ nelt = ISC_LIST_NEXT(elt, link);
+ if ((action)(elt->key, elt->type, elt->value, arg))
+ free_elt(symtab, i, elt);
+ }
+ }
+}
diff --git a/lib/isccc/version.c b/lib/isccc/version.c
new file mode 100644
index 0000000..0d65dcb
--- /dev/null
+++ b/lib/isccc/version.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: version.c,v 1.3.18.2 2005/04/29 00:17:12 marka Exp $ */
+
+/*! \file */
+
+#include <isccc/version.h>
+
+const char isccc_version[] = VERSION;
+
+const unsigned int isccc_libinterface = LIBINTERFACE;
+const unsigned int isccc_librevision = LIBREVISION;
+const unsigned int isccc_libage = LIBAGE;
diff --git a/lib/isccfg/Makefile.in b/lib/isccfg/Makefile.in
new file mode 100644
index 0000000..7d19123
--- /dev/null
+++ b/lib/isccfg/Makefile.in
@@ -0,0 +1,83 @@
+# Copyright (C) 2004, 2005 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: Makefile.in,v 1.12.18.4 2005/09/05 00:18:30 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+@LIBISCCFG_API@
+
+@BIND9_MAKE_INCLUDES@
+
+CINCLUDES = -I. ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES}
+
+CDEFINES = @USE_DLZ@
+CWARNINGS =
+
+ISCLIBS = ../../lib/isc/libisc.@A@
+ISCCCLIBS = ../../lib/isccc/libisccc.@A@
+DNSLIBS = ../../lib/dns/libdns.@A@
+ISCCFGLIBS = ../../lib/cfg/libisccfg.@A@
+
+ISCDEPLIBS = ../../lib/isc/libisc.@A@
+ISCCFGDEPLIBS = libisccfg.@A@
+
+LIBS = @LIBS@
+
+SUBDIRS = include
+
+# Alphabetically
+OBJS = aclconf.@O@ log.@O@ namedconf.@O@ parser.@O@ version.@O@
+
+# Alphabetically
+SRCS = aclconf.c log.c namedconf.c parser.c version.c
+
+TARGETS = timestamp
+
+@BIND9_MAKE_RULES@
+
+version.@O@: version.c
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \
+ -DVERSION=\"${VERSION}\" \
+ -DLIBINTERFACE=${LIBINTERFACE} \
+ -DLIBREVISION=${LIBREVISION} \
+ -DLIBAGE=${LIBAGE} \
+ -c ${srcdir}/version.c
+
+libisccfg.@SA@: ${OBJS}
+ ${AR} ${ARFLAGS} $@ ${OBJS}
+ ${RANLIB} $@
+
+libisccfg.la: ${OBJS}
+ ${LIBTOOL_MODE_LINK} \
+ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisccfg.la -rpath ${libdir} \
+ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ ${OBJS} ${LIBS} ${DNSLIBS} ${ISCCCLIBS} ${ISCLIBS}
+
+timestamp: libisccfg.@A@
+ touch timestamp
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+
+install:: timestamp installdirs
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libisccfg.@A@ ${DESTDIR}${libdir}
+
+clean distclean::
+ rm -f libisccfg.@A@ timestamp
diff --git a/lib/isccfg/aclconf.c b/lib/isccfg/aclconf.c
new file mode 100644
index 0000000..d7b41ce
--- /dev/null
+++ b/lib/isccfg/aclconf.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2004-2006 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: aclconf.c,v 1.2.2.6 2006/03/02 00:37:22 marka Exp $ */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/util.h>
+
+#include <isccfg/namedconf.h>
+#include <isccfg/aclconf.h>
+
+#include <dns/acl.h>
+#include <dns/fixedname.h>
+#include <dns/log.h>
+
+#define LOOP_MAGIC ISC_MAGIC('L','O','O','P')
+
+void
+cfg_aclconfctx_init(cfg_aclconfctx_t *ctx) {
+ ISC_LIST_INIT(ctx->named_acl_cache);
+}
+
+void
+cfg_aclconfctx_destroy(cfg_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(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
+ isc_result_t result;
+ const cfg_obj_t *acls = NULL;
+ const 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)) {
+ const 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(const cfg_obj_t *nameobj, const cfg_obj_t *cctx,
+ isc_log_t *lctx, cfg_aclconfctx_t *ctx,
+ isc_mem_t *mctx, dns_acl_t **target)
+{
+ isc_result_t result;
+ const cfg_obj_t *cacl = NULL;
+ dns_acl_t *dacl;
+ dns_acl_t loop;
+ const 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) {
+ if (ISC_MAGIC_VALID(dacl, LOOP_MAGIC)) {
+ cfg_obj_log(nameobj, lctx, ISC_LOG_ERROR,
+ "acl loop detected: %s", aclname);
+ return (ISC_R_FAILURE);
+ }
+ 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, lctx, ISC_LOG_WARNING,
+ "undefined ACL '%s'", aclname);
+ return (result);
+ }
+ /*
+ * Add a loop detection element.
+ */
+ memset(&loop, 0, sizeof(loop));
+ ISC_LINK_INIT(&loop, nextincache);
+ DE_CONST(aclname, loop.name);
+ loop.magic = LOOP_MAGIC;
+ ISC_LIST_APPEND(ctx->named_acl_cache, &loop, nextincache);
+ result = cfg_acl_fromconfig(cacl, cctx, lctx, ctx, mctx, &dacl);
+ ISC_LIST_UNLINK(ctx->named_acl_cache, &loop, nextincache);
+ loop.magic = 0;
+ loop.name = NULL;
+ 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(const cfg_obj_t *keyobj, isc_log_t *lctx, 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, 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
+cfg_acl_fromconfig(const cfg_obj_t *caml,
+ const cfg_obj_t *cctx,
+ isc_log_t *lctx,
+ cfg_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;
+ const 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))
+ {
+ const 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, lctx, 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 = cfg_acl_fromconfig(ce, cctx, lctx, ctx,
+ mctx, &de->u.nestedacl);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ } else if (cfg_obj_isstring(ce)) {
+ /* ACL name */
+ const 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, lctx,
+ ctx, mctx,
+ &de->u.nestedacl);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ }
+ } else {
+ cfg_obj_log(ce, 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/lib/isccfg/api b/lib/isccfg/api
new file mode 100644
index 0000000..aba393a
--- /dev/null
+++ b/lib/isccfg/api
@@ -0,0 +1,3 @@
+LIBINTERFACE = 30
+LIBREVISION = 3
+LIBAGE = 0
diff --git a/lib/isccfg/include/Makefile.in b/lib/isccfg/include/Makefile.in
new file mode 100644
index 0000000..4eddd92
--- /dev/null
+++ b/lib/isccfg/include/Makefile.in
@@ -0,0 +1,25 @@
+# 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: Makefile.in,v 1.5 2004/03/05 05:12:24 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isccfg
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isccfg/include/isccfg/Makefile.in b/lib/isccfg/include/isccfg/Makefile.in
new file mode 100644
index 0000000..d71d2c2
--- /dev/null
+++ b/lib/isccfg/include/isccfg/Makefile.in
@@ -0,0 +1,42 @@
+# Copyright (C) 2004, 2005 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: Makefile.in,v 1.8.18.2 2005/01/12 01:54:57 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+#
+# Only list headers that are to be installed and are not
+# machine generated. The latter are handled specially in the
+# install target below.
+#
+HEADERS = aclconf.h cfg.h grammar.h log.h namedconf.h version.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/isccfg
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/isccfg ; \
+ done
diff --git a/lib/isccfg/include/isccfg/aclconf.h b/lib/isccfg/include/isccfg/aclconf.h
new file mode 100644
index 0000000..a13740c
--- /dev/null
+++ b/lib/isccfg/include/isccfg/aclconf.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2004-2006 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.2.2.5 2006/03/02 00:37:22 marka Exp $ */
+
+#ifndef ISCCFG_ACLCONF_H
+#define ISCCFG_ACLCONF_H 1
+
+#include <isc/lang.h>
+
+#include <isccfg/cfg.h>
+
+#include <dns/types.h>
+
+typedef struct cfg_aclconfctx {
+ ISC_LIST(dns_acl_t) named_acl_cache;
+} cfg_aclconfctx_t;
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+void
+cfg_aclconfctx_init(cfg_aclconfctx_t *ctx);
+/*
+ * Initialize an ACL configuration context.
+ */
+
+void
+cfg_aclconfctx_destroy(cfg_aclconfctx_t *ctx);
+/*
+ * Destroy an ACL configuration context.
+ */
+
+isc_result_t
+cfg_acl_fromconfig(const cfg_obj_t *caml,
+ const cfg_obj_t *cctx,
+ isc_log_t *lctx,
+ cfg_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
+ * into 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 /* ISCCFG_ACLCONF_H */
diff --git a/lib/isccfg/include/isccfg/cfg.h b/lib/isccfg/include/isccfg/cfg.h
new file mode 100644
index 0000000..6a30a1c
--- /dev/null
+++ b/lib/isccfg/include/isccfg/cfg.h
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2004-2006 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: cfg.h,v 1.34.18.5 2006/03/02 00:37:22 marka Exp $ */
+
+#ifndef ISCCFG_CFG_H
+#define ISCCFG_CFG_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * This is the new, table-driven, YACC-free configuration file parser.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+#include <isc/types.h>
+#include <isc/list.h>
+
+
+/***
+ *** Types
+ ***/
+
+/*%
+ * A configuration parser.
+ */
+typedef struct cfg_parser cfg_parser_t;
+
+/*%
+ * A configuration type definition object. There is a single
+ * static cfg_type_t object for each data type supported by
+ * the configuration parser.
+ */
+typedef struct cfg_type cfg_type_t;
+
+/*%
+ * A configuration object. This is the basic building block of the
+ * configuration parse tree. It contains a value (which may be
+ * of one of several types) and information identifying the file
+ * and line number the value came from, for printing error
+ * messages.
+ */
+typedef struct cfg_obj cfg_obj_t;
+
+/*%
+ * A configuration object list element.
+ */
+typedef struct cfg_listelt cfg_listelt_t;
+
+/*%
+ * A callback function to be called when parsing an option
+ * that needs to be interpreted at parsing time, like
+ * "directory".
+ */
+typedef isc_result_t
+(*cfg_parsecallback_t)(const char *clausename, const cfg_obj_t *obj, void *arg);
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret);
+/*%<
+ * Create a configuration file parser. Any warning and error
+ * messages will be logged to 'lctx'.
+ *
+ * The parser object returned can be used for a single call
+ * to cfg_parse_file() or cfg_parse_buffer(). It must not
+ * be reused for parsing multiple files or buffers.
+ */
+
+void
+cfg_parser_setcallback(cfg_parser_t *pctx,
+ cfg_parsecallback_t callback,
+ void *arg);
+/*%<
+ * Make the parser call 'callback' whenever it encounters
+ * a configuration clause with the callback attribute,
+ * passing it the clause name, the clause value,
+ * and 'arg' as arguments.
+ *
+ * To restore the default of not invoking callbacks, pass
+ * callback==NULL and arg==NULL.
+ */
+
+isc_result_t
+cfg_parse_file(cfg_parser_t *pctx, const char *filename,
+ const cfg_type_t *type, cfg_obj_t **ret);
+isc_result_t
+cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer,
+ const cfg_type_t *type, cfg_obj_t **ret);
+/*%<
+ * Read a configuration containing data of type 'type'
+ * and make '*ret' point to its parse tree.
+ *
+ * The configuration is read from the file 'filename'
+ * (isc_parse_file()) or the buffer 'buffer'
+ * (isc_parse_buffer()).
+ *
+ * Returns an error if the file does not parse correctly.
+ *
+ * Requires:
+ *\li "filename" is valid.
+ *\li "mem" is valid.
+ *\li "type" is valid.
+ *\li "cfg" is non-NULL and "*cfg" is NULL.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS - success
+ *\li #ISC_R_NOMEMORY - no memory available
+ *\li #ISC_R_INVALIDFILE - file doesn't exist or is unreadable
+ *\li others - file contains errors
+ */
+
+void
+cfg_parser_destroy(cfg_parser_t **pctxp);
+/*%<
+ * Destroy a configuration parser.
+ */
+
+isc_boolean_t
+cfg_obj_isvoid(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of void type (e.g., an optional
+ * value not specified).
+ */
+
+isc_boolean_t
+cfg_obj_ismap(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of a map type.
+ */
+
+isc_result_t
+cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj);
+/*%<
+ * Extract an element from a configuration object, which
+ * must be of a map type.
+ *
+ * Requires:
+ * \li 'mapobj' points to a valid configuration object of a map type.
+ * \li 'name' points to a null-terminated string.
+ * \li 'obj' is non-NULL and '*obj' is NULL.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS - success
+ * \li #ISC_R_NOTFOUND - name not found in map
+ */
+
+const cfg_obj_t *
+cfg_map_getname(const cfg_obj_t *mapobj);
+/*%<
+ * Get the name of a named map object, like a server "key" clause.
+ *
+ * Requires:
+ * \li 'mapobj' points to a valid configuration object of a map type.
+ *
+ * Returns:
+ * \li A pointer to a configuration object naming the map object,
+ * or NULL if the map object does not have a name.
+ */
+
+isc_boolean_t
+cfg_obj_istuple(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of a map type.
+ */
+
+const cfg_obj_t *
+cfg_tuple_get(const cfg_obj_t *tupleobj, const char *name);
+/*%<
+ * Extract an element from a configuration object, which
+ * must be of a tuple type.
+ *
+ * Requires:
+ * \li 'tupleobj' points to a valid configuration object of a tuple type.
+ * \li 'name' points to a null-terminated string naming one of the
+ *\li fields of said tuple type.
+ */
+
+isc_boolean_t
+cfg_obj_isuint32(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of integer type.
+ */
+
+isc_uint32_t
+cfg_obj_asuint32(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object of 32-bit integer type.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of 32-bit integer type.
+ *
+ * Returns:
+ * \li A 32-bit unsigned integer.
+ */
+
+isc_boolean_t
+cfg_obj_isuint64(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of integer type.
+ */
+
+isc_uint64_t
+cfg_obj_asuint64(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object of 64-bit integer type.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of 64-bit integer type.
+ *
+ * Returns:
+ * \li A 64-bit unsigned integer.
+ */
+
+isc_boolean_t
+cfg_obj_isstring(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of string type.
+ */
+
+const char *
+cfg_obj_asstring(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object of a string type
+ * as a null-terminated string.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of a string type.
+ *
+ * Returns:
+ * \li A pointer to a null terminated string.
+ */
+
+isc_boolean_t
+cfg_obj_isboolean(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of a boolean type.
+ */
+
+isc_boolean_t
+cfg_obj_asboolean(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object of a boolean type.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of a boolean type.
+ *
+ * Returns:
+ * \li A boolean value.
+ */
+
+isc_boolean_t
+cfg_obj_issockaddr(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is a socket address.
+ */
+
+const isc_sockaddr_t *
+cfg_obj_assockaddr(const cfg_obj_t *obj);
+/*%<
+ * Returns the value of a configuration object representing a socket address.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of a socket address type.
+ *
+ * Returns:
+ * \li A pointer to a sockaddr. The sockaddr must be copied by the caller
+ * if necessary.
+ */
+
+isc_boolean_t
+cfg_obj_isnetprefix(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is a network prefix.
+ */
+
+void
+cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr,
+ unsigned int *prefixlen);
+/*%<
+ * Gets the value of a configuration object representing a network
+ * prefix. The network address is returned through 'netaddr' and the
+ * prefix length in bits through 'prefixlen'.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of network prefix type.
+ *\li 'netaddr' and 'prefixlen' are non-NULL.
+ */
+
+isc_boolean_t
+cfg_obj_islist(const cfg_obj_t *obj);
+/*%<
+ * Return true iff 'obj' is of list type.
+ */
+
+const cfg_listelt_t *
+cfg_list_first(const cfg_obj_t *obj);
+/*%<
+ * Returns the first list element in a configuration object of a list type.
+ *
+ * Requires:
+ * \li 'obj' points to a valid configuration object of a list type or NULL.
+ *
+ * Returns:
+ * \li A pointer to a cfg_listelt_t representing the first list element,
+ * or NULL if the list is empty or nonexistent.
+ */
+
+const cfg_listelt_t *
+cfg_list_next(const cfg_listelt_t *elt);
+/*%<
+ * Returns the next element of a list of configuration objects.
+ *
+ * Requires:
+ * \li 'elt' points to cfg_listelt_t obtained from cfg_list_first() or
+ * a previous call to cfg_list_next().
+ *
+ * Returns:
+ * \li A pointer to a cfg_listelt_t representing the next element,
+ * or NULL if there are no more elements.
+ */
+
+const cfg_obj_t *
+cfg_listelt_value(const cfg_listelt_t *elt);
+/*%<
+ * Returns the configuration object associated with cfg_listelt_t.
+ *
+ * Requires:
+ * \li 'elt' points to cfg_listelt_t obtained from cfg_list_first() or
+ * cfg_list_next().
+ *
+ * Returns:
+ * \li A non-NULL pointer to a configuration object.
+ */
+
+void
+cfg_print(const cfg_obj_t *obj,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure);
+/*%<
+ * Print the configuration object 'obj' by repeatedly calling the
+ * function 'f', passing 'closure' and a region of text starting
+ * at 'text' and comprising 'textlen' characters.
+ */
+
+void
+cfg_print_grammar(const cfg_type_t *type,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure);
+/*%<
+ * Print a summary of the grammar of the configuration type 'type'.
+ */
+
+isc_boolean_t
+cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type);
+/*%<
+ * Return true iff 'obj' is of type 'type'.
+ */
+
+void cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **obj);
+/*%<
+ * Destroy a configuration object.
+ */
+
+void
+cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level,
+ const char *fmt, ...)
+ ISC_FORMAT_PRINTF(4, 5);
+/*%<
+ * Log a message concerning configuration object 'obj' to the logging
+ * channel of 'pctx', at log level 'level'. The message will be prefixed
+ * with the file name(s) and line number where 'obj' was defined.
+ */
+
+const char *
+cfg_obj_file(const cfg_obj_t *obj);
+/*%<
+ * Return the file that defined this object.
+ */
+
+unsigned int
+cfg_obj_line(const cfg_obj_t *obj);
+/*%<
+ * Return the line in file where this object was defined.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCFG_CFG_H */
diff --git a/lib/isccfg/include/isccfg/grammar.h b/lib/isccfg/include/isccfg/grammar.h
new file mode 100644
index 0000000..fa66146
--- /dev/null
+++ b/lib/isccfg/include/isccfg/grammar.h
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2002, 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: grammar.h,v 1.4.18.8 2006/02/28 03:10:49 marka Exp $ */
+
+#ifndef ISCCFG_GRAMMAR_H
+#define ISCCFG_GRAMMAR_H 1
+
+/*! \file */
+
+#include <isc/lex.h>
+#include <isc/netaddr.h>
+#include <isc/sockaddr.h>
+#include <isc/region.h>
+#include <isc/types.h>
+
+#include <isccfg/cfg.h>
+
+/*
+ * Definitions shared between the configuration parser
+ * and the grammars; not visible to users of the parser.
+ */
+
+/*% Clause may occur multiple times (e.g., "zone") */
+#define CFG_CLAUSEFLAG_MULTI 0x00000001
+/*% Clause is obsolete */
+#define CFG_CLAUSEFLAG_OBSOLETE 0x00000002
+/*% Clause is not implemented, and may never be */
+#define CFG_CLAUSEFLAG_NOTIMP 0x00000004
+/*% Clause is not implemented yet */
+#define CFG_CLAUSEFLAG_NYI 0x00000008
+/*% Default value has changed since earlier release */
+#define CFG_CLAUSEFLAG_NEWDEFAULT 0x00000010
+/*%
+ * Clause needs to be interpreted during parsing
+ * by calling a callback function, like the
+ * "directory" option.
+ */
+#define CFG_CLAUSEFLAG_CALLBACK 0x00000020
+
+typedef struct cfg_clausedef cfg_clausedef_t;
+typedef struct cfg_tuplefielddef cfg_tuplefielddef_t;
+typedef struct cfg_printer cfg_printer_t;
+typedef ISC_LIST(cfg_listelt_t) cfg_list_t;
+typedef struct cfg_map cfg_map_t;
+typedef struct cfg_rep cfg_rep_t;
+
+/*
+ * Function types for configuration object methods
+ */
+
+typedef isc_result_t (*cfg_parsefunc_t)(cfg_parser_t *, const cfg_type_t *type,
+ cfg_obj_t **);
+typedef void (*cfg_printfunc_t)(cfg_printer_t *, const cfg_obj_t *);
+typedef void (*cfg_docfunc_t)(cfg_printer_t *, const cfg_type_t *);
+typedef void (*cfg_freefunc_t)(cfg_parser_t *, cfg_obj_t *);
+
+/*
+ * Structure definitions
+ */
+
+/*%
+ * A configuration printer object. This is an abstract
+ * interface to a destination to which text can be printed
+ * by calling the function 'f'.
+ */
+struct cfg_printer {
+ void (*f)(void *closure, const char *text, int textlen);
+ void *closure;
+ int indent;
+};
+
+/*% A clause definition. */
+struct cfg_clausedef {
+ const char *name;
+ cfg_type_t *type;
+ unsigned int flags;
+};
+
+/*% A tuple field definition. */
+struct cfg_tuplefielddef {
+ const char *name;
+ cfg_type_t *type;
+ unsigned int flags;
+};
+
+/*% A configuration object type definition. */
+struct cfg_type {
+ const char *name; /*%< For debugging purposes only */
+ cfg_parsefunc_t parse;
+ cfg_printfunc_t print;
+ cfg_docfunc_t doc; /*%< Print grammar description */
+ cfg_rep_t * rep; /*%< Data representation */
+ const void * of; /*%< Additional data for meta-types */
+};
+
+/*% A keyword-type definition, for things like "port <integer>". */
+typedef struct {
+ const char *name;
+ const cfg_type_t *type;
+} keyword_type_t;
+
+struct cfg_map {
+ cfg_obj_t *id; /*%< Used for 'named maps' like keys, zones, &c */
+ const cfg_clausedef_t * const *clausesets; /*%< The clauses that
+ can occur in this map;
+ used for printing */
+ isc_symtab_t *symtab;
+};
+
+typedef struct cfg_netprefix cfg_netprefix_t;
+
+struct cfg_netprefix {
+ isc_netaddr_t address; /* IP4/IP6 */
+ unsigned int prefixlen;
+};
+
+/*%
+ * A configuration data representation.
+ */
+struct cfg_rep {
+ const char * name; /*%< For debugging only */
+ cfg_freefunc_t free; /*%< How to free this kind of data. */
+};
+
+/*%
+ * A configuration object. This is the main building block
+ * of the configuration parse tree.
+ */
+
+struct cfg_obj {
+ const cfg_type_t *type;
+ union {
+ isc_uint32_t uint32;
+ isc_uint64_t uint64;
+ isc_textregion_t string; /*%< null terminated, too */
+ isc_boolean_t boolean;
+ cfg_map_t map;
+ cfg_list_t list;
+ cfg_obj_t ** tuple;
+ isc_sockaddr_t sockaddr;
+ cfg_netprefix_t netprefix;
+ } value;
+ const char * file;
+ unsigned int line;
+};
+
+
+/*% A list element. */
+struct cfg_listelt {
+ cfg_obj_t *obj;
+ ISC_LINK(cfg_listelt_t) link;
+};
+
+/*% The parser object. */
+struct cfg_parser {
+ isc_mem_t * mctx;
+ isc_log_t * lctx;
+ isc_lex_t * lexer;
+ unsigned int errors;
+ unsigned int warnings;
+ isc_token_t token;
+
+ /*% We are at the end of all input. */
+ isc_boolean_t seen_eof;
+
+ /*% The current token has been pushed back. */
+ isc_boolean_t ungotten;
+
+ /*%
+ * The stack of currently active files, represented
+ * as a configuration list of configuration strings.
+ * The head is the top-level file, subsequent elements
+ * (if any) are the nested include files, and the
+ * last element is the file currently being parsed.
+ */
+ cfg_obj_t * open_files;
+
+ /*%
+ * Names of files that we have parsed and closed
+ * and were previously on the open_file list.
+ * We keep these objects around after closing
+ * the files because the file names may still be
+ * referenced from other configuration objects
+ * for use in reporting semantic errors after
+ * parsing is complete.
+ */
+ cfg_obj_t * closed_files;
+
+ /*%
+ * Current line number. We maintain our own
+ * copy of this so that it is available even
+ * when a file has just been closed.
+ */
+ unsigned int line;
+
+ cfg_parsecallback_t callback;
+ void *callbackarg;
+};
+
+
+/*@{*/
+/*%
+ * Flags defining whether to accept certain types of network addresses.
+ */
+#define CFG_ADDR_V4OK 0x00000001
+#define CFG_ADDR_V4PREFIXOK 0x00000002
+#define CFG_ADDR_V6OK 0x00000004
+#define CFG_ADDR_WILDOK 0x00000008
+#define CFG_ADDR_MASK (CFG_ADDR_V6OK|CFG_ADDR_V4OK)
+/*@}*/
+
+/*@{*/
+/*%
+ * Predefined data representation types.
+ */
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_uint32;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_uint64;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_string;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_boolean;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_map;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_list;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_tuple;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_sockaddr;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_netprefix;
+LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_void;
+/*@}*/
+
+/*@{*/
+/*%
+ * Predefined configuration object types.
+ */
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_boolean;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_uint32;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_uint64;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_qstring;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_astring;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_ustring;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddr;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr4;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr4wild;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr6;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr6wild;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netprefix;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_void;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_token;
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_unsupported;
+/*@}*/
+
+isc_result_t
+cfg_gettoken(cfg_parser_t *pctx, int options);
+
+isc_result_t
+cfg_peektoken(cfg_parser_t *pctx, int options);
+
+void
+cfg_ungettoken(cfg_parser_t *pctx);
+
+#define CFG_LEXOPT_QSTRING (ISC_LEXOPT_QSTRING | ISC_LEXOPT_QSTRINGMULTILINE)
+
+isc_result_t
+cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
+
+void
+cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u);
+
+isc_result_t
+cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+isc_result_t
+cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+isc_result_t
+cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na);
+
+void
+cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na);
+
+isc_boolean_t
+cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags);
+
+isc_result_t
+cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port);
+
+isc_result_t
+cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_special(cfg_parser_t *pctx, int special);
+/*%< Parse a required special character 'special'. */
+
+isc_result_t
+cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
+
+isc_result_t
+cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
+
+isc_result_t
+cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
+ cfg_listelt_t **ret);
+
+isc_result_t
+cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+isc_result_t
+cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type);
+
+void
+cfg_print_chars(cfg_printer_t *pctx, const char *text, int len);
+/*%< Print 'len' characters at 'text' */
+
+void
+cfg_print_cstr(cfg_printer_t *pctx, const char *s);
+/*%< Print the null-terminated string 's' */
+
+isc_result_t
+cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+isc_result_t
+cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **
+ret);
+
+void
+cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type);
+
+isc_result_t
+cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+void
+cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+void
+cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type);
+/*%<
+ * Print a description of the grammar of an arbitrary configuration
+ * type 'type'
+ */
+
+void
+cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type);
+/*%<
+ * Document the type 'type' as a terminal by printing its
+ * name in angle brackets, e.g., &lt;uint32>.
+ */
+
+void
+cfg_parser_error(cfg_parser_t *pctx, unsigned int flags,
+ const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4);
+/*!
+ * Pass one of these flags to cfg_parser_error() to include the
+ * token text in log message.
+ */
+#define CFG_LOG_NEAR 0x00000001 /*%< Say "near <token>" */
+#define CFG_LOG_BEFORE 0x00000002 /*%< Say "before <token>" */
+#define CFG_LOG_NOPREP 0x00000004 /*%< Say just "<token>" */
+
+void
+cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags,
+ const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4);
+
+isc_boolean_t
+cfg_is_enum(const char *s, const char *const *enums);
+/*%< Return true iff the string 's' is one of the strings in 'enums' */
+
+#endif /* ISCCFG_GRAMMAR_H */
diff --git a/lib/isccfg/include/isccfg/log.h b/lib/isccfg/include/isccfg/log.h
new file mode 100644
index 0000000..f66c37f
--- /dev/null
+++ b/lib/isccfg/include/isccfg/log.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2004, 2005 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: log.h,v 1.6.18.2 2005/04/29 00:17:16 marka Exp $ */
+
+#ifndef ISCCFG_LOG_H
+#define ISCCFG_LOG_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/log.h>
+
+LIBISCCFG_EXTERNAL_DATA extern isc_logcategory_t cfg_categories[];
+LIBISCCFG_EXTERNAL_DATA extern isc_logmodule_t cfg_modules[];
+
+#define CFG_LOGCATEGORY_CONFIG (&cfg_categories[0])
+
+#define CFG_LOGMODULE_PARSER (&cfg_modules[0])
+
+ISC_LANG_BEGINDECLS
+
+void
+cfg_log_init(isc_log_t *lctx);
+/*%<
+ * Make the libisccfg categories and modules available for use with the
+ * ISC logging library.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ *\li cfg_log_init() is called only once.
+ *
+ * Ensures:
+ * \li The catgories and modules defined above are available for
+ * use by isc_log_usechannnel() and isc_log_write().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISCCFG_LOG_H */
diff --git a/lib/isccfg/include/isccfg/namedconf.h b/lib/isccfg/include/isccfg/namedconf.h
new file mode 100644
index 0000000..6125b26
--- /dev/null
+++ b/lib/isccfg/include/isccfg/namedconf.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: namedconf.h,v 1.3.18.2 2005/04/29 00:17:16 marka Exp $ */
+
+#ifndef ISCCFG_NAMEDCONF_H
+#define ISCCFG_NAMEDCONF_H 1
+
+/*! \file
+ * \brief
+ * This module defines the named.conf, rndc.conf, and rndc.key grammars.
+ */
+
+#include <isccfg/cfg.h>
+
+/*
+ * Configuration object types.
+ */
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_namedconf;
+/*%< A complete named.conf file. */
+
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_rndcconf;
+/*%< A complete rndc.conf file. */
+
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_rndckey;
+/*%< A complete rndc.key file. */
+
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_keyref;
+/*%< A key reference, used as an ACL element */
+
+#endif /* ISCCFG_CFG_H */
diff --git a/lib/isccfg/include/isccfg/version.h b/lib/isccfg/include/isccfg/version.h
new file mode 100644
index 0000000..38bb14b
--- /dev/null
+++ b/lib/isccfg/include/isccfg/version.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005 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: version.h,v 1.3.18.2 2005/04/29 00:17:16 marka Exp $ */
+
+/*! \file */
+
+#include <isc/platform.h>
+
+LIBISCCFG_EXTERNAL_DATA extern const char cfg_version[];
+
+LIBISCCFG_EXTERNAL_DATA extern const unsigned int cfg_libinterface;
+LIBISCCFG_EXTERNAL_DATA extern const unsigned int cfg_librevision;
+LIBISCCFG_EXTERNAL_DATA extern const unsigned int cfg_libage;
diff --git a/lib/isccfg/log.c b/lib/isccfg/log.c
new file mode 100644
index 0000000..5d5ccb5
--- /dev/null
+++ b/lib/isccfg/log.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2004, 2005 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: log.c,v 1.5.18.2 2005/04/29 00:17:15 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/util.h>
+
+#include <isccfg/log.h>
+
+/*%
+ * When adding a new category, be sure to add the appropriate
+ * #define to <isccfg/log.h>.
+ */
+LIBISCCFG_EXTERNAL_DATA isc_logcategory_t cfg_categories[] = {
+ { "config", 0 },
+ { NULL, 0 }
+};
+
+/*%
+ * When adding a new module, be sure to add the appropriate
+ * #define to <isccfg/log.h>.
+ */
+LIBISCCFG_EXTERNAL_DATA isc_logmodule_t cfg_modules[] = {
+ { "isccfg/parser", 0 },
+ { NULL, 0 }
+};
+
+void
+cfg_log_init(isc_log_t *lctx) {
+ REQUIRE(lctx != NULL);
+
+ isc_log_registercategories(lctx, cfg_categories);
+ isc_log_registermodules(lctx, cfg_modules);
+}
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
new file mode 100644
index 0000000..65e30a2
--- /dev/null
+++ b/lib/isccfg/namedconf.c
@@ -0,0 +1,2049 @@
+/*
+ * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2002, 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: namedconf.c,v 1.30.18.38 2006/05/03 01:46:40 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <isc/lex.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <isccfg/cfg.h>
+#include <isccfg/grammar.h>
+#include <isccfg/log.h>
+
+#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
+
+/*% Check a return value. */
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto cleanup; \
+ } while (0)
+
+/*% Clean up a configuration object if non-NULL. */
+#define CLEANUP_OBJ(obj) \
+ do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
+
+
+/*%
+ * Forward declarations of static functions.
+ */
+
+static isc_result_t
+parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
+ const cfg_type_t *othertype, cfg_obj_t **ret);
+
+static isc_result_t
+parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+static isc_result_t
+parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+static void
+print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+static void
+doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
+
+static void
+doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
+
+static cfg_type_t cfg_type_acl;
+static cfg_type_t cfg_type_addrmatchelt;
+static cfg_type_t cfg_type_bracketed_aml;
+static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
+static cfg_type_t cfg_type_bracketed_sockaddrlist;
+static cfg_type_t cfg_type_bracketed_sockaddrnameportlist;
+static cfg_type_t cfg_type_controls;
+static cfg_type_t cfg_type_controls_sockaddr;
+static cfg_type_t cfg_type_destinationlist;
+static cfg_type_t cfg_type_dialuptype;
+static cfg_type_t cfg_type_ixfrdifftype;
+static cfg_type_t cfg_type_key;
+static cfg_type_t cfg_type_logfile;
+static cfg_type_t cfg_type_logging;
+static cfg_type_t cfg_type_logseverity;
+static cfg_type_t cfg_type_lwres;
+static cfg_type_t cfg_type_masterselement;
+static cfg_type_t cfg_type_nameportiplist;
+static cfg_type_t cfg_type_negated;
+static cfg_type_t cfg_type_notifytype;
+static cfg_type_t cfg_type_optional_class;
+static cfg_type_t cfg_type_optional_facility;
+static cfg_type_t cfg_type_optional_facility;
+static cfg_type_t cfg_type_optional_keyref;
+static cfg_type_t cfg_type_optional_port;
+static cfg_type_t cfg_type_options;
+static cfg_type_t cfg_type_portiplist;
+static cfg_type_t cfg_type_querysource4;
+static cfg_type_t cfg_type_querysource6;
+static cfg_type_t cfg_type_querysource;
+static cfg_type_t cfg_type_server;
+static cfg_type_t cfg_type_server_key_kludge;
+static cfg_type_t cfg_type_size;
+static cfg_type_t cfg_type_sizenodefault;
+static cfg_type_t cfg_type_sockaddr4wild;
+static cfg_type_t cfg_type_sockaddr6wild;
+static cfg_type_t cfg_type_view;
+static cfg_type_t cfg_type_viewopts;
+static cfg_type_t cfg_type_zone;
+static cfg_type_t cfg_type_zoneopts;
+static cfg_type_t cfg_type_dynamically_loadable_zones;
+static cfg_type_t cfg_type_dynamically_loadable_zones_opts;
+
+/*
+ * Clauses that can be found in a 'dynamically loadable zones' statement
+ */
+static cfg_clausedef_t
+dynamically_loadable_zones_clauses[] = {
+ { "database", &cfg_type_astring, 0 },
+ { NULL, NULL, 0 }
+};
+
+/*
+ * A dynamically loadable zones statement.
+ */
+static cfg_tuplefielddef_t dynamically_loadable_zones_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "options", &cfg_type_dynamically_loadable_zones_opts, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_dynamically_loadable_zones = {
+ "dlz", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple,
+ dynamically_loadable_zones_fields
+ };
+
+
+/*% tkey-dhkey */
+
+static cfg_tuplefielddef_t tkey_dhkey_fields[] = {
+ { "name", &cfg_type_qstring, 0 },
+ { "keyid", &cfg_type_uint32, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_tkey_dhkey = {
+ "tkey-dhkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
+ tkey_dhkey_fields
+};
+
+/*% listen-on */
+
+static cfg_tuplefielddef_t listenon_fields[] = {
+ { "port", &cfg_type_optional_port, 0 },
+ { "acl", &cfg_type_bracketed_aml, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_listenon = {
+ "listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, listenon_fields };
+
+/*% acl */
+
+static cfg_tuplefielddef_t acl_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "value", &cfg_type_bracketed_aml, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_acl = {
+ "acl", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, acl_fields };
+
+/*% masters */
+static cfg_tuplefielddef_t masters_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "port", &cfg_type_optional_port, 0 },
+ { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_masters = {
+ "masters", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, masters_fields };
+
+/*%
+ * "sockaddrkeylist", a list of socket addresses with optional keys
+ * and an optional default port, as used in the masters option.
+ * E.g.,
+ * "port 1234 { mymasters; 10.0.0.1 key foo; 1::2 port 69; }"
+ */
+
+static cfg_tuplefielddef_t namesockaddrkey_fields[] = {
+ { "masterselement", &cfg_type_masterselement, 0 },
+ { "key", &cfg_type_optional_keyref, 0 },
+ { NULL, NULL, 0 },
+};
+
+static cfg_type_t cfg_type_namesockaddrkey = {
+ "namesockaddrkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
+ namesockaddrkey_fields
+};
+
+static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
+ "bracketed_namesockaddrkeylist", cfg_parse_bracketed_list,
+ cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_namesockaddrkey
+};
+
+static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = {
+ { "port", &cfg_type_optional_port, 0 },
+ { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_namesockaddrkeylist = {
+ "sockaddrkeylist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
+ namesockaddrkeylist_fields
+};
+
+/*%
+ * A list of socket addresses with an optional default port,
+ * as used in the also-notify option. E.g.,
+ * "port 1234 { 10.0.0.1; 1::2 port 69; }"
+ */
+static cfg_tuplefielddef_t portiplist_fields[] = {
+ { "port", &cfg_type_optional_port, 0 },
+ { "addresses", &cfg_type_bracketed_sockaddrlist, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_portiplist = {
+ "portiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
+ portiplist_fields
+};
+
+/*%
+ * A public key, as in the "pubkey" statement.
+ */
+static cfg_tuplefielddef_t pubkey_fields[] = {
+ { "flags", &cfg_type_uint32, 0 },
+ { "protocol", &cfg_type_uint32, 0 },
+ { "algorithm", &cfg_type_uint32, 0 },
+ { "key", &cfg_type_qstring, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_pubkey = {
+ "pubkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, pubkey_fields };
+
+/*%
+ * A list of RR types, used in grant statements.
+ * Note that the old parser allows quotes around the RR type names.
+ */
+static cfg_type_t cfg_type_rrtypelist = {
+ "rrtypelist", cfg_parse_spacelist, cfg_print_spacelist, cfg_doc_terminal,
+ &cfg_rep_list, &cfg_type_astring
+};
+
+static const char *mode_enums[] = { "grant", "deny", NULL };
+static cfg_type_t cfg_type_mode = {
+ "mode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
+ &mode_enums
+};
+
+static const char *matchtype_enums[] = {
+ "name", "subdomain", "wildcard", "self", "selfsub", "selfwild", NULL };
+static cfg_type_t cfg_type_matchtype = {
+ "matchtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
+ &matchtype_enums
+};
+
+/*%
+ * A grant statement, used in the update policy.
+ */
+static cfg_tuplefielddef_t grant_fields[] = {
+ { "mode", &cfg_type_mode, 0 },
+ { "identity", &cfg_type_astring, 0 }, /* domain name */
+ { "matchtype", &cfg_type_matchtype, 0 },
+ { "name", &cfg_type_astring, 0 }, /* domain name */
+ { "types", &cfg_type_rrtypelist, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_grant = {
+ "grant", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, grant_fields };
+
+static cfg_type_t cfg_type_updatepolicy = {
+ "update_policy", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
+ &cfg_rep_list, &cfg_type_grant
+};
+
+/*%
+ * A view statement.
+ */
+static cfg_tuplefielddef_t view_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "class", &cfg_type_optional_class, 0 },
+ { "options", &cfg_type_viewopts, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_view = {
+ "view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, view_fields };
+
+/*%
+ * A zone statement.
+ */
+static cfg_tuplefielddef_t zone_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "class", &cfg_type_optional_class, 0 },
+ { "options", &cfg_type_zoneopts, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_zone = {
+ "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, zone_fields };
+
+/*%
+ * A "category" clause in the "logging" statement.
+ */
+static cfg_tuplefielddef_t category_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "destinations", &cfg_type_destinationlist,0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_category = {
+ "category", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, category_fields };
+
+
+/*%
+ * A trusted key, as used in the "trusted-keys" statement.
+ */
+static cfg_tuplefielddef_t trustedkey_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "flags", &cfg_type_uint32, 0 },
+ { "protocol", &cfg_type_uint32, 0 },
+ { "algorithm", &cfg_type_uint32, 0 },
+ { "key", &cfg_type_qstring, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_trustedkey = {
+ "trustedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
+ trustedkey_fields
+};
+
+static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring };
+
+static cfg_type_t cfg_type_optional_wild_class = {
+ "optional_wild_class", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_string, &wild_class_kw
+};
+
+static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring };
+
+static cfg_type_t cfg_type_optional_wild_type = {
+ "optional_wild_type", parse_optional_keyvalue,
+ print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_type_kw
+};
+
+static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring };
+
+static cfg_type_t cfg_type_optional_wild_name = {
+ "optional_wild_name", parse_optional_keyvalue,
+ print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_name_kw
+};
+
+/*%
+ * An rrset ordering element.
+ */
+static cfg_tuplefielddef_t rrsetorderingelement_fields[] = {
+ { "class", &cfg_type_optional_wild_class, 0 },
+ { "type", &cfg_type_optional_wild_type, 0 },
+ { "name", &cfg_type_optional_wild_name, 0 },
+ { "order", &cfg_type_ustring, 0 }, /* must be literal "order" */
+ { "ordering", &cfg_type_ustring, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_rrsetorderingelement = {
+ "rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
+ rrsetorderingelement_fields
+};
+
+/*%
+ * A global or view "check-names" option. Note that the zone
+ * "check-names" option has a different syntax.
+ */
+
+static const char *checktype_enums[] = { "master", "slave", "response", NULL };
+static cfg_type_t cfg_type_checktype = {
+ "checktype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &checktype_enums
+};
+
+static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL };
+static cfg_type_t cfg_type_checkmode = {
+ "checkmode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &checkmode_enums
+};
+
+static cfg_tuplefielddef_t checknames_fields[] = {
+ { "type", &cfg_type_checktype, 0 },
+ { "mode", &cfg_type_checkmode, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_checknames = {
+ "checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
+ checknames_fields
+};
+
+static cfg_type_t cfg_type_bracketed_sockaddrlist = {
+ "bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
+ &cfg_rep_list, &cfg_type_sockaddr
+};
+
+static cfg_type_t cfg_type_rrsetorder = {
+ "rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
+ &cfg_rep_list, &cfg_type_rrsetorderingelement
+};
+
+static keyword_type_t port_kw = { "port", &cfg_type_uint32 };
+
+static cfg_type_t cfg_type_optional_port = {
+ "optional_port", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_uint32, &port_kw
+};
+
+/*% A list of keys, as in the "key" clause of the controls statement. */
+static cfg_type_t cfg_type_keylist = {
+ "keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
+ &cfg_type_astring
+};
+
+static cfg_type_t cfg_type_trustedkeys = {
+ "trusted-keys", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list,
+ &cfg_type_trustedkey
+};
+
+static const char *forwardtype_enums[] = { "first", "only", NULL };
+static cfg_type_t cfg_type_forwardtype = {
+ "forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
+ &forwardtype_enums
+};
+
+static const char *zonetype_enums[] = {
+ "master", "slave", "stub", "hint", "forward", "delegation-only", NULL };
+static cfg_type_t cfg_type_zonetype = {
+ "zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &zonetype_enums
+};
+
+static const char *loglevel_enums[] = {
+ "critical", "error", "warning", "notice", "info", "dynamic", NULL };
+static cfg_type_t cfg_type_loglevel = {
+ "loglevel", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
+ &loglevel_enums
+};
+
+static const char *transferformat_enums[] = {
+ "many-answers", "one-answer", NULL };
+static cfg_type_t cfg_type_transferformat = {
+ "transferformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
+ &transferformat_enums
+};
+
+/*%
+ * The special keyword "none", as used in the pid-file option.
+ */
+
+static void
+print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ UNUSED(obj);
+ cfg_print_chars(pctx, "none", 4);
+}
+
+static cfg_type_t cfg_type_none = {
+ "none", NULL, print_none, NULL, &cfg_rep_void, NULL
+};
+
+/*%
+ * A quoted string or the special keyword "none". Used in the pid-file option.
+ */
+static isc_result_t
+parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "none") == 0)
+ return (cfg_create_obj(pctx, &cfg_type_none, ret));
+ cfg_ungettoken(pctx);
+ return (cfg_parse_qstring(pctx, type, ret));
+ cleanup:
+ return (result);
+}
+
+static void
+doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_chars(pctx, "( <quoted_string> | none )", 26);
+}
+
+static cfg_type_t cfg_type_qstringornone = {
+ "qstringornone", parse_qstringornone, NULL, doc_qstringornone, NULL, NULL };
+
+/*%
+ * keyword hostname
+ */
+
+static void
+print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ UNUSED(obj);
+ cfg_print_chars(pctx, "hostname", 4);
+}
+
+static cfg_type_t cfg_type_hostname = {
+ "hostname", NULL, print_hostname, NULL, &cfg_rep_boolean, NULL
+};
+
+/*%
+ * "server-id" argument.
+ */
+
+static isc_result_t
+parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "none") == 0)
+ return (cfg_create_obj(pctx, &cfg_type_none, ret));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "hostname") == 0) {
+ return (cfg_create_obj(pctx, &cfg_type_hostname, ret));
+ }
+ cfg_ungettoken(pctx);
+ return (cfg_parse_qstring(pctx, type, ret));
+ cleanup:
+ return (result);
+}
+
+static void
+doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_chars(pctx, "( <quoted_string> | none | hostname )", 26);
+}
+
+static cfg_type_t cfg_type_serverid = {
+ "serverid", parse_serverid, NULL, doc_serverid, NULL, NULL };
+
+/*%
+ * Port list.
+ */
+static isc_result_t
+parse_port(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+
+ UNUSED(type);
+
+ CHECK(cfg_parse_uint32(pctx, NULL, ret));
+ if ((*ret)->value.uint32 > 0xffff) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port");
+ cfg_obj_destroy(pctx, ret);
+ result = ISC_R_RANGE;
+ }
+ cleanup:
+ return (result);
+}
+
+static cfg_type_t cfg_type_port = {
+ "port", parse_port, NULL, cfg_doc_terminal,
+ NULL, NULL
+};
+
+static cfg_type_t cfg_type_bracketed_portlist = {
+ "bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
+ &cfg_rep_list, &cfg_type_port
+};
+
+/*%
+ * Clauses that can be found within the top level of the named.conf
+ * file only.
+ */
+static cfg_clausedef_t
+namedconf_clauses[] = {
+ { "options", &cfg_type_options, 0 },
+ { "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
+ { "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
+ { "masters", &cfg_type_masters, CFG_CLAUSEFLAG_MULTI },
+ { "logging", &cfg_type_logging, 0 },
+ { "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI },
+ { "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+
+/*%
+ * Clauses that can occur at the top level or in the view
+ * statement, but not in the options block.
+ */
+static cfg_clausedef_t
+namedconf_or_view_clauses[] = {
+ { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
+ { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
+ /* only 1 DLZ per view allowed */
+ { "dlz", &cfg_type_dynamically_loadable_zones, 0 },
+ { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
+ { "trusted-keys", &cfg_type_trustedkeys, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+
+/*%
+ * Clauses that can be found within the 'options' statement.
+ */
+static cfg_clausedef_t
+options_clauses[] = {
+ { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
+ { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
+ { "blackhole", &cfg_type_bracketed_aml, 0 },
+ { "coresize", &cfg_type_size, 0 },
+ { "datasize", &cfg_type_size, 0 },
+ { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK },
+ { "dump-file", &cfg_type_qstring, 0 },
+ { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "files", &cfg_type_size, 0 },
+ { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "heartbeat-interval", &cfg_type_uint32, 0 },
+ { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP },
+ { "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
+ { "hostname", &cfg_type_qstringornone, 0 },
+ { "interface-interval", &cfg_type_uint32, 0 },
+ { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
+ { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
+ { "match-mapped-addresses", &cfg_type_boolean, 0 },
+ { "memstatistics-file", &cfg_type_qstring, 0 },
+ { "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
+ { "pid-file", &cfg_type_qstringornone, 0 },
+ { "port", &cfg_type_uint32, 0 },
+ { "querylog", &cfg_type_boolean, 0 },
+ { "recursing-file", &cfg_type_qstring, 0 },
+ { "random-device", &cfg_type_qstring, 0 },
+ { "recursive-clients", &cfg_type_uint32, 0 },
+ { "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
+ { "serial-query-rate", &cfg_type_uint32, 0 },
+ { "server-id", &cfg_type_serverid, 0 },
+ { "stacksize", &cfg_type_size, 0 },
+ { "statistics-file", &cfg_type_qstring, 0 },
+ { "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_NYI },
+ { "tcp-clients", &cfg_type_uint32, 0 },
+ { "tcp-listen-queue", &cfg_type_uint32, 0 },
+ { "tkey-dhkey", &cfg_type_tkey_dhkey, 0 },
+ { "tkey-gssapi-credential", &cfg_type_qstring, 0 },
+ { "tkey-domain", &cfg_type_qstring, 0 },
+ { "transfers-per-ns", &cfg_type_uint32, 0 },
+ { "transfers-in", &cfg_type_uint32, 0 },
+ { "transfers-out", &cfg_type_uint32, 0 },
+ { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "use-ixfr", &cfg_type_boolean, 0 },
+ { "version", &cfg_type_qstringornone, 0 },
+ { "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+
+
+static cfg_type_t cfg_type_namelist = {
+ "namelist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_qstring };
+
+static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist };
+
+static cfg_type_t cfg_type_optional_exclude = {
+ "optional_exclude", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_list, &exclude_kw };
+
+static cfg_type_t cfg_type_algorithmlist = {
+ "algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
+
+static cfg_tuplefielddef_t disablealgorithm_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "algorithms", &cfg_type_algorithmlist, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_disablealgorithm = {
+ "disablealgorithm", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, disablealgorithm_fields
+};
+
+static cfg_tuplefielddef_t mustbesecure_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "value", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_mustbesecure = {
+ "mustbesecure", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, mustbesecure_fields
+};
+
+static const char *masterformat_enums[] = { "text", "raw", NULL };
+static cfg_type_t cfg_type_masterformat = {
+ "masterformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &masterformat_enums
+};
+
+/*%
+ * dnssec-lookaside
+ */
+
+static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring };
+
+static cfg_type_t cfg_type_trustanchor = {
+ "trust-anchor", parse_keyvalue, print_keyvalue, doc_keyvalue,
+ &cfg_rep_string, &trustanchor_kw
+};
+
+static cfg_tuplefielddef_t lookaside_fields[] = {
+ { "domain", &cfg_type_astring, 0 },
+ { "trust-anchor", &cfg_type_trustanchor, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_lookaside = {
+ "lookaside", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, lookaside_fields
+};
+
+/*%
+ * Clauses that can be found within the 'view' statement,
+ * with defaults in the 'options' statement.
+ */
+
+static cfg_clausedef_t
+view_clauses[] = {
+ { "allow-query-cache", &cfg_type_bracketed_aml, 0 },
+ { "allow-recursion", &cfg_type_bracketed_aml, 0 },
+ { "allow-v6-synthesis", &cfg_type_bracketed_aml,
+ CFG_CLAUSEFLAG_OBSOLETE },
+ { "sortlist", &cfg_type_bracketed_aml, 0 },
+ { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
+ { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT },
+ { "minimal-responses", &cfg_type_boolean, 0 },
+ { "recursion", &cfg_type_boolean, 0 },
+ { "rrset-order", &cfg_type_rrsetorder, 0 },
+ { "provide-ixfr", &cfg_type_boolean, 0 },
+ { "request-ixfr", &cfg_type_boolean, 0 },
+ { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
+ { "additional-from-auth", &cfg_type_boolean, 0 },
+ { "additional-from-cache", &cfg_type_boolean, 0 },
+ /*
+ * Note that the query-source option syntax is different
+ * from the other -source options.
+ */
+ { "query-source", &cfg_type_querysource4, 0 },
+ { "query-source-v6", &cfg_type_querysource6, 0 },
+ { "cleaning-interval", &cfg_type_uint32, 0 },
+ { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
+ { "lame-ttl", &cfg_type_uint32, 0 },
+ { "max-ncache-ttl", &cfg_type_uint32, 0 },
+ { "max-cache-ttl", &cfg_type_uint32, 0 },
+ { "transfer-format", &cfg_type_transferformat, 0 },
+ { "max-cache-size", &cfg_type_sizenodefault, 0 },
+ { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
+ { "cache-file", &cfg_type_qstring, 0 },
+ { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
+ { "preferred-glue", &cfg_type_astring, 0 },
+ { "dual-stack-servers", &cfg_type_nameportiplist, 0 },
+ { "edns-udp-size", &cfg_type_uint32, 0 },
+ { "max-udp-size", &cfg_type_uint32, 0 },
+ { "root-delegation-only", &cfg_type_optional_exclude, 0 },
+ { "disable-algorithms", &cfg_type_disablealgorithm,
+ CFG_CLAUSEFLAG_MULTI },
+ { "dnssec-enable", &cfg_type_boolean, 0 },
+ { "dnssec-validation", &cfg_type_boolean, 0 },
+ { "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI },
+ { "dnssec-must-be-secure", &cfg_type_mustbesecure,
+ CFG_CLAUSEFLAG_MULTI },
+ { "dnssec-accept-expired", &cfg_type_boolean, 0 },
+ { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 },
+ { "acache-enable", &cfg_type_boolean, 0 },
+ { "acache-cleaning-interval", &cfg_type_uint32, 0 },
+ { "max-acache-size", &cfg_type_sizenodefault, 0 },
+ { "clients-per-query", &cfg_type_uint32, 0 },
+ { "max-clients-per-query", &cfg_type_uint32, 0 },
+ { "empty-server", &cfg_type_astring, 0 },
+ { "empty-contact", &cfg_type_astring, 0 },
+ { "empty-zones-enable", &cfg_type_boolean, 0 },
+ { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI },
+ { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+
+/*%
+ * Clauses that can be found within the 'view' statement only.
+ */
+static cfg_clausedef_t
+view_only_clauses[] = {
+ { "match-clients", &cfg_type_bracketed_aml, 0 },
+ { "match-destinations", &cfg_type_bracketed_aml, 0 },
+ { "match-recursive-only", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+
+/*%
+ * Clauses that can be found in a 'zone' statement,
+ * with defaults in the 'view' or 'options' statement.
+ */
+static cfg_clausedef_t
+zone_clauses[] = {
+ { "allow-query", &cfg_type_bracketed_aml, 0 },
+ { "allow-transfer", &cfg_type_bracketed_aml, 0 },
+ { "allow-update", &cfg_type_bracketed_aml, 0 },
+ { "allow-update-forwarding", &cfg_type_bracketed_aml, 0 },
+ { "allow-notify", &cfg_type_bracketed_aml, 0 },
+ { "masterfile-format", &cfg_type_masterformat, 0 },
+ { "notify", &cfg_type_notifytype, 0 },
+ { "notify-source", &cfg_type_sockaddr4wild, 0 },
+ { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
+ { "also-notify", &cfg_type_portiplist, 0 },
+ { "notify-delay", &cfg_type_uint32, 0 },
+ { "dialup", &cfg_type_dialuptype, 0 },
+ { "forward", &cfg_type_forwardtype, 0 },
+ { "forwarders", &cfg_type_portiplist, 0 },
+ { "maintain-ixfr-base", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_OBSOLETE },
+ { "max-journal-size", &cfg_type_sizenodefault, 0 },
+ { "max-transfer-time-in", &cfg_type_uint32, 0 },
+ { "max-transfer-time-out", &cfg_type_uint32, 0 },
+ { "max-transfer-idle-in", &cfg_type_uint32, 0 },
+ { "max-transfer-idle-out", &cfg_type_uint32, 0 },
+ { "max-retry-time", &cfg_type_uint32, 0 },
+ { "min-retry-time", &cfg_type_uint32, 0 },
+ { "max-refresh-time", &cfg_type_uint32, 0 },
+ { "min-refresh-time", &cfg_type_uint32, 0 },
+ { "multi-master", &cfg_type_boolean, 0 },
+ { "sig-validity-interval", &cfg_type_uint32, 0 },
+ { "transfer-source", &cfg_type_sockaddr4wild, 0 },
+ { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
+ { "alt-transfer-source", &cfg_type_sockaddr4wild, 0 },
+ { "alt-transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
+ { "use-alt-transfer-source", &cfg_type_boolean, 0 },
+ { "zone-statistics", &cfg_type_boolean, 0 },
+ { "key-directory", &cfg_type_qstring, 0 },
+ { "check-wildcard", &cfg_type_boolean, 0 },
+ { "check-integrity", &cfg_type_boolean, 0 },
+ { "check-mx", &cfg_type_checkmode, 0 },
+ { "check-mx-cname", &cfg_type_checkmode, 0 },
+ { "check-srv-cname", &cfg_type_checkmode, 0 },
+ { "check-sibling", &cfg_type_boolean, 0 },
+ { "zero-no-soa-ttl", &cfg_type_boolean, 0 },
+ { "update-check-ksk", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+
+/*%
+ * Clauses that can be found in a 'zone' statement
+ * only.
+ */
+static cfg_clausedef_t
+zone_only_clauses[] = {
+ { "type", &cfg_type_zonetype, 0 },
+ { "file", &cfg_type_qstring, 0 },
+ { "journal", &cfg_type_qstring, 0 },
+ { "ixfr-base", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
+ { "ixfr-tmp-file", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
+ { "masters", &cfg_type_namesockaddrkeylist, 0 },
+ { "pubkey", &cfg_type_pubkey,
+ CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE },
+ { "update-policy", &cfg_type_updatepolicy, 0 },
+ { "database", &cfg_type_astring, 0 },
+ { "delegation-only", &cfg_type_boolean, 0 },
+ /*
+ * Note that the format of the check-names option is different between
+ * the zone options and the global/view options. Ugh.
+ */
+ { "check-names", &cfg_type_checkmode, 0 },
+ { "ixfr-from-differences", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+
+
+/*% The top-level named.conf syntax. */
+
+static cfg_clausedef_t *
+namedconf_clausesets[] = {
+ namedconf_clauses,
+ namedconf_or_view_clauses,
+ NULL
+};
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = {
+ "namedconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
+ &cfg_rep_map, namedconf_clausesets
+};
+
+/*% The "options" statement syntax. */
+
+static cfg_clausedef_t *
+options_clausesets[] = {
+ options_clauses,
+ view_clauses,
+ zone_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_options = {
+ "options", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, options_clausesets };
+
+/*% The "view" statement syntax. */
+
+static cfg_clausedef_t *
+view_clausesets[] = {
+ view_only_clauses,
+ namedconf_or_view_clauses,
+ view_clauses,
+ zone_clauses,
+ dynamically_loadable_zones_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_viewopts = {
+ "view", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, view_clausesets };
+
+/*% The "zone" statement syntax. */
+
+static cfg_clausedef_t *
+zone_clausesets[] = {
+ zone_only_clauses,
+ zone_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_zoneopts = {
+ "zoneopts", cfg_parse_map, cfg_print_map,
+ cfg_doc_map, &cfg_rep_map, zone_clausesets };
+
+/*% The "dynamically loadable zones" statement syntax. */
+
+static cfg_clausedef_t *
+dynamically_loadable_zones_clausesets[] = {
+ dynamically_loadable_zones_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_dynamically_loadable_zones_opts = {
+ "dynamically_loadable_zones_opts", cfg_parse_map,
+ cfg_print_map, cfg_doc_map, &cfg_rep_map,
+ dynamically_loadable_zones_clausesets
+};
+
+/*%
+ * Clauses that can be found within the 'key' statement.
+ */
+static cfg_clausedef_t
+key_clauses[] = {
+ { "algorithm", &cfg_type_astring, 0 },
+ { "secret", &cfg_type_astring, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+key_clausesets[] = {
+ key_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_key = {
+ "key", cfg_parse_named_map, cfg_print_map,
+ cfg_doc_map, &cfg_rep_map, key_clausesets
+};
+
+
+/*%
+ * Clauses that can be found in a 'server' statement.
+ */
+static cfg_clausedef_t
+server_clauses[] = {
+ { "bogus", &cfg_type_boolean, 0 },
+ { "provide-ixfr", &cfg_type_boolean, 0 },
+ { "request-ixfr", &cfg_type_boolean, 0 },
+ { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "transfers", &cfg_type_uint32, 0 },
+ { "transfer-format", &cfg_type_transferformat, 0 },
+ { "keys", &cfg_type_server_key_kludge, 0 },
+ { "edns", &cfg_type_boolean, 0 },
+ { "edns-udp-size", &cfg_type_uint32, 0 },
+ { "max-udp-size", &cfg_type_uint32, 0 },
+ { "notify-source", &cfg_type_sockaddr4wild, 0 },
+ { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
+ { "query-source", &cfg_type_querysource4, 0 },
+ { "query-source-v6", &cfg_type_querysource6, 0 },
+ { "transfer-source", &cfg_type_sockaddr4wild, 0 },
+ { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_clausedef_t *
+server_clausesets[] = {
+ server_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_server = {
+ "server", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
+ server_clausesets
+};
+
+
+/*%
+ * Clauses that can be found in a 'channel' clause in the
+ * 'logging' statement.
+ *
+ * These have some additional constraints that need to be
+ * checked after parsing:
+ * - There must exactly one of file/syslog/null/stderr
+ *
+ */
+static cfg_clausedef_t
+channel_clauses[] = {
+ /* Destinations. We no longer require these to be first. */
+ { "file", &cfg_type_logfile, 0 },
+ { "syslog", &cfg_type_optional_facility, 0 },
+ { "null", &cfg_type_void, 0 },
+ { "stderr", &cfg_type_void, 0 },
+ /* Options. We now accept these for the null channel, too. */
+ { "severity", &cfg_type_logseverity, 0 },
+ { "print-time", &cfg_type_boolean, 0 },
+ { "print-severity", &cfg_type_boolean, 0 },
+ { "print-category", &cfg_type_boolean, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_clausedef_t *
+channel_clausesets[] = {
+ channel_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_channel = {
+ "channel", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, channel_clausesets
+};
+
+/*% A list of log destination, used in the "category" clause. */
+static cfg_type_t cfg_type_destinationlist = {
+ "destinationlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
+ &cfg_rep_list, &cfg_type_astring };
+
+/*%
+ * Clauses that can be found in a 'logging' statement.
+ */
+static cfg_clausedef_t
+logging_clauses[] = {
+ { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI },
+ { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+static cfg_clausedef_t *
+logging_clausesets[] = {
+ logging_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_logging = {
+ "logging", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, logging_clausesets };
+
+
+static isc_result_t
+parse_unitstring(char *str, isc_resourcevalue_t *valuep) {
+ char *endp;
+ unsigned int len;
+ isc_uint64_t value;
+ isc_uint64_t unit;
+
+ value = isc_string_touint64(str, &endp, 10);
+ if (*endp == 0) {
+ *valuep = value;
+ return (ISC_R_SUCCESS);
+ }
+
+ len = strlen(str);
+ if (len < 2 || endp[1] != '\0')
+ return (ISC_R_FAILURE);
+
+ switch (str[len - 1]) {
+ case 'k':
+ case 'K':
+ unit = 1024;
+ break;
+ case 'm':
+ case 'M':
+ unit = 1024 * 1024;
+ break;
+ case 'g':
+ case 'G':
+ unit = 1024 * 1024 * 1024;
+ break;
+ default:
+ return (ISC_R_FAILURE);
+ }
+ if (value > ISC_UINT64_MAX / unit)
+ return (ISC_R_FAILURE);
+ *valuep = value * unit;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ isc_uint64_t val;
+
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type != isc_tokentype_string) {
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+ CHECK(parse_unitstring(TOKEN_STRING(pctx), &val));
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj));
+ obj->value.uint64 = val;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected integer and optional unit");
+ return (result);
+}
+
+/*%
+ * A size value (number + optional unit).
+ */
+static cfg_type_t cfg_type_sizeval = {
+ "sizeval", parse_sizeval, cfg_print_uint64, cfg_doc_terminal,
+ &cfg_rep_uint64, NULL };
+
+/*%
+ * A size, "unlimited", or "default".
+ */
+
+static isc_result_t
+parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret));
+}
+
+static const char *size_enums[] = { "unlimited", "default", NULL };
+static cfg_type_t cfg_type_size = {
+ "size", parse_size, cfg_print_ustring, cfg_doc_terminal,
+ &cfg_rep_string, size_enums
+};
+
+/*%
+ * A size or "unlimited", but not "default".
+ */
+static const char *sizenodefault_enums[] = { "unlimited", NULL };
+static cfg_type_t cfg_type_sizenodefault = {
+ "size_no_default", parse_size, cfg_print_ustring, cfg_doc_terminal,
+ &cfg_rep_string, sizenodefault_enums
+};
+
+/*%
+ * optional_keyvalue
+ */
+static isc_result_t
+parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
+ isc_boolean_t optional, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ const keyword_type_t *kw = type->of;
+
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), kw->name) == 0) {
+ CHECK(cfg_gettoken(pctx, 0));
+ CHECK(kw->type->parse(pctx, kw->type, &obj));
+ obj->type = type; /* XXX kludge */
+ } else {
+ if (optional) {
+ CHECK(cfg_parse_void(pctx, NULL, &obj));
+ } else {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected '%s'",
+ kw->name);
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+ }
+ *ret = obj;
+ cleanup:
+ return (result);
+}
+
+static isc_result_t
+parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
+ const cfg_type_t *othertype, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string &&
+ cfg_is_enum(TOKEN_STRING(pctx), enumtype->of)) {
+ CHECK(cfg_parse_enum(pctx, enumtype, ret));
+ } else {
+ CHECK(cfg_parse_obj(pctx, othertype, ret));
+ }
+ cleanup:
+ return (result);
+}
+
+static void
+doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *type) {
+ cfg_doc_terminal(pctx, type);
+#if 0 /* XXX */
+ cfg_print_chars(pctx, "( ", 2);...
+#endif
+
+}
+
+static isc_result_t
+parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_maybe_optional_keyvalue(pctx, type, ISC_FALSE, ret));
+}
+
+static isc_result_t
+parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_maybe_optional_keyvalue(pctx, type, ISC_TRUE, ret));
+}
+
+static void
+print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ const keyword_type_t *kw = obj->type->of;
+ cfg_print_cstr(pctx, kw->name);
+ cfg_print_chars(pctx, " ", 1);
+ kw->type->print(pctx, obj);
+}
+
+static void
+doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const keyword_type_t *kw = type->of;
+ cfg_print_cstr(pctx, kw->name);
+ cfg_print_chars(pctx, " ", 1);
+ cfg_doc_obj(pctx, kw->type);
+}
+
+static void
+doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const keyword_type_t *kw = type->of;
+ cfg_print_chars(pctx, "[ ", 2);
+ cfg_print_cstr(pctx, kw->name);
+ cfg_print_chars(pctx, " ", 1);
+ cfg_doc_obj(pctx, kw->type);
+ cfg_print_chars(pctx, " ]", 2);
+}
+
+static const char *dialup_enums[] = {
+ "notify", "notify-passive", "refresh", "passive", NULL };
+static isc_result_t
+parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
+}
+static cfg_type_t cfg_type_dialuptype = {
+ "dialuptype", parse_dialup_type, cfg_print_ustring, doc_enum_or_other,
+ &cfg_rep_string, dialup_enums
+};
+
+static const char *notify_enums[] = { "explicit", "master-only", NULL };
+static isc_result_t
+parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
+}
+static cfg_type_t cfg_type_notifytype = {
+ "notifytype", parse_notify_type, cfg_print_ustring, doc_enum_or_other,
+ &cfg_rep_string, notify_enums,
+};
+
+static const char *ixfrdiff_enums[] = { "master", "slave", NULL };
+static isc_result_t
+parse_ixfrdiff_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
+}
+static cfg_type_t cfg_type_ixfrdifftype = {
+ "ixfrdiff", parse_ixfrdiff_type, cfg_print_ustring, doc_enum_or_other,
+ &cfg_rep_string, ixfrdiff_enums,
+};
+
+static keyword_type_t key_kw = { "key", &cfg_type_astring };
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = {
+ "keyref", parse_keyvalue, print_keyvalue, doc_keyvalue,
+ &cfg_rep_string, &key_kw
+};
+
+static cfg_type_t cfg_type_optional_keyref = {
+ "optional_keyref", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_string, &key_kw
+};
+
+/*%
+ * A "controls" statement is represented as a map with the multivalued
+ * "inet" and "unix" clauses.
+ */
+
+static keyword_type_t controls_allow_kw = {
+ "allow", &cfg_type_bracketed_aml };
+
+static cfg_type_t cfg_type_controls_allow = {
+ "controls_allow", parse_keyvalue,
+ print_keyvalue, doc_keyvalue,
+ &cfg_rep_list, &controls_allow_kw
+};
+
+static keyword_type_t controls_keys_kw = {
+ "keys", &cfg_type_keylist };
+
+static cfg_type_t cfg_type_controls_keys = {
+ "controls_keys", parse_optional_keyvalue,
+ print_keyvalue, doc_optional_keyvalue,
+ &cfg_rep_list, &controls_keys_kw
+};
+
+static cfg_tuplefielddef_t inetcontrol_fields[] = {
+ { "address", &cfg_type_controls_sockaddr, 0 },
+ { "allow", &cfg_type_controls_allow, 0 },
+ { "keys", &cfg_type_controls_keys, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_inetcontrol = {
+ "inetcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
+ inetcontrol_fields
+};
+
+static keyword_type_t controls_perm_kw = {
+ "perm", &cfg_type_uint32 };
+
+static cfg_type_t cfg_type_controls_perm = {
+ "controls_perm", parse_keyvalue,
+ print_keyvalue, doc_keyvalue,
+ &cfg_rep_uint32, &controls_perm_kw
+};
+
+static keyword_type_t controls_owner_kw = {
+ "owner", &cfg_type_uint32 };
+
+static cfg_type_t cfg_type_controls_owner = {
+ "controls_owner", parse_keyvalue,
+ print_keyvalue, doc_keyvalue,
+ &cfg_rep_uint32, &controls_owner_kw
+};
+
+static keyword_type_t controls_group_kw = {
+ "group", &cfg_type_uint32 };
+
+static cfg_type_t cfg_type_controls_group = {
+ "controls_allow", parse_keyvalue,
+ print_keyvalue, doc_keyvalue,
+ &cfg_rep_uint32, &controls_group_kw
+};
+
+static cfg_tuplefielddef_t unixcontrol_fields[] = {
+ { "path", &cfg_type_qstring, 0 },
+ { "perm", &cfg_type_controls_perm, 0 },
+ { "owner", &cfg_type_controls_owner, 0 },
+ { "group", &cfg_type_controls_group, 0 },
+ { "keys", &cfg_type_controls_keys, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_unixcontrol = {
+ "unixcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
+ unixcontrol_fields
+};
+
+static cfg_clausedef_t
+controls_clauses[] = {
+ { "inet", &cfg_type_inetcontrol, CFG_CLAUSEFLAG_MULTI },
+ { "unix", &cfg_type_unixcontrol, CFG_CLAUSEFLAG_MULTI },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+controls_clausesets[] = {
+ controls_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_controls = {
+ "controls", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, &controls_clausesets
+};
+
+/*%
+ * An optional class, as used in view and zone statements.
+ */
+static isc_result_t
+parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ UNUSED(type);
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string)
+ CHECK(cfg_parse_obj(pctx, &cfg_type_ustring, ret));
+ else
+ CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
+ cleanup:
+ return (result);
+}
+
+static cfg_type_t cfg_type_optional_class = {
+ "optional_class", parse_optional_class, NULL, cfg_doc_terminal,
+ NULL, NULL
+};
+
+static isc_result_t
+parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ isc_netaddr_t netaddr;
+ in_port_t port;
+ unsigned int have_address = 0;
+ unsigned int have_port = 0;
+ const unsigned int *flagp = type->of;
+
+ if ((*flagp & CFG_ADDR_V4OK) != 0)
+ isc_netaddr_any(&netaddr);
+ else if ((*flagp & CFG_ADDR_V6OK) != 0)
+ isc_netaddr_any6(&netaddr);
+ else
+ INSIST(0);
+
+ port = 0;
+
+ for (;;) {
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string) {
+ if (strcasecmp(TOKEN_STRING(pctx),
+ "address") == 0)
+ {
+ /* read "address" */
+ CHECK(cfg_gettoken(pctx, 0));
+ CHECK(cfg_parse_rawaddr(pctx, *flagp,
+ &netaddr));
+ have_address++;
+ } else if (strcasecmp(TOKEN_STRING(pctx), "port") == 0)
+ {
+ /* read "port" */
+ CHECK(cfg_gettoken(pctx, 0));
+ CHECK(cfg_parse_rawport(pctx,
+ CFG_ADDR_WILDOK,
+ &port));
+ have_port++;
+ } else if (have_port == 0 && have_address == 0) {
+ return (cfg_parse_sockaddr(pctx, type, ret));
+ } else {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected 'address' or 'port'");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ } else
+ break;
+ }
+ if (have_address > 1 || have_port > 1 ||
+ have_address + have_port == 0) {
+ cfg_parser_error(pctx, 0, "expected one address and/or port");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_querysource, &obj));
+ isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid query source");
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static void
+print_querysource(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ isc_netaddr_t na;
+ isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr);
+ cfg_print_chars(pctx, "address ", 8);
+ cfg_print_rawaddr(pctx, &na);
+ cfg_print_chars(pctx, " port ", 6);
+ cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr));
+}
+
+static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK;
+static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK;
+static cfg_type_t cfg_type_querysource4 = {
+ "querysource4", parse_querysource, NULL, cfg_doc_terminal,
+ NULL, &sockaddr4wild_flags
+};
+
+static cfg_type_t cfg_type_querysource6 = {
+ "querysource6", parse_querysource, NULL, cfg_doc_terminal,
+ NULL, &sockaddr6wild_flags
+};
+
+static cfg_type_t cfg_type_querysource = {
+ "querysource", NULL, print_querysource, NULL, &cfg_rep_sockaddr, NULL
+};
+
+/*% addrmatchelt */
+
+static isc_result_t
+parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
+
+ if (pctx->token.type == isc_tokentype_string ||
+ pctx->token.type == isc_tokentype_qstring) {
+ if (pctx->token.type == isc_tokentype_string &&
+ (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) {
+ CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret));
+ } else {
+ if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK |
+ CFG_ADDR_V4PREFIXOK |
+ CFG_ADDR_V6OK))
+ {
+ CHECK(cfg_parse_netprefix(pctx, NULL, ret));
+ } else {
+ CHECK(cfg_parse_astring(pctx, NULL, ret));
+ }
+ }
+ } else if (pctx->token.type == isc_tokentype_special) {
+ if (pctx->token.value.as_char == '{') {
+ /* Nested match list. */
+ CHECK(cfg_parse_obj(pctx, &cfg_type_bracketed_aml, ret));
+ } else if (pctx->token.value.as_char == '!') {
+ CHECK(cfg_gettoken(pctx, 0)); /* read "!" */
+ CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret));
+ } else {
+ goto bad;
+ }
+ } else {
+ bad:
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IP match list element");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ cleanup:
+ return (result);
+}
+
+/*%
+ * A negated address match list element (like "! 10.0.0.1").
+ * Somewhat sneakily, the caller is expected to parse the
+ * "!", but not to print it.
+ */
+
+static cfg_tuplefielddef_t negated_fields[] = {
+ { "value", &cfg_type_addrmatchelt, 0 },
+ { NULL, NULL, 0 }
+};
+
+static void
+print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ cfg_print_chars(pctx, "!", 1);
+ cfg_print_tuple(pctx, obj);
+}
+
+static cfg_type_t cfg_type_negated = {
+ "negated", cfg_parse_tuple, print_negated, NULL, &cfg_rep_tuple,
+ &negated_fields
+};
+
+/*% An address match list element */
+
+static cfg_type_t cfg_type_addrmatchelt = {
+ "address_match_element", parse_addrmatchelt, NULL, cfg_doc_terminal,
+ NULL, NULL
+};
+
+/*% A bracketed address match list */
+
+static cfg_type_t cfg_type_bracketed_aml = {
+ "bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt
+};
+
+/*%
+ * The socket address syntax in the "controls" statement is silly.
+ * It allows both socket address families, but also allows "*",
+ * whis is gratuitously interpreted as the IPv4 wildcard address.
+ */
+static unsigned int controls_sockaddr_flags =
+ CFG_ADDR_V4OK | CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
+static cfg_type_t cfg_type_controls_sockaddr = {
+ "controls_sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr,
+ cfg_doc_sockaddr, &cfg_rep_sockaddr, &controls_sockaddr_flags
+};
+
+/*%
+ * Handle the special kludge syntax of the "keys" clause in the "server"
+ * statement, which takes a single key with or without braces and semicolon.
+ */
+static isc_result_t
+parse_server_key_kludge(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ isc_boolean_t braces = ISC_FALSE;
+ UNUSED(type);
+
+ /* Allow opening brace. */
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == '{') {
+ result = cfg_gettoken(pctx, 0);
+ braces = ISC_TRUE;
+ }
+
+ CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
+
+ if (braces) {
+ /* Skip semicolon if present. */
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == ';')
+ CHECK(cfg_gettoken(pctx, 0));
+
+ CHECK(cfg_parse_special(pctx, '}'));
+ }
+ cleanup:
+ return (result);
+}
+static cfg_type_t cfg_type_server_key_kludge = {
+ "server_key", parse_server_key_kludge, NULL, cfg_doc_terminal,
+ NULL, NULL
+};
+
+
+/*%
+ * An optional logging facility.
+ */
+
+static isc_result_t
+parse_optional_facility(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_string ||
+ pctx->token.type == isc_tokentype_qstring) {
+ CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
+ } else {
+ CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
+ }
+ cleanup:
+ return (result);
+}
+
+static cfg_type_t cfg_type_optional_facility = {
+ "optional_facility", parse_optional_facility, NULL, cfg_doc_terminal,
+ NULL, NULL };
+
+
+/*%
+ * A log severity. Return as a string, except "debug N",
+ * which is returned as a keyword object.
+ */
+
+static keyword_type_t debug_kw = { "debug", &cfg_type_uint32 };
+static cfg_type_t cfg_type_debuglevel = {
+ "debuglevel", parse_keyvalue,
+ print_keyvalue, doc_keyvalue,
+ &cfg_rep_uint32, &debug_kw
+};
+
+static isc_result_t
+parse_logseverity(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "debug") == 0) {
+ CHECK(cfg_gettoken(pctx, 0)); /* read "debug" */
+ CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER));
+ if (pctx->token.type == isc_tokentype_number) {
+ CHECK(cfg_parse_uint32(pctx, NULL, ret));
+ } else {
+ /*
+ * The debug level is optional and defaults to 1.
+ * This makes little sense, but we support it for
+ * compatibility with BIND 8.
+ */
+ CHECK(cfg_create_obj(pctx, &cfg_type_uint32, ret));
+ (*ret)->value.uint32 = 1;
+ }
+ (*ret)->type = &cfg_type_debuglevel; /* XXX kludge */
+ } else {
+ CHECK(cfg_parse_obj(pctx, &cfg_type_loglevel, ret));
+ }
+ cleanup:
+ return (result);
+}
+
+static cfg_type_t cfg_type_logseverity = {
+ "log_severity", parse_logseverity, NULL, cfg_doc_terminal,
+ NULL, NULL };
+
+/*%
+ * The "file" clause of the "channel" statement.
+ * This is yet another special case.
+ */
+
+static const char *logversions_enums[] = { "unlimited", NULL };
+static isc_result_t
+parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_uint32, ret));
+}
+static cfg_type_t cfg_type_logversions = {
+ "logversions", parse_logversions, cfg_print_ustring, cfg_doc_terminal,
+ &cfg_rep_string, logversions_enums
+};
+
+static cfg_tuplefielddef_t logfile_fields[] = {
+ { "file", &cfg_type_qstring, 0 },
+ { "versions", &cfg_type_logversions, 0 },
+ { "size", &cfg_type_size, 0 },
+ { NULL, NULL, 0 }
+};
+
+static isc_result_t
+parse_logfile(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ const cfg_tuplefielddef_t *fields = type->of;
+
+ CHECK(cfg_create_tuple(pctx, type, &obj));
+
+ /* Parse the mandatory "file" field */
+ CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
+
+ /* Parse "versions" and "size" fields in any order. */
+ for (;;) {
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string) {
+ CHECK(cfg_gettoken(pctx, 0));
+ if (strcasecmp(TOKEN_STRING(pctx),
+ "versions") == 0 &&
+ obj->value.tuple[1] == NULL) {
+ CHECK(cfg_parse_obj(pctx, fields[1].type,
+ &obj->value.tuple[1]));
+ } else if (strcasecmp(TOKEN_STRING(pctx),
+ "size") == 0 &&
+ obj->value.tuple[2] == NULL) {
+ CHECK(cfg_parse_obj(pctx, fields[2].type,
+ &obj->value.tuple[2]));
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ /* Create void objects for missing optional values. */
+ if (obj->value.tuple[1] == NULL)
+ CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
+ if (obj->value.tuple[2] == NULL)
+ CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2]));
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static void
+print_logfile(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ cfg_print_obj(pctx, obj->value.tuple[0]); /* file */
+ if (obj->value.tuple[1]->type->print != cfg_print_void) {
+ cfg_print_chars(pctx, " versions ", 10);
+ cfg_print_obj(pctx, obj->value.tuple[1]);
+ }
+ if (obj->value.tuple[2]->type->print != cfg_print_void) {
+ cfg_print_chars(pctx, " size ", 6);
+ cfg_print_obj(pctx, obj->value.tuple[2]);
+ }
+}
+
+static cfg_type_t cfg_type_logfile = {
+ "log_file", parse_logfile, print_logfile, cfg_doc_terminal,
+ &cfg_rep_tuple, logfile_fields
+};
+
+/*% An IPv4 address with optional port, "*" accepted as wildcard. */
+static cfg_type_t cfg_type_sockaddr4wild = {
+ "sockaddr4wild", cfg_parse_sockaddr, cfg_print_sockaddr,
+ cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr4wild_flags
+};
+
+/*% An IPv6 address with optional port, "*" accepted as wildcard. */
+static cfg_type_t cfg_type_sockaddr6wild = {
+ "v6addrportwild", cfg_parse_sockaddr, cfg_print_sockaddr,
+ cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr6wild_flags
+};
+
+/*%
+ * lwres
+ */
+
+static cfg_tuplefielddef_t lwres_view_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "class", &cfg_type_optional_class, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_lwres_view = {
+ "lwres_view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
+ lwres_view_fields
+};
+
+static cfg_type_t cfg_type_lwres_searchlist = {
+ "lwres_searchlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
+ &cfg_rep_list, &cfg_type_astring };
+
+static cfg_clausedef_t
+lwres_clauses[] = {
+ { "listen-on", &cfg_type_portiplist, 0 },
+ { "view", &cfg_type_lwres_view, 0 },
+ { "search", &cfg_type_lwres_searchlist, 0 },
+ { "ndots", &cfg_type_uint32, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+lwres_clausesets[] = {
+ lwres_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_lwres = {
+ "lwres", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
+ lwres_clausesets
+};
+
+/*%
+ * rndc
+ */
+
+static cfg_clausedef_t
+rndcconf_options_clauses[] = {
+ { "default-key", &cfg_type_astring, 0 },
+ { "default-port", &cfg_type_uint32, 0 },
+ { "default-server", &cfg_type_astring, 0 },
+ { "default-source-address", &cfg_type_netaddr4wild, 0 },
+ { "default-source-address-v6", &cfg_type_netaddr6wild, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+rndcconf_options_clausesets[] = {
+ rndcconf_options_clauses,
+ NULL
+};
+
+static cfg_type_t cfg_type_rndcconf_options = {
+ "rndcconf_options", cfg_parse_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, rndcconf_options_clausesets
+};
+
+static cfg_clausedef_t
+rndcconf_server_clauses[] = {
+ { "key", &cfg_type_astring, 0 },
+ { "port", &cfg_type_uint32, 0 },
+ { "source-address", &cfg_type_netaddr4wild, 0 },
+ { "source-address-v6", &cfg_type_netaddr6wild, 0 },
+ { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+rndcconf_server_clausesets[] = {
+ rndcconf_server_clauses,
+ NULL
+};
+
+static cfg_type_t cfg_type_rndcconf_server = {
+ "rndcconf_server", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
+ &cfg_rep_map, rndcconf_server_clausesets
+};
+
+static cfg_clausedef_t
+rndcconf_clauses[] = {
+ { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
+ { "server", &cfg_type_rndcconf_server, CFG_CLAUSEFLAG_MULTI },
+ { "options", &cfg_type_rndcconf_options, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+rndcconf_clausesets[] = {
+ rndcconf_clauses,
+ NULL
+};
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndcconf = {
+ "rndcconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
+ &cfg_rep_map, rndcconf_clausesets
+};
+
+static cfg_clausedef_t
+rndckey_clauses[] = {
+ { "key", &cfg_type_key, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_clausedef_t *
+rndckey_clausesets[] = {
+ rndckey_clauses,
+ NULL
+};
+
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = {
+ "rndckey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
+ &cfg_rep_map, rndckey_clausesets
+};
+
+static cfg_tuplefielddef_t nameport_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "port", &cfg_type_optional_port, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_nameport = {
+ "nameport", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, nameport_fields
+};
+
+static void
+doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_chars(pctx, "( ", 2);
+ cfg_print_cstr(pctx, "<quoted_string>");
+ cfg_print_chars(pctx, " ", 1);
+ cfg_print_cstr(pctx, "[port <integer>]");
+ cfg_print_chars(pctx, " | ", 3);
+ cfg_print_cstr(pctx, "<ipv4_address>");
+ cfg_print_chars(pctx, " ", 1);
+ cfg_print_cstr(pctx, "[port <integer>]");
+ cfg_print_chars(pctx, " | ", 3);
+ cfg_print_cstr(pctx, "<ipv6_address>");
+ cfg_print_chars(pctx, " ", 1);
+ cfg_print_cstr(pctx, "[port <integer>]");
+ cfg_print_chars(pctx, " )", 2);
+}
+
+static isc_result_t
+parse_sockaddrnameport(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_string ||
+ pctx->token.type == isc_tokentype_qstring) {
+ if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
+ CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret));
+ else {
+ const cfg_tuplefielddef_t *fields =
+ cfg_type_nameport.of;
+ CHECK(cfg_create_tuple(pctx, &cfg_type_nameport,
+ &obj));
+ CHECK(cfg_parse_obj(pctx, fields[0].type,
+ &obj->value.tuple[0]));
+ CHECK(cfg_parse_obj(pctx, fields[1].type,
+ &obj->value.tuple[1]));
+ *ret = obj;
+ obj = NULL;
+ }
+ } else {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IP address or hostname");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static cfg_type_t cfg_type_sockaddrnameport = {
+ "sockaddrnameport_element", parse_sockaddrnameport, NULL,
+ doc_sockaddrnameport, NULL, NULL
+};
+
+static cfg_type_t cfg_type_bracketed_sockaddrnameportlist = {
+ "bracketed_sockaddrnameportlist", cfg_parse_bracketed_list,
+ cfg_print_bracketed_list, cfg_doc_bracketed_list,
+ &cfg_rep_list, &cfg_type_sockaddrnameport
+};
+
+/*%
+ * A list of socket addresses or name with an optional default port,
+ * as used in the dual-stack-servers option. E.g.,
+ * "port 1234 { dual-stack-servers.net; 10.0.0.1; 1::2 port 69; }"
+ */
+static cfg_tuplefielddef_t nameportiplist_fields[] = {
+ { "port", &cfg_type_optional_port, 0 },
+ { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_nameportiplist = {
+ "nameportiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, nameportiplist_fields
+};
+
+/*%
+ * masters element.
+ */
+
+static void
+doc_masterselement(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(type);
+ cfg_print_chars(pctx, "( ", 2);
+ cfg_print_cstr(pctx, "<masters>");
+ cfg_print_chars(pctx, " | ", 3);
+ cfg_print_cstr(pctx, "<ipv4_address>");
+ cfg_print_chars(pctx, " ", 1);
+ cfg_print_cstr(pctx, "[port <integer>]");
+ cfg_print_chars(pctx, " | ", 3);
+ cfg_print_cstr(pctx, "<ipv6_address>");
+ cfg_print_chars(pctx, " ", 1);
+ cfg_print_cstr(pctx, "[port <integer>]");
+ cfg_print_chars(pctx, " )", 2);
+}
+
+static isc_result_t
+parse_masterselement(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ UNUSED(type);
+
+ CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_string ||
+ pctx->token.type == isc_tokentype_qstring) {
+ if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
+ CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret));
+ else
+ CHECK(cfg_parse_astring(pctx, &cfg_type_astring, ret));
+ } else {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IP address or masters name");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static cfg_type_t cfg_type_masterselement = {
+ "masters_element", parse_masterselement, NULL,
+ doc_masterselement, NULL, NULL
+};
diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c
new file mode 100644
index 0000000..19a51a6
--- /dev/null
+++ b/lib/isccfg/parser.c
@@ -0,0 +1,2382 @@
+/*
+ * Copyright (C) 2004-2006 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: parser.c,v 1.112.18.11 2006/02/28 03:10:49 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/buffer.h>
+#include <isc/dir.h>
+#include <isc/formatcheck.h>
+#include <isc/lex.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/net.h>
+#include <isc/netaddr.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/sockaddr.h>
+#include <isc/netscope.h>
+#include <isc/util.h>
+#include <isc/symtab.h>
+
+#include <isccfg/cfg.h>
+#include <isccfg/grammar.h>
+#include <isccfg/log.h>
+
+/* Shorthand */
+#define CAT CFG_LOGCATEGORY_CONFIG
+#define MOD CFG_LOGMODULE_PARSER
+
+#define MAP_SYM 1 /* Unique type for isc_symtab */
+
+#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
+
+/* Check a return value. */
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto cleanup; \
+ } while (0)
+
+/* Clean up a configuration object if non-NULL. */
+#define CLEANUP_OBJ(obj) \
+ do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
+
+
+/*
+ * Forward declarations of static functions.
+ */
+
+static void
+free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj);
+
+static isc_result_t
+parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
+
+static void
+print_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
+
+static void
+free_list(cfg_parser_t *pctx, cfg_obj_t *obj);
+
+static isc_result_t
+create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp);
+
+static isc_result_t
+create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
+ cfg_obj_t **ret);
+
+static void
+free_string(cfg_parser_t *pctx, cfg_obj_t *obj);
+
+static isc_result_t
+create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
+
+static void
+free_map(cfg_parser_t *pctx, cfg_obj_t *obj);
+
+static isc_result_t
+parse_symtab_elt(cfg_parser_t *pctx, const char *name,
+ cfg_type_t *elttype, isc_symtab_t *symtab,
+ isc_boolean_t callback);
+
+static void
+free_noop(cfg_parser_t *pctx, cfg_obj_t *obj);
+
+static isc_result_t
+cfg_getstringtoken(cfg_parser_t *pctx);
+
+static void
+parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
+ unsigned int flags, const char *format, va_list args);
+
+/*
+ * Data representations. These correspond to members of the
+ * "value" union in struct cfg_obj (except "void", which does
+ * not need a union member).
+ */
+
+cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop };
+cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop };
+cfg_rep_t cfg_rep_string = { "string", free_string };
+cfg_rep_t cfg_rep_boolean = { "boolean", free_noop };
+cfg_rep_t cfg_rep_map = { "map", free_map };
+cfg_rep_t cfg_rep_list = { "list", free_list };
+cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple };
+cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop };
+cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop };
+cfg_rep_t cfg_rep_void = { "void", free_noop };
+
+/*
+ * Configuration type definitions.
+ */
+
+/*%
+ * An implicit list. These are formed by clauses that occur multiple times.
+ */
+static cfg_type_t cfg_type_implicitlist = {
+ "implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL };
+
+/* Functions. */
+
+void
+cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ obj->type->print(pctx, obj);
+}
+
+void
+cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) {
+ pctx->f(pctx->closure, text, len);
+}
+
+static void
+print_open(cfg_printer_t *pctx) {
+ cfg_print_chars(pctx, "{\n", 2);
+ pctx->indent++;
+}
+
+static void
+print_indent(cfg_printer_t *pctx) {
+ int indent = pctx->indent;
+ while (indent > 0) {
+ cfg_print_chars(pctx, "\t", 1);
+ indent--;
+ }
+}
+
+static void
+print_close(cfg_printer_t *pctx) {
+ pctx->indent--;
+ print_indent(pctx);
+ cfg_print_chars(pctx, "}", 1);
+}
+
+isc_result_t
+cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ INSIST(ret != NULL && *ret == NULL);
+ result = type->parse(pctx, type, ret);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ INSIST(*ret != NULL);
+ return (ISC_R_SUCCESS);
+}
+
+void
+cfg_print(const cfg_obj_t *obj,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure)
+{
+ cfg_printer_t pctx;
+ pctx.f = f;
+ pctx.closure = closure;
+ pctx.indent = 0;
+ obj->type->print(&pctx, obj);
+}
+
+
+/* Tuples. */
+
+isc_result_t
+cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ const cfg_tuplefielddef_t *fields = type->of;
+ const cfg_tuplefielddef_t *f;
+ cfg_obj_t *obj = NULL;
+ unsigned int nfields = 0;
+ int i;
+
+ for (f = fields; f->name != NULL; f++)
+ nfields++;
+
+ CHECK(cfg_create_obj(pctx, type, &obj));
+ obj->value.tuple = isc_mem_get(pctx->mctx,
+ nfields * sizeof(cfg_obj_t *));
+ if (obj->value.tuple == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ for (f = fields, i = 0; f->name != NULL; f++, i++)
+ obj->value.tuple[i] = NULL;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (obj != NULL)
+ isc_mem_put(pctx->mctx, obj, sizeof(*obj));
+ return (result);
+}
+
+isc_result_t
+cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ const cfg_tuplefielddef_t *fields = type->of;
+ const cfg_tuplefielddef_t *f;
+ cfg_obj_t *obj = NULL;
+ unsigned int i;
+
+ CHECK(cfg_create_tuple(pctx, type, &obj));
+ for (f = fields, i = 0; f->name != NULL; f++, i++)
+ CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i]));
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+void
+cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ unsigned int i;
+ const cfg_tuplefielddef_t *fields = obj->type->of;
+ const cfg_tuplefielddef_t *f;
+ isc_boolean_t need_space = ISC_FALSE;
+
+ for (f = fields, i = 0; f->name != NULL; f++, i++) {
+ const cfg_obj_t *fieldobj = obj->value.tuple[i];
+ if (need_space)
+ cfg_print_chars(pctx, " ", 1);
+ cfg_print_obj(pctx, fieldobj);
+ need_space = ISC_TF(fieldobj->type->print != cfg_print_void);
+ }
+}
+
+void
+cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const cfg_tuplefielddef_t *fields = type->of;
+ const cfg_tuplefielddef_t *f;
+ isc_boolean_t need_space = ISC_FALSE;
+
+ for (f = fields; f->name != NULL; f++) {
+ if (need_space)
+ cfg_print_chars(pctx, " ", 1);
+ cfg_doc_obj(pctx, f->type);
+ need_space = ISC_TF(f->type->print != cfg_print_void);
+ }
+}
+
+static void
+free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) {
+ unsigned int i;
+ const cfg_tuplefielddef_t *fields = obj->type->of;
+ const cfg_tuplefielddef_t *f;
+ unsigned int nfields = 0;
+
+ if (obj->value.tuple == NULL)
+ return;
+
+ for (f = fields, i = 0; f->name != NULL; f++, i++) {
+ CLEANUP_OBJ(obj->value.tuple[i]);
+ nfields++;
+ }
+ isc_mem_put(pctx->mctx, obj->value.tuple,
+ nfields * sizeof(cfg_obj_t *));
+}
+
+isc_boolean_t
+cfg_obj_istuple(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (ISC_TF(obj->type->rep == &cfg_rep_tuple));
+}
+
+const cfg_obj_t *
+cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) {
+ unsigned int i;
+ const cfg_tuplefielddef_t *fields;
+ const cfg_tuplefielddef_t *f;
+
+ REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple);
+
+ fields = tupleobj->type->of;
+ for (f = fields, i = 0; f->name != NULL; f++, i++) {
+ if (strcmp(f->name, name) == 0)
+ return (tupleobj->value.tuple[i]);
+ }
+ INSIST(0);
+ return (NULL);
+}
+
+isc_result_t
+cfg_parse_special(cfg_parser_t *pctx, int special) {
+ isc_result_t result;
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == special)
+ return (ISC_R_SUCCESS);
+
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special);
+ return (ISC_R_UNEXPECTEDTOKEN);
+ cleanup:
+ return (result);
+}
+
+/*
+ * Parse a required semicolon. If it is not there, log
+ * an error and increment the error count but continue
+ * parsing. Since the next token is pushed back,
+ * care must be taken to make sure it is eventually
+ * consumed or an infinite loop may result.
+ */
+static isc_result_t
+parse_semicolon(cfg_parser_t *pctx) {
+ isc_result_t result;
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == ';')
+ return (ISC_R_SUCCESS);
+
+ cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'");
+ cfg_ungettoken(pctx);
+ cleanup:
+ return (result);
+}
+
+/*
+ * Parse EOF, logging and returning an error if not there.
+ */
+static isc_result_t
+parse_eof(cfg_parser_t *pctx) {
+ isc_result_t result;
+ CHECK(cfg_gettoken(pctx, 0));
+
+ if (pctx->token.type == isc_tokentype_eof)
+ return (ISC_R_SUCCESS);
+
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ cleanup:
+ return (result);
+}
+
+/* A list of files, used internally for pctx->files. */
+
+static cfg_type_t cfg_type_filelist = {
+ "filelist", NULL, print_list, NULL, &cfg_rep_list,
+ &cfg_type_qstring
+};
+
+isc_result_t
+cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) {
+ isc_result_t result;
+ cfg_parser_t *pctx;
+ isc_lexspecials_t specials;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(ret != NULL && *ret == NULL);
+
+ pctx = isc_mem_get(mctx, sizeof(*pctx));
+ if (pctx == NULL)
+ return (ISC_R_NOMEMORY);
+
+ pctx->mctx = mctx;
+ pctx->lctx = lctx;
+ pctx->lexer = NULL;
+ pctx->seen_eof = ISC_FALSE;
+ pctx->ungotten = ISC_FALSE;
+ pctx->errors = 0;
+ pctx->warnings = 0;
+ pctx->open_files = NULL;
+ pctx->closed_files = NULL;
+ pctx->line = 0;
+ pctx->callback = NULL;
+ pctx->callbackarg = NULL;
+ pctx->token.type = isc_tokentype_unknown;
+
+ memset(specials, 0, sizeof(specials));
+ specials['{'] = 1;
+ specials['}'] = 1;
+ specials[';'] = 1;
+ specials['/'] = 1;
+ specials['"'] = 1;
+ specials['!'] = 1;
+
+ CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer));
+
+ isc_lex_setspecials(pctx->lexer, specials);
+ isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C |
+ ISC_LEXCOMMENT_CPLUSPLUS |
+ ISC_LEXCOMMENT_SHELL));
+
+ CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files));
+ CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files));
+
+ *ret = pctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (pctx->lexer != NULL)
+ isc_lex_destroy(&pctx->lexer);
+ CLEANUP_OBJ(pctx->open_files);
+ CLEANUP_OBJ(pctx->closed_files);
+ isc_mem_put(mctx, pctx, sizeof(*pctx));
+ return (result);
+}
+
+static isc_result_t
+parser_openfile(cfg_parser_t *pctx, const char *filename) {
+ isc_result_t result;
+ cfg_listelt_t *elt = NULL;
+ cfg_obj_t *stringobj = NULL;
+
+ result = isc_lex_openfile(pctx->lexer, filename);
+ if (result != ISC_R_SUCCESS) {
+ cfg_parser_error(pctx, 0, "open: %s: %s",
+ filename, isc_result_totext(result));
+ goto cleanup;
+ }
+
+ CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj));
+ CHECK(create_listelt(pctx, &elt));
+ elt->obj = stringobj;
+ ISC_LIST_APPEND(pctx->open_files->value.list, elt, link);
+
+ return (ISC_R_SUCCESS);
+ cleanup:
+ CLEANUP_OBJ(stringobj);
+ return (result);
+}
+
+void
+cfg_parser_setcallback(cfg_parser_t *pctx,
+ cfg_parsecallback_t callback,
+ void *arg)
+{
+ pctx->callback = callback;
+ pctx->callbackarg = arg;
+}
+
+/*
+ * Parse a configuration using a pctx where a lexer has already
+ * been set up with a source.
+ */
+static isc_result_t
+parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+
+ result = cfg_parse_obj(pctx, type, &obj);
+
+ if (pctx->errors != 0) {
+ /* Errors have been logged. */
+ if (result == ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ if (result != ISC_R_SUCCESS) {
+ /* Parsing failed but no errors have been logged. */
+ cfg_parser_error(pctx, 0, "parsing failed");
+ goto cleanup;
+ }
+
+ CHECK(parse_eof(pctx));
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+isc_result_t
+cfg_parse_file(cfg_parser_t *pctx, const char *filename,
+ const cfg_type_t *type, cfg_obj_t **ret)
+{
+ isc_result_t result;
+
+ REQUIRE(filename != NULL);
+
+ CHECK(parser_openfile(pctx, filename));
+ CHECK(parse2(pctx, type, ret));
+ cleanup:
+ return (result);
+}
+
+
+isc_result_t
+cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer,
+ const cfg_type_t *type, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ REQUIRE(buffer != NULL);
+ CHECK(isc_lex_openbuffer(pctx->lexer, buffer));
+ CHECK(parse2(pctx, type, ret));
+ cleanup:
+ return (result);
+}
+
+void
+cfg_parser_destroy(cfg_parser_t **pctxp) {
+ cfg_parser_t *pctx = *pctxp;
+ isc_lex_destroy(&pctx->lexer);
+ /*
+ * Cleaning up open_files does not
+ * close the files; that was already done
+ * by closing the lexer.
+ */
+ CLEANUP_OBJ(pctx->open_files);
+ CLEANUP_OBJ(pctx->closed_files);
+ isc_mem_put(pctx->mctx, pctx, sizeof(*pctx));
+ *pctxp = NULL;
+}
+
+/*
+ * void
+ */
+isc_result_t
+cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ UNUSED(type);
+ return (cfg_create_obj(pctx, &cfg_type_void, ret));
+}
+
+void
+cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ UNUSED(pctx);
+ UNUSED(obj);
+}
+
+void
+cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) {
+ UNUSED(pctx);
+ UNUSED(type);
+}
+
+isc_boolean_t
+cfg_obj_isvoid(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (ISC_TF(obj->type->rep == &cfg_rep_void));
+}
+
+cfg_type_t cfg_type_void = {
+ "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void,
+ NULL };
+
+
+/*
+ * uint32
+ */
+isc_result_t
+cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
+ if (pctx->token.type != isc_tokentype_number) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
+
+ obj->value.uint32 = pctx->token.value.as_ulong;
+ *ret = obj;
+ cleanup:
+ return (result);
+}
+
+void
+cfg_print_cstr(cfg_printer_t *pctx, const char *s) {
+ cfg_print_chars(pctx, s, strlen(s));
+}
+
+void
+cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%u", u);
+ cfg_print_cstr(pctx, buf);
+}
+
+void
+cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ cfg_print_rawuint(pctx, obj->value.uint32);
+}
+
+isc_boolean_t
+cfg_obj_isuint32(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (ISC_TF(obj->type->rep == &cfg_rep_uint32));
+}
+
+isc_uint32_t
+cfg_obj_asuint32(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32);
+ return (obj->value.uint32);
+}
+
+cfg_type_t cfg_type_uint32 = {
+ "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal,
+ &cfg_rep_uint32, NULL
+};
+
+
+/*
+ * uint64
+ */
+isc_boolean_t
+cfg_obj_isuint64(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (ISC_TF(obj->type->rep == &cfg_rep_uint64));
+}
+
+isc_uint64_t
+cfg_obj_asuint64(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64);
+ return (obj->value.uint64);
+}
+
+void
+cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%" ISC_PRINT_QUADFORMAT "u",
+ obj->value.uint64);
+ cfg_print_cstr(pctx, buf);
+}
+
+cfg_type_t cfg_type_uint64 = {
+ "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal,
+ &cfg_rep_uint64, NULL
+};
+
+/*
+ * qstring (quoted string), ustring (unquoted string), astring
+ * (any string)
+ */
+
+/* Create a string object from a null-terminated C string. */
+static isc_result_t
+create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ int len;
+
+ CHECK(cfg_create_obj(pctx, type, &obj));
+ len = strlen(contents);
+ obj->value.string.length = len;
+ obj->value.string.base = isc_mem_get(pctx->mctx, len + 1);
+ if (obj->value.string.base == 0) {
+ isc_mem_put(pctx->mctx, obj, sizeof(*obj));
+ return (ISC_R_NOMEMORY);
+ }
+ memcpy(obj->value.string.base, contents, len);
+ obj->value.string.base[len] = '\0';
+
+ *ret = obj;
+ cleanup:
+ return (result);
+}
+
+isc_result_t
+cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type != isc_tokentype_qstring) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ return (create_string(pctx,
+ TOKEN_STRING(pctx),
+ &cfg_type_qstring,
+ ret));
+ cleanup:
+ return (result);
+}
+
+static isc_result_t
+parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type != isc_tokentype_string) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ return (create_string(pctx,
+ TOKEN_STRING(pctx),
+ &cfg_type_ustring,
+ ret));
+ cleanup:
+ return (result);
+}
+
+isc_result_t
+cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ UNUSED(type);
+
+ CHECK(cfg_getstringtoken(pctx));
+ return (create_string(pctx,
+ TOKEN_STRING(pctx),
+ &cfg_type_qstring,
+ ret));
+ cleanup:
+ return (result);
+}
+
+isc_boolean_t
+cfg_is_enum(const char *s, const char *const *enums) {
+ const char * const *p;
+ for (p = enums; *p != NULL; p++) {
+ if (strcasecmp(*p, s) == 0)
+ return (ISC_TRUE);
+ }
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) {
+ const char *s = obj->value.string.base;
+ if (cfg_is_enum(s, enums))
+ return (ISC_R_SUCCESS);
+ cfg_parser_error(pctx, 0, "'%s' unexpected", s);
+ return (ISC_R_UNEXPECTEDTOKEN);
+}
+
+isc_result_t
+cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ CHECK(parse_ustring(pctx, NULL, &obj));
+ CHECK(check_enum(pctx, obj, type->of));
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+void
+cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const char * const *p;
+ cfg_print_chars(pctx, "( ", 2);
+ for (p = type->of; *p != NULL; p++) {
+ cfg_print_cstr(pctx, *p);
+ if (p[1] != NULL)
+ cfg_print_chars(pctx, " | ", 3);
+ }
+ cfg_print_chars(pctx, " )", 2);
+}
+
+void
+cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
+}
+
+static void
+print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ cfg_print_chars(pctx, "\"", 1);
+ cfg_print_ustring(pctx, obj);
+ cfg_print_chars(pctx, "\"", 1);
+}
+
+static void
+free_string(cfg_parser_t *pctx, cfg_obj_t *obj) {
+ isc_mem_put(pctx->mctx, obj->value.string.base,
+ obj->value.string.length + 1);
+}
+
+isc_boolean_t
+cfg_obj_isstring(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (ISC_TF(obj->type->rep == &cfg_rep_string));
+}
+
+const char *
+cfg_obj_asstring(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string);
+ return (obj->value.string.base);
+}
+
+/* Quoted string only */
+cfg_type_t cfg_type_qstring = {
+ "quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal,
+ &cfg_rep_string, NULL
+};
+
+/* Unquoted string only */
+cfg_type_t cfg_type_ustring = {
+ "string", parse_ustring, cfg_print_ustring, cfg_doc_terminal,
+ &cfg_rep_string, NULL
+};
+
+/* Any string (quoted or unquoted); printed with quotes */
+cfg_type_t cfg_type_astring = {
+ "string", cfg_parse_astring, print_qstring, cfg_doc_terminal,
+ &cfg_rep_string, NULL
+};
+
+/*
+ * Booleans
+ */
+
+isc_boolean_t
+cfg_obj_isboolean(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (ISC_TF(obj->type->rep == &cfg_rep_boolean));
+}
+
+isc_boolean_t
+cfg_obj_asboolean(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean);
+ return (obj->value.boolean);
+}
+
+static isc_result_t
+parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ isc_boolean_t value;
+ cfg_obj_t *obj = NULL;
+ UNUSED(type);
+
+ result = cfg_gettoken(pctx, 0);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (pctx->token.type != isc_tokentype_string)
+ goto bad_boolean;
+
+ if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) ||
+ (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) ||
+ (strcmp(TOKEN_STRING(pctx), "1") == 0)) {
+ value = ISC_TRUE;
+ } else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) ||
+ (strcasecmp(TOKEN_STRING(pctx), "no") == 0) ||
+ (strcmp(TOKEN_STRING(pctx), "0") == 0)) {
+ value = ISC_FALSE;
+ } else {
+ goto bad_boolean;
+ }
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj));
+ obj->value.boolean = value;
+ *ret = obj;
+ return (result);
+
+ bad_boolean:
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected");
+ return (ISC_R_UNEXPECTEDTOKEN);
+
+ cleanup:
+ return (result);
+}
+
+static void
+print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ if (obj->value.boolean)
+ cfg_print_chars(pctx, "yes", 3);
+ else
+ cfg_print_chars(pctx, "no", 2);
+}
+
+cfg_type_t cfg_type_boolean = {
+ "boolean", parse_boolean, print_boolean, cfg_doc_terminal,
+ &cfg_rep_boolean, NULL
+};
+
+/*
+ * Lists.
+ */
+
+isc_result_t
+cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) {
+ isc_result_t result;
+ CHECK(cfg_create_obj(pctx, type, obj));
+ ISC_LIST_INIT((*obj)->value.list);
+ cleanup:
+ return (result);
+}
+
+static isc_result_t
+create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) {
+ cfg_listelt_t *elt;
+ elt = isc_mem_get(pctx->mctx, sizeof(*elt));
+ if (elt == NULL)
+ return (ISC_R_NOMEMORY);
+ elt->obj = NULL;
+ ISC_LINK_INIT(elt, link);
+ *eltp = elt;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+free_list_elt(cfg_parser_t *pctx, cfg_listelt_t *elt) {
+ cfg_obj_destroy(pctx, &elt->obj);
+ isc_mem_put(pctx->mctx, elt, sizeof(*elt));
+}
+
+static void
+free_list(cfg_parser_t *pctx, cfg_obj_t *obj) {
+ cfg_listelt_t *elt, *next;
+ for (elt = ISC_LIST_HEAD(obj->value.list);
+ elt != NULL;
+ elt = next)
+ {
+ next = ISC_LIST_NEXT(elt, link);
+ free_list_elt(pctx, elt);
+ }
+}
+
+isc_result_t
+cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
+ cfg_listelt_t **ret)
+{
+ isc_result_t result;
+ cfg_listelt_t *elt = NULL;
+ cfg_obj_t *value = NULL;
+
+ CHECK(create_listelt(pctx, &elt));
+
+ result = cfg_parse_obj(pctx, elttype, &value);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ elt->obj = value;
+
+ *ret = elt;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ isc_mem_put(pctx->mctx, elt, sizeof(*elt));
+ return (result);
+}
+
+/*
+ * Parse a homogeneous list whose elements are of type 'elttype'
+ * and where each element is terminated by a semicolon.
+ */
+static isc_result_t
+parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret)
+{
+ cfg_obj_t *listobj = NULL;
+ const cfg_type_t *listof = listtype->of;
+ isc_result_t result;
+ cfg_listelt_t *elt = NULL;
+
+ CHECK(cfg_create_list(pctx, listtype, &listobj));
+
+ for (;;) {
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == /*{*/ '}')
+ break;
+ CHECK(cfg_parse_listelt(pctx, listof, &elt));
+ CHECK(parse_semicolon(pctx));
+ ISC_LIST_APPEND(listobj->value.list, elt, link);
+ elt = NULL;
+ }
+ *ret = listobj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (elt != NULL)
+ free_list_elt(pctx, elt);
+ CLEANUP_OBJ(listobj);
+ return (result);
+}
+
+static void
+print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ const cfg_list_t *list = &obj->value.list;
+ const cfg_listelt_t *elt;
+
+ for (elt = ISC_LIST_HEAD(*list);
+ elt != NULL;
+ elt = ISC_LIST_NEXT(elt, link)) {
+ print_indent(pctx);
+ cfg_print_obj(pctx, elt->obj);
+ cfg_print_chars(pctx, ";\n", 2);
+ }
+}
+
+isc_result_t
+cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ CHECK(cfg_parse_special(pctx, '{'));
+ CHECK(parse_list(pctx, type, ret));
+ CHECK(cfg_parse_special(pctx, '}'));
+ cleanup:
+ return (result);
+}
+
+void
+cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ print_open(pctx);
+ print_list(pctx, obj);
+ print_close(pctx);
+}
+
+void
+cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
+ cfg_print_chars(pctx, "{ ", 2);
+ cfg_doc_obj(pctx, type->of);
+ cfg_print_chars(pctx, "; ... }", 7);
+}
+
+/*
+ * Parse a homogeneous list whose elements are of type 'elttype'
+ * and where elements are separated by space. The list ends
+ * before the first semicolon.
+ */
+isc_result_t
+cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype,
+ cfg_obj_t **ret)
+{
+ cfg_obj_t *listobj = NULL;
+ const cfg_type_t *listof = listtype->of;
+ isc_result_t result;
+
+ CHECK(cfg_create_list(pctx, listtype, &listobj));
+
+ for (;;) {
+ cfg_listelt_t *elt = NULL;
+
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == ';')
+ break;
+ CHECK(cfg_parse_listelt(pctx, listof, &elt));
+ ISC_LIST_APPEND(listobj->value.list, elt, link);
+ }
+ *ret = listobj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(listobj);
+ return (result);
+}
+
+void
+cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ const cfg_list_t *list = &obj->value.list;
+ const cfg_listelt_t *elt;
+
+ for (elt = ISC_LIST_HEAD(*list);
+ elt != NULL;
+ elt = ISC_LIST_NEXT(elt, link)) {
+ cfg_print_obj(pctx, elt->obj);
+ if (ISC_LIST_NEXT(elt, link) != NULL)
+ cfg_print_chars(pctx, " ", 1);
+ }
+}
+
+isc_boolean_t
+cfg_obj_islist(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (ISC_TF(obj->type->rep == &cfg_rep_list));
+}
+
+const cfg_listelt_t *
+cfg_list_first(const cfg_obj_t *obj) {
+ REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list);
+ if (obj == NULL)
+ return (NULL);
+ return (ISC_LIST_HEAD(obj->value.list));
+}
+
+const cfg_listelt_t *
+cfg_list_next(const cfg_listelt_t *elt) {
+ REQUIRE(elt != NULL);
+ return (ISC_LIST_NEXT(elt, link));
+}
+
+const cfg_obj_t *
+cfg_listelt_value(const cfg_listelt_t *elt) {
+ REQUIRE(elt != NULL);
+ return (elt->obj);
+}
+
+/*
+ * Maps.
+ */
+
+/*
+ * Parse a map body. That's something like
+ *
+ * "foo 1; bar { glub; }; zap true; zap false;"
+ *
+ * i.e., a sequence of option names followed by values and
+ * terminated by semicolons. Used for the top level of
+ * the named.conf syntax, as well as for the body of the
+ * options, view, zone, and other statements.
+ */
+isc_result_t
+cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
+{
+ const cfg_clausedef_t * const *clausesets = type->of;
+ isc_result_t result;
+ const cfg_clausedef_t * const *clauseset;
+ const cfg_clausedef_t *clause;
+ cfg_obj_t *value = NULL;
+ cfg_obj_t *obj = NULL;
+ cfg_obj_t *eltobj = NULL;
+ cfg_obj_t *includename = NULL;
+ isc_symvalue_t symval;
+ cfg_list_t *list = NULL;
+
+ CHECK(create_map(pctx, type, &obj));
+
+ obj->value.map.clausesets = clausesets;
+
+ for (;;) {
+ cfg_listelt_t *elt;
+
+ redo:
+ /*
+ * Parse the option name and see if it is known.
+ */
+ CHECK(cfg_gettoken(pctx, 0));
+
+ if (pctx->token.type != isc_tokentype_string) {
+ cfg_ungettoken(pctx);
+ break;
+ }
+
+ /*
+ * We accept "include" statements wherever a map body
+ * clause can occur.
+ */
+ if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) {
+ /*
+ * Turn the file name into a temporary configuration
+ * object just so that it is not overwritten by the
+ * semicolon token.
+ */
+ CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename));
+ CHECK(parse_semicolon(pctx));
+ CHECK(parser_openfile(pctx, includename->
+ value.string.base));
+ cfg_obj_destroy(pctx, &includename);
+ goto redo;
+ }
+
+ clause = NULL;
+ for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
+ for (clause = *clauseset;
+ clause->name != NULL;
+ clause++) {
+ if (strcasecmp(TOKEN_STRING(pctx),
+ clause->name) == 0)
+ goto done;
+ }
+ }
+ done:
+ if (clause == NULL || clause->name == NULL) {
+ cfg_parser_error(pctx, CFG_LOG_NOPREP, "unknown option");
+ /*
+ * Try to recover by parsing this option as an unknown
+ * option and discarding it.
+ */
+ CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported, &eltobj));
+ cfg_obj_destroy(pctx, &eltobj);
+ CHECK(parse_semicolon(pctx));
+ continue;
+ }
+
+ /* Clause is known. */
+
+ /* Issue warnings if appropriate */
+ if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0)
+ cfg_parser_warning(pctx, 0, "option '%s' is obsolete",
+ clause->name);
+ if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0)
+ cfg_parser_warning(pctx, 0, "option '%s' is "
+ "not implemented", clause->name);
+ if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0)
+ cfg_parser_warning(pctx, 0, "option '%s' is "
+ "not implemented", clause->name);
+ /*
+ * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
+ * set here - we need to log the *lack* of such an option,
+ * not its presence.
+ */
+
+ /* See if the clause already has a value; if not create one. */
+ result = isc_symtab_lookup(obj->value.map.symtab,
+ clause->name, 0, &symval);
+
+ if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
+ /* Multivalued clause */
+ cfg_obj_t *listobj = NULL;
+ if (result == ISC_R_NOTFOUND) {
+ CHECK(cfg_create_list(pctx,
+ &cfg_type_implicitlist,
+ &listobj));
+ symval.as_pointer = listobj;
+ result = isc_symtab_define(obj->value.
+ map.symtab,
+ clause->name,
+ 1, symval,
+ isc_symexists_reject);
+ if (result != ISC_R_SUCCESS) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "isc_symtab_define(%s) "
+ "failed", clause->name);
+ isc_mem_put(pctx->mctx, list,
+ sizeof(cfg_list_t));
+ goto cleanup;
+ }
+ } else {
+ INSIST(result == ISC_R_SUCCESS);
+ listobj = symval.as_pointer;
+ }
+
+ elt = NULL;
+ CHECK(cfg_parse_listelt(pctx, clause->type, &elt));
+ CHECK(parse_semicolon(pctx));
+
+ ISC_LIST_APPEND(listobj->value.list, elt, link);
+ } else {
+ /* Single-valued clause */
+ if (result == ISC_R_NOTFOUND) {
+ isc_boolean_t callback =
+ ISC_TF((clause->flags &
+ CFG_CLAUSEFLAG_CALLBACK) != 0);
+ CHECK(parse_symtab_elt(pctx, clause->name,
+ clause->type,
+ obj->value.map.symtab,
+ callback));
+ CHECK(parse_semicolon(pctx));
+ } else if (result == ISC_R_SUCCESS) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined",
+ clause->name);
+ result = ISC_R_EXISTS;
+ goto cleanup;
+ } else {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "isc_symtab_define() failed");
+ goto cleanup;
+ }
+ }
+ }
+
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(value);
+ CLEANUP_OBJ(obj);
+ CLEANUP_OBJ(eltobj);
+ CLEANUP_OBJ(includename);
+ return (result);
+}
+
+static isc_result_t
+parse_symtab_elt(cfg_parser_t *pctx, const char *name,
+ cfg_type_t *elttype, isc_symtab_t *symtab,
+ isc_boolean_t callback)
+{
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ isc_symvalue_t symval;
+
+ CHECK(cfg_parse_obj(pctx, elttype, &obj));
+
+ if (callback && pctx->callback != NULL)
+ CHECK(pctx->callback(name, obj, pctx->callbackarg));
+
+ symval.as_pointer = obj;
+ CHECK(isc_symtab_define(symtab, name,
+ 1, symval,
+ isc_symexists_reject));
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+/*
+ * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
+ */
+isc_result_t
+cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ CHECK(cfg_parse_special(pctx, '{'));
+ CHECK(cfg_parse_mapbody(pctx, type, ret));
+ CHECK(cfg_parse_special(pctx, '}'));
+ cleanup:
+ return (result);
+}
+
+/*
+ * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map().
+ */
+static isc_result_t
+parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ isc_result_t result;
+ cfg_obj_t *idobj = NULL;
+ cfg_obj_t *mapobj = NULL;
+
+ CHECK(cfg_parse_obj(pctx, nametype, &idobj));
+ CHECK(cfg_parse_map(pctx, type, &mapobj));
+ mapobj->value.map.id = idobj;
+ idobj = NULL;
+ *ret = mapobj;
+ cleanup:
+ CLEANUP_OBJ(idobj);
+ return (result);
+}
+
+/*
+ * Parse a map identified by a string name. E.g., "name { foo 1; }".
+ * Used for the "key" and "channel" statements.
+ */
+isc_result_t
+cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_any_named_map(pctx, &cfg_type_astring, type, ret));
+}
+
+/*
+ * Parse a map identified by a network address.
+ * Used to be used for the "server" statement.
+ */
+isc_result_t
+cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret));
+}
+
+/*
+ * Parse a map identified by a network prefix.
+ * Used for the "server" statement.
+ */
+isc_result_t
+cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret));
+}
+
+void
+cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ const cfg_clausedef_t * const *clauseset;
+
+ for (clauseset = obj->value.map.clausesets;
+ *clauseset != NULL;
+ clauseset++)
+ {
+ isc_symvalue_t symval;
+ const cfg_clausedef_t *clause;
+
+ for (clause = *clauseset;
+ clause->name != NULL;
+ clause++) {
+ result = isc_symtab_lookup(obj->value.map.symtab,
+ clause->name, 0, &symval);
+ if (result == ISC_R_SUCCESS) {
+ cfg_obj_t *obj = symval.as_pointer;
+ if (obj->type == &cfg_type_implicitlist) {
+ /* Multivalued. */
+ cfg_list_t *list = &obj->value.list;
+ cfg_listelt_t *elt;
+ for (elt = ISC_LIST_HEAD(*list);
+ elt != NULL;
+ elt = ISC_LIST_NEXT(elt, link)) {
+ print_indent(pctx);
+ cfg_print_cstr(pctx, clause->name);
+ cfg_print_chars(pctx, " ", 1);
+ cfg_print_obj(pctx, elt->obj);
+ cfg_print_chars(pctx, ";\n", 2);
+ }
+ } else {
+ /* Single-valued. */
+ print_indent(pctx);
+ cfg_print_cstr(pctx, clause->name);
+ cfg_print_chars(pctx, " ", 1);
+ cfg_print_obj(pctx, obj);
+ cfg_print_chars(pctx, ";\n", 2);
+ }
+ } else if (result == ISC_R_NOTFOUND) {
+ ; /* do nothing */
+ } else {
+ INSIST(0);
+ }
+ }
+ }
+}
+
+void
+cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const cfg_clausedef_t * const *clauseset;
+ const cfg_clausedef_t *clause;
+
+ for (clauseset = type->of; *clauseset != NULL; clauseset++) {
+ for (clause = *clauseset;
+ clause->name != NULL;
+ clause++) {
+ cfg_print_cstr(pctx, clause->name);
+ cfg_print_chars(pctx, " ", 1);
+ cfg_doc_obj(pctx, clause->type);
+ cfg_print_chars(pctx, ";", 1);
+ /* XXX print flags here? */
+ cfg_print_chars(pctx, "\n\n", 2);
+ }
+ }
+}
+
+static struct flagtext {
+ unsigned int flag;
+ const char *text;
+} flagtexts[] = {
+ { CFG_CLAUSEFLAG_NOTIMP, "not implemented" },
+ { CFG_CLAUSEFLAG_NYI, "not yet implemented" },
+ { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" },
+ { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" },
+ { 0, NULL }
+};
+
+void
+cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ if (obj->value.map.id != NULL) {
+ cfg_print_obj(pctx, obj->value.map.id);
+ cfg_print_chars(pctx, " ", 1);
+ }
+ print_open(pctx);
+ cfg_print_mapbody(pctx, obj);
+ print_close(pctx);
+}
+
+static void
+print_clause_flags(cfg_printer_t *pctx, unsigned int flags) {
+ struct flagtext *p;
+ isc_boolean_t first = ISC_TRUE;
+ for (p = flagtexts; p->flag != 0; p++) {
+ if ((flags & p->flag) != 0) {
+ if (first)
+ cfg_print_chars(pctx, " // ", 4);
+ else
+ cfg_print_chars(pctx, ", ", 2);
+ cfg_print_cstr(pctx, p->text);
+ first = ISC_FALSE;
+ }
+ }
+}
+
+void
+cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const cfg_clausedef_t * const *clauseset;
+ const cfg_clausedef_t *clause;
+
+ if (type->parse == cfg_parse_named_map) {
+ cfg_doc_obj(pctx, &cfg_type_astring);
+ cfg_print_chars(pctx, " ", 1);
+ } else if (type->parse == cfg_parse_addressed_map) {
+ cfg_doc_obj(pctx, &cfg_type_netaddr);
+ cfg_print_chars(pctx, " ", 1);
+ } else if (type->parse == cfg_parse_netprefix_map) {
+ cfg_doc_obj(pctx, &cfg_type_netprefix);
+ cfg_print_chars(pctx, " ", 1);
+ }
+
+ print_open(pctx);
+
+ for (clauseset = type->of; *clauseset != NULL; clauseset++) {
+ for (clause = *clauseset;
+ clause->name != NULL;
+ clause++) {
+ print_indent(pctx);
+ cfg_print_cstr(pctx, clause->name);
+ if (clause->type->print != cfg_print_void)
+ cfg_print_chars(pctx, " ", 1);
+ cfg_doc_obj(pctx, clause->type);
+ cfg_print_chars(pctx, ";", 1);
+ print_clause_flags(pctx, clause->flags);
+ cfg_print_chars(pctx, "\n", 1);
+ }
+ }
+ print_close(pctx);
+}
+
+isc_boolean_t
+cfg_obj_ismap(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (ISC_TF(obj->type->rep == &cfg_rep_map));
+}
+
+isc_result_t
+cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) {
+ isc_result_t result;
+ isc_symvalue_t val;
+ const cfg_map_t *map;
+
+ REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
+ REQUIRE(name != NULL);
+ REQUIRE(obj != NULL && *obj == NULL);
+
+ map = &mapobj->value.map;
+
+ result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ *obj = val.as_pointer;
+ return (ISC_R_SUCCESS);
+}
+
+const cfg_obj_t *
+cfg_map_getname(const cfg_obj_t *mapobj) {
+ REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
+ return (mapobj->value.map.id);
+}
+
+
+/* Parse an arbitrary token, storing its raw text representation. */
+static isc_result_t
+parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ cfg_obj_t *obj = NULL;
+ isc_result_t result;
+ isc_region_t r;
+
+ UNUSED(type);
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj));
+ CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
+ if (pctx->token.type == isc_tokentype_eof) {
+ cfg_ungettoken(pctx);
+ result = ISC_R_EOF;
+ goto cleanup;
+ }
+
+ isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r);
+
+ obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1);
+ if (obj->value.string.base == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ obj->value.string.length = r.length;
+ memcpy(obj->value.string.base, r.base, r.length);
+ obj->value.string.base[r.length] = '\0';
+ *ret = obj;
+ return (result);
+
+ cleanup:
+ if (obj != NULL)
+ isc_mem_put(pctx->mctx, obj, sizeof(*obj));
+ return (result);
+}
+
+cfg_type_t cfg_type_token = {
+ "token", parse_token, cfg_print_ustring, cfg_doc_terminal,
+ &cfg_rep_string, NULL
+};
+
+/*
+ * An unsupported option. This is just a list of tokens with balanced braces
+ * ending in a semicolon.
+ */
+
+static isc_result_t
+parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ cfg_obj_t *listobj = NULL;
+ isc_result_t result;
+ int braces = 0;
+
+ CHECK(cfg_create_list(pctx, type, &listobj));
+
+ for (;;) {
+ cfg_listelt_t *elt = NULL;
+
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special) {
+ if (pctx->token.value.as_char == '{')
+ braces++;
+ else if (pctx->token.value.as_char == '}')
+ braces--;
+ else if (pctx->token.value.as_char == ';')
+ if (braces == 0)
+ break;
+ }
+ if (pctx->token.type == isc_tokentype_eof || braces < 0) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token");
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+
+ CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt));
+ ISC_LIST_APPEND(listobj->value.list, elt, link);
+ }
+ INSIST(braces == 0);
+ *ret = listobj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(listobj);
+ return (result);
+}
+
+cfg_type_t cfg_type_unsupported = {
+ "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal,
+ &cfg_rep_list, NULL
+};
+
+/*
+ * Try interpreting the current token as a network address.
+ *
+ * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard
+ * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set. The
+ * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is
+ * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set),
+ * and the IPv6 wildcard address otherwise.
+ */
+static isc_result_t
+token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
+ char *s;
+ struct in_addr in4a;
+ struct in6_addr in6a;
+
+ if (pctx->token.type != isc_tokentype_string)
+ return (ISC_R_UNEXPECTEDTOKEN);
+
+ s = TOKEN_STRING(pctx);
+ if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) {
+ if ((flags & CFG_ADDR_V4OK) != 0) {
+ isc_netaddr_any(na);
+ return (ISC_R_SUCCESS);
+ } else if ((flags & CFG_ADDR_V6OK) != 0) {
+ isc_netaddr_any6(na);
+ return (ISC_R_SUCCESS);
+ } else {
+ INSIST(0);
+ }
+ } else {
+ if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) {
+ if (inet_pton(AF_INET, s, &in4a) == 1) {
+ isc_netaddr_fromin(na, &in4a);
+ return (ISC_R_SUCCESS);
+ }
+ }
+ if ((flags & CFG_ADDR_V4PREFIXOK) != 0 &&
+ strlen(s) <= 15U) {
+ char buf[64];
+ int i;
+
+ strcpy(buf, s);
+ for (i = 0; i < 3; i++) {
+ strcat(buf, ".0");
+ if (inet_pton(AF_INET, buf, &in4a) == 1) {
+ isc_netaddr_fromin(na, &in4a);
+ return (ISC_R_SUCCESS);
+ }
+ }
+ }
+ if ((flags & CFG_ADDR_V6OK) != 0 &&
+ strlen(s) <= 127U) {
+ char buf[128]; /* see lib/bind9/getaddresses.c */
+ char *d; /* zone delimiter */
+ isc_uint32_t zone = 0; /* scope zone ID */
+
+ strcpy(buf, s);
+ d = strchr(buf, '%');
+ if (d != NULL)
+ *d = '\0';
+
+ if (inet_pton(AF_INET6, buf, &in6a) == 1) {
+ if (d != NULL) {
+#ifdef ISC_PLATFORM_HAVESCOPEID
+ isc_result_t result;
+
+ result = isc_netscope_pton(AF_INET6,
+ d + 1,
+ &in6a,
+ &zone);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#else
+ return (ISC_R_BADADDRESSFORM);
+#endif
+ }
+
+ isc_netaddr_fromin6(na, &in6a);
+ isc_netaddr_setzone(na, zone);
+ return (ISC_R_SUCCESS);
+ }
+ }
+ }
+ return (ISC_R_UNEXPECTEDTOKEN);
+}
+
+isc_result_t
+cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
+ isc_result_t result;
+ const char *wild = "";
+ const char *prefix = "";
+
+ CHECK(cfg_gettoken(pctx, 0));
+ result = token_addr(pctx, flags, na);
+ if (result == ISC_R_UNEXPECTEDTOKEN) {
+ if ((flags & CFG_ADDR_WILDOK) != 0)
+ wild = " or '*'";
+ if ((flags & CFG_ADDR_V4PREFIXOK) != 0)
+ wild = " or IPv4 prefix";
+ if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK)
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IPv4 address%s%s",
+ prefix, wild);
+ else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK)
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IPv6 address%s%s",
+ prefix, wild);
+ else
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected IP address%s%s",
+ prefix, wild);
+ }
+ cleanup:
+ return (result);
+}
+
+isc_boolean_t
+cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) {
+ isc_result_t result;
+ isc_netaddr_t na_dummy;
+ result = token_addr(pctx, flags, &na_dummy);
+ return (ISC_TF(result == ISC_R_SUCCESS));
+}
+
+isc_result_t
+cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) {
+ isc_result_t result;
+
+ CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
+
+ if ((flags & CFG_ADDR_WILDOK) != 0 &&
+ pctx->token.type == isc_tokentype_string &&
+ strcmp(TOKEN_STRING(pctx), "*") == 0) {
+ *port = 0;
+ return (ISC_R_SUCCESS);
+ }
+ if (pctx->token.type != isc_tokentype_number) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected port number or '*'");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ if (pctx->token.value.as_ulong >= 65536U) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "port number out of range");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ *port = (in_port_t)(pctx->token.value.as_ulong);
+ return (ISC_R_SUCCESS);
+ cleanup:
+ return (result);
+}
+
+void
+cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) {
+ isc_result_t result;
+ char text[128];
+ isc_buffer_t buf;
+
+ isc_buffer_init(&buf, text, sizeof(text));
+ result = isc_netaddr_totext(na, &buf);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf));
+}
+
+/* netaddr */
+
+static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
+static unsigned int netaddr4_flags = CFG_ADDR_V4OK;
+static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK;
+static unsigned int netaddr6_flags = CFG_ADDR_V6OK;
+static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
+
+static isc_result_t
+parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ isc_netaddr_t netaddr;
+ unsigned int flags = *(const unsigned int *)type->of;
+
+ CHECK(cfg_create_obj(pctx, type, &obj));
+ CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
+ isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0);
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static void
+cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const unsigned int *flagp = type->of;
+ int n = 0;
+ if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
+ cfg_print_chars(pctx, "( ", 2);
+ if (*flagp & CFG_ADDR_V4OK) {
+ cfg_print_cstr(pctx, "<ipv4_address>");
+ n++;
+ }
+ if (*flagp & CFG_ADDR_V6OK) {
+ if (n != 0)
+ cfg_print_chars(pctx, " | ", 3);
+ cfg_print_cstr(pctx, "<ipv6_address>");
+ n++;
+ }
+ if (*flagp & CFG_ADDR_WILDOK) {
+ if (n != 0)
+ cfg_print_chars(pctx, " | ", 3);
+ cfg_print_chars(pctx, "*", 1);
+ n++;
+ }
+ if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
+ cfg_print_chars(pctx, " )", 2);
+}
+
+cfg_type_t cfg_type_netaddr = {
+ "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
+ &cfg_rep_sockaddr, &netaddr_flags
+};
+
+cfg_type_t cfg_type_netaddr4 = {
+ "netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
+ &cfg_rep_sockaddr, &netaddr4_flags
+};
+
+cfg_type_t cfg_type_netaddr4wild = {
+ "netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
+ &cfg_rep_sockaddr, &netaddr4wild_flags
+};
+
+cfg_type_t cfg_type_netaddr6 = {
+ "netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
+ &cfg_rep_sockaddr, &netaddr6_flags
+};
+
+cfg_type_t cfg_type_netaddr6wild = {
+ "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
+ &cfg_rep_sockaddr, &netaddr6wild_flags
+};
+
+/* netprefix */
+
+isc_result_t
+cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type,
+ cfg_obj_t **ret)
+{
+ cfg_obj_t *obj = NULL;
+ isc_result_t result;
+ isc_netaddr_t netaddr;
+ unsigned int addrlen, prefixlen;
+ UNUSED(type);
+
+ CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK |
+ CFG_ADDR_V6OK, &netaddr));
+ switch (netaddr.family) {
+ case AF_INET:
+ addrlen = 32;
+ break;
+ case AF_INET6:
+ addrlen = 128;
+ break;
+ default:
+ addrlen = 0;
+ INSIST(0);
+ break;
+ }
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_special &&
+ pctx->token.value.as_char == '/') {
+ CHECK(cfg_gettoken(pctx, 0)); /* read "/" */
+ CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
+ if (pctx->token.type != isc_tokentype_number) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR,
+ "expected prefix length");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ prefixlen = pctx->token.value.as_ulong;
+ if (prefixlen > addrlen) {
+ cfg_parser_error(pctx, CFG_LOG_NOPREP,
+ "invalid prefix length");
+ return (ISC_R_RANGE);
+ }
+ } else {
+ prefixlen = addrlen;
+ }
+ CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj));
+ obj->value.netprefix.address = netaddr;
+ obj->value.netprefix.prefixlen = prefixlen;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+ cleanup:
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix");
+ return (result);
+}
+
+static void
+print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ const cfg_netprefix_t *p = &obj->value.netprefix;
+
+ cfg_print_rawaddr(pctx, &p->address);
+ cfg_print_chars(pctx, "/", 1);
+ cfg_print_rawuint(pctx, p->prefixlen);
+}
+
+isc_boolean_t
+cfg_obj_isnetprefix(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (ISC_TF(obj->type->rep == &cfg_rep_netprefix));
+}
+
+void
+cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr,
+ unsigned int *prefixlen) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix);
+ *netaddr = obj->value.netprefix.address;
+ *prefixlen = obj->value.netprefix.prefixlen;
+}
+
+cfg_type_t cfg_type_netprefix = {
+ "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal,
+ &cfg_rep_netprefix, NULL
+};
+
+static isc_result_t
+parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type,
+ int flags, cfg_obj_t **ret)
+{
+ isc_result_t result;
+ isc_netaddr_t netaddr;
+ in_port_t port = 0;
+ cfg_obj_t *obj = NULL;
+
+ CHECK(cfg_create_obj(pctx, type, &obj));
+ CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
+ CHECK(cfg_peektoken(pctx, 0));
+ if (pctx->token.type == isc_tokentype_string &&
+ strcasecmp(TOKEN_STRING(pctx), "port") == 0) {
+ CHECK(cfg_gettoken(pctx, 0)); /* read "port" */
+ CHECK(cfg_parse_rawport(pctx, flags, &port));
+ }
+ isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ CLEANUP_OBJ(obj);
+ return (result);
+}
+
+static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
+cfg_type_t cfg_type_sockaddr = {
+ "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
+ &cfg_rep_sockaddr, &sockaddr_flags
+};
+
+isc_result_t
+cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ const unsigned int *flagp = type->of;
+ return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret));
+}
+
+void
+cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) {
+ isc_netaddr_t netaddr;
+ in_port_t port;
+ char buf[ISC_NETADDR_FORMATSIZE];
+
+ isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr);
+ isc_netaddr_format(&netaddr, buf, sizeof(buf));
+ cfg_print_cstr(pctx, buf);
+ port = isc_sockaddr_getport(&obj->value.sockaddr);
+ if (port != 0) {
+ cfg_print_chars(pctx, " port ", 6);
+ cfg_print_rawuint(pctx, port);
+ }
+}
+
+void
+cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
+ const unsigned int *flagp = type->of;
+ int n = 0;
+ cfg_print_chars(pctx, "( ", 2);
+ if (*flagp & CFG_ADDR_V4OK) {
+ cfg_print_cstr(pctx, "<ipv4_address>");
+ n++;
+ }
+ if (*flagp & CFG_ADDR_V6OK) {
+ if (n != 0)
+ cfg_print_chars(pctx, " | ", 3);
+ cfg_print_cstr(pctx, "<ipv6_address>");
+ n++;
+ }
+ if (*flagp & CFG_ADDR_WILDOK) {
+ if (n != 0)
+ cfg_print_chars(pctx, " | ", 3);
+ cfg_print_chars(pctx, "*", 1);
+ n++;
+ }
+ cfg_print_chars(pctx, " ) ", 3);
+ if (*flagp & CFG_ADDR_WILDOK) {
+ cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]");
+ } else {
+ cfg_print_cstr(pctx, "[ port <integer> ]");
+ }
+}
+
+isc_boolean_t
+cfg_obj_issockaddr(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL);
+ return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr));
+}
+
+const isc_sockaddr_t *
+cfg_obj_assockaddr(const cfg_obj_t *obj) {
+ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
+ return (&obj->value.sockaddr);
+}
+
+isc_result_t
+cfg_gettoken(cfg_parser_t *pctx, int options) {
+ isc_result_t result;
+
+ if (pctx->seen_eof)
+ return (ISC_R_SUCCESS);
+
+ options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE);
+
+ redo:
+ pctx->token.type = isc_tokentype_unknown;
+ result = isc_lex_gettoken(pctx->lexer, options, &pctx->token);
+ pctx->ungotten = ISC_FALSE;
+ pctx->line = isc_lex_getsourceline(pctx->lexer);
+
+ switch (result) {
+ case ISC_R_SUCCESS:
+ if (pctx->token.type == isc_tokentype_eof) {
+ result = isc_lex_close(pctx->lexer);
+ INSIST(result == ISC_R_NOMORE ||
+ result == ISC_R_SUCCESS);
+
+ if (isc_lex_getsourcename(pctx->lexer) != NULL) {
+ /*
+ * Closed an included file, not the main file.
+ */
+ cfg_listelt_t *elt;
+ elt = ISC_LIST_TAIL(pctx->open_files->
+ value.list);
+ INSIST(elt != NULL);
+ ISC_LIST_UNLINK(pctx->open_files->
+ value.list, elt, link);
+ ISC_LIST_APPEND(pctx->closed_files->
+ value.list, elt, link);
+ goto redo;
+ }
+ pctx->seen_eof = ISC_TRUE;
+ }
+ break;
+
+ case ISC_R_NOSPACE:
+ /* More understandable than "ran out of space". */
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big");
+ break;
+
+ case ISC_R_IOERROR:
+ cfg_parser_error(pctx, 0, "%s",
+ isc_result_totext(result));
+ break;
+
+ default:
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "%s",
+ isc_result_totext(result));
+ break;
+ }
+ return (result);
+}
+
+void
+cfg_ungettoken(cfg_parser_t *pctx) {
+ if (pctx->seen_eof)
+ return;
+ isc_lex_ungettoken(pctx->lexer, &pctx->token);
+ pctx->ungotten = ISC_TRUE;
+}
+
+isc_result_t
+cfg_peektoken(cfg_parser_t *pctx, int options) {
+ isc_result_t result;
+ CHECK(cfg_gettoken(pctx, options));
+ cfg_ungettoken(pctx);
+ cleanup:
+ return (result);
+}
+
+/*
+ * Get a string token, accepting both the quoted and the unquoted form.
+ * Log an error if the next token is not a string.
+ */
+static isc_result_t
+cfg_getstringtoken(cfg_parser_t *pctx) {
+ isc_result_t result;
+
+ result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (pctx->token.type != isc_tokentype_string &&
+ pctx->token.type != isc_tokentype_qstring) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string");
+ return (ISC_R_UNEXPECTEDTOKEN);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+void
+cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ parser_complain(pctx, ISC_FALSE, flags, fmt, args);
+ va_end(args);
+ pctx->errors++;
+}
+
+void
+cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ parser_complain(pctx, ISC_TRUE, flags, fmt, args);
+ va_end(args);
+ pctx->warnings++;
+}
+
+#define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */
+
+static char *
+current_file(cfg_parser_t *pctx) {
+ static char none[] = "none";
+ cfg_listelt_t *elt;
+ cfg_obj_t *fileobj;
+
+ if (pctx->open_files == NULL)
+ return (none);
+ elt = ISC_LIST_TAIL(pctx->open_files->value.list);
+ if (elt == NULL)
+ return (none);
+
+ fileobj = elt->obj;
+ INSIST(fileobj->type == &cfg_type_qstring);
+ return (fileobj->value.string.base);
+}
+
+static void
+parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
+ unsigned int flags, const char *format,
+ va_list args)
+{
+ char tokenbuf[MAX_LOG_TOKEN + 10];
+ static char where[ISC_DIR_PATHMAX + 100];
+ static char message[2048];
+ int level = ISC_LOG_ERROR;
+ const char *prep = "";
+ size_t len;
+
+ if (is_warning)
+ level = ISC_LOG_WARNING;
+
+ snprintf(where, sizeof(where), "%s:%u: ",
+ current_file(pctx), pctx->line);
+
+ len = vsnprintf(message, sizeof(message), format, args);
+ if (len >= sizeof(message))
+ FATAL_ERROR(__FILE__, __LINE__,
+ "error message would overflow");
+
+ if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) {
+ isc_region_t r;
+
+ if (pctx->ungotten)
+ (void)cfg_gettoken(pctx, 0);
+
+ if (pctx->token.type == isc_tokentype_eof) {
+ snprintf(tokenbuf, sizeof(tokenbuf), "end of file");
+ } else if (pctx->token.type == isc_tokentype_unknown) {
+ flags = 0;
+ tokenbuf[0] = '\0';
+ } else {
+ isc_lex_getlasttokentext(pctx->lexer,
+ &pctx->token, &r);
+ if (r.length > MAX_LOG_TOKEN)
+ snprintf(tokenbuf, sizeof(tokenbuf),
+ "'%.*s...'", MAX_LOG_TOKEN, r.base);
+ else
+ snprintf(tokenbuf, sizeof(tokenbuf),
+ "'%.*s'", (int)r.length, r.base);
+ }
+
+ /* Choose a preposition. */
+ if (flags & CFG_LOG_NEAR)
+ prep = " near ";
+ else if (flags & CFG_LOG_BEFORE)
+ prep = " before ";
+ else
+ prep = " ";
+ } else {
+ tokenbuf[0] = '\0';
+ }
+ isc_log_write(pctx->lctx, CAT, MOD, level,
+ "%s%s%s%s", where, message, prep, tokenbuf);
+}
+
+void
+cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level,
+ const char *fmt, ...) {
+ va_list ap;
+ char msgbuf[2048];
+
+ if (! isc_log_wouldlog(lctx, level))
+ return;
+
+ va_start(ap, fmt);
+
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ isc_log_write(lctx, CAT, MOD, level,
+ "%s:%u: %s",
+ obj->file == NULL ? "<unknown file>" : obj->file,
+ obj->line, msgbuf);
+ va_end(ap);
+}
+
+const char *
+cfg_obj_file(const cfg_obj_t *obj) {
+ return (obj->file);
+}
+
+unsigned int
+cfg_obj_line(const cfg_obj_t *obj) {
+ return (obj->line);
+}
+
+isc_result_t
+cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ cfg_obj_t *obj;
+
+ obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t));
+ if (obj == NULL)
+ return (ISC_R_NOMEMORY);
+ obj->type = type;
+ obj->file = current_file(pctx);
+ obj->line = pctx->line;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+map_symtabitem_destroy(char *key, unsigned int type,
+ isc_symvalue_t symval, void *userarg)
+{
+ cfg_obj_t *obj = symval.as_pointer;
+ cfg_parser_t *pctx = (cfg_parser_t *)userarg;
+
+ UNUSED(key);
+ UNUSED(type);
+
+ cfg_obj_destroy(pctx, &obj);
+}
+
+
+static isc_result_t
+create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ isc_symtab_t *symtab = NULL;
+ cfg_obj_t *obj = NULL;
+
+ CHECK(cfg_create_obj(pctx, type, &obj));
+ CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */
+ map_symtabitem_destroy,
+ pctx, ISC_FALSE, &symtab));
+ obj->value.map.symtab = symtab;
+ obj->value.map.id = NULL;
+
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (obj != NULL)
+ isc_mem_put(pctx->mctx, obj, sizeof(*obj));
+ return (result);
+}
+
+static void
+free_map(cfg_parser_t *pctx, cfg_obj_t *obj) {
+ CLEANUP_OBJ(obj->value.map.id);
+ isc_symtab_destroy(&obj->value.map.symtab);
+}
+
+isc_boolean_t
+cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) {
+ return (ISC_TF(obj->type == type));
+}
+
+/*
+ * Destroy 'obj', a configuration object created in 'pctx'.
+ */
+void
+cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) {
+ cfg_obj_t *obj = *objp;
+ obj->type->rep->free(pctx, obj);
+ isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
+ *objp = NULL;
+}
+
+static void
+free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) {
+ UNUSED(pctx);
+ UNUSED(obj);
+}
+
+void
+cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) {
+ type->doc(pctx, type);
+}
+
+void
+cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) {
+ cfg_print_chars(pctx, "<", 1);
+ cfg_print_cstr(pctx, type->name);
+ cfg_print_chars(pctx, ">", 1);
+}
+
+void
+cfg_print_grammar(const cfg_type_t *type,
+ void (*f)(void *closure, const char *text, int textlen),
+ void *closure)
+{
+ cfg_printer_t pctx;
+ pctx.f = f;
+ pctx.closure = closure;
+ pctx.indent = 0;
+ cfg_doc_obj(&pctx, type);
+}
diff --git a/lib/isccfg/version.c b/lib/isccfg/version.c
new file mode 100644
index 0000000..0b7287b
--- /dev/null
+++ b/lib/isccfg/version.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-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: version.c,v 1.3.18.2 2005/04/29 00:17:15 marka Exp $ */
+
+/*! \file */
+
+#include <isccfg/version.h>
+
+const char cfg_version[] = VERSION;
+
+const unsigned int cfg_libinterface = LIBINTERFACE;
+const unsigned int cfg_librevision = LIBREVISION;
+const unsigned int cfg_libage = LIBAGE;
+
diff --git a/lib/lwres/Makefile.in b/lib/lwres/Makefile.in
new file mode 100644
index 0000000..a06bd8a
--- /dev/null
+++ b/lib/lwres/Makefile.in
@@ -0,0 +1,84 @@
+# Copyright (C) 2004, 2005 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: Makefile.in,v 1.28.18.4 2005/06/09 23:55:10 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+@LIBLWRES_API@
+
+@BIND9_MAKE_INCLUDES@
+
+CINCLUDES = -I${srcdir}/unix/include \
+ -I. -I./include -I${srcdir}/include ${ISC_INCLUDES}
+CDEFINES =
+CWARNINGS =
+
+# Alphabetically
+OBJS = context.@O@ gai_strerror.@O@ getaddrinfo.@O@ gethost.@O@ \
+ getipnode.@O@ getnameinfo.@O@ getrrset.@O@ herror.@O@ \
+ lwbuffer.@O@ lwconfig.@O@ lwpacket.@O@ lwresutil.@O@ \
+ lwres_gabn.@O@ lwres_gnba.@O@ lwres_grbn.@O@ lwres_noop.@O@ \
+ lwinetaton.@O@ lwinetpton.@O@ lwinetntop.@O@ print.@O@ \
+ strtoul.@O@
+
+# Alphabetically
+SRCS = context.c gai_strerror.c getaddrinfo.c gethost.c \
+ getipnode.c getnameinfo.c getrrset.c herror.c \
+ lwbuffer.c lwconfig.c lwpacket.c lwresutil.c \
+ lwres_gabn.c lwres_gnba.c lwres_grbn.c lwres_noop.c \
+ lwinetaton.c lwinetpton.c lwinetntop.c print.c \
+ strtoul.c
+
+LIBS = @LIBS@
+
+SUBDIRS = include man unix
+TARGETS = timestamp
+
+@BIND9_MAKE_RULES@
+
+version.@O@: version.c
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \
+ -DVERSION=\"${VERSION}\" \
+ -DLIBINTERFACE=${LIBINTERFACE} \
+ -DLIBREVISION=${LIBREVISION} \
+ -DLIBAGE=${LIBAGE} \
+ -c ${srcdir}/version.c
+
+liblwres.@SA@: ${OBJS} version.@O@
+ ${AR} ${ARFLAGS} $@ ${OBJS} version.@O@
+ ${RANLIB} $@
+
+liblwres.la: ${OBJS} version.@O@
+ ${LIBTOOL_MODE_LINK} \
+ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o liblwres.la -rpath ${libdir} \
+ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ ${OBJS} version.@O@ ${LIBS}
+
+timestamp: liblwres.@A@
+ touch timestamp
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+
+install:: timestamp installdirs
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} liblwres.@A@ ${DESTDIR}${libdir}
+
+clean distclean::
+ rm -f liblwres.@A@ liblwres.la timestamp
diff --git a/lib/lwres/api b/lib/lwres/api
new file mode 100644
index 0000000..510e9a9
--- /dev/null
+++ b/lib/lwres/api
@@ -0,0 +1,3 @@
+LIBINTERFACE = 30
+LIBREVISION = 5
+LIBAGE = 0
diff --git a/lib/lwres/assert_p.h b/lib/lwres/assert_p.h
new file mode 100644
index 0000000..c47ecec
--- /dev/null
+++ b/lib/lwres/assert_p.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2004, 2005 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: assert_p.h,v 1.10.18.2 2005/04/29 00:17:16 marka Exp $ */
+
+#ifndef LWRES_ASSERT_P_H
+#define LWRES_ASSERT_P_H 1
+
+/*! \file */
+
+#include <assert.h> /* Required for assert() prototype. */
+
+#define REQUIRE(x) assert(x)
+#define INSIST(x) assert(x)
+
+#define UNUSED(x) ((void)(x))
+
+#define SPACE_OK(b, s) (LWRES_BUFFER_AVAILABLECOUNT(b) >= (s))
+#define SPACE_REMAINING(b, s) (LWRES_BUFFER_REMAINING(b) >= (s))
+
+#endif /* LWRES_ASSERT_P_H */
diff --git a/lib/lwres/context.c b/lib/lwres/context.c
new file mode 100644
index 0000000..c731bb7
--- /dev/null
+++ b/lib/lwres/context.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: context.c,v 1.45.18.7 2007/08/28 07:20:06 tbox Exp $ */
+
+/*! \file context.c
+ lwres_context_create() creates a #lwres_context_t structure for use in
+ lightweight resolver operations. It holds a socket and other data
+ needed for communicating with a resolver daemon. The new
+ lwres_context_t is returned through contextp, a pointer to a
+ lwres_context_t pointer. This lwres_context_t pointer must initially
+ be NULL, and is modified to point to the newly created
+ lwres_context_t.
+
+ When the lightweight resolver needs to perform dynamic memory
+ allocation, it will call malloc_function to allocate memory and
+ free_function to free it. If malloc_function and free_function are
+ NULL, memory is allocated using malloc and free. It is not
+ permitted to have a NULL malloc_function and a non-NULL free_function
+ or vice versa. arg is passed as the first parameter to the memory
+ allocation functions. If malloc_function and free_function are NULL,
+ arg is unused and should be passed as NULL.
+
+ Once memory for the structure has been allocated, it is initialized
+ using lwres_conf_init() and returned via *contextp.
+
+ lwres_context_destroy() destroys a #lwres_context_t, closing its
+ socket. contextp is a pointer to a pointer to the context that is to
+ be destroyed. The pointer will be set to NULL when the context has
+ been destroyed.
+
+ The context holds a serial number that is used to identify resolver
+ request packets and associate responses with the corresponding
+ requests. This serial number is controlled using
+ lwres_context_initserial() and lwres_context_nextserial().
+ lwres_context_initserial() sets the serial number for context *ctx to
+ serial. lwres_context_nextserial() increments the serial number and
+ returns the previous value.
+
+ Memory for a lightweight resolver context is allocated and freed using
+ lwres_context_allocmem() and lwres_context_freemem(). These use
+ whatever allocations were defined when the context was created with
+ lwres_context_create(). lwres_context_allocmem() allocates len bytes
+ of memory and if successful returns a pointer to the allocated
+ storage. lwres_context_freemem() frees len bytes of space starting at
+ location mem.
+
+ lwres_context_sendrecv() performs I/O for the context ctx. Data are
+ read and written from the context's socket. It writes data from
+ sendbase -- typically a lightweight resolver query packet -- and waits
+ for a reply which is copied to the receive buffer at recvbase. The
+ number of bytes that were written to this receive buffer is returned
+ in *recvd_len.
+
+\section context_return Return Values
+
+ lwres_context_create() returns #LWRES_R_NOMEMORY if memory for the
+ struct lwres_context could not be allocated, #LWRES_R_SUCCESS
+ otherwise.
+
+ Successful calls to the memory allocator lwres_context_allocmem()
+ return a pointer to the start of the allocated space. It returns NULL
+ if memory could not be allocated.
+
+ #LWRES_R_SUCCESS is returned when lwres_context_sendrecv() completes
+ successfully. #LWRES_R_IOERROR is returned if an I/O error occurs and
+ #LWRES_R_TIMEOUT is returned if lwres_context_sendrecv() times out
+ waiting for a response.
+
+\section context_see See Also
+
+ lwres_conf_init(), malloc, free.
+ */
+#include <config.h>
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/platform.h>
+
+#ifdef LWRES_PLATFORM_NEEDSYSSELECTH
+#include <sys/select.h>
+#endif
+
+#include "context_p.h"
+#include "assert_p.h"
+
+/*!
+ * Some systems define the socket length argument as an int, some as size_t,
+ * some as socklen_t. The last is what the current POSIX standard mandates.
+ * This definition is here so it can be portable but easily changed if needed.
+ */
+#ifndef LWRES_SOCKADDR_LEN_T
+#define LWRES_SOCKADDR_LEN_T unsigned int
+#endif
+
+/*!
+ * Make a socket nonblocking.
+ */
+#ifndef MAKE_NONBLOCKING
+#define MAKE_NONBLOCKING(sd, retval) \
+do { \
+ retval = fcntl(sd, F_GETFL, 0); \
+ if (retval != -1) { \
+ retval |= O_NONBLOCK; \
+ retval = fcntl(sd, F_SETFL, retval); \
+ } \
+} while (0)
+#endif
+
+LIBLWRES_EXTERNAL_DATA lwres_uint16_t lwres_udp_port = LWRES_UDP_PORT;
+LIBLWRES_EXTERNAL_DATA const char *lwres_resolv_conf = LWRES_RESOLV_CONF;
+
+static void *
+lwres_malloc(void *, size_t);
+
+static void
+lwres_free(void *, void *, size_t);
+
+/*!
+ * lwres_result_t
+ */
+static lwres_result_t
+context_connect(lwres_context_t *);
+
+/*%
+ * Creates a #lwres_context_t structure for use in
+ * lightweight resolver operations.
+ */
+lwres_result_t
+lwres_context_create(lwres_context_t **contextp, void *arg,
+ lwres_malloc_t malloc_function,
+ lwres_free_t free_function,
+ unsigned int flags)
+{
+ lwres_context_t *ctx;
+
+ REQUIRE(contextp != NULL && *contextp == NULL);
+ UNUSED(flags);
+
+ /*
+ * If we were not given anything special to use, use our own
+ * functions. These are just wrappers around malloc() and free().
+ */
+ if (malloc_function == NULL || free_function == NULL) {
+ REQUIRE(malloc_function == NULL);
+ REQUIRE(free_function == NULL);
+ malloc_function = lwres_malloc;
+ free_function = lwres_free;
+ }
+
+ ctx = malloc_function(arg, sizeof(lwres_context_t));
+ if (ctx == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ /*
+ * Set up the context.
+ */
+ ctx->malloc = malloc_function;
+ ctx->free = free_function;
+ ctx->arg = arg;
+ ctx->sock = -1;
+
+ ctx->timeout = LWRES_DEFAULT_TIMEOUT;
+ ctx->serial = time(NULL); /* XXXMLG or BEW */
+
+ /*
+ * Init resolv.conf bits.
+ */
+ lwres_conf_init(ctx);
+
+ *contextp = ctx;
+ return (LWRES_R_SUCCESS);
+}
+
+/*%
+Destroys a #lwres_context_t, closing its socket.
+contextp is a pointer to a pointer to the context that is
+to be destroyed. The pointer will be set to NULL
+when the context has been destroyed.
+ */
+void
+lwres_context_destroy(lwres_context_t **contextp) {
+ lwres_context_t *ctx;
+
+ REQUIRE(contextp != NULL && *contextp != NULL);
+
+ ctx = *contextp;
+ *contextp = NULL;
+
+ if (ctx->sock != -1) {
+#ifdef WIN32
+ DestroySockets();
+#endif
+ (void)close(ctx->sock);
+ ctx->sock = -1;
+ }
+
+ CTXFREE(ctx, sizeof(lwres_context_t));
+}
+/*% Increments the serial number and returns the previous value. */
+lwres_uint32_t
+lwres_context_nextserial(lwres_context_t *ctx) {
+ REQUIRE(ctx != NULL);
+
+ return (ctx->serial++);
+}
+
+/*% Sets the serial number for context *ctx to serial. */
+void
+lwres_context_initserial(lwres_context_t *ctx, lwres_uint32_t serial) {
+ REQUIRE(ctx != NULL);
+
+ ctx->serial = serial;
+}
+
+/*% Frees len bytes of space starting at location mem. */
+void
+lwres_context_freemem(lwres_context_t *ctx, void *mem, size_t len) {
+ REQUIRE(mem != NULL);
+ REQUIRE(len != 0U);
+
+ CTXFREE(mem, len);
+}
+
+/*% Allocates len bytes of memory and if successful returns a pointer to the allocated storage. */
+void *
+lwres_context_allocmem(lwres_context_t *ctx, size_t len) {
+ REQUIRE(len != 0U);
+
+ return (CTXMALLOC(len));
+}
+
+static void *
+lwres_malloc(void *arg, size_t len) {
+ void *mem;
+
+ UNUSED(arg);
+
+ mem = malloc(len);
+ if (mem == NULL)
+ return (NULL);
+
+ memset(mem, 0xe5, len);
+
+ return (mem);
+}
+
+static void
+lwres_free(void *arg, void *mem, size_t len) {
+ UNUSED(arg);
+
+ memset(mem, 0xa9, len);
+ free(mem);
+}
+
+static lwres_result_t
+context_connect(lwres_context_t *ctx) {
+ int s;
+ int ret;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr *sa;
+ LWRES_SOCKADDR_LEN_T salen;
+ int domain;
+
+ if (ctx->confdata.lwnext != 0) {
+ memcpy(&ctx->address, &ctx->confdata.lwservers[0],
+ sizeof(lwres_addr_t));
+ LWRES_LINK_INIT(&ctx->address, link);
+ } else {
+ /* The default is the IPv4 loopback address 127.0.0.1. */
+ memset(&ctx->address, 0, sizeof(ctx->address));
+ ctx->address.family = LWRES_ADDRTYPE_V4;
+ ctx->address.length = 4;
+ ctx->address.address[0] = 127;
+ ctx->address.address[1] = 0;
+ ctx->address.address[2] = 0;
+ ctx->address.address[3] = 1;
+ }
+
+ if (ctx->address.family == LWRES_ADDRTYPE_V4) {
+ memcpy(&sin.sin_addr, ctx->address.address,
+ sizeof(sin.sin_addr));
+ sin.sin_port = htons(lwres_udp_port);
+ sin.sin_family = AF_INET;
+ sa = (struct sockaddr *)&sin;
+ salen = sizeof(sin);
+ domain = PF_INET;
+ } else if (ctx->address.family == LWRES_ADDRTYPE_V6) {
+ memcpy(&sin6.sin6_addr, ctx->address.address,
+ sizeof(sin6.sin6_addr));
+ sin6.sin6_port = htons(lwres_udp_port);
+ sin6.sin6_family = AF_INET6;
+ sa = (struct sockaddr *)&sin6;
+ salen = sizeof(sin6);
+ domain = PF_INET6;
+ } else
+ return (LWRES_R_IOERROR);
+
+#ifdef WIN32
+ InitSockets();
+#endif
+ s = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
+ if (s < 0) {
+#ifdef WIN32
+ DestroySockets();
+#endif
+ return (LWRES_R_IOERROR);
+ }
+
+ ret = connect(s, sa, salen);
+ if (ret != 0) {
+#ifdef WIN32
+ DestroySockets();
+#endif
+ (void)close(s);
+ return (LWRES_R_IOERROR);
+ }
+
+ MAKE_NONBLOCKING(s, ret);
+ if (ret < 0) {
+#ifdef WIN32
+ DestroySockets();
+#endif
+ (void)close(s);
+ return (LWRES_R_IOERROR);
+ }
+
+ ctx->sock = s;
+
+ return (LWRES_R_SUCCESS);
+}
+
+int
+lwres_context_getsocket(lwres_context_t *ctx) {
+ return (ctx->sock);
+}
+
+lwres_result_t
+lwres_context_send(lwres_context_t *ctx,
+ void *sendbase, int sendlen) {
+ int ret;
+ lwres_result_t lwresult;
+
+ if (ctx->sock == -1) {
+ lwresult = context_connect(ctx);
+ if (lwresult != LWRES_R_SUCCESS)
+ return (lwresult);
+ }
+
+ ret = sendto(ctx->sock, sendbase, sendlen, 0, NULL, 0);
+ if (ret < 0)
+ return (LWRES_R_IOERROR);
+ if (ret != sendlen)
+ return (LWRES_R_IOERROR);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_context_recv(lwres_context_t *ctx,
+ void *recvbase, int recvlen,
+ int *recvd_len)
+{
+ LWRES_SOCKADDR_LEN_T fromlen;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr *sa;
+ int ret;
+
+ if (ctx->address.family == LWRES_ADDRTYPE_V4) {
+ sa = (struct sockaddr *)&sin;
+ fromlen = sizeof(sin);
+ } else {
+ sa = (struct sockaddr *)&sin6;
+ fromlen = sizeof(sin6);
+ }
+
+ /*
+ * The address of fromlen is cast to void * to shut up compiler
+ * warnings, namely on systems that have the sixth parameter
+ * prototyped as a signed int when LWRES_SOCKADDR_LEN_T is
+ * defined as unsigned.
+ */
+ ret = recvfrom(ctx->sock, recvbase, recvlen, 0, sa, (void *)&fromlen);
+
+ if (ret < 0)
+ return (LWRES_R_IOERROR);
+
+ if (ret == recvlen)
+ return (LWRES_R_TOOLARGE);
+
+ /*
+ * If we got something other than what we expect, have the caller
+ * wait for another packet. This can happen if an old result
+ * comes in, or if someone is sending us random stuff.
+ */
+ if (ctx->address.family == LWRES_ADDRTYPE_V4) {
+ if (fromlen != sizeof(sin)
+ || memcmp(&sin.sin_addr, ctx->address.address,
+ sizeof(sin.sin_addr)) != 0
+ || sin.sin_port != htons(lwres_udp_port))
+ return (LWRES_R_RETRY);
+ } else {
+ if (fromlen != sizeof(sin6)
+ || memcmp(&sin6.sin6_addr, ctx->address.address,
+ sizeof(sin6.sin6_addr)) != 0
+ || sin6.sin6_port != htons(lwres_udp_port))
+ return (LWRES_R_RETRY);
+ }
+
+ if (recvd_len != NULL)
+ *recvd_len = ret;
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% performs I/O for the context ctx. */
+lwres_result_t
+lwres_context_sendrecv(lwres_context_t *ctx,
+ void *sendbase, int sendlen,
+ void *recvbase, int recvlen,
+ int *recvd_len)
+{
+ lwres_result_t result;
+ int ret2;
+ fd_set readfds;
+ struct timeval timeout;
+
+ /*
+ * Type of tv_sec is 32 bits long.
+ */
+ if (ctx->timeout <= 0x7FFFFFFFU)
+ timeout.tv_sec = (int)ctx->timeout;
+ else
+ timeout.tv_sec = 0x7FFFFFFF;
+
+ timeout.tv_usec = 0;
+
+ result = lwres_context_send(ctx, sendbase, sendlen);
+ if (result != LWRES_R_SUCCESS)
+ return (result);
+ again:
+ FD_ZERO(&readfds);
+ FD_SET(ctx->sock, &readfds);
+ ret2 = select(ctx->sock + 1, &readfds, NULL, NULL, &timeout);
+
+ /*
+ * What happened with select?
+ */
+ if (ret2 < 0)
+ return (LWRES_R_IOERROR);
+ if (ret2 == 0)
+ return (LWRES_R_TIMEOUT);
+
+ result = lwres_context_recv(ctx, recvbase, recvlen, recvd_len);
+ if (result == LWRES_R_RETRY)
+ goto again;
+
+ return (result);
+}
diff --git a/lib/lwres/context_p.h b/lib/lwres/context_p.h
new file mode 100644
index 0000000..d255ef6
--- /dev/null
+++ b/lib/lwres/context_p.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2004, 2005 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: context_p.h,v 1.13.18.2 2005/04/29 00:17:17 marka Exp $ */
+
+#ifndef LWRES_CONTEXT_P_H
+#define LWRES_CONTEXT_P_H 1
+
+/*! \file */
+
+/*@{*/
+/**
+ * Helper functions, assuming the context is always called "ctx" in
+ * the scope these functions are called from.
+ */
+#define CTXMALLOC(len) ctx->malloc(ctx->arg, (len))
+#define CTXFREE(addr, len) ctx->free(ctx->arg, (addr), (len))
+/*@}*/
+
+#define LWRES_DEFAULT_TIMEOUT 120 /* 120 seconds for a reply */
+
+/**
+ * Not all the attributes here are actually settable by the application at
+ * this time.
+ */
+struct lwres_context {
+ unsigned int timeout; /*%< time to wait for reply */
+ lwres_uint32_t serial; /*%< serial number state */
+
+ /*
+ * For network I/O.
+ */
+ int sock; /*%< socket to send on */
+ lwres_addr_t address; /*%< address to send to */
+
+ /*@{*/
+ /*
+ * Function pointers for allocating memory.
+ */
+ lwres_malloc_t malloc;
+ lwres_free_t free;
+ void *arg;
+ /*@}*/
+
+ /*%
+ * resolv.conf-like data
+ */
+ lwres_conf_t confdata;
+};
+
+#endif /* LWRES_CONTEXT_P_H */
diff --git a/lib/lwres/gai_strerror.c b/lib/lwres/gai_strerror.c
new file mode 100644
index 0000000..0dcfe40
--- /dev/null
+++ b/lib/lwres/gai_strerror.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2004-2006 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: gai_strerror.c,v 1.16.18.4 2006/08/25 05:25:51 marka Exp $ */
+
+/*! \file gai_strerror.c
+ * lwres_gai_strerror() returns an error message corresponding to an
+ * error code returned by getaddrinfo(). The following error codes and
+ * their meaning are defined in \link netdb.h include/lwres/netdb.h.\endlink
+ *
+ * \li #EAI_ADDRFAMILY address family for hostname not supported
+ * \li #EAI_AGAIN temporary failure in name resolution
+ * \li #EAI_BADFLAGS invalid value for #ai_flags
+ * \li #EAI_FAIL non-recoverable failure in name resolution
+ * \li #EAI_FAMILY ai_family not supported
+ * \li #EAI_MEMORY memory allocation failure
+ * \li #EAI_NODATA no address associated with hostname
+ * \li #EAI_NONAME hostname or servname not provided, or not known
+ * \li #EAI_SERVICE servname not supported for ai_socktype
+ * \li #EAI_SOCKTYPE ai_socktype not supported
+ * \li #EAI_SYSTEM system error returned in errno
+ *
+ * The message invalid error code is returned if ecode is out of range.
+ *
+ * ai_flags, ai_family and ai_socktype are elements of the struct
+ * addrinfo used by lwres_getaddrinfo().
+ *
+ * \section gai_strerror_see See Also
+ *
+ * strerror, lwres_getaddrinfo(), getaddrinfo(), RFC2133.
+ */
+
+#include <config.h>
+
+#include <lwres/netdb.h>
+
+/*% Text of error messages. */
+static const char *gai_messages[] = {
+ "no error",
+ "address family for hostname not supported",
+ "temporary failure in name resolution",
+ "invalid value for ai_flags",
+ "non-recoverable failure in name resolution",
+ "ai_family not supported",
+ "memory allocation failure",
+ "no address associated with hostname",
+ "hostname nor servname provided, or not known",
+ "servname not supported for ai_socktype",
+ "ai_socktype not supported",
+ "system error returned in errno",
+ "bad hints",
+ "bad protocol"
+};
+
+/*% Returns an error message corresponding to an error code returned by getaddrinfo() */
+char *
+lwres_gai_strerror(int ecode) {
+ union {
+ const char *const_ptr;
+ char *deconst_ptr;
+ } ptr;
+
+ if ((ecode < 0) ||
+ (ecode >= (int)(sizeof(gai_messages)/sizeof(*gai_messages))))
+ ptr.const_ptr = "invalid error code";
+ else
+ ptr.const_ptr = gai_messages[ecode];
+ return (ptr.deconst_ptr);
+}
diff --git a/lib/lwres/getaddrinfo.c b/lib/lwres/getaddrinfo.c
new file mode 100644
index 0000000..6056f24
--- /dev/null
+++ b/lib/lwres/getaddrinfo.c
@@ -0,0 +1,808 @@
+/*
+ * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001 Internet Software Consortium.
+ *
+ * This code is derived from software contributed to ISC by
+ * Berkeley Software Design, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND BERKELEY SOFTWARE DESIGN, INC.
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
+ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: getaddrinfo.c,v 1.43.18.8 2007/09/13 23:46:26 tbox Exp $ */
+
+/*! \file */
+
+/**
+ * lwres_getaddrinfo() is used to get a list of IP addresses and port
+ * numbers for host hostname and service servname. The function is the
+ * lightweight resolver's implementation of getaddrinfo() as defined in
+ * RFC2133. hostname and servname are pointers to null-terminated strings
+ * or NULL. hostname is either a host name or a numeric host address
+ * string: a dotted decimal IPv4 address or an IPv6 address. servname is
+ * either a decimal port number or a service name as listed in
+ * /etc/services.
+ *
+ * If the operating system does not provide a struct addrinfo, the
+ * following structure is used:
+ *
+ * \code
+ * struct addrinfo {
+ * int ai_flags; // AI_PASSIVE, AI_CANONNAME
+ * int ai_family; // PF_xxx
+ * int ai_socktype; // SOCK_xxx
+ * int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6
+ * size_t ai_addrlen; // length of ai_addr
+ * char *ai_canonname; // canonical name for hostname
+ * struct sockaddr *ai_addr; // binary address
+ * struct addrinfo *ai_next; // next structure in linked list
+ * };
+ * \endcode
+ *
+ *
+ * hints is an optional pointer to a struct addrinfo. This structure can
+ * be used to provide hints concerning the type of socket that the caller
+ * supports or wishes to use. The caller can supply the following
+ * structure elements in *hints:
+ *
+ * <ul>
+ * <li>ai_family:
+ * The protocol family that should be used. When ai_family is set
+ * to PF_UNSPEC, it means the caller will accept any protocol
+ * family supported by the operating system.</li>
+ *
+ * <li>ai_socktype:
+ * denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or
+ * SOCK_RAW -- that is wanted. When ai_socktype is zero the caller
+ * will accept any socket type.</li>
+ *
+ * <li>ai_protocol:
+ * indicates which transport protocol is wanted: IPPROTO_UDP or
+ * IPPROTO_TCP. If ai_protocol is zero the caller will accept any
+ * protocol.</li>
+ *
+ * <li>ai_flags:
+ * Flag bits. If the AI_CANONNAME bit is set, a successful call to
+ * lwres_getaddrinfo() will return a null-terminated string
+ * containing the canonical name of the specified hostname in
+ * ai_canonname of the first addrinfo structure returned. Setting
+ * the AI_PASSIVE bit indicates that the returned socket address
+ * structure is intended for used in a call to bind(2). In this
+ * case, if the hostname argument is a NULL pointer, then the IP
+ * address portion of the socket address structure will be set to
+ * INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6
+ * address.<br /><br />
+ *
+ * When ai_flags does not set the AI_PASSIVE bit, the returned
+ * socket address structure will be ready for use in a call to
+ * connect(2) for a connection-oriented protocol or connect(2),
+ * sendto(2), or sendmsg(2) if a connectionless protocol was
+ * chosen. The IP address portion of the socket address structure
+ * will be set to the loopback address if hostname is a NULL
+ * pointer and AI_PASSIVE is not set in ai_flags.<br /><br />
+ *
+ * If ai_flags is set to AI_NUMERICHOST it indicates that hostname
+ * should be treated as a numeric string defining an IPv4 or IPv6
+ * address and no name resolution should be attempted.
+ * </li></ul>
+ *
+ * All other elements of the struct addrinfo passed via hints must be
+ * zero.
+ *
+ * A hints of NULL is treated as if the caller provided a struct addrinfo
+ * initialized to zero with ai_familyset to PF_UNSPEC.
+ *
+ * After a successful call to lwres_getaddrinfo(), *res is a pointer to a
+ * linked list of one or more addrinfo structures. Each struct addrinfo
+ * in this list cn be processed by following the ai_next pointer, until a
+ * NULL pointer is encountered. The three members ai_family, ai_socktype,
+ * and ai_protocol in each returned addrinfo structure contain the
+ * corresponding arguments for a call to socket(2). For each addrinfo
+ * structure in the list, the ai_addr member points to a filled-in socket
+ * address structure of length ai_addrlen.
+ *
+ * All of the information returned by lwres_getaddrinfo() is dynamically
+ * allocated: the addrinfo structures, and the socket address structures
+ * and canonical host name strings pointed to by the addrinfostructures.
+ * Memory allocated for the dynamically allocated structures created by a
+ * successful call to lwres_getaddrinfo() is released by
+ * lwres_freeaddrinfo(). ai is a pointer to a struct addrinfo created by
+ * a call to lwres_getaddrinfo().
+ *
+ * \section lwresreturn RETURN VALUES
+ *
+ * lwres_getaddrinfo() returns zero on success or one of the error codes
+ * listed in gai_strerror() if an error occurs. If both hostname and
+ * servname are NULL lwres_getaddrinfo() returns #EAI_NONAME.
+ *
+ * \section lwressee SEE ALSO
+ *
+ * lwres(3), lwres_getaddrinfo(), lwres_freeaddrinfo(),
+ * lwres_gai_strerror(), RFC2133, getservbyname(3), connect(2),
+ * sendto(2), sendmsg(2), socket(2).
+ */
+
+#include <config.h>
+
+#include <errno.h>
+
+#include <isc/string.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/netdb.h>
+#include <lwres/stdlib.h>
+
+#define SA(addr) ((struct sockaddr *)(addr))
+#define SIN(addr) ((struct sockaddr_in *)(addr))
+#define SIN6(addr) ((struct sockaddr_in6 *)(addr))
+#define SUN(addr) ((struct sockaddr_un *)(addr))
+
+/*! \struct addrinfo
+ */
+static struct addrinfo
+ *ai_reverse(struct addrinfo *oai),
+ *ai_clone(struct addrinfo *oai, int family),
+ *ai_alloc(int family, int addrlen);
+#ifdef AF_LOCAL
+static int get_local(const char *name, int socktype, struct addrinfo **res);
+#endif
+
+static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
+ int socktype, int port);
+static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
+ int socktype, int port);
+static void set_order(int, int (**)(const char *, int, struct addrinfo **,
+ int, int));
+
+#define FOUND_IPV4 0x1
+#define FOUND_IPV6 0x2
+#define FOUND_MAX 2
+
+#define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
+/*% Get a list of IP addresses and port numbers for host hostname and service servname. */
+int
+lwres_getaddrinfo(const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ struct servent *sp;
+ const char *proto;
+ int family, socktype, flags, protocol;
+ struct addrinfo *ai, *ai_list;
+ int port, err, i;
+ int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
+ int, int);
+
+ if (hostname == NULL && servname == NULL)
+ return (EAI_NONAME);
+
+ proto = NULL;
+ if (hints != NULL) {
+ if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
+ return (EAI_BADFLAGS);
+ if (hints->ai_addrlen || hints->ai_canonname ||
+ hints->ai_addr || hints->ai_next) {
+ errno = EINVAL;
+ return (EAI_SYSTEM);
+ }
+ family = hints->ai_family;
+ socktype = hints->ai_socktype;
+ protocol = hints->ai_protocol;
+ flags = hints->ai_flags;
+ switch (family) {
+ case AF_UNSPEC:
+ switch (hints->ai_socktype) {
+ case SOCK_STREAM:
+ proto = "tcp";
+ break;
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ }
+ break;
+ case AF_INET:
+ case AF_INET6:
+ switch (hints->ai_socktype) {
+ case 0:
+ break;
+ case SOCK_STREAM:
+ proto = "tcp";
+ break;
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ case SOCK_RAW:
+ break;
+ default:
+ return (EAI_SOCKTYPE);
+ }
+ break;
+#ifdef AF_LOCAL
+ case AF_LOCAL:
+ switch (hints->ai_socktype) {
+ case 0:
+ break;
+ case SOCK_STREAM:
+ break;
+ case SOCK_DGRAM:
+ break;
+ default:
+ return (EAI_SOCKTYPE);
+ }
+ break;
+#endif
+ default:
+ return (EAI_FAMILY);
+ }
+ } else {
+ protocol = 0;
+ family = 0;
+ socktype = 0;
+ flags = 0;
+ }
+
+#ifdef AF_LOCAL
+ /*!
+ * First, deal with AF_LOCAL. If the family was not set,
+ * then assume AF_LOCAL if the first character of the
+ * hostname/servname is '/'.
+ */
+
+ if (hostname != NULL &&
+ (family == AF_LOCAL || (family == 0 && *hostname == '/')))
+ return (get_local(hostname, socktype, res));
+
+ if (servname != NULL &&
+ (family == AF_LOCAL || (family == 0 && *servname == '/')))
+ return (get_local(servname, socktype, res));
+#endif
+
+ /*
+ * Ok, only AF_INET and AF_INET6 left.
+ */
+ ai_list = NULL;
+
+ /*
+ * First, look up the service name (port) if it was
+ * requested. If the socket type wasn't specified, then
+ * try and figure it out.
+ */
+ if (servname != NULL) {
+ char *e;
+
+ port = strtol(servname, &e, 10);
+ if (*e == '\0') {
+ if (socktype == 0)
+ return (EAI_SOCKTYPE);
+ if (port < 0 || port > 65535)
+ return (EAI_SERVICE);
+ port = htons((unsigned short) port);
+ } else {
+ sp = getservbyname(servname, proto);
+ if (sp == NULL)
+ return (EAI_SERVICE);
+ port = sp->s_port;
+ if (socktype == 0) {
+ if (strcmp(sp->s_proto, "tcp") == 0)
+ socktype = SOCK_STREAM;
+ else if (strcmp(sp->s_proto, "udp") == 0)
+ socktype = SOCK_DGRAM;
+ }
+ }
+ } else
+ port = 0;
+
+ /*
+ * Next, deal with just a service name, and no hostname.
+ * (we verified that one of them was non-null up above).
+ */
+ if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
+ if (family == AF_INET || family == 0) {
+ ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
+ if (ai == NULL)
+ return (EAI_MEMORY);
+ ai->ai_socktype = socktype;
+ ai->ai_protocol = protocol;
+ SIN(ai->ai_addr)->sin_port = port;
+ ai->ai_next = ai_list;
+ ai_list = ai;
+ }
+
+ if (family == AF_INET6 || family == 0) {
+ ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
+ if (ai == NULL) {
+ lwres_freeaddrinfo(ai_list);
+ return (EAI_MEMORY);
+ }
+ ai->ai_socktype = socktype;
+ ai->ai_protocol = protocol;
+ SIN6(ai->ai_addr)->sin6_port = port;
+ ai->ai_next = ai_list;
+ ai_list = ai;
+ }
+
+ *res = ai_list;
+ return (0);
+ }
+
+ /*
+ * If the family isn't specified or AI_NUMERICHOST specified,
+ * check first to see if it is a numeric address.
+ * Though the gethostbyname2() routine
+ * will recognize numeric addresses, it will only recognize
+ * the format that it is being called for. Thus, a numeric
+ * AF_INET address will be treated by the AF_INET6 call as
+ * a domain name, and vice versa. Checking for both numerics
+ * here avoids that.
+ */
+ if (hostname != NULL &&
+ (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
+ char abuf[sizeof(struct in6_addr)];
+ char nbuf[NI_MAXHOST];
+ int addrsize, addroff;
+#ifdef LWRES_HAVE_SIN6_SCOPE_ID
+ char *p, *ep;
+ char ntmp[NI_MAXHOST];
+ lwres_uint32_t scopeid;
+#endif
+
+#ifdef LWRES_HAVE_SIN6_SCOPE_ID
+ /*
+ * Scope identifier portion.
+ */
+ ntmp[0] = '\0';
+ if (strchr(hostname, '%') != NULL) {
+ strncpy(ntmp, hostname, sizeof(ntmp) - 1);
+ ntmp[sizeof(ntmp) - 1] = '\0';
+ p = strchr(ntmp, '%');
+ ep = NULL;
+
+ /*
+ * Vendors may want to support non-numeric
+ * scopeid around here.
+ */
+
+ if (p != NULL)
+ scopeid = (lwres_uint32_t)strtoul(p + 1,
+ &ep, 10);
+ if (p != NULL && ep != NULL && ep[0] == '\0')
+ *p = '\0';
+ else {
+ ntmp[0] = '\0';
+ scopeid = 0;
+ }
+ } else
+ scopeid = 0;
+#endif
+
+ if (lwres_net_pton(AF_INET, hostname, (struct in_addr *)abuf)
+ == 1)
+ {
+ if (family == AF_INET6) {
+ /*
+ * Convert to a V4 mapped address.
+ */
+ struct in6_addr *a6 = (struct in6_addr *)abuf;
+ memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4);
+ memset(&a6->s6_addr[10], 0xff, 2);
+ memset(&a6->s6_addr[0], 0, 10);
+ goto inet6_addr;
+ }
+ addrsize = sizeof(struct in_addr);
+ addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
+ family = AF_INET;
+ goto common;
+#ifdef LWRES_HAVE_SIN6_SCOPE_ID
+ } else if (ntmp[0] != '\0' &&
+ lwres_net_pton(AF_INET6, ntmp, abuf) == 1)
+ {
+ if (family && family != AF_INET6)
+ return (EAI_NONAME);
+ addrsize = sizeof(struct in6_addr);
+ addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
+ family = AF_INET6;
+ goto common;
+#endif
+ } else if (lwres_net_pton(AF_INET6, hostname, abuf) == 1) {
+ if (family != 0 && family != AF_INET6)
+ return (EAI_NONAME);
+ inet6_addr:
+ addrsize = sizeof(struct in6_addr);
+ addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
+ family = AF_INET6;
+
+ common:
+ ai = ai_clone(ai_list, family);
+ if (ai == NULL)
+ return (EAI_MEMORY);
+ ai_list = ai;
+ ai->ai_socktype = socktype;
+ SIN(ai->ai_addr)->sin_port = port;
+ memcpy((char *)ai->ai_addr + addroff, abuf, addrsize);
+ if (flags & AI_CANONNAME) {
+#if defined(LWRES_HAVE_SIN6_SCOPE_ID)
+ if (ai->ai_family == AF_INET6)
+ SIN6(ai->ai_addr)->sin6_scope_id =
+ scopeid;
+#endif
+ if (lwres_getnameinfo(ai->ai_addr,
+ ai->ai_addrlen, nbuf, sizeof(nbuf),
+ NULL, 0,
+ NI_NUMERICHOST) == 0) {
+ ai->ai_canonname = strdup(nbuf);
+ if (ai->ai_canonname == NULL) {
+ lwres_freeaddrinfo(ai_list);
+ return (EAI_MEMORY);
+ }
+ } else {
+ /* XXX raise error? */
+ ai->ai_canonname = NULL;
+ }
+ }
+ goto done;
+ } else if ((flags & AI_NUMERICHOST) != 0) {
+ return (EAI_NONAME);
+ }
+ }
+
+ set_order(family, net_order);
+ for (i = 0; i < FOUND_MAX; i++) {
+ if (net_order[i] == NULL)
+ break;
+ err = (net_order[i])(hostname, flags, &ai_list,
+ socktype, port);
+ if (err != 0)
+ return (err);
+ }
+
+ if (ai_list == NULL)
+ return (EAI_NODATA);
+
+done:
+ ai_list = ai_reverse(ai_list);
+
+ *res = ai_list;
+ return (0);
+}
+
+static char *
+lwres_strsep(char **stringp, const char *delim) {
+ char *string = *stringp;
+ char *s;
+ const char *d;
+ char sc, dc;
+
+ if (string == NULL)
+ return (NULL);
+
+ for (s = string; *s != '\0'; s++) {
+ sc = *s;
+ for (d = delim; (dc = *d) != '\0'; d++)
+ if (sc == dc) {
+ *s++ = '\0';
+ *stringp = s;
+ return (string);
+ }
+ }
+ *stringp = NULL;
+ return (string);
+}
+
+static void
+set_order(int family, int (**net_order)(const char *, int, struct addrinfo **,
+ int, int))
+{
+ char *order, *tok;
+ int found;
+
+ if (family) {
+ switch (family) {
+ case AF_INET:
+ *net_order++ = add_ipv4;
+ break;
+ case AF_INET6:
+ *net_order++ = add_ipv6;
+ break;
+ }
+ } else {
+ order = getenv("NET_ORDER");
+ found = 0;
+ while (order != NULL) {
+ /*
+ * We ignore any unknown names.
+ */
+ tok = lwres_strsep(&order, ":");
+ if (strcasecmp(tok, "inet6") == 0) {
+ if ((found & FOUND_IPV6) == 0)
+ *net_order++ = add_ipv6;
+ found |= FOUND_IPV6;
+ } else if (strcasecmp(tok, "inet") == 0 ||
+ strcasecmp(tok, "inet4") == 0) {
+ if ((found & FOUND_IPV4) == 0)
+ *net_order++ = add_ipv4;
+ found |= FOUND_IPV4;
+ }
+ }
+
+ /*
+ * Add in anything that we didn't find.
+ */
+ if ((found & FOUND_IPV4) == 0)
+ *net_order++ = add_ipv4;
+ if ((found & FOUND_IPV6) == 0)
+ *net_order++ = add_ipv6;
+ }
+ *net_order = NULL;
+ return;
+}
+
+static char v4_loop[4] = { 127, 0, 0, 1 };
+
+/*
+ * The test against 0 is there to keep the Solaris compiler
+ * from complaining about "end-of-loop code not reached".
+ */
+#define SETERROR(code) \
+ do { result = (code); \
+ if (result != 0) goto cleanup; \
+ } while (0)
+
+static int
+add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
+ int socktype, int port)
+{
+ struct addrinfo *ai;
+ lwres_context_t *lwrctx = NULL;
+ lwres_gabnresponse_t *by = NULL;
+ lwres_addr_t *addr;
+ lwres_result_t lwres;
+ int result = 0;
+
+ lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (lwres != LWRES_R_SUCCESS)
+ SETERROR(EAI_FAIL);
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+ if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
+ ai = ai_clone(*aip, AF_INET);
+ if (ai == NULL) {
+ lwres_freeaddrinfo(*aip);
+ SETERROR(EAI_MEMORY);
+ }
+
+ *aip = ai;
+ ai->ai_socktype = socktype;
+ SIN(ai->ai_addr)->sin_port = port;
+ memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
+ } else {
+ lwres = lwres_getaddrsbyname(lwrctx, hostname,
+ LWRES_ADDRTYPE_V4, &by);
+ if (lwres != LWRES_R_SUCCESS) {
+ if (lwres == LWRES_R_NOTFOUND)
+ goto cleanup;
+ else
+ SETERROR(EAI_FAIL);
+ }
+ addr = LWRES_LIST_HEAD(by->addrs);
+ while (addr != NULL) {
+ ai = ai_clone(*aip, AF_INET);
+ if (ai == NULL) {
+ lwres_freeaddrinfo(*aip);
+ SETERROR(EAI_MEMORY);
+ }
+ *aip = ai;
+ ai->ai_socktype = socktype;
+ SIN(ai->ai_addr)->sin_port = port;
+ memcpy(&SIN(ai->ai_addr)->sin_addr,
+ addr->address, 4);
+ if (flags & AI_CANONNAME) {
+ ai->ai_canonname = strdup(by->realname);
+ if (ai->ai_canonname == NULL)
+ SETERROR(EAI_MEMORY);
+ }
+ addr = LWRES_LIST_NEXT(addr, link);
+ }
+ }
+ cleanup:
+ if (by != NULL)
+ lwres_gabnresponse_free(lwrctx, &by);
+ if (lwrctx != NULL) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ }
+ return (result);
+}
+
+static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+
+static int
+add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
+ int socktype, int port)
+{
+ struct addrinfo *ai;
+ lwres_context_t *lwrctx = NULL;
+ lwres_gabnresponse_t *by = NULL;
+ lwres_addr_t *addr;
+ lwres_result_t lwres;
+ int result = 0;
+
+ lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (lwres != LWRES_R_SUCCESS)
+ SETERROR(EAI_FAIL);
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+
+ if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
+ ai = ai_clone(*aip, AF_INET6);
+ if (ai == NULL) {
+ lwres_freeaddrinfo(*aip);
+ SETERROR(EAI_MEMORY);
+ }
+
+ *aip = ai;
+ ai->ai_socktype = socktype;
+ SIN6(ai->ai_addr)->sin6_port = port;
+ memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
+ } else {
+ lwres = lwres_getaddrsbyname(lwrctx, hostname,
+ LWRES_ADDRTYPE_V6, &by);
+ if (lwres != LWRES_R_SUCCESS) {
+ if (lwres == LWRES_R_NOTFOUND)
+ goto cleanup;
+ else
+ SETERROR(EAI_FAIL);
+ }
+ addr = LWRES_LIST_HEAD(by->addrs);
+ while (addr != NULL) {
+ ai = ai_clone(*aip, AF_INET6);
+ if (ai == NULL) {
+ lwres_freeaddrinfo(*aip);
+ SETERROR(EAI_MEMORY);
+ }
+ *aip = ai;
+ ai->ai_socktype = socktype;
+ SIN6(ai->ai_addr)->sin6_port = port;
+ memcpy(&SIN6(ai->ai_addr)->sin6_addr,
+ addr->address, 16);
+ if (flags & AI_CANONNAME) {
+ ai->ai_canonname = strdup(by->realname);
+ if (ai->ai_canonname == NULL)
+ SETERROR(EAI_MEMORY);
+ }
+ addr = LWRES_LIST_NEXT(addr, link);
+ }
+ }
+ cleanup:
+ if (by != NULL)
+ lwres_gabnresponse_free(lwrctx, &by);
+ if (lwrctx != NULL) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ }
+ return (result);
+}
+
+/*% Free address info. */
+void
+lwres_freeaddrinfo(struct addrinfo *ai) {
+ struct addrinfo *ai_next;
+
+ while (ai != NULL) {
+ ai_next = ai->ai_next;
+ if (ai->ai_addr != NULL)
+ free(ai->ai_addr);
+ if (ai->ai_canonname)
+ free(ai->ai_canonname);
+ free(ai);
+ ai = ai_next;
+ }
+}
+
+#ifdef AF_LOCAL
+static int
+get_local(const char *name, int socktype, struct addrinfo **res) {
+ struct addrinfo *ai;
+ struct sockaddr_un *sun;
+
+ if (socktype == 0)
+ return (EAI_SOCKTYPE);
+
+ ai = ai_alloc(AF_LOCAL, sizeof(*sun));
+ if (ai == NULL)
+ return (EAI_MEMORY);
+
+ sun = SUN(ai->ai_addr);
+ strncpy(sun->sun_path, name, sizeof(sun->sun_path));
+
+ ai->ai_socktype = socktype;
+ /*
+ * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
+ * and ai->ai_next were initialized to zero.
+ */
+
+ *res = ai;
+ return (0);
+}
+#endif
+
+/*!
+ * Allocate an addrinfo structure, and a sockaddr structure
+ * of the specificed length. We initialize:
+ * ai_addrlen
+ * ai_family
+ * ai_addr
+ * ai_addr->sa_family
+ * ai_addr->sa_len (LWRES_PLATFORM_HAVESALEN)
+ * and everything else is initialized to zero.
+ */
+static struct addrinfo *
+ai_alloc(int family, int addrlen) {
+ struct addrinfo *ai;
+
+ ai = (struct addrinfo *)calloc(1, sizeof(*ai));
+ if (ai == NULL)
+ return (NULL);
+
+ ai->ai_addr = SA(calloc(1, addrlen));
+ if (ai->ai_addr == NULL) {
+ free(ai);
+ return (NULL);
+ }
+ ai->ai_addrlen = addrlen;
+ ai->ai_family = family;
+ ai->ai_addr->sa_family = family;
+#ifdef LWRES_PLATFORM_HAVESALEN
+ ai->ai_addr->sa_len = addrlen;
+#endif
+ return (ai);
+}
+
+static struct addrinfo *
+ai_clone(struct addrinfo *oai, int family) {
+ struct addrinfo *ai;
+
+ ai = ai_alloc(family, ((family == AF_INET6) ?
+ sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
+
+ if (ai == NULL) {
+ lwres_freeaddrinfo(oai);
+ return (NULL);
+ }
+ if (oai == NULL)
+ return (ai);
+
+ ai->ai_flags = oai->ai_flags;
+ ai->ai_socktype = oai->ai_socktype;
+ ai->ai_protocol = oai->ai_protocol;
+ ai->ai_canonname = NULL;
+ ai->ai_next = oai;
+ return (ai);
+}
+
+static struct addrinfo *
+ai_reverse(struct addrinfo *oai) {
+ struct addrinfo *nai, *tai;
+
+ nai = NULL;
+
+ while (oai != NULL) {
+ /*
+ * Grab one off the old list.
+ */
+ tai = oai;
+ oai = oai->ai_next;
+ /*
+ * Put it on the front of the new list.
+ */
+ tai->ai_next = nai;
+ nai = tai;
+ }
+ return (nai);
+}
diff --git a/lib/lwres/gethost.c b/lib/lwres/gethost.c
new file mode 100644
index 0000000..3cd6e4a
--- /dev/null
+++ b/lib/lwres/gethost.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2004, 2005 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: gethost.c,v 1.30.18.2 2005/04/29 00:17:17 marka Exp $ */
+
+/*! \file */
+
+/**
+ * These functions provide hostname-to-address and address-to-hostname
+ * lookups by means of the lightweight resolver. They are similar to the
+ * standard gethostent(3) functions provided by most operating systems.
+ * They use a struct hostent which is usually defined in <namedb.h>.
+ *
+ * \code
+ * 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 compatibility
+ * \endcode
+ *
+ * The members of this structure are:
+ *
+ * \li h_name:
+ * The official (canonical) name of the host.
+ *
+ * \li h_aliases:
+ * A NULL-terminated array of alternate names (nicknames) for the
+ * host.
+ *
+ * \li h_addrtype:
+ * The type of address being returned -- PF_INET or PF_INET6.
+ *
+ * \li h_length:
+ * The length of the address in bytes.
+ *
+ * \li h_addr_list:
+ * A NULL terminated array of network addresses for the host. Host
+ * addresses are returned in network byte order.
+ *
+ * For backward compatibility with very old software, h_addr is the first
+ * address in h_addr_list.
+ *
+ * lwres_gethostent(), lwres_sethostent(), lwres_endhostent(),
+ * lwres_gethostent_r(), lwres_sethostent_r() and lwres_endhostent_r()
+ * provide iteration over the known host entries on systems that provide
+ * such functionality through facilities like /etc/hosts or NIS. The
+ * lightweight resolver does not currently implement these functions; it
+ * only provides them as stub functions that always return failure.
+ *
+ * lwres_gethostbyname() and lwres_gethostbyname2() look up the hostname
+ * name. lwres_gethostbyname() always looks for an IPv4 address while
+ * lwres_gethostbyname2() looks for an address of protocol family af:
+ * either PF_INET or PF_INET6 -- IPv4 or IPV6 addresses respectively.
+ * Successful calls of the functions return a struct hostent for the name
+ * that was looked up. NULL is returned if the lookups by
+ * lwres_gethostbyname() or lwres_gethostbyname2() fail.
+ *
+ * Reverse lookups of addresses are performed by lwres_gethostbyaddr().
+ * addr is an address of length len bytes and protocol family type --
+ * PF_INET or PF_INET6. lwres_gethostbyname_r() is a thread-safe function
+ * for forward lookups. If an error occurs, an error code is returned in
+ * *error. resbuf is a pointer to a struct hostent which is initialised
+ * by a successful call to lwres_gethostbyname_r() . buf is a buffer of
+ * length len bytes which is used to store the h_name, h_aliases, and
+ * h_addr_list elements of the struct hostent returned in resbuf.
+ * Successful calls to lwres_gethostbyname_r() return resbuf, which is a
+ * pointer to the struct hostent it created.
+ *
+ * lwres_gethostbyaddr_r() is a thread-safe function that performs a
+ * reverse lookup of address addr which is len bytes long and is of
+ * protocol family type -- PF_INET or PF_INET6. If an error occurs, the
+ * error code is returned in *error. The other function parameters are
+ * identical to those in lwres_gethostbyname_r(). resbuf is a pointer to
+ * a struct hostent which is initialised by a successful call to
+ * lwres_gethostbyaddr_r(). buf is a buffer of length len bytes which is
+ * used to store the h_name, h_aliases, and h_addr_list elements of the
+ * struct hostent returned in resbuf. Successful calls to
+ * lwres_gethostbyaddr_r() return resbuf, which is a pointer to the
+ * struct hostent it created.
+ *
+ * \section gethost_return Return Values
+ *
+ * The functions lwres_gethostbyname(), lwres_gethostbyname2(),
+ * lwres_gethostbyaddr(), and lwres_gethostent() return NULL to indicate
+ * an error. In this case the global variable lwres_h_errno will contain
+ * one of the following error codes defined in \link netdb.h <lwres/netdb.h>:\endlink
+ *
+ * \li #HOST_NOT_FOUND:
+ * The host or address was not found.
+ *
+ * \li #TRY_AGAIN:
+ * A recoverable error occurred, e.g., a timeout. Retrying the
+ * lookup may succeed.
+ *
+ * \li #NO_RECOVERY:
+ * A non-recoverable error occurred.
+ *
+ * \li #NO_DATA:
+ * The name exists, but has no address information associated with
+ * it (or vice versa in the case of a reverse lookup). The code
+ * NO_ADDRESS is accepted as a synonym for NO_DATA for backwards
+ * compatibility.
+ *
+ * lwres_hstrerror() translates these error codes to suitable error
+ * messages.
+ *
+ * lwres_gethostent() and lwres_gethostent_r() always return NULL.
+ *
+ * Successful calls to lwres_gethostbyname_r() and
+ * lwres_gethostbyaddr_r() return resbuf, a pointer to the struct hostent
+ * that was initialised by these functions. They return NULL if the
+ * lookups fail or if buf was too small to hold the list of addresses and
+ * names referenced by the h_name, h_aliases, and h_addr_list elements of
+ * the struct hostent. If buf was too small, both lwres_gethostbyname_r()
+ * and lwres_gethostbyaddr_r() set the global variable errno to ERANGE.
+ *
+ * \section gethost_see See Also
+ *
+ * gethostent(), \link getipnode.c getipnode\endlink, lwres_hstrerror()
+ *
+ * \section gethost_bugs Bugs
+ *
+ * lwres_gethostbyname(), lwres_gethostbyname2(), lwres_gethostbyaddr()
+ * and lwres_endhostent() are not thread safe; they return pointers to
+ * static data and provide error codes through a global variable.
+ * Thread-safe versions for name and address lookup are provided by
+ * lwres_gethostbyname_r(), and lwres_gethostbyaddr_r() respectively.
+ *
+ * The resolver daemon does not currently support any non-DNS name
+ * services such as /etc/hosts or NIS, consequently the above functions
+ * don't, either.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <lwres/net.h>
+#include <lwres/netdb.h>
+
+#include "assert_p.h"
+
+#define LWRES_ALIGNBYTES (sizeof(char *) - 1)
+#define LWRES_ALIGN(p) \
+ (((unsigned long)(p) + LWRES_ALIGNBYTES) &~ LWRES_ALIGNBYTES)
+
+static struct hostent *he = NULL;
+static int copytobuf(struct hostent *, struct hostent *, char *, int);
+
+/*% Always looks for an IPv4 address. */
+struct hostent *
+lwres_gethostbyname(const char *name) {
+
+ if (he != NULL)
+ lwres_freehostent(he);
+
+ he = lwres_getipnodebyname(name, AF_INET, 0, &lwres_h_errno);
+ return (he);
+}
+
+/*% Looks for either an IPv4 or IPv6 address. */
+struct hostent *
+lwres_gethostbyname2(const char *name, int af) {
+ if (he != NULL)
+ lwres_freehostent(he);
+
+ he = lwres_getipnodebyname(name, af, 0, &lwres_h_errno);
+ return (he);
+}
+
+/*% Reverse lookup of addresses. */
+struct hostent *
+lwres_gethostbyaddr(const char *addr, int len, int type) {
+
+ if (he != NULL)
+ lwres_freehostent(he);
+
+ he = lwres_getipnodebyaddr(addr, len, type, &lwres_h_errno);
+ return (he);
+}
+
+/*% Stub function. Always returns failure. */
+struct hostent *
+lwres_gethostent(void) {
+ if (he != NULL)
+ lwres_freehostent(he);
+
+ return (NULL);
+}
+
+/*% Stub function. Always returns failure. */
+void
+lwres_sethostent(int stayopen) {
+ /*
+ * Empty.
+ */
+ UNUSED(stayopen);
+}
+
+/*% Stub function. Always returns failure. */
+void
+lwres_endhostent(void) {
+ /*
+ * Empty.
+ */
+}
+
+/*% Thread-safe function for forward lookups. */
+struct hostent *
+lwres_gethostbyname_r(const char *name, struct hostent *resbuf,
+ char *buf, int buflen, int *error)
+{
+ struct hostent *he;
+ int res;
+
+ he = lwres_getipnodebyname(name, AF_INET, 0, error);
+ if (he == NULL)
+ return (NULL);
+ res = copytobuf(he, resbuf, buf, buflen);
+ lwres_freehostent(he);
+ if (res != 0) {
+ errno = ERANGE;
+ return (NULL);
+ }
+ return (resbuf);
+}
+
+/*% Thread-safe reverse lookup. */
+struct hostent *
+lwres_gethostbyaddr_r(const char *addr, int len, int type,
+ struct hostent *resbuf, char *buf, int buflen,
+ int *error)
+{
+ struct hostent *he;
+ int res;
+
+ he = lwres_getipnodebyaddr(addr, len, type, error);
+ if (he == NULL)
+ return (NULL);
+ res = copytobuf(he, resbuf, buf, buflen);
+ lwres_freehostent(he);
+ if (res != 0) {
+ errno = ERANGE;
+ return (NULL);
+ }
+ return (resbuf);
+}
+
+/*% Stub function. Always returns failure. */
+struct hostent *
+lwres_gethostent_r(struct hostent *resbuf, char *buf, int buflen, int *error) {
+ UNUSED(resbuf);
+ UNUSED(buf);
+ UNUSED(buflen);
+ *error = 0;
+ return (NULL);
+}
+
+/*% Stub function. Always returns failure. */
+void
+lwres_sethostent_r(int stayopen) {
+ /*
+ * Empty.
+ */
+ UNUSED(stayopen);
+}
+
+/*% Stub function. Always returns failure. */
+void
+lwres_endhostent_r(void) {
+ /*
+ * Empty.
+ */
+}
+
+static int
+copytobuf(struct hostent *he, struct hostent *hptr, char *buf, int buflen) {
+ 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 *)LWRES_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) {
+ return (-1);
+ }
+
+ /*
+ * Copy address size and type.
+ */
+ hptr->h_addrtype = he->h_addrtype;
+ n = hptr->h_length = he->h_length;
+
+ ptr = (char **)LWRES_ALIGN(buf);
+ cp = (char *)LWRES_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 (0);
+}
diff --git a/lib/lwres/getipnode.c b/lib/lwres/getipnode.c
new file mode 100644
index 0000000..ab49814
--- /dev/null
+++ b/lib/lwres/getipnode.c
@@ -0,0 +1,1148 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: getipnode.c,v 1.37.18.7 2007/08/28 07:20:06 tbox Exp $ */
+
+/*! \file */
+
+/**
+ * These functions perform thread safe, protocol independent
+ * nodename-to-address and address-to-nodename translation as defined in
+ * RFC2553. This use a struct hostent which is defined in namedb.h:
+ *
+ * \code
+ * 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 compatibility
+ * \endcode
+ *
+ * The members of this structure are:
+ *
+ * \li h_name:
+ * The official (canonical) name of the host.
+ *
+ * \li h_aliases:
+ * A NULL-terminated array of alternate names (nicknames) for the
+ * host.
+ *
+ * \li h_addrtype:
+ * The type of address being returned - usually PF_INET or
+ * PF_INET6.
+ *
+ * \li h_length:
+ * The length of the address in bytes.
+ *
+ * \li h_addr_list:
+ * A NULL terminated array of network addresses for the host. Host
+ * addresses are returned in network byte order.
+ *
+ * lwres_getipnodebyname() looks up addresses of protocol family af for
+ * the hostname name. The flags parameter contains ORed flag bits to
+ * specify the types of addresses that are searched for, and the types of
+ * addresses that are returned. The flag bits are:
+ *
+ * \li #AI_V4MAPPED:
+ * This is used with an af of #AF_INET6, and causes IPv4 addresses
+ * to be returned as IPv4-mapped IPv6 addresses.
+ *
+ * \li #AI_ALL:
+ * This is used with an af of #AF_INET6, and causes all known
+ * addresses (IPv6 and IPv4) to be returned. If #AI_V4MAPPED is
+ * also set, the IPv4 addresses are return as mapped IPv6
+ * addresses.
+ *
+ * \li #AI_ADDRCONFIG:
+ * Only return an IPv6 or IPv4 address if here is an active
+ * network interface of that type. This is not currently
+ * implemented in the BIND 9 lightweight resolver, and the flag is
+ * ignored.
+ *
+ * \li #AI_DEFAULT:
+ * This default sets the #AI_V4MAPPED and #AI_ADDRCONFIG flag bits.
+ *
+ * lwres_getipnodebyaddr() performs a reverse lookup of address src which
+ * is len bytes long. af denotes the protocol family, typically PF_INET
+ * or PF_INET6.
+ *
+ * lwres_freehostent() releases all the memory associated with the struct
+ * hostent pointer. Any memory allocated for the h_name, h_addr_list
+ * and h_aliases is freed, as is the memory for the hostent structure
+ * itself.
+ *
+ * \section getipnode_return Return Values
+ *
+ * If an error occurs, lwres_getipnodebyname() and
+ * lwres_getipnodebyaddr() set *error_num to an appropriate error code
+ * and the function returns a NULL pointer. The error codes and their
+ * meanings are defined in \link netdb.h <lwres/netdb.h>\endlink:
+ *
+ * \li #HOST_NOT_FOUND:
+ * No such host is known.
+ *
+ * \li #NO_ADDRESS:
+ * The server recognised the request and the name but no address
+ * is available. Another type of request to the name server for
+ * the domain might return an answer.
+ *
+ * \li #TRY_AGAIN:
+ * A temporary and possibly transient error occurred, such as a
+ * failure of a server to respond. The request may succeed if
+ * retried.
+ *
+ * \li #NO_RECOVERY:
+ * An unexpected failure occurred, and retrying the request is
+ * pointless.
+ *
+ * lwres_hstrerror() translates these error codes to suitable error
+ * messages.
+ *
+ * \section getipnode_see See Also
+ *
+ * getaddrinfo.c, gethost.c, getnameinfo.c, herror.c, RFC2553
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/netdb.h> /* XXX #include <netdb.h> */
+
+#include "assert_p.h"
+
+#ifndef INADDRSZ
+#define INADDRSZ 4
+#endif
+#ifndef IN6ADDRSZ
+#define IN6ADDRSZ 16
+#endif
+
+#ifdef LWRES_PLATFORM_NEEDIN6ADDRANY
+LIBLWRES_EXTERNAL_DATA const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+#endif
+
+#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
+};
+
+/***
+ *** Forward declarations.
+ ***/
+
+static int
+scan_interfaces(int *, int *);
+
+static struct hostent *
+copyandmerge(struct hostent *, struct hostent *, int, int *);
+
+static struct hostent *
+hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src);
+
+static struct hostent *
+hostfromname(lwres_gabnresponse_t *name, int af);
+
+/***
+ *** 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 *
+lwres_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 = NULL;
+ int v4 = 0, v6 = 0;
+ int tmp_err;
+ lwres_context_t *lwrctx = NULL;
+ lwres_gabnresponse_t *by = NULL;
+ int n;
+
+ /*
+ * 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 = lwres_net_pton(AF_INET, name, &in4)) != 1)
+ v6 = lwres_net_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 &&
+ (((flags & AI_V4MAPPED) != 0 && have_v4) ||
+ (flags & AI_V4MAPPED) == 0))) {
+ *error_num = HOST_NOT_FOUND;
+ return (NULL);
+ }
+
+ /*
+ * Literal address?
+ */
+ if (v4 == 1 || v6 == 1) {
+ char *addr_list[2];
+ char *aliases[1];
+ char mappedname[sizeof("::ffff:123.123.123.123")];
+ union {
+ const char *const_name;
+ char *deconst_name;
+ } u;
+
+ u.const_name = name;
+ if (v4 == 1 && af == AF_INET6) {
+ strcpy(mappedname, "::ffff:");
+ lwres_net_ntop(AF_INET, (char *)&in4,
+ mappedname + sizeof("::ffff:") - 1,
+ sizeof(mappedname) - sizeof("::ffff:")
+ + 1);
+ he.h_name = mappedname;
+ } else
+ he.h_name = u.deconst_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));
+ }
+
+ n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (n != 0) {
+ *error_num = NO_RECOVERY;
+ goto cleanup;
+ }
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+ tmp_err = NO_RECOVERY;
+ if (have_v6 && af == AF_INET6) {
+
+ n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V6, &by);
+ if (n == 0) {
+ he1 = hostfromname(by, AF_INET6);
+ lwres_gabnresponse_free(lwrctx, &by);
+ if (he1 == NULL) {
+ *error_num = NO_RECOVERY;
+ goto cleanup;
+ }
+ } else {
+ tmp_err = HOST_NOT_FOUND;
+ }
+ }
+
+ if (have_v4 &&
+ ((af == AF_INET) ||
+ (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
+ (he1 == NULL || (flags & AI_ALL) != 0)))) {
+ n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V4, &by);
+ if (n == 0) {
+ he2 = hostfromname(by, AF_INET);
+ lwres_gabnresponse_free(lwrctx, &by);
+ if (he2 == NULL) {
+ *error_num = NO_RECOVERY;
+ goto cleanup;
+ }
+ } else if (he1 == NULL) {
+ if (n == LWRES_R_NOTFOUND)
+ *error_num = HOST_NOT_FOUND;
+ else
+ *error_num = NO_RECOVERY;
+ goto cleanup;
+ }
+ } else
+ *error_num = tmp_err;
+
+ he3 = copyandmerge(he1, he2, af, error_num);
+
+ cleanup:
+ if (he1 != NULL)
+ lwres_freehostent(he1);
+ if (he2 != NULL)
+ lwres_freehostent(he2);
+ if (lwrctx != NULL) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ }
+ return (he3);
+}
+
+/*% performs a reverse lookup of address src which is len bytes long. af denotes the protocol family, typically #PF_INET or PF_INET6. */
+struct hostent *
+lwres_getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
+ struct hostent *he1, *he2;
+ lwres_context_t *lwrctx = NULL;
+ lwres_gnbaresponse_t *by = NULL;
+ lwres_result_t n;
+ union {
+ const void *konst;
+ struct in6_addr *in6;
+ } u;
+
+ /*
+ * Sanity checks.
+ */
+ if (src == NULL) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ switch (af) {
+ case AF_INET:
+ if (len != (unsigned int)INADDRSZ) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+ break;
+ case AF_INET6:
+ if (len != (unsigned int)IN6ADDRSZ) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+ break;
+ default:
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ /*
+ * The de-"const"-ing game is done because at least one
+ * vendor's system (RedHat 6.0) defines the IN6_IS_ADDR_*
+ * macros in such a way that they discard the const with
+ * internal casting, and gcc ends up complaining. Rather
+ * than replacing their own (possibly optimized) definitions
+ * with our own, cleanly discarding the const is the easiest
+ * thing to do.
+ */
+ u.konst = src;
+
+ /*
+ * Look up IPv4 and IPv4 mapped/compatible addresses.
+ */
+ if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT(u.in6)) ||
+ (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(u.in6)) ||
+ (af == AF_INET)) {
+ const unsigned char *cp = src;
+
+ if (af == AF_INET6)
+ cp += 12;
+ n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (n == LWRES_R_SUCCESS)
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+ if (n == LWRES_R_SUCCESS)
+ n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V4,
+ INADDRSZ, cp, &by);
+ if (n != LWRES_R_SUCCESS) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ if (n == LWRES_R_NOTFOUND)
+ *error_num = HOST_NOT_FOUND;
+ else
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+ he1 = hostfromaddr(by, AF_INET, cp);
+ lwres_gnbaresponse_free(lwrctx, &by);
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ if (af != AF_INET6)
+ return (he1);
+
+ /*
+ * Convert from AF_INET to AF_INET6.
+ */
+ he2 = copyandmerge(he1, NULL, af, error_num);
+ lwres_freehostent(he1);
+ if (he2 == NULL)
+ return (NULL);
+ /*
+ * Restore original address.
+ */
+ memcpy(he2->h_addr, src, len);
+ return (he2);
+ }
+
+ /*
+ * Lookup IPv6 address.
+ */
+ if (memcmp(src, &in6addr_any, IN6ADDRSZ) == 0) {
+ *error_num = HOST_NOT_FOUND;
+ return (NULL);
+ }
+
+ n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (n == LWRES_R_SUCCESS)
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+ if (n == LWRES_R_SUCCESS)
+ n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V6, IN6ADDRSZ,
+ src, &by);
+ if (n != 0) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ *error_num = HOST_NOT_FOUND;
+ return (NULL);
+ }
+ he1 = hostfromaddr(by, AF_INET6, src);
+ lwres_gnbaresponse_free(lwrctx, &by);
+ if (he1 == NULL)
+ *error_num = NO_RECOVERY;
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ return (he1);
+}
+
+/*% releases all the memory associated with the struct hostent pointer */
+void
+lwres_freehostent(struct hostent *he) {
+ char **cpp;
+ int names = 1;
+ int addresses = 1;
+
+ free(he->h_name);
+
+ cpp = he->h_addr_list;
+ while (*cpp != NULL) {
+ free(*cpp);
+ *cpp = NULL;
+ cpp++;
+ addresses++;
+ }
+
+ cpp = he->h_aliases;
+ while (*cpp != NULL) {
+ free(*cpp);
+ cpp++;
+ names++;
+ }
+
+ free(he->h_aliases);
+ free(he->h_addr_list);
+ free(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 ISC_HAVE_LIFC_FAMILY 1
+#define ISC_HAVE_LIFC_FLAGS 1
+#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 int
+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;
+
+ /*
+ * Set to zero. Used as loop terminators below.
+ */
+ *have_v4 = *have_v6 = 0;
+
+ /*
+ * Get interface list from system.
+ */
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
+ goto err_ret;
+
+ /*
+ * Grow buffer until large enough to contain all interface
+ * descriptions.
+ */
+ for (;;) {
+ buf = malloc(bufsiz);
+ if (buf == NULL)
+ goto err_ret;
+#ifdef ISC_HAVE_LIFC_FAMILY
+ lifc.lifc_family = AF_UNSPEC; /* request all families */
+#endif
+#ifdef ISC_HAVE_LIFC_FLAGS
+ 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 err_ret;
+
+ if (bufsiz > 1000000)
+ goto err_ret;
+
+ free(buf);
+ 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 LWRES_PLATFORM_HAVESALEN
+#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)
+ free(buf);
+ close(s);
+ return (0);
+ err_ret:
+ if (buf != NULL)
+ free(buf);
+ if (s != -1)
+ close(s);
+ return (-1);
+}
+#endif
+
+static int
+scan_interfaces(int *have_v4, int *have_v6) {
+#if !defined(SIOCGIFCONF) || !defined(SIOCGIFADDR)
+ *have_v4 = *have_v6 = 1;
+ return (0);
+#else
+ 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;
+
+#ifdef WIN32
+ InitSockets();
+#endif
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
+ !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
+ /*
+ * Try to scan the interfaces using IPv6 ioctls().
+ */
+ if (!scan_interfaces6(have_v4, have_v6)) {
+#ifdef WIN32
+ DestroySockets();
+#endif
+ return (0);
+ }
+#endif
+
+ /*
+ * Set to zero. Used as loop terminators below.
+ */
+ *have_v4 = *have_v6 = 0;
+
+ /*
+ * 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 = malloc(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;
+
+ free(buf);
+ 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 LWRES_PLATFORM_HAVESALEN
+#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)
+ free(buf);
+#ifdef WIN32
+ DestroySockets();
+#endif
+ close(s);
+ return (0);
+
+ err_ret:
+ if (buf != NULL)
+ free(buf);
+ if (s != -1)
+ close(s);
+#ifdef WIN32
+ DestroySockets();
+#endif
+ return (-1);
+#endif
+}
+
+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 = malloc(sizeof(*he));
+ if (he == NULL)
+ goto no_recovery;
+
+ he->h_addr_list = malloc(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 = malloc((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 = malloc((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 = malloc(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 = malloc(len);
+ if (*npp == NULL)
+ goto cleanup2;
+ strcpy(*npp, *cpp);
+ npp++;
+ cpp++;
+ }
+
+ /*
+ * Copy hostname.
+ */
+ he->h_name = malloc(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) {
+ free(*cpp);
+ cpp++;
+ }
+ free(he->h_aliases);
+
+ cleanup1:
+ cpp = he->h_addr_list;
+ while (*cpp != NULL) {
+ free(*cpp);
+ *cpp = NULL;
+ cpp++;
+ }
+ free(he->h_addr_list);
+
+ cleanup0:
+ free(he);
+
+ no_recovery:
+ *error_num = NO_RECOVERY;
+ return (NULL);
+}
+
+static struct hostent *
+hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src) {
+ struct hostent *he;
+ int i;
+
+ he = malloc(sizeof(*he));
+ if (he == NULL)
+ goto cleanup;
+ memset(he, 0, sizeof(*he));
+
+ /*
+ * Set family and length.
+ */
+ he->h_addrtype = af;
+ switch (af) {
+ case AF_INET:
+ he->h_length = INADDRSZ;
+ break;
+ case AF_INET6:
+ he->h_length = IN6ADDRSZ;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ /*
+ * Copy name.
+ */
+ he->h_name = strdup(addr->realname);
+ if (he->h_name == NULL)
+ goto cleanup;
+
+ /*
+ * Copy aliases.
+ */
+ he->h_aliases = malloc(sizeof(char *) * (addr->naliases + 1));
+ if (he->h_aliases == NULL)
+ goto cleanup;
+ for (i = 0; i < addr->naliases; i++) {
+ he->h_aliases[i] = strdup(addr->aliases[i]);
+ if (he->h_aliases[i] == NULL)
+ goto cleanup;
+ }
+ he->h_aliases[i] = NULL;
+
+ /*
+ * Copy address.
+ */
+ he->h_addr_list = malloc(sizeof(char *) * 2);
+ if (he->h_addr_list == NULL)
+ goto cleanup;
+ he->h_addr_list[0] = malloc(he->h_length);
+ if (he->h_addr_list[0] == NULL)
+ goto cleanup;
+ memcpy(he->h_addr_list[0], src, he->h_length);
+ he->h_addr_list[1] = NULL;
+ return (he);
+
+ cleanup:
+ if (he != NULL && he->h_addr_list != NULL) {
+ for (i = 0; he->h_addr_list[i] != NULL; i++)
+ free(he->h_addr_list[i]);
+ free(he->h_addr_list);
+ }
+ if (he != NULL && he->h_aliases != NULL) {
+ for (i = 0; he->h_aliases[i] != NULL; i++)
+ free(he->h_aliases[i]);
+ free(he->h_aliases);
+ }
+ if (he != NULL && he->h_name != NULL)
+ free(he->h_name);
+ if (he != NULL)
+ free(he);
+ return (NULL);
+}
+
+static struct hostent *
+hostfromname(lwres_gabnresponse_t *name, int af) {
+ struct hostent *he;
+ int i;
+ lwres_addr_t *addr;
+
+ he = malloc(sizeof(*he));
+ if (he == NULL)
+ goto cleanup;
+ memset(he, 0, sizeof(*he));
+
+ /*
+ * Set family and length.
+ */
+ he->h_addrtype = af;
+ switch (af) {
+ case AF_INET:
+ he->h_length = INADDRSZ;
+ break;
+ case AF_INET6:
+ he->h_length = IN6ADDRSZ;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ /*
+ * Copy name.
+ */
+ he->h_name = strdup(name->realname);
+ if (he->h_name == NULL)
+ goto cleanup;
+
+ /*
+ * Copy aliases.
+ */
+ he->h_aliases = malloc(sizeof(char *) * (name->naliases + 1));
+ for (i = 0; i < name->naliases; i++) {
+ he->h_aliases[i] = strdup(name->aliases[i]);
+ if (he->h_aliases[i] == NULL)
+ goto cleanup;
+ }
+ he->h_aliases[i] = NULL;
+
+ /*
+ * Copy addresses.
+ */
+ he->h_addr_list = malloc(sizeof(char *) * (name->naddrs + 1));
+ addr = LWRES_LIST_HEAD(name->addrs);
+ i = 0;
+ while (addr != NULL) {
+ he->h_addr_list[i] = malloc(he->h_length);
+ if (he->h_addr_list[i] == NULL)
+ goto cleanup;
+ memcpy(he->h_addr_list[i], addr->address, he->h_length);
+ addr = LWRES_LIST_NEXT(addr, link);
+ i++;
+ }
+ he->h_addr_list[i] = NULL;
+ return (he);
+
+ cleanup:
+ if (he != NULL && he->h_addr_list != NULL) {
+ for (i = 0; he->h_addr_list[i] != NULL; i++)
+ free(he->h_addr_list[i]);
+ free(he->h_addr_list);
+ }
+ if (he != NULL && he->h_aliases != NULL) {
+ for (i = 0; he->h_aliases[i] != NULL; i++)
+ free(he->h_aliases[i]);
+ free(he->h_aliases);
+ }
+ if (he != NULL && he->h_name != NULL)
+ free(he->h_name);
+ if (he != NULL)
+ free(he);
+ return (NULL);
+}
diff --git a/lib/lwres/getnameinfo.c b/lib/lwres/getnameinfo.c
new file mode 100644
index 0000000..d1874a0
--- /dev/null
+++ b/lib/lwres/getnameinfo.c
@@ -0,0 +1,346 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions 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: getnameinfo.c,v 1.34.18.3 2005/04/29 00:17:18 marka Exp $ */
+
+/*! \file */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * XXX
+ * Issues to be discussed:
+ * - Return values. There seems to be no standard for return value (RFC2553)
+ * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
+ */
+
+
+/**
+ * This function is equivalent to the getnameinfo(3) function defined in
+ * RFC2133. lwres_getnameinfo() returns the hostname for the struct
+ * sockaddr sa which is salen bytes long. The hostname is of length
+ * hostlen and is returned via *host. The maximum length of the hostname
+ * is 1025 bytes: #NI_MAXHOST.
+ *
+ * The name of the service associated with the port number in sa is
+ * returned in *serv. It is servlen bytes long. The maximum length of the
+ * service name is #NI_MAXSERV - 32 bytes.
+ *
+ * The flags argument sets the following bits:
+ *
+ * \li #NI_NOFQDN:
+ * A fully qualified domain name is not required for local hosts.
+ * The local part of the fully qualified domain name is returned
+ * instead.
+ *
+ * \li #NI_NUMERICHOST
+ * Return the address in numeric form, as if calling inet_ntop(),
+ * instead of a host name.
+ *
+ * \li #NI_NAMEREQD
+ * A name is required. If the hostname cannot be found in the DNS
+ * and this flag is set, a non-zero error code is returned. If the
+ * hostname is not found and the flag is not set, the address is
+ * returned in numeric form.
+ *
+ * \li #NI_NUMERICSERV
+ * The service name is returned as a digit string representing the
+ * port number.
+ *
+ * \li #NI_DGRAM
+ * Specifies that the service being looked up is a datagram
+ * service, and causes getservbyport() to be called with a second
+ * argument of "udp" instead of its default of "tcp". This is
+ * required for the few ports (512-514) that have different
+ * services for UDP and TCP.
+ *
+ * \section getnameinfo_return Return Values
+ *
+ * lwres_getnameinfo() returns 0 on success or a non-zero error code if
+ * an error occurs.
+ *
+ * \section getname_see See Also
+ *
+ * RFC2133, getservbyport(),
+ * lwres_getnamebyaddr(). lwres_net_ntop().
+ *
+ * \section getnameinfo_bugs Bugs
+ *
+ * RFC2133 fails to define what the nonzero return values of
+ * getnameinfo() are.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/netdb.h>
+#include "print_p.h"
+
+#include "assert_p.h"
+
+#define SUCCESS 0
+
+/*% afd structure definition */
+static struct afd {
+ int a_af;
+ size_t a_addrlen;
+ size_t a_socklen;
+} afdl [] = {
+ /*!
+ * First entry is linked last...
+ */
+ { AF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in) },
+ { AF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6) },
+ {0, 0, 0},
+};
+
+#define ENI_NOSERVNAME 1
+#define ENI_NOHOSTNAME 2
+#define ENI_MEMORY 3
+#define ENI_SYSTEM 4
+#define ENI_FAMILY 5
+#define ENI_SALEN 6
+#define ENI_NOSOCKET 7
+
+/*!
+ * The test against 0 is there to keep the Solaris compiler
+ * from complaining about "end-of-loop code not reached".
+ */
+#define ERR(code) \
+ do { result = (code); \
+ if (result != 0) goto cleanup; \
+ } while (0)
+
+/*% lightweight resolver socket address structure to hostname and service name */
+int
+lwres_getnameinfo(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;
+ unsigned short port;
+#ifdef LWRES_PLATFORM_HAVESALEN
+ size_t len;
+#endif
+ int family, i;
+ const void *addr;
+ char *p;
+#if 0
+ unsigned long v4a;
+ unsigned char pfx;
+#endif
+ char numserv[sizeof("65000")];
+ char numaddr[sizeof("abcd:abcd:abcd:abcd:abcd:abcd:255.255.255.255")
+ + 1 + sizeof("4294967295")];
+ const char *proto;
+ lwres_uint32_t lwf = 0;
+ lwres_context_t *lwrctx = NULL;
+ lwres_gnbaresponse_t *by = NULL;
+ int result = SUCCESS;
+ int n;
+
+ if (sa == NULL)
+ ERR(ENI_NOSOCKET);
+
+#ifdef LWRES_PLATFORM_HAVESALEN
+ len = sa->sa_len;
+ if (len != salen)
+ ERR(ENI_SALEN);
+#endif
+
+ family = sa->sa_family;
+ for (i = 0; afdl[i].a_af; i++)
+ if (afdl[i].a_af == family) {
+ afd = &afdl[i];
+ goto found;
+ }
+ ERR(ENI_FAMILY);
+
+ found:
+ if (salen != afd->a_socklen)
+ ERR(ENI_SALEN);
+
+ switch (family) {
+ case AF_INET:
+ port = ((const struct sockaddr_in *)sa)->sin_port;
+ addr = &((const struct sockaddr_in *)sa)->sin_addr.s_addr;
+ break;
+
+ case AF_INET6:
+ port = ((const struct sockaddr_in6 *)sa)->sin6_port;
+ addr = ((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
+ break;
+
+ default:
+ port = 0;
+ addr = NULL;
+ INSIST(0);
+ }
+ proto = (flags & NI_DGRAM) ? "udp" : "tcp";
+
+ if (serv == NULL || servlen == 0U) {
+ /*
+ * Caller does not want service.
+ */
+ } else if ((flags & NI_NUMERICSERV) != 0 ||
+ (sp = getservbyport(port, proto)) == NULL) {
+ snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
+ if ((strlen(numserv) + 1) > servlen)
+ ERR(ENI_MEMORY);
+ strcpy(serv, numserv);
+ } else {
+ if ((strlen(sp->s_name) + 1) > servlen)
+ ERR(ENI_MEMORY);
+ strcpy(serv, sp->s_name);
+ }
+
+#if 0
+ switch (sa->sa_family) {
+ case AF_INET:
+ v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
+ if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+ flags |= NI_NUMERICHOST;
+ v4a >>= IN_CLASSA_NSHIFT;
+ if (v4a == 0 || v4a == IN_LOOPBACKNET)
+ flags |= NI_NUMERICHOST;
+ break;
+
+ case AF_INET6:
+ pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0];
+ if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
+ flags |= NI_NUMERICHOST;
+ break;
+ }
+#endif
+
+ if (host == NULL || hostlen == 0U) {
+ /*
+ * What should we do?
+ */
+ } else if (flags & NI_NUMERICHOST) {
+ if (lwres_net_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
+ == NULL)
+ ERR(ENI_SYSTEM);
+#if defined(LWRES_HAVE_SIN6_SCOPE_ID)
+ if (afd->a_af == AF_INET6 &&
+ ((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
+ char *p = numaddr + strlen(numaddr);
+ const char *stringscope = NULL;
+#if 0
+ if ((flags & NI_NUMERICSCOPE) == 0) {
+ /*
+ * Vendors may want to add support for
+ * non-numeric scope identifier.
+ */
+ stringscope = foo;
+ }
+#endif
+ if (stringscope == NULL) {
+ snprintf(p, sizeof(numaddr) - (p - numaddr),
+ "%%%u",
+ ((const struct sockaddr_in6 *)sa)->sin6_scope_id);
+ } else {
+ snprintf(p, sizeof(numaddr) - (p - numaddr),
+ "%%%s", stringscope);
+ }
+ }
+#endif
+ if (strlen(numaddr) + 1 > hostlen)
+ ERR(ENI_MEMORY);
+ strcpy(host, numaddr);
+ } else {
+ switch (family) {
+ case AF_INET:
+ lwf = LWRES_ADDRTYPE_V4;
+ break;
+ case AF_INET6:
+ lwf = LWRES_ADDRTYPE_V6;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (n == 0)
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+
+ if (n == 0)
+ n = lwres_getnamebyaddr(lwrctx, lwf,
+ (lwres_uint16_t)afd->a_addrlen,
+ addr, &by);
+ if (n == 0) {
+ if (flags & NI_NOFQDN) {
+ p = strchr(by->realname, '.');
+ if (p)
+ *p = '\0';
+ }
+ if ((strlen(by->realname) + 1) > hostlen)
+ ERR(ENI_MEMORY);
+ strcpy(host, by->realname);
+ } else {
+ if (flags & NI_NAMEREQD)
+ ERR(ENI_NOHOSTNAME);
+ if (lwres_net_ntop(afd->a_af, addr, numaddr,
+ sizeof(numaddr))
+ == NULL)
+ ERR(ENI_NOHOSTNAME);
+ if ((strlen(numaddr) + 1) > hostlen)
+ ERR(ENI_MEMORY);
+ strcpy(host, numaddr);
+ }
+ }
+ result = SUCCESS;
+ cleanup:
+ if (by != NULL)
+ lwres_gnbaresponse_free(lwrctx, &by);
+ if (lwrctx != NULL) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ }
+ return (result);
+}
diff --git a/lib/lwres/getrrset.c b/lib/lwres/getrrset.c
new file mode 100644
index 0000000..6b7e5e5
--- /dev/null
+++ b/lib/lwres/getrrset.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2004, 2005 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: getrrset.c,v 1.14.18.2 2005/04/29 00:17:18 marka Exp $ */
+
+/*! \file */
+
+/**
+ * DESCRIPTION
+ *
+ * lwres_getrrsetbyname() gets a set of resource records associated with
+ * a hostname, class, and type. hostname is a pointer a to
+ * null-terminated string. The flags field is currently unused and must
+ * be zero.
+ *
+ * After a successful call to lwres_getrrsetbyname(), *res is a pointer
+ * to an #rrsetinfo structure, containing a list of one or more #rdatainfo
+ * structures containing resource records and potentially another list of
+ * rdatainfo structures containing SIG resource records associated with
+ * those records. The members #rri_rdclass and #rri_rdtype are copied from
+ * the parameters. #rri_ttl and #rri_name are properties of the obtained
+ * rrset. The resource records contained in #rri_rdatas and #rri_sigs are
+ * in uncompressed DNS wire format. Properties of the rdataset are
+ * represented in the #rri_flags bitfield. If the #RRSET_VALIDATED bit is
+ * set, the data has been DNSSEC validated and the signatures verified.
+ *
+ * All of the information returned by lwres_getrrsetbyname() is
+ * dynamically allocated: the rrsetinfo and rdatainfo structures, and the
+ * canonical host name strings pointed to by the rrsetinfostructure.
+ * Memory allocated for the dynamically allocated structures created by a
+ * successful call to lwres_getrrsetbyname() is released by
+ * lwres_freerrset(). rrset is a pointer to a struct rrset created by a
+ * call to lwres_getrrsetbyname().
+ *
+ * The following structures are used:
+ *
+ * \code
+ * struct rdatainfo {
+ * unsigned int rdi_length; // length of data
+ * unsigned char *rdi_data; // record data
+ * };
+ *
+ * struct rrsetinfo {
+ * unsigned int rri_flags; // RRSET_VALIDATED...
+ * unsigned int rri_rdclass; // class number
+ * unsigned int rri_rdtype; // RR type number
+ * unsigned int rri_ttl; // time to live
+ * unsigned int rri_nrdatas; // size of rdatas array
+ * unsigned int rri_nsigs; // size of sigs array
+ * char *rri_name; // canonical name
+ * struct rdatainfo *rri_rdatas; // individual records
+ * struct rdatainfo *rri_sigs; // individual signatures
+ * };
+ * \endcode
+ *
+ * \section getrrset_return Return Values
+ *
+ * lwres_getrrsetbyname() returns zero on success, and one of the
+ * following error codes if an error occurred:
+ *
+ * \li #ERRSET_NONAME: the name does not exist
+ *
+ * \li #ERRSET_NODATA:
+ * the name exists, but does not have data of the desired type
+ *
+ * \li #ERRSET_NOMEMORY:
+ * memory could not be allocated
+ *
+ * \li #ERRSET_INVAL:
+ * a parameter is invalid
+ *
+ * \li #ERRSET_FAIL:
+ * other failure
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/netdb.h> /* XXX #include <netdb.h> */
+
+#include "assert_p.h"
+
+/*!
+ * Structure to map results
+ */
+static unsigned int
+lwresult_to_result(lwres_result_t lwresult) {
+ switch (lwresult) {
+ case LWRES_R_SUCCESS: return (ERRSET_SUCCESS);
+ case LWRES_R_NOMEMORY: return (ERRSET_NOMEMORY);
+ case LWRES_R_NOTFOUND: return (ERRSET_NONAME);
+ case LWRES_R_TYPENOTFOUND: return (ERRSET_NODATA);
+ default: return (ERRSET_FAIL);
+ }
+}
+
+/*@{*/
+/*!
+ * malloc / calloc functions that guarantee to only
+ * return NULL if there is an error, like they used
+ * to before the ANSI C committee broke them.
+ */
+
+static void *
+sane_malloc(size_t size) {
+ if (size == 0U)
+ size = 1;
+ return (malloc(size));
+}
+
+static void *
+sane_calloc(size_t number, size_t size) {
+ size_t len = number * size;
+ void *mem = sane_malloc(len);
+ if (mem != NULL)
+ memset(mem, 0, len);
+ return (mem);
+}
+/*@}*/
+
+/*% Returns a set of resource records associated with a hostname, class, and type. hostname is a pointer a to null-terminated string. */
+int
+lwres_getrrsetbyname(const char *hostname, unsigned int rdclass,
+ unsigned int rdtype, unsigned int flags,
+ struct rrsetinfo **res)
+{
+ lwres_context_t *lwrctx = NULL;
+ lwres_result_t lwresult;
+ lwres_grbnresponse_t *response = NULL;
+ struct rrsetinfo *rrset = NULL;
+ unsigned int i;
+ unsigned int lwflags;
+ unsigned int result;
+
+ if (rdclass > 0xffff || rdtype > 0xffff) {
+ result = ERRSET_INVAL;
+ goto fail;
+ }
+
+ /*
+ * Don't allow queries of class or type ANY
+ */
+ if (rdclass == 0xff || rdtype == 0xff) {
+ result = ERRSET_INVAL;
+ goto fail;
+ }
+
+ lwresult = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (lwresult != LWRES_R_SUCCESS) {
+ result = lwresult_to_result(lwresult);
+ goto fail;
+ }
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+
+ /*
+ * If any input flags were defined, lwflags would be set here
+ * based on them
+ */
+ UNUSED(flags);
+ lwflags = 0;
+
+ lwresult = lwres_getrdatabyname(lwrctx, hostname,
+ (lwres_uint16_t)rdclass,
+ (lwres_uint16_t)rdtype,
+ lwflags, &response);
+ if (lwresult != LWRES_R_SUCCESS) {
+ result = lwresult_to_result(lwresult);
+ goto fail;
+ }
+
+ rrset = sane_malloc(sizeof(struct rrsetinfo));
+ if (rrset == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ rrset->rri_name = NULL;
+ rrset->rri_rdclass = response->rdclass;
+ rrset->rri_rdtype = response->rdtype;
+ rrset->rri_ttl = response->ttl;
+ rrset->rri_flags = 0;
+ rrset->rri_nrdatas = 0;
+ rrset->rri_rdatas = NULL;
+ rrset->rri_nsigs = 0;
+ rrset->rri_sigs = NULL;
+
+ rrset->rri_name = sane_malloc(response->realnamelen + 1);
+ if (rrset->rri_name == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ strncpy(rrset->rri_name, response->realname, response->realnamelen);
+ rrset->rri_name[response->realnamelen] = 0;
+
+ if ((response->flags & LWRDATA_VALIDATED) != 0)
+ rrset->rri_flags |= RRSET_VALIDATED;
+
+ rrset->rri_nrdatas = response->nrdatas;
+ rrset->rri_rdatas = sane_calloc(rrset->rri_nrdatas,
+ sizeof(struct rdatainfo));
+ if (rrset->rri_rdatas == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ for (i = 0; i < rrset->rri_nrdatas; i++) {
+ rrset->rri_rdatas[i].rdi_length = response->rdatalen[i];
+ rrset->rri_rdatas[i].rdi_data =
+ sane_malloc(rrset->rri_rdatas[i].rdi_length);
+ if (rrset->rri_rdatas[i].rdi_data == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ memcpy(rrset->rri_rdatas[i].rdi_data, response->rdatas[i],
+ rrset->rri_rdatas[i].rdi_length);
+ }
+ rrset->rri_nsigs = response->nsigs;
+ rrset->rri_sigs = sane_calloc(rrset->rri_nsigs,
+ sizeof(struct rdatainfo));
+ if (rrset->rri_sigs == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ for (i = 0; i < rrset->rri_nsigs; i++) {
+ rrset->rri_sigs[i].rdi_length = response->siglen[i];
+ rrset->rri_sigs[i].rdi_data =
+ sane_malloc(rrset->rri_sigs[i].rdi_length);
+ if (rrset->rri_sigs[i].rdi_data == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ memcpy(rrset->rri_sigs[i].rdi_data, response->sigs[i],
+ rrset->rri_sigs[i].rdi_length);
+ }
+
+ lwres_grbnresponse_free(lwrctx, &response);
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ *res = rrset;
+ return (ERRSET_SUCCESS);
+ fail:
+ if (rrset != NULL)
+ lwres_freerrset(rrset);
+ if (response != NULL)
+ lwres_grbnresponse_free(lwrctx, &response);
+ if (lwrctx != NULL) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ }
+ return (result);
+}
+
+/*% Releases memory allocated for the dynamically allocated structures created by a successful call to lwres_getrrsetbyname(). */
+void
+lwres_freerrset(struct rrsetinfo *rrset) {
+ unsigned int i;
+ for (i = 0; i < rrset->rri_nrdatas; i++) {
+ if (rrset->rri_rdatas[i].rdi_data == NULL)
+ break;
+ free(rrset->rri_rdatas[i].rdi_data);
+ }
+ free(rrset->rri_rdatas);
+ for (i = 0; i < rrset->rri_nsigs; i++) {
+ if (rrset->rri_sigs[i].rdi_data == NULL)
+ break;
+ free(rrset->rri_sigs[i].rdi_data);
+ }
+ free(rrset->rri_sigs);
+ free(rrset->rri_name);
+ free(rrset);
+}
diff --git a/lib/lwres/herror.c b/lib/lwres/herror.c
new file mode 100644
index 0000000..42b6c71
--- /dev/null
+++ b/lib/lwres/herror.c
@@ -0,0 +1,122 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions 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.
+ */
+
+/*
+ * 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.
+ */
+
+/*! \file herror.c
+ lwres_herror() prints the string s on stderr followed by the string
+ generated by lwres_hstrerror() for the error code stored in the global
+ variable lwres_h_errno.
+
+ lwres_hstrerror() returns an appropriate string for the error code
+ gievn by err. The values of the error codes and messages are as
+ follows:
+
+\li #NETDB_SUCCESS: Resolver Error 0 (no error)
+
+\li #HOST_NOT_FOUND: Unknown host
+
+\li #TRY_AGAIN: Host name lookup failure
+
+\li #NO_RECOVERY: Unknown server error
+
+\li #NO_DATA: No address associated with name
+
+ */
+
+#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.13.18.2 2005/04/29 00:17:18 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <lwres/netdb.h>
+#include <lwres/platform.h>
+
+LIBLWRES_EXTERNAL_DATA int lwres_h_errno;
+
+/*!
+ * these have never been declared in any header file so make them static
+ */
+
+static const char *h_errlist[] = {
+ "Resolver Error 0 (no 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 */
+};
+
+static int h_nerr = { sizeof(h_errlist) / sizeof(h_errlist[0]) };
+
+
+/*!
+ * herror --
+ * print the error indicated by the h_errno value.
+ */
+void
+lwres_herror(const char *s) {
+ fprintf(stderr, "%s: %s\n", s, lwres_hstrerror(lwres_h_errno));
+}
+
+/*!
+ * hstrerror --
+ * return the string associated with a given "host" errno value.
+ */
+const char *
+lwres_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/lib/lwres/include/Makefile.in b/lib/lwres/include/Makefile.in
new file mode 100644
index 0000000..7501060
--- /dev/null
+++ b/lib/lwres/include/Makefile.in
@@ -0,0 +1,25 @@
+# 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: Makefile.in,v 1.6 2004/03/05 05:12:49 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = lwres
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/lwres/include/lwres/Makefile.in b/lib/lwres/include/lwres/Makefile.in
new file mode 100644
index 0000000..98b8f48
--- /dev/null
+++ b/lib/lwres/include/lwres/Makefile.in
@@ -0,0 +1,46 @@
+# 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: Makefile.in,v 1.21 2004/03/05 05:12:52 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+#
+# Only list headers that are to be installed and are not
+# machine generated. The latter are handled specially in the
+# install target below.
+#
+HEADERS = context.h lwbuffer.h lwpacket.h lwres.h result.h \
+ int.h lang.h list.h ipv6.h version.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/lwres
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/lwres ; \
+ done
+ ${INSTALL_DATA} netdb.h ${DESTDIR}${includedir}/lwres
+ ${INSTALL_DATA} platform.h ${DESTDIR}${includedir}/lwres
+
+distclean::
+ rm -f netdb.h platform.h
diff --git a/lib/lwres/include/lwres/context.h b/lib/lwres/include/lwres/context.h
new file mode 100644
index 0000000..bd24446
--- /dev/null
+++ b/lib/lwres/include/lwres/context.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2004, 2005 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: context.h,v 1.15.18.2 2005/04/29 00:17:21 marka Exp $ */
+
+#ifndef LWRES_CONTEXT_H
+#define LWRES_CONTEXT_H 1
+
+/*! \file */
+
+#include <stddef.h>
+
+#include <lwres/lang.h>
+#include <lwres/int.h>
+#include <lwres/result.h>
+
+/*!
+ * Used to set various options such as timeout, authentication, etc
+ */
+typedef struct lwres_context lwres_context_t;
+
+LWRES_LANG_BEGINDECLS
+
+typedef void *(*lwres_malloc_t)(void *arg, size_t length);
+typedef void (*lwres_free_t)(void *arg, void *mem, size_t length);
+
+/*
+ * XXXMLG
+ *
+ * Make the server reload /etc/resolv.conf periodically.
+ *
+ * Make the server do sortlist/searchlist.
+ *
+ * Client side can disable the search/sortlist processing.
+ *
+ * Use an array of addresses/masks and searchlist for client-side, and
+ * if added to the client disable the processing on the server.
+ *
+ * Share /etc/resolv.conf data between contexts.
+ */
+
+/*!
+ * _SERVERMODE
+ * Don't allocate and connect a socket to the server, since the
+ * caller _is_ a server.
+ */
+#define LWRES_CONTEXT_SERVERMODE 0x00000001U
+
+lwres_result_t
+lwres_context_create(lwres_context_t **contextp, void *arg,
+ lwres_malloc_t malloc_function,
+ lwres_free_t free_function,
+ unsigned int flags);
+/**<
+ * Allocate a lwres context. This is used in all lwres calls.
+ *
+ * Memory management can be replaced here by passing in two functions.
+ * If one is non-NULL, they must both be non-NULL. "arg" is passed to
+ * these functions.
+ *
+ * Contexts are not thread safe. Document at the top of the file.
+ * XXXMLG
+ *
+ * If they are NULL, the standard malloc() and free() will be used.
+ *
+ *\pre contextp != NULL && contextp == NULL.
+ *
+ *\return Returns 0 on success, non-zero on failure.
+ */
+
+void
+lwres_context_destroy(lwres_context_t **contextp);
+/**<
+ * Frees all memory associated with a lwres context.
+ *
+ *\pre contextp != NULL && contextp == NULL.
+ */
+
+lwres_uint32_t
+lwres_context_nextserial(lwres_context_t *ctx);
+/**<
+ * XXXMLG Document
+ */
+
+void
+lwres_context_initserial(lwres_context_t *ctx, lwres_uint32_t serial);
+
+void
+lwres_context_freemem(lwres_context_t *ctx, void *mem, size_t len);
+
+void *
+lwres_context_allocmem(lwres_context_t *ctx, size_t len);
+
+int
+lwres_context_getsocket(lwres_context_t *ctx);
+
+lwres_result_t
+lwres_context_send(lwres_context_t *ctx,
+ void *sendbase, int sendlen);
+
+lwres_result_t
+lwres_context_recv(lwres_context_t *ctx,
+ void *recvbase, int recvlen,
+ int *recvd_len);
+
+lwres_result_t
+lwres_context_sendrecv(lwres_context_t *ctx,
+ void *sendbase, int sendlen,
+ void *recvbase, int recvlen,
+ int *recvd_len);
+
+LWRES_LANG_ENDDECLS
+
+#endif /* LWRES_CONTEXT_H */
+
diff --git a/lib/lwres/include/lwres/int.h b/lib/lwres/include/lwres/int.h
new file mode 100644
index 0000000..337316e
--- /dev/null
+++ b/lib/lwres/include/lwres/int.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2004, 2005 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: int.h,v 1.8.18.2 2005/04/29 00:17:21 marka Exp $ */
+
+#ifndef LWRES_INT_H
+#define LWRES_INT_H 1
+
+/*! \file */
+
+typedef char lwres_int8_t;
+typedef unsigned char lwres_uint8_t;
+typedef short lwres_int16_t;
+typedef unsigned short lwres_uint16_t;
+typedef int lwres_int32_t;
+typedef unsigned int lwres_uint32_t;
+typedef long long lwres_int64_t;
+typedef unsigned long long lwres_uint64_t;
+
+#endif /* LWRES_INT_H */
diff --git a/lib/lwres/include/lwres/ipv6.h b/lib/lwres/include/lwres/ipv6.h
new file mode 100644
index 0000000..06dab59
--- /dev/null
+++ b/lib/lwres/include/lwres/ipv6.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2004, 2005 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: ipv6.h,v 1.10.18.2 2005/04/29 00:17:21 marka Exp $ */
+
+#ifndef LWRES_IPV6_H
+#define LWRES_IPV6_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file ipv6.h
+ * IPv6 definitions for systems which do not support IPv6.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <lwres/int.h>
+#include <lwres/platform.h>
+
+/***
+ *** Types.
+ ***/
+
+/*% in6_addr structure */
+struct in6_addr {
+ union {
+ lwres_uint8_t _S6_u8[16];
+ lwres_uint16_t _S6_u16[8];
+ lwres_uint32_t _S6_u32[4];
+ } _S6_un;
+};
+/*@{*/
+/*% IP v6 types */
+#define s6_addr _S6_un._S6_u8
+#define s6_addr8 _S6_un._S6_u8
+#define s6_addr16 _S6_un._S6_u16
+#define s6_addr32 _S6_un._S6_u32
+/*@}*/
+
+#define IN6ADDR_ANY_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}}
+#define IN6ADDR_LOOPBACK_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}}
+
+LIBLWRES_EXTERNAL_DATA extern const struct in6_addr in6addr_any;
+LIBLWRES_EXTERNAL_DATA extern const struct in6_addr in6addr_loopback;
+
+/*% used in getaddrinfo.c and getnameinfo.c */
+struct sockaddr_in6 {
+#ifdef LWRES_PLATFORM_HAVESALEN
+ lwres_uint8_t sin6_len;
+ lwres_uint8_t sin6_family;
+#else
+ lwres_uint16_t sin6_family;
+#endif
+ lwres_uint16_t sin6_port;
+ lwres_uint32_t sin6_flowinfo;
+ struct in6_addr sin6_addr;
+ lwres_uint32_t sin6_scope_id;
+};
+
+#ifdef LWRES_PLATFORM_HAVESALEN
+#define SIN6_LEN 1
+#endif
+
+/*% in6_pktinfo structure */
+struct in6_pktinfo {
+ struct in6_addr ipi6_addr; /*%< src/dst IPv6 address */
+ unsigned int ipi6_ifindex; /*%< send/recv interface index */
+};
+
+/*!
+ * Unspecified IPv6 address
+ */
+#define IN6_IS_ADDR_UNSPECIFIED(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] == 0))
+
+/*
+ * Loopback
+ */
+#define IN6_IS_ADDR_LOOPBACK(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] == htonl(1)))
+
+/*
+ * IPv4 compatible
+ */
+#define IN6_IS_ADDR_V4COMPAT(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] != 0) && \
+ ((a)->s6_addr32[3] != htonl(1)))
+
+/*
+ * Mapped
+ */
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == htonl(0x0000ffff)))
+
+#endif /* LWRES_IPV6_H */
diff --git a/lib/lwres/include/lwres/lang.h b/lib/lwres/include/lwres/lang.h
new file mode 100644
index 0000000..a38f19d
--- /dev/null
+++ b/lib/lwres/include/lwres/lang.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2004, 2005 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: lang.h,v 1.7.18.2 2005/04/29 00:17:21 marka Exp $ */
+
+#ifndef LWRES_LANG_H
+#define LWRES_LANG_H 1
+
+/*! \file */
+
+#ifdef __cplusplus
+#define LWRES_LANG_BEGINDECLS extern "C" {
+#define LWRES_LANG_ENDDECLS }
+#else
+#define LWRES_LANG_BEGINDECLS
+#define LWRES_LANG_ENDDECLS
+#endif
+
+#endif /* LWRES_LANG_H */
diff --git a/lib/lwres/include/lwres/list.h b/lib/lwres/include/lwres/list.h
new file mode 100644
index 0000000..c22c596
--- /dev/null
+++ b/lib/lwres/include/lwres/list.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-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: list.h,v 1.8.18.2 2005/04/29 00:17:22 marka Exp $ */
+
+#ifndef LWRES_LIST_H
+#define LWRES_LIST_H 1
+
+/*! \file */
+
+#define LWRES_LIST(type) struct { type *head, *tail; }
+#define LWRES_LIST_INIT(list) \
+ do { (list).head = NULL; (list).tail = NULL; } while (0)
+
+#define LWRES_LINK(type) struct { type *prev, *next; }
+#define LWRES_LINK_INIT(elt, link) \
+ do { \
+ (elt)->link.prev = (void *)(-1); \
+ (elt)->link.next = (void *)(-1); \
+ } while (0)
+#define LWRES_LINK_LINKED(elt, link) \
+ ((void *)((elt)->link.prev) != (void *)(-1))
+
+#define LWRES_LIST_HEAD(list) ((list).head)
+#define LWRES_LIST_TAIL(list) ((list).tail)
+#define LWRES_LIST_EMPTY(list) LWRES_TF((list).head == NULL)
+
+#define LWRES_LIST_PREPEND(list, elt, link) \
+ do { \
+ 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 LWRES_LIST_APPEND(list, elt, link) \
+ do { \
+ 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 LWRES_LIST_UNLINK(list, elt, link) \
+ do { \
+ 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; \
+ (elt)->link.prev = (void *)(-1); \
+ (elt)->link.next = (void *)(-1); \
+ } while (0)
+
+#define LWRES_LIST_PREV(elt, link) ((elt)->link.prev)
+#define LWRES_LIST_NEXT(elt, link) ((elt)->link.next)
+
+#define LWRES_LIST_INSERTBEFORE(list, before, elt, link) \
+ do { \
+ if ((before)->link.prev == NULL) \
+ LWRES_LIST_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 LWRES_LIST_INSERTAFTER(list, after, elt, link) \
+ do { \
+ if ((after)->link.next == NULL) \
+ LWRES_LIST_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 LWRES_LIST_APPENDLIST(list1, list2, link) \
+ do { \
+ if (LWRES_LIST_EMPTY(list1)) \
+ (list1) = (list2); \
+ else if (!LWRES_LIST_EMPTY(list2)) { \
+ (list1).tail->link.next = (list2).head; \
+ (list2).head->link.prev = (list1).tail; \
+ (list1).tail = (list2).tail; \
+ } \
+ (list2).head = NULL; \
+ (list2).tail = NULL; \
+ } while (0)
+
+#define LWRES_LIST_ENQUEUE(list, elt, link) LWRES_LIST_APPEND(list, elt, link)
+#define LWRES_LIST_DEQUEUE(list, elt, link) LWRES_LIST_UNLINK(list, elt, link)
+
+#endif /* LWRES_LIST_H */
diff --git a/lib/lwres/include/lwres/lwbuffer.h b/lib/lwres/include/lwres/lwbuffer.h
new file mode 100644
index 0000000..51b1aad
--- /dev/null
+++ b/lib/lwres/include/lwres/lwbuffer.h
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2004, 2005 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: lwbuffer.h,v 1.16.18.2 2005/04/29 00:17:22 marka Exp $ */
+
+
+/*! \file lwbuffer.h
+ *
+ * A buffer is a region of memory, together with a set of related subregions.
+ * Buffers are used for parsing and I/O operations.
+ *
+ * The 'used region' and the 'available' region are disjoint, and their
+ * union is the buffer's region. The used region extends from the beginning
+ * of the buffer region to the last used byte. The available region
+ * extends from one byte greater than the last used byte to the end of the
+ * buffer's region. The size of the used region can be changed using various
+ * buffer commands. Initially, the used region is empty.
+ *
+ * The used region is further subdivided into two disjoint regions: the
+ * 'consumed region' and the 'remaining region'. The union of these two
+ * regions is the used region. The consumed region extends from the beginning
+ * of the used region to the byte before the 'current' offset (if any). The
+ * 'remaining' region the current pointer to the end of the used
+ * region. The size of the consumed region can be changed using various
+ * buffer commands. Initially, the consumed region is empty.
+ *
+ * The 'active region' is an (optional) subregion of the remaining region.
+ * It extends from the current offset to an offset in the remaining region
+ * that is selected with lwres_buffer_setactive(). Initially, the active
+ * region is empty. If the current offset advances beyond the chosen offset,
+ * the active region will also be empty.
+ *
+ * \verbatim
+ * /----- used region -----\/-- available --\
+ * +----------------------------------------+
+ * | consumed | remaining | |
+ * +----------------------------------------+
+ * a b c d e
+ *
+ * a == base of buffer.
+ * b == current pointer. Can be anywhere between a and d.
+ * c == active pointer. Meaningful between b and d.
+ * d == used pointer.
+ * e == length of buffer.
+ *
+ * a-e == entire (length) of buffer.
+ * a-d == used region.
+ * a-b == consumed region.
+ * b-d == remaining region.
+ * b-c == optional active region.
+ * \endverbatim
+ *
+ * The following invariants are maintained by all routines:
+ *
+ *\verbatim
+ * length > 0
+ *
+ * base is a valid pointer to length bytes of memory
+ *
+ * 0 <= used <= length
+ *
+ * 0 <= current <= used
+ *
+ * 0 <= active <= used
+ * (although active < current implies empty active region)
+ *\endverbatim
+ *
+ * \li MP:
+ * Buffers have no synchronization. Clients must ensure exclusive
+ * access.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * Memory: 1 pointer + 6 unsigned integers per buffer.
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+#ifndef LWRES_LWBUFFER_H
+#define LWRES_LWBUFFER_H 1
+
+/***
+ *** Imports
+ ***/
+
+#include <lwres/lang.h>
+#include <lwres/int.h>
+
+LWRES_LANG_BEGINDECLS
+
+/***
+ *** Magic numbers
+ ***/
+#define LWRES_BUFFER_MAGIC 0x4275663fU /* Buf?. */
+
+#define LWRES_BUFFER_VALID(b) ((b) != NULL && \
+ (b)->magic == LWRES_BUFFER_MAGIC)
+
+/*!
+ * The following macros MUST be used only on valid buffers. It is the
+ * caller's responsibility to ensure this by using the LWRES_BUFFER_VALID
+ * check above, or by calling another lwres_buffer_*() function (rather than
+ * another macro.)
+ */
+
+/*!
+ * Get the length of the used region of buffer "b"
+ */
+#define LWRES_BUFFER_USEDCOUNT(b) ((b)->used)
+
+/*!
+ * Get the length of the available region of buffer "b"
+ */
+#define LWRES_BUFFER_AVAILABLECOUNT(b) ((b)->length - (b)->used)
+
+#define LWRES_BUFFER_REMAINING(b) ((b)->used - (b)->current)
+
+/*!
+ * Note that the buffer structure is public. This is principally so buffer
+ * operations can be implemented using macros. Applications are strongly
+ * discouraged from directly manipulating the structure.
+ */
+
+typedef struct lwres_buffer lwres_buffer_t;
+/*!
+ * Buffer data structure
+ */
+struct lwres_buffer {
+ unsigned int magic;
+ unsigned char *base;
+ /* The following integers are byte offsets from 'base'. */
+ unsigned int length;
+ unsigned int used;
+ unsigned int current;
+ unsigned int active;
+};
+
+/***
+ *** Functions
+ ***/
+
+void
+lwres_buffer_init(lwres_buffer_t *b, void *base, unsigned int length);
+/**<
+ * Make 'b' refer to the 'length'-byte region starting at base.
+ *
+ * Requires:
+ *
+ * 'length' > 0
+ *
+ * 'base' is a pointer to a sequence of 'length' bytes.
+ *
+ */
+
+void
+lwres_buffer_invalidate(lwres_buffer_t *b);
+/**<
+ * Make 'b' an invalid buffer.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * Ensures:
+ * If assertion checking is enabled, future attempts to use 'b' without
+ * calling lwres_buffer_init() on it will cause an assertion failure.
+ */
+
+void
+lwres_buffer_add(lwres_buffer_t *b, unsigned int n);
+/**<
+ * Increase the 'used' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * used + n <= length
+ *
+ */
+
+void
+lwres_buffer_subtract(lwres_buffer_t *b, unsigned int n);
+/**<
+ * Decrease the 'used' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * used >= n
+ *
+ */
+
+void
+lwres_buffer_clear(lwres_buffer_t *b);
+/**<
+ * Make the used region empty.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ * used = 0
+ *
+ */
+
+
+void
+lwres_buffer_first(lwres_buffer_t *b);
+/**<
+ * Make the consumed region empty.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ * current == 0
+ *
+ */
+
+void
+lwres_buffer_forward(lwres_buffer_t *b, unsigned int n);
+/**<
+ * Increase the 'consumed' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * current + n <= used
+ *
+ */
+
+void
+lwres_buffer_back(lwres_buffer_t *b, unsigned int n);
+/**<
+ * Decrease the 'consumed' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * n <= current
+ *
+ */
+
+lwres_uint8_t
+lwres_buffer_getuint8(lwres_buffer_t *b);
+/**<
+ * Read an unsigned 8-bit integer from 'b' and return it.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer.
+ *
+ * The length of the available region of 'b' is at least 1.
+ *
+ * Ensures:
+ *
+ * The current pointer in 'b' is advanced by 1.
+ *
+ * Returns:
+ *
+ * A 8-bit unsigned integer.
+ */
+
+void
+lwres_buffer_putuint8(lwres_buffer_t *b, lwres_uint8_t val);
+/**<
+ * Store an unsigned 8-bit integer from 'val' into 'b'.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * The length of the unused region of 'b' is at least 1.
+ *
+ * Ensures:
+ * The used pointer in 'b' is advanced by 1.
+ */
+
+lwres_uint16_t
+lwres_buffer_getuint16(lwres_buffer_t *b);
+/**<
+ * Read an unsigned 16-bit integer in network byte order from 'b', convert
+ * it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer.
+ *
+ * The length of the available region of 'b' is at least 2.
+ *
+ * Ensures:
+ *
+ * The current pointer in 'b' is advanced by 2.
+ *
+ * Returns:
+ *
+ * A 16-bit unsigned integer.
+ */
+
+void
+lwres_buffer_putuint16(lwres_buffer_t *b, lwres_uint16_t val);
+/**<
+ * Store an unsigned 16-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * The length of the unused region of 'b' is at least 2.
+ *
+ * Ensures:
+ * The used pointer in 'b' is advanced by 2.
+ */
+
+lwres_uint32_t
+lwres_buffer_getuint32(lwres_buffer_t *b);
+/**<
+ * Read an unsigned 32-bit integer in network byte order from 'b', convert
+ * it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer.
+ *
+ * The length of the available region of 'b' is at least 2.
+ *
+ * Ensures:
+ *
+ * The current pointer in 'b' is advanced by 2.
+ *
+ * Returns:
+ *
+ * A 32-bit unsigned integer.
+ */
+
+void
+lwres_buffer_putuint32(lwres_buffer_t *b, lwres_uint32_t val);
+/**<
+ * Store an unsigned 32-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * The length of the unused region of 'b' is at least 4.
+ *
+ * Ensures:
+ * The used pointer in 'b' is advanced by 4.
+ */
+
+void
+lwres_buffer_putmem(lwres_buffer_t *b, const unsigned char *base,
+ unsigned int length);
+/**<
+ * Copy 'length' bytes of memory at 'base' into 'b'.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * 'base' points to 'length' bytes of valid memory.
+ *
+ */
+
+void
+lwres_buffer_getmem(lwres_buffer_t *b, unsigned char *base,
+ unsigned int length);
+/**<
+ * Copy 'length' bytes of memory from 'b' into 'base'.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * 'base' points to at least 'length' bytes of valid memory.
+ *
+ * 'b' have at least 'length' bytes remaining.
+ */
+
+LWRES_LANG_ENDDECLS
+
+#endif /* LWRES_LWBUFFER_H */
diff --git a/lib/lwres/include/lwres/lwpacket.h b/lib/lwres/include/lwres/lwpacket.h
new file mode 100644
index 0000000..c37353d
--- /dev/null
+++ b/lib/lwres/include/lwres/lwpacket.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2004, 2005 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: lwpacket.h,v 1.18.18.2 2005/04/29 00:17:22 marka Exp $ */
+
+#ifndef LWRES_LWPACKET_H
+#define LWRES_LWPACKET_H 1
+
+#include <lwres/lang.h>
+#include <lwres/lwbuffer.h>
+#include <lwres/result.h>
+
+/*% lwres_lwpacket_t */
+typedef struct lwres_lwpacket lwres_lwpacket_t;
+
+/*% lwres_lwpacket structure */
+struct lwres_lwpacket {
+ /*! The overall packet length, including the
+ * entire packet header.
+ * This field is filled in by the
+ * \link lwres_gabn.c lwres_gabn_*()\endlink
+ * and \link lwres_gnba.c lwres_gnba_*()\endlink calls.
+ */
+ lwres_uint32_t length;
+ /*! Specifies the header format. Currently,
+ * there is only one format, #LWRES_LWPACKETVERSION_0.
+ * This field is filled in by the
+ * \link lwres_gabn.c lwres_gabn_*()\endlink
+ * and \link lwres_gnba.c lwres_gnba_*()\endlink calls.
+ */
+ lwres_uint16_t version;
+ /*! Specifies library-defined flags for this packet, such as
+ * whether the packet is a request or a reply. None of
+ * these are definable by the caller, but library-defined values
+ * can be set by the caller. For example, one bit in this field
+ * indicates if the packet is a request or a response.
+ * This field is filled in by
+ * the application wits the exception of the
+ * #LWRES_LWPACKETFLAG_RESPONSE bit, which is set by the library
+ * in the
+ * \link lwres_gabn.c lwres_gabn_*()\endlink
+ * and \link lwres_gnba.c lwres_gnba_*()\endlink calls.
+ */
+ lwres_uint16_t pktflags;
+ /*! Set by the requestor and is returned in all replies.
+ * If two packets from the same source have the same serial
+ * number and are from the same source, they are assumed to
+ * be duplicates and the latter ones may be dropped.
+ * (The library does not do this by default on replies, but
+ * does so on requests.)
+ */
+ lwres_uint32_t serial;
+ /*! Opcodes between 0x04000000 and 0xffffffff
+ * are application defined. Opcodes between
+ * 0x00000000 and 0x03ffffff are
+ * reserved for library use.
+ * This field is filled in by the
+ * \link lwres_gabn.c lwres_gabn_*()\endlink
+ * and \link lwres_gnba.c lwres_gnba_*()\endlink calls.
+ */
+ lwres_uint32_t opcode;
+ /*! Only valid for results.
+ * Results between 0x04000000 and 0xffffffff are application
+ * defined.
+ * Results between 0x00000000 and 0x03ffffff are reserved for
+ * library use.
+ * (This is the same reserved range defined in <isc/resultclass.h>,
+ * so it
+ * would be trivial to map ISC_R_* result codes into packet result
+ * codes when appropriate.)
+ * This field is filled in by the
+ * \link lwres_gabn.c lwres_gabn_*()\endlink
+ * and \link lwres_gnba.c lwres_gnba_*()\endlink calls.
+ */
+ lwres_uint32_t result;
+ /*! Set to the maximum buffer size that the receiver can
+ * handle on requests, and the size of the buffer needed to
+ * satisfy a request
+ * when the buffer is too large for replies.
+ * This field is supplied by the application.
+ */
+ lwres_uint32_t recvlength;
+ /*! The packet level auth type used.
+ * Authtypes between 0x1000 and 0xffff are application defined.
+ * Authtypes
+ * between 0x0000 and 0x0fff are reserved for library use.
+ * This is currently
+ * unused and MUST be set to zero.
+ */
+ lwres_uint16_t authtype;
+ /*! The length of the authentication data.
+ * See the specific
+ * authtypes for more information on what is contained
+ * in this field. This is currently unused, and
+ * MUST be set to zero.
+ */
+ lwres_uint16_t authlength;
+};
+
+#define LWRES_LWPACKET_LENGTH (4 * 5 + 2 * 4) /*%< Overall length. */
+
+#define LWRES_LWPACKETFLAG_RESPONSE 0x0001U /*%< If set, pkt is a response. */
+
+
+#define LWRES_LWPACKETVERSION_0 0 /*%< Header format. */
+
+/*! \file lwpacket.h
+ *
+ *
+ * The remainder of the packet consists of two regions, one described by
+ * "authlen" and one of "length - authlen - sizeof(lwres_lwpacket_t)".
+ *
+ * That is:
+ *
+ * \code
+ * pkt header
+ * authlen bytes of auth information
+ * data bytes
+ * \endcode
+ *
+ * Currently defined opcodes:
+ *
+ *\li #LWRES_OPCODE_NOOP. Success is always returned, with the packet contents echoed.
+ *
+ *\li #LWRES_OPCODE_GETADDRSBYNAME. Return all known addresses for a given name.
+ * This may return NIS or /etc/hosts info as well as DNS
+ * information. Flags will be provided to indicate ip4/ip6
+ * addresses are desired.
+ *
+ *\li #LWRES_OPCODE_GETNAMEBYADDR. Return the hostname for the given address. Once
+ * again, it will return data from multiple sources.
+ */
+
+LWRES_LANG_BEGINDECLS
+
+/* XXXMLG document */
+lwres_result_t
+lwres_lwpacket_renderheader(lwres_buffer_t *b, lwres_lwpacket_t *pkt);
+
+lwres_result_t
+lwres_lwpacket_parseheader(lwres_buffer_t *b, lwres_lwpacket_t *pkt);
+
+LWRES_LANG_ENDDECLS
+
+#endif /* LWRES_LWPACKET_H */
diff --git a/lib/lwres/include/lwres/lwres.h b/lib/lwres/include/lwres/lwres.h
new file mode 100644
index 0000000..b245363
--- /dev/null
+++ b/lib/lwres/include/lwres/lwres.h
@@ -0,0 +1,579 @@
+/*
+ * Copyright (C) 2004, 2005 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: lwres.h,v 1.51.18.2 2005/04/29 00:17:22 marka Exp $ */
+
+#ifndef LWRES_LWRES_H
+#define LWRES_LWRES_H 1
+
+#include <stdio.h>
+
+#include <lwres/context.h>
+#include <lwres/lang.h>
+#include <lwres/list.h>
+#include <lwres/lwpacket.h>
+#include <lwres/platform.h>
+
+/*! \file */
+
+/*!
+ * Design notes:
+ *
+ * Each opcode has two structures and three functions which operate on each
+ * structure. For example, using the "no operation/ping" opcode as an
+ * example:
+ *
+ * <ul><li>lwres_nooprequest_t:
+ *
+ * lwres_nooprequest_render() takes a lwres_nooprequest_t and
+ * and renders it into wire format, storing the allocated
+ * buffer information in a passed-in buffer. When this buffer
+ * is no longer needed, it must be freed by
+ * lwres_context_freemem(). All other memory used by the
+ * caller must be freed manually, including the
+ * lwres_nooprequest_t passed in.<br /><br />
+ *
+ * lwres_nooprequest_parse() takes a wire format message and
+ * breaks it out into a lwres_nooprequest_t. The structure
+ * must be freed via lwres_nooprequest_free() when it is no longer
+ * needed.<br /><br />
+ *
+ * lwres_nooprequest_free() releases into the lwres_context_t
+ * any space allocated during parsing.</li>
+ *
+ * <li>lwres_noopresponse_t:
+ *
+ * The functions used are similar to the three used for
+ * requests, just with different names.</li></ul>
+ *
+ * Typically, the client will use request_render, response_parse, and
+ * response_free, while the daemon will use request_parse, response_render,
+ * and request_free.
+ *
+ * The basic flow of a typical client is:
+ *
+ * \li fill in a request_t, and call the render function.
+ *
+ * \li Transmit the buffer returned to the daemon.
+ *
+ * \li Wait for a response.
+ *
+ * \li When a response is received, parse it into a response_t.
+ *
+ * \li free the request buffer using lwres_context_freemem().
+ *
+ * \li free the response structure and its associated buffer using
+ * response_free().
+ */
+
+#define LWRES_UDP_PORT 921 /*%< UDP Port Number */
+#define LWRES_RECVLENGTH 16384 /*%< Maximum Packet Length */
+#define LWRES_ADDR_MAXLEN 16 /*%< changing this breaks ABI */
+#define LWRES_RESOLV_CONF "/etc/resolv.conf" /*%< Location of resolv.conf */
+
+/*% DNSSEC is not required (input). Only relevant to rrset queries. */
+#define LWRES_FLAG_TRUSTNOTREQUIRED 0x00000001U
+/*% The data was crypto-verified with DNSSEC (output). */
+#define LWRES_FLAG_SECUREDATA 0x00000002U
+
+/*% no-op */
+#define LWRES_OPCODE_NOOP 0x00000000U
+
+/*% lwres_nooprequest_t */
+typedef struct {
+ /* public */
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_nooprequest_t;
+
+/*% lwres_noopresponse_t */
+typedef struct {
+ /* public */
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_noopresponse_t;
+
+/*% get addresses by name */
+#define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
+
+/*% lwres_addr_t */
+typedef struct lwres_addr lwres_addr_t;
+
+/*% LWRES_LIST */
+typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
+
+/*% lwres_addr */
+struct lwres_addr {
+ lwres_uint32_t family;
+ lwres_uint16_t length;
+ unsigned char address[LWRES_ADDR_MAXLEN];
+ LWRES_LINK(lwres_addr_t) link;
+};
+
+/*% lwres_gabnrequest_t */
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_uint32_t addrtypes;
+ lwres_uint16_t namelen;
+ char *name;
+} lwres_gabnrequest_t;
+
+/*% lwres_gabnresponse_t */
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ /*! if base != NULL, it will be freed when this structure is freed. */
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+
+/*% get name by address */
+#define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
+
+/*% lwres_gnbarequest_t */
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_addr_t addr;
+} lwres_gnbarequest_t;
+
+/*% lwres_gnbaresponse_t */
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ /*! if base != NULL, it will be freed when this structure is freed. */
+ void *base;
+ size_t baselen;
+} lwres_gnbaresponse_t;
+
+/*% get rdata by name */
+#define LWRES_OPCODE_GETRDATABYNAME 0x00010003U
+
+/*% lwres_grbnrequest_t */
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_uint16_t rdclass;
+ lwres_uint16_t rdtype;
+ lwres_uint16_t namelen;
+ char *name;
+} lwres_grbnrequest_t;
+
+/*% lwres_grbnresponse_t */
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_uint16_t rdclass;
+ lwres_uint16_t rdtype;
+ lwres_uint32_t ttl;
+ lwres_uint16_t nrdatas;
+ lwres_uint16_t nsigs;
+ char *realname;
+ lwres_uint16_t realnamelen;
+ unsigned char **rdatas;
+ lwres_uint16_t *rdatalen;
+ unsigned char **sigs;
+ lwres_uint16_t *siglen;
+ /*% if base != NULL, it will be freed when this structure is freed. */
+ void *base;
+ size_t baselen;
+} lwres_grbnresponse_t;
+
+/*% Used by lwres_getrrsetbyname() */
+#define LWRDATA_VALIDATED 0x00000001
+
+/*!
+ * resolv.conf data
+ */
+
+#define LWRES_CONFMAXNAMESERVERS 3 /*%< max 3 "nameserver" entries */
+#define LWRES_CONFMAXLWSERVERS 1 /*%< max 1 "lwserver" entry */
+#define LWRES_CONFMAXSEARCH 8 /*%< max 8 domains in "search" entry */
+#define LWRES_CONFMAXLINELEN 256 /*%< max size of a line */
+#define LWRES_CONFMAXSORTLIST 10 /*%< max 10 */
+
+/*% lwres_conf_t */
+typedef struct {
+ lwres_context_t *lwctx;
+ lwres_addr_t nameservers[LWRES_CONFMAXNAMESERVERS];
+ lwres_uint8_t nsnext; /*%< index for next free slot */
+
+ lwres_addr_t lwservers[LWRES_CONFMAXLWSERVERS];
+ lwres_uint8_t lwnext; /*%< index for next free slot */
+
+ char *domainname;
+
+ char *search[LWRES_CONFMAXSEARCH];
+ lwres_uint8_t searchnxt; /*%< index for next free slot */
+
+ struct {
+ lwres_addr_t addr;
+ /*% mask has a non-zero 'family' and 'length' if set */
+ lwres_addr_t mask;
+ } sortlist[LWRES_CONFMAXSORTLIST];
+ lwres_uint8_t sortlistnxt;
+
+ lwres_uint8_t resdebug; /*%< non-zero if 'options debug' set */
+ lwres_uint8_t ndots; /*%< set to n in 'options ndots:n' */
+ lwres_uint8_t no_tld_query; /*%< non-zero if 'options no_tld_query' */
+} lwres_conf_t;
+
+#define LWRES_ADDRTYPE_V4 0x00000001U /*%< ipv4 */
+#define LWRES_ADDRTYPE_V6 0x00000002U /*%< ipv6 */
+
+#define LWRES_MAX_ALIASES 16 /*%< max # of aliases */
+#define LWRES_MAX_ADDRS 64 /*%< max # of addrs */
+
+LWRES_LANG_BEGINDECLS
+
+/*% This is in host byte order. */
+LIBLWRES_EXTERNAL_DATA extern lwres_uint16_t lwres_udp_port;
+
+LIBLWRES_EXTERNAL_DATA extern const char *lwres_resolv_conf;
+
+lwres_result_t
+lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_gabnresponse_render(lwres_context_t *ctx, lwres_gabnresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gabnrequest_t **structp);
+
+lwres_result_t
+lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt,
+ lwres_gabnresponse_t **structp);
+
+void
+lwres_gabnrequest_free(lwres_context_t *ctx, lwres_gabnrequest_t **structp);
+/**<
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_context_create().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+void
+lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp);
+/**<
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_context_create().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+
+lwres_result_t
+lwres_gnbarequest_render(lwres_context_t *ctx, lwres_gnbarequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_gnbaresponse_render(lwres_context_t *ctx, lwres_gnbaresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_gnbarequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gnbarequest_t **structp);
+
+lwres_result_t
+lwres_gnbaresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt,
+ lwres_gnbaresponse_t **structp);
+
+void
+lwres_gnbarequest_free(lwres_context_t *ctx, lwres_gnbarequest_t **structp);
+/**<
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_context_create().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+void
+lwres_gnbaresponse_free(lwres_context_t *ctx, lwres_gnbaresponse_t **structp);
+/**<
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_context_create().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+lwres_result_t
+lwres_grbnrequest_render(lwres_context_t *ctx, lwres_grbnrequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_grbnresponse_render(lwres_context_t *ctx, lwres_grbnresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_grbnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_grbnrequest_t **structp);
+
+lwres_result_t
+lwres_grbnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt,
+ lwres_grbnresponse_t **structp);
+
+void
+lwres_grbnrequest_free(lwres_context_t *ctx, lwres_grbnrequest_t **structp);
+/**<
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_context_create().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+void
+lwres_grbnresponse_free(lwres_context_t *ctx, lwres_grbnresponse_t **structp);
+/**<
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_context_create().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+lwres_result_t
+lwres_nooprequest_render(lwres_context_t *ctx, lwres_nooprequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+/**<
+ * Allocate space and render into wire format a noop request packet.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_context_create().
+ *
+ * b != NULL, and points to a lwres_buffer_t. The contents of the
+ * buffer structure will be initialized to contain the wire-format
+ * noop request packet.
+ *
+ * Caller needs to fill in parts of "pkt" before calling:
+ * serial, maxrecv, result.
+ *
+ * Returns:
+ *
+ * Returns 0 on success, non-zero on failure.
+ *
+ * On successful return, *b will contain data about the wire-format
+ * packet. It can be transmitted in any way, including lwres_sendblock().
+ */
+
+lwres_result_t
+lwres_noopresponse_render(lwres_context_t *ctx, lwres_noopresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_nooprequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_nooprequest_t **structp);
+/**<
+ * Parse a noop request. Note that to get here, the lwpacket must have
+ * already been parsed and removed by the caller, otherwise it would be
+ * pretty hard for it to know this is the right function to call.
+ *
+ * The function verifies bits of the header, but does not modify it.
+ */
+
+lwres_result_t
+lwres_noopresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt,
+ lwres_noopresponse_t **structp);
+
+void
+lwres_nooprequest_free(lwres_context_t *ctx, lwres_nooprequest_t **structp);
+
+void
+lwres_noopresponse_free(lwres_context_t *ctx, lwres_noopresponse_t **structp);
+
+/**<
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_context_create().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+lwres_result_t
+lwres_conf_parse(lwres_context_t *ctx, const char *filename);
+/**<
+ * parses a resolv.conf-format file and stores the results in the structure
+ * pointed to by *ctx.
+ *
+ * Requires:
+ * ctx != NULL
+ * filename != NULL && strlen(filename) > 0
+ *
+ * Returns:
+ * LWRES_R_SUCCESS on a successful parse.
+ * Anything else on error, although the structure may be partially filled
+ * in.
+ */
+
+lwres_result_t
+lwres_conf_print(lwres_context_t *ctx, FILE *fp);
+/**<
+ * Prints a resolv.conf-format of confdata output to fp.
+ *
+ * Requires:
+ * ctx != NULL
+ */
+
+void
+lwres_conf_init(lwres_context_t *ctx);
+/**<
+ * sets all internal fields to a default state. Used to initialize a new
+ * lwres_conf_t structure (not reset a used on).
+ *
+ * Requires:
+ * ctx != NULL
+ */
+
+void
+lwres_conf_clear(lwres_context_t *ctx);
+/**<
+ * frees all internally allocated memory in confdata. Uses the memory
+ * routines supplied by ctx.
+ *
+ * Requires:
+ * ctx != NULL
+ */
+
+lwres_conf_t *
+lwres_conf_get(lwres_context_t *ctx);
+/**<
+ * Be extremely cautions in modifying the contents of this structure; it
+ * needs an API to return the various bits of data, walk lists, etc.
+ *
+ * Requires:
+ * ctx != NULL
+ */
+
+/*
+ * Helper functions
+ */
+
+lwres_result_t
+lwres_data_parse(lwres_buffer_t *b, unsigned char **p, lwres_uint16_t *len);
+
+lwres_result_t
+lwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len);
+
+lwres_result_t
+lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr);
+
+lwres_result_t
+lwres_getaddrsbyname(lwres_context_t *ctx, const char *name,
+ lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp);
+
+lwres_result_t
+lwres_getnamebyaddr(lwres_context_t *ctx, lwres_uint32_t addrtype,
+ lwres_uint16_t addrlen, const unsigned char *addr,
+ lwres_gnbaresponse_t **structp);
+
+lwres_result_t
+lwres_getrdatabyname(lwres_context_t *ctx, const char *name,
+ lwres_uint16_t rdclass, lwres_uint16_t rdtype,
+ lwres_uint32_t flags, lwres_grbnresponse_t **structp);
+
+LWRES_LANG_ENDDECLS
+
+#endif /* LWRES_LWRES_H */
diff --git a/lib/lwres/include/lwres/netdb.h.in b/lib/lwres/include/lwres/netdb.h.in
new file mode 100644
index 0000000..eaef63b
--- /dev/null
+++ b/lib/lwres/include/lwres/netdb.h.in
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2004, 2005 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: netdb.h.in,v 1.35.18.2 2005/04/29 00:17:22 marka Exp $ */
+
+/*! \file */
+
+#ifndef LWRES_NETDB_H
+#define LWRES_NETDB_H 1
+
+#include <stddef.h> /* Required on FreeBSD (and others?) for size_t. */
+#include <netdb.h> /* Contractual provision. */
+
+#include <lwres/lang.h>
+
+/*
+ * Define if <netdb.h> does not declare struct addrinfo.
+ */
+@ISC_LWRES_NEEDADDRINFO@
+
+#ifdef ISC_LWRES_NEEDADDRINFO
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* Length of ai_addr */
+ char *ai_canonname; /* Canonical name for hostname */
+ struct sockaddr *ai_addr; /* Binary address */
+ struct addrinfo *ai_next; /* Next structure in linked list */
+};
+#endif
+
+/*
+ * Undefine all #defines we are interested in as <netdb.h> may or may not have
+ * defined them.
+ */
+
+/*
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (left in extern int h_errno).
+ */
+
+#undef NETDB_INTERNAL
+#undef NETDB_SUCCESS
+#undef HOST_NOT_FOUND
+#undef TRY_AGAIN
+#undef NO_RECOVERY
+#undef NO_DATA
+#undef NO_ADDRESS
+
+#define NETDB_INTERNAL -1 /* see errno */
+#define NETDB_SUCCESS 0 /* no problem */
+#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */
+#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */
+#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define NO_DATA 4 /* Valid name, no data record of requested type */
+#define NO_ADDRESS NO_DATA /* no address, look for MX record */
+
+/*
+ * Error return codes from getaddrinfo()
+ */
+
+#undef EAI_ADDRFAMILY
+#undef EAI_AGAIN
+#undef EAI_BADFLAGS
+#undef EAI_FAIL
+#undef EAI_FAMILY
+#undef EAI_MEMORY
+#undef EAI_NODATA
+#undef EAI_NONAME
+#undef EAI_SERVICE
+#undef EAI_SOCKTYPE
+#undef EAI_SYSTEM
+#undef EAI_BADHINTS
+#undef EAI_PROTOCOL
+#undef EAI_MAX
+
+#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */
+#define EAI_AGAIN 2 /* temporary failure in name resolution */
+#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
+#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
+#define EAI_FAMILY 5 /* ai_family not supported */
+#define EAI_MEMORY 6 /* memory allocation failure */
+#define EAI_NODATA 7 /* no address associated with hostname */
+#define EAI_NONAME 8 /* hostname nor servname provided, or not known */
+#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
+#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
+#define EAI_SYSTEM 11 /* system error returned in errno */
+#define EAI_BADHINTS 12
+#define EAI_PROTOCOL 13
+#define EAI_MAX 14
+
+/*
+ * Flag values for getaddrinfo()
+ */
+#undef AI_PASSIVE
+#undef AI_CANONNAME
+#undef AI_NUMERICHOST
+
+#define AI_PASSIVE 0x00000001
+#define AI_CANONNAME 0x00000002
+#define AI_NUMERICHOST 0x00000004
+
+/*
+ * Flag values for getipnodebyname()
+ */
+#undef AI_V4MAPPED
+#undef AI_ALL
+#undef AI_ADDRCONFIG
+#undef AI_DEFAULT
+
+#define AI_V4MAPPED 0x00000008
+#define AI_ALL 0x00000010
+#define AI_ADDRCONFIG 0x00000020
+#define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG)
+
+/*
+ * Constants for lwres_getnameinfo()
+ */
+#undef NI_MAXHOST
+#undef NI_MAXSERV
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+/*
+ * Flag values for lwres_getnameinfo()
+ */
+#undef NI_NOFQDN
+#undef NI_NUMERICHOST
+#undef NI_NAMEREQD
+#undef NI_NUMERICSERV
+#undef NI_DGRAM
+#undef NI_NUMERICSCOPE
+
+#define NI_NOFQDN 0x00000001
+#define NI_NUMERICHOST 0x00000002
+#define NI_NAMEREQD 0x00000004
+#define NI_NUMERICSERV 0x00000008
+#define NI_DGRAM 0x00000010
+#define NI_NUMERICSCOPE 0x00000020 /*2553bis-00*/
+
+/*
+ * Define if <netdb.h> does not declare struct rrsetinfo.
+ */
+@ISC_LWRES_NEEDRRSETINFO@
+
+#ifdef ISC_LWRES_NEEDRRSETINFO
+/*
+ * Structures for getrrsetbyname()
+ */
+struct rdatainfo {
+ unsigned int rdi_length;
+ unsigned char *rdi_data;
+};
+
+struct rrsetinfo {
+ unsigned int rri_flags;
+ int rri_rdclass;
+ int rri_rdtype;
+ unsigned int rri_ttl;
+ unsigned int rri_nrdatas;
+ unsigned int rri_nsigs;
+ char *rri_name;
+ struct rdatainfo *rri_rdatas;
+ struct rdatainfo *rri_sigs;
+};
+
+/*
+ * Flags for getrrsetbyname()
+ */
+#define RRSET_VALIDATED 0x00000001
+ /* Set was dnssec validated */
+
+/*
+ * Return codes for getrrsetbyname()
+ */
+#define ERRSET_SUCCESS 0
+#define ERRSET_NOMEMORY 1
+#define ERRSET_FAIL 2
+#define ERRSET_INVAL 3
+#define ERRSET_NONAME 4
+#define ERRSET_NODATA 5
+#endif
+
+/*
+ * Define to map into lwres_ namespace.
+ */
+
+#define LWRES_NAMESPACE
+
+#ifdef LWRES_NAMESPACE
+
+/*
+ * Use our versions not the ones from the C library.
+ */
+
+#ifdef getnameinfo
+#undef getnameinfo
+#endif
+#define getnameinfo lwres_getnameinfo
+
+#ifdef getaddrinfo
+#undef getaddrinfo
+#endif
+#define getaddrinfo lwres_getaddrinfo
+
+#ifdef freeaddrinfo
+#undef freeaddrinfo
+#endif
+#define freeaddrinfo lwres_freeaddrinfo
+
+#ifdef gai_strerror
+#undef gai_strerror
+#endif
+#define gai_strerror lwres_gai_strerror
+
+#ifdef herror
+#undef herror
+#endif
+#define herror lwres_herror
+
+#ifdef hstrerror
+#undef hstrerror
+#endif
+#define hstrerror lwres_hstrerror
+
+#ifdef getipnodebyname
+#undef getipnodebyname
+#endif
+#define getipnodebyname lwres_getipnodebyname
+
+#ifdef getipnodebyaddr
+#undef getipnodebyaddr
+#endif
+#define getipnodebyaddr lwres_getipnodebyaddr
+
+#ifdef freehostent
+#undef freehostent
+#endif
+#define freehostent lwres_freehostent
+
+#ifdef gethostbyname
+#undef gethostbyname
+#endif
+#define gethostbyname lwres_gethostbyname
+
+#ifdef gethostbyname2
+#undef gethostbyname2
+#endif
+#define gethostbyname2 lwres_gethostbyname2
+
+#ifdef gethostbyaddr
+#undef gethostbyaddr
+#endif
+#define gethostbyaddr lwres_gethostbyaddr
+
+#ifdef gethostent
+#undef gethostent
+#endif
+#define gethostent lwres_gethostent
+
+#ifdef sethostent
+#undef sethostent
+#endif
+#define sethostent lwres_sethostent
+
+#ifdef endhostent
+#undef endhostent
+#endif
+#define endhostent lwres_endhostent
+
+/* #define sethostfile lwres_sethostfile */
+
+#ifdef gethostbyname_r
+#undef gethostbyname_r
+#endif
+#define gethostbyname_r lwres_gethostbyname_r
+
+#ifdef gethostbyaddr_r
+#undef gethostbyaddr_r
+#endif
+#define gethostbyaddr_r lwres_gethostbyaddr_r
+
+#ifdef gethostent_r
+#undef gethostent_r
+#endif
+#define gethostent_r lwres_gethostent_r
+
+#ifdef sethostent_r
+#undef sethostent_r
+#endif
+#define sethostent_r lwres_sethostent_r
+
+#ifdef endhostent_r
+#undef endhostent_r
+#endif
+#define endhostent_r lwres_endhostent_r
+
+#ifdef getrrsetbyname
+#undef getrrsetbyname
+#endif
+#define getrrsetbyname lwres_getrrsetbyname
+
+#ifdef freerrset
+#undef freerrset
+#endif
+#define freerrset lwres_freerrset
+
+#ifdef notyet
+#define getservbyname lwres_getservbyname
+#define getservbyport lwres_getservbyport
+#define getservent lwres_getservent
+#define setservent lwres_setservent
+#define endservent lwres_endservent
+
+#define getservbyname_r lwres_getservbyname_r
+#define getservbyport_r lwres_getservbyport_r
+#define getservent_r lwres_getservent_r
+#define setservent_r lwres_setservent_r
+#define endservent_r lwres_endservent_r
+
+#define getprotobyname lwres_getprotobyname
+#define getprotobynumber lwres_getprotobynumber
+#define getprotoent lwres_getprotoent
+#define setprotoent lwres_setprotoent
+#define endprotoent lwres_endprotoent
+
+#define getprotobyname_r lwres_getprotobyname_r
+#define getprotobynumber_r lwres_getprotobynumber_r
+#define getprotoent_r lwres_getprotoent_r
+#define setprotoent_r lwres_setprotoent_r
+#define endprotoent_r lwres_endprotoent_r
+
+#ifdef getnetbyname
+#undef getnetbyname
+#endif
+#define getnetbyname lwres_getnetbyname
+
+#ifdef getnetbyaddr
+#undef getnetbyaddr
+#endif
+#define getnetbyaddr lwres_getnetbyaddr
+
+#ifdef getnetent
+#undef getnetent
+#endif
+#define getnetent lwres_getnetent
+
+#ifdef setnetent
+#undef setnetent
+#endif
+#define setnetent lwres_setnetent
+
+#ifdef endnetent
+#undef endnetent
+#endif
+#define endnetent lwres_endnetent
+
+
+#ifdef getnetbyname_r
+#undef getnetbyname_r
+#endif
+#define getnetbyname_r lwres_getnetbyname_r
+
+#ifdef getnetbyaddr_r
+#undef getnetbyaddr_r
+#endif
+#define getnetbyaddr_r lwres_getnetbyaddr_r
+
+#ifdef getnetent_r
+#undef getnetent_r
+#endif
+#define getnetent_r lwres_getnetent_r
+
+#ifdef setnetent_r
+#undef setnetent_r
+#endif
+#define setnetent_r lwres_setnetent_r
+
+#ifdef endnetent_r
+#undef endnetent_r
+#endif
+#define endnetent_r lwres_endnetent_r
+#endif /* notyet */
+
+#ifdef h_errno
+#undef h_errno
+#endif
+#define h_errno lwres_h_errno
+
+#endif /* LWRES_NAMESPACE */
+
+LWRES_LANG_BEGINDECLS
+
+extern int lwres_h_errno;
+
+int lwres_getaddrinfo(const char *, const char *,
+ const struct addrinfo *, struct addrinfo **);
+int lwres_getnameinfo(const struct sockaddr *, size_t, char *,
+ size_t, char *, size_t, int);
+void lwres_freeaddrinfo(struct addrinfo *);
+char *lwres_gai_strerror(int);
+
+struct hostent *lwres_gethostbyaddr(const char *, int, int);
+struct hostent *lwres_gethostbyname(const char *);
+struct hostent *lwres_gethostbyname2(const char *, int);
+struct hostent *lwres_gethostent(void);
+struct hostent *lwres_getipnodebyname(const char *, int, int, int *);
+struct hostent *lwres_getipnodebyaddr(const void *, size_t, int, int *);
+void lwres_endhostent(void);
+void lwres_sethostent(int);
+/* void lwres_sethostfile(const char *); */
+void lwres_freehostent(struct hostent *);
+
+int lwres_getrrsetbyname(const char *, unsigned int, unsigned int,
+ unsigned int, struct rrsetinfo **);
+void lwres_freerrset(struct rrsetinfo *);
+
+#ifdef notyet
+struct netent *lwres_getnetbyaddr(unsigned long, int);
+struct netent *lwres_getnetbyname(const char *);
+struct netent *lwres_getnetent(void);
+void lwres_endnetent(void);
+void lwres_setnetent(int);
+
+struct protoent *lwres_getprotobyname(const char *);
+struct protoent *lwres_getprotobynumber(int);
+struct protoent *lwres_getprotoent(void);
+void lwres_endprotoent(void);
+void lwres_setprotoent(int);
+
+struct servent *lwres_getservbyname(const char *, const char *);
+struct servent *lwres_getservbyport(int, const char *);
+struct servent *lwres_getservent(void);
+void lwres_endservent(void);
+void lwres_setservent(int);
+#endif /* notyet */
+
+void lwres_herror(const char *);
+const char *lwres_hstrerror(int);
+
+
+struct hostent *lwres_gethostbyaddr_r(const char *, int, int, struct hostent *,
+ char *, int, int *);
+struct hostent *lwres_gethostbyname_r(const char *, struct hostent *,
+ char *, int, int *);
+struct hostent *lwres_gethostent_r(struct hostent *, char *, int, int *);
+void lwres_sethostent_r(int);
+void lwres_endhostent_r(void);
+
+#ifdef notyet
+struct netent *lwres_getnetbyname_r(const char *, struct netent *,
+ char *, int);
+struct netent *lwres_getnetbyaddr_r(long, int, struct netent *,
+ char *, int);
+struct netent *lwres_getnetent_r(struct netent *, char *, int);
+void lwres_setnetent_r(int);
+void lwres_endnetent_r(void);
+
+struct protoent *lwres_getprotobyname_r(const char *,
+ struct protoent *, char *, int);
+struct protoent *lwres_getprotobynumber_r(int,
+ struct protoent *, char *, int);
+struct protoent *lwres_getprotoent_r(struct protoent *, char *, int);
+void lwres_setprotoent_r(int);
+void lwres_endprotoent_r(void);
+
+struct servent *lwres_getservbyname_r(const char *name, const char *,
+ struct servent *, char *, int);
+struct servent *lwres_getservbyport_r(int port, const char *,
+ struct servent *, char *, int);
+struct servent *lwres_getservent_r(struct servent *, char *, int);
+void lwres_setservent_r(int);
+void lwres_endservent_r(void);
+#endif /* notyet */
+
+LWRES_LANG_ENDDECLS
+
+#ifdef notyet
+/* This is nec'y to make this include file properly replace the sun version. */
+#ifdef sun
+#ifdef __GNU_LIBRARY__
+#include <rpc/netdb.h> /* Required. */
+#else /* !__GNU_LIBRARY__ */
+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 *lwres_getrpcbyname();
+struct rpcent *lwres_getrpcbynumber(),
+struct rpcent *lwres_getrpcent();
+#endif /* __GNU_LIBRARY__ */
+#endif /* sun */
+#endif /* notyet */
+
+/*
+ * Tell Emacs to use C mode on this file.
+ * Local variables:
+ * mode: c
+ * End:
+ */
+
+#endif /* LWRES_NETDB_H */
diff --git a/lib/lwres/include/lwres/platform.h.in b/lib/lwres/include/lwres/platform.h.in
new file mode 100644
index 0000000..f69e09f
--- /dev/null
+++ b/lib/lwres/include/lwres/platform.h.in
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2004, 2005 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: platform.h.in,v 1.14.18.5 2005/06/08 02:07:59 marka Exp $ */
+
+/*! \file */
+
+#ifndef LWRES_PLATFORM_H
+#define LWRES_PLATFORM_H 1
+
+/*****
+ ***** Platform-dependent defines.
+ *****/
+
+/***
+ *** Network.
+ ***/
+
+/*
+ * Define if this system needs the <netinet/in6.h> header file for IPv6.
+ */
+@LWRES_PLATFORM_NEEDNETINETIN6H@
+
+/*
+ * Define if this system needs the <netinet6/in6.h> header file for IPv6.
+ */
+@LWRES_PLATFORM_NEEDNETINET6IN6H@
+
+/*
+ * If sockaddrs on this system have an sa_len field, LWRES_PLATFORM_HAVESALEN
+ * will be defined.
+ */
+@LWRES_PLATFORM_HAVESALEN@
+
+/*
+ * If this system has the IPv6 structure definitions, LWRES_PLATFORM_HAVEIPV6
+ * will be defined.
+ */
+@LWRES_PLATFORM_HAVEIPV6@
+
+/*
+ * If this system is missing in6addr_any, LWRES_PLATFORM_NEEDIN6ADDRANY will
+ * be defined.
+ */
+@LWRES_PLATFORM_NEEDIN6ADDRANY@
+
+/*
+ * If this system is missing in6addr_loopback,
+ * LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK will be defined.
+ */
+@LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK@
+
+/*
+ * If this system has in_addr6, rather than in6_addr,
+ * LWRES_PLATFORM_HAVEINADDR6 will be defined.
+ */
+@LWRES_PLATFORM_HAVEINADDR6@
+
+/*
+ * Defined if unistd.h does not cause fd_set to be delared.
+ */
+@LWRES_PLATFORM_NEEDSYSSELECTH@
+
+/*
+ * Used to control how extern data is linked; needed for Win32 platforms.
+ */
+@LWRES_PLATFORM_USEDECLSPEC@
+
+/*
+ * Defined this system needs vsnprintf() and snprintf().
+ */
+@LWRES_PLATFORM_NEEDVSNPRINTF@
+
+/*
+ * If this system need a modern sprintf() that returns (int) not (char*).
+ */
+@LWRES_PLATFORM_NEEDSPRINTF@
+
+/*
+ * The printf format string modifier to use with lwres_uint64_t values.
+ */
+@LWRES_PLATFORM_QUADFORMAT@
+
+/*! \brief
+ * Define if this system needs strtoul.
+ */
+@LWRES_PLATFORM_NEEDSTRTOUL@
+
+#ifndef LWRES_PLATFORM_USEDECLSPEC
+#define LIBLWRES_EXTERNAL_DATA
+#else
+#ifdef LIBLWRES_EXPORTS
+#define LIBLWRES_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBLWRES_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#endif
+
+/*
+ * Tell Emacs to use C mode on this file.
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
+#endif /* LWRES_PLATFORM_H */
diff --git a/lib/lwres/include/lwres/result.h b/lib/lwres/include/lwres/result.h
new file mode 100644
index 0000000..6253fb2
--- /dev/null
+++ b/lib/lwres/include/lwres/result.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2004, 2005 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: result.h,v 1.15.18.2 2005/04/29 00:17:23 marka Exp $ */
+
+#ifndef LWRES_RESULT_H
+#define LWRES_RESULT_H 1
+
+/*! \file */
+
+typedef unsigned int lwres_result_t;
+
+#define LWRES_R_SUCCESS 0
+#define LWRES_R_NOMEMORY 1
+#define LWRES_R_TIMEOUT 2
+#define LWRES_R_NOTFOUND 3
+#define LWRES_R_UNEXPECTEDEND 4 /* unexpected end of input */
+#define LWRES_R_FAILURE 5 /* generic failure */
+#define LWRES_R_IOERROR 6
+#define LWRES_R_NOTIMPLEMENTED 7
+#define LWRES_R_UNEXPECTED 8
+#define LWRES_R_TRAILINGDATA 9
+#define LWRES_R_INCOMPLETE 10
+#define LWRES_R_RETRY 11
+#define LWRES_R_TYPENOTFOUND 12
+#define LWRES_R_TOOLARGE 13
+
+#endif /* LWRES_RESULT_H */
diff --git a/lib/lwres/include/lwres/stdlib.h b/lib/lwres/include/lwres/stdlib.h
new file mode 100644
index 0000000..6855fcf
--- /dev/null
+++ b/lib/lwres/include/lwres/stdlib.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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: stdlib.h,v 1.2.2.1 2005/06/08 02:08:01 marka Exp $ */
+
+#ifndef LWRES_STDLIB_H
+#define LWRES_STDLIB_H 1
+
+/*! \file */
+
+#include <stdlib.h>
+
+#include <lwres/lang.h>
+#include <lwres/platform.h>
+
+#ifdef LWRES_PLATFORM_NEEDSTRTOUL
+#define strtoul lwres_strtoul
+#endif
+
+LWRES_LANG_BEGINDECLS
+
+unsigned long lwres_strtoul(const char *, char **, int);
+
+LWRES_LANG_ENDDECLS
+
+#endif
diff --git a/lib/lwres/include/lwres/version.h b/lib/lwres/include/lwres/version.h
new file mode 100644
index 0000000..252b903
--- /dev/null
+++ b/lib/lwres/include/lwres/version.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005 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: version.h,v 1.3.18.2 2005/04/29 00:17:23 marka Exp $ */
+
+/*! \file */
+
+#include <lwres/platform.h>
+
+LIBLWRES_EXTERNAL_DATA extern const char lwres_version[];
+
+LIBLWRES_EXTERNAL_DATA extern const unsigned int lwres_libinterface;
+LIBLWRES_EXTERNAL_DATA extern const unsigned int lwres_librevision;
+LIBLWRES_EXTERNAL_DATA extern const unsigned int lwres_libage;
diff --git a/lib/lwres/lwbuffer.c b/lib/lwres/lwbuffer.c
new file mode 100644
index 0000000..5191592
--- /dev/null
+++ b/lib/lwres/lwbuffer.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2004, 2005 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: lwbuffer.c,v 1.11.18.2 2005/04/29 00:17:18 marka Exp $ */
+
+/*! \file */
+
+/**
+ * These functions provide bounds checked access to a region of memory
+ * where data is being read or written. They are based on, and similar
+ * to, the isc_buffer_ functions in the ISC library.
+ *
+ * A buffer is a region of memory, together with a set of related
+ * subregions. The used region and the available region are disjoint, and
+ * their union is the buffer's region. The used region extends from the
+ * beginning of the buffer region to the last used byte. The available
+ * region extends from one byte greater than the last used byte to the
+ * end of the buffer's region. The size of the used region can be changed
+ * using various buffer commands. Initially, the used region is empty.
+ *
+ * The used region is further subdivided into two disjoint regions: the
+ * consumed region and the remaining region. The union of these two
+ * regions is the used region. The consumed region extends from the
+ * beginning of the used region to the byte before the current offset (if
+ * any). The remaining region the current pointer to the end of the used
+ * region. The size of the consumed region can be changed using various
+ * buffer commands. Initially, the consumed region is empty.
+ *
+ * The active region is an (optional) subregion of the remaining region.
+ * It extends from the current offset to an offset in the remaining
+ * region. Initially, the active region is empty. If the current offset
+ * advances beyond the chosen offset, the active region will also be
+ * empty.
+ *
+ *
+ * \verbatim
+ * /------------entire length---------------\\
+ * /----- used region -----\\/-- available --\\
+ * +----------------------------------------+
+ * | consumed | remaining | |
+ * +----------------------------------------+
+ * a b c d e
+ *
+ * a == base of buffer.
+ * b == current pointer. Can be anywhere between a and d.
+ * c == active pointer. Meaningful between b and d.
+ * d == used pointer.
+ * e == length of buffer.
+ *
+ * a-e == entire length of buffer.
+ * a-d == used region.
+ * a-b == consumed region.
+ * b-d == remaining region.
+ * b-c == optional active region.
+ * \endverbatim
+ *
+ * lwres_buffer_init() initializes the lwres_buffer_t *b and assocates it
+ * with the memory region of size length bytes starting at location base.
+ *
+ * lwres_buffer_invalidate() marks the buffer *b as invalid. Invalidating
+ * a buffer after use is not required, but makes it possible to catch its
+ * possible accidental use.
+ *
+ * The functions lwres_buffer_add() and lwres_buffer_subtract()
+ * respectively increase and decrease the used space in buffer *b by n
+ * bytes. lwres_buffer_add() checks for buffer overflow and
+ * lwres_buffer_subtract() checks for underflow. These functions do not
+ * allocate or deallocate memory. They just change the value of used.
+ *
+ * A buffer is re-initialised by lwres_buffer_clear(). The function sets
+ * used , current and active to zero.
+ *
+ * lwres_buffer_first() makes the consumed region of buffer *p empty by
+ * setting current to zero (the start of the buffer).
+ *
+ * lwres_buffer_forward() increases the consumed region of buffer *b by n
+ * bytes, checking for overflow. Similarly, lwres_buffer_back() decreases
+ * buffer b's consumed region by n bytes and checks for underflow.
+ *
+ * lwres_buffer_getuint8() reads an unsigned 8-bit integer from *b and
+ * returns it. lwres_buffer_putuint8() writes the unsigned 8-bit integer
+ * val to buffer *b.
+ *
+ * lwres_buffer_getuint16() and lwres_buffer_getuint32() are identical to
+ * lwres_buffer_putuint8() except that they respectively read an unsigned
+ * 16-bit or 32-bit integer in network byte order from b. Similarly,
+ * lwres_buffer_putuint16() and lwres_buffer_putuint32() writes the
+ * unsigned 16-bit or 32-bit integer val to buffer b, in network byte
+ * order.
+ *
+ * Arbitrary amounts of data are read or written from a lightweight
+ * resolver buffer with lwres_buffer_getmem() and lwres_buffer_putmem()
+ * respectively. lwres_buffer_putmem() copies length bytes of memory at
+ * base to b. Conversely, lwres_buffer_getmem() copies length bytes of
+ * memory from b to base.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+
+#include "assert_p.h"
+
+void
+lwres_buffer_init(lwres_buffer_t *b, void *base, unsigned int length)
+{
+ /*
+ * Make 'b' refer to the 'length'-byte region starting at base.
+ */
+
+ REQUIRE(b != NULL);
+
+ b->magic = LWRES_BUFFER_MAGIC;
+ b->base = base;
+ b->length = length;
+ b->used = 0;
+ b->current = 0;
+ b->active = 0;
+}
+
+/* Make 'b' an invalid buffer. */
+void
+lwres_buffer_invalidate(lwres_buffer_t *b)
+{
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+
+ b->magic = 0;
+ b->base = NULL;
+ b->length = 0;
+ b->used = 0;
+ b->current = 0;
+ b->active = 0;
+}
+
+/* Increase the 'used' region of 'b' by 'n' bytes. */
+void
+lwres_buffer_add(lwres_buffer_t *b, unsigned int n)
+{
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used + n <= b->length);
+
+ b->used += n;
+}
+
+/* Decrease the 'used' region of 'b' by 'n' bytes. */
+void
+lwres_buffer_subtract(lwres_buffer_t *b, unsigned int n)
+{
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used >= n);
+
+ b->used -= n;
+ if (b->current > b->used)
+ b->current = b->used;
+ if (b->active > b->used)
+ b->active = b->used;
+}
+
+/* Make the used region empty. */
+void
+lwres_buffer_clear(lwres_buffer_t *b)
+{
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+
+ b->used = 0;
+ b->current = 0;
+ b->active = 0;
+}
+
+/* Make the consumed region empty. */
+void
+lwres_buffer_first(lwres_buffer_t *b)
+{
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+
+ b->current = 0;
+}
+
+/* Increase the 'consumed' region of 'b' by 'n' bytes. */
+void
+lwres_buffer_forward(lwres_buffer_t *b, unsigned int n)
+{
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->current + n <= b->used);
+
+ b->current += n;
+}
+
+/* Decrease the 'consumed' region of 'b' by 'n' bytes. */
+void
+lwres_buffer_back(lwres_buffer_t *b, unsigned int n)
+{
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(n <= b->current);
+
+ b->current -= n;
+}
+
+/* Read an unsigned 8-bit integer from 'b' and return it. */
+lwres_uint8_t
+lwres_buffer_getuint8(lwres_buffer_t *b)
+{
+ unsigned char *cp;
+ lwres_uint8_t result;
+
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 1);
+
+ cp = b->base;
+ cp += b->current;
+ b->current += 1;
+ result = ((unsigned int)(cp[0]));
+
+ return (result);
+}
+
+/* Put an unsigned 8-bit integer */
+void
+lwres_buffer_putuint8(lwres_buffer_t *b, lwres_uint8_t val)
+{
+ unsigned char *cp;
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used + 1 <= b->length);
+
+ cp = b->base;
+ cp += b->used;
+ b->used += 1;
+ cp[0] = (val & 0x00ff);
+}
+
+/* Read an unsigned 16-bit integer in network byte order from 'b', convert it to host byte order, and return it. */
+lwres_uint16_t
+lwres_buffer_getuint16(lwres_buffer_t *b)
+{
+ unsigned char *cp;
+ lwres_uint16_t result;
+
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 2);
+
+ cp = b->base;
+ cp += b->current;
+ b->current += 2;
+ result = ((unsigned int)(cp[0])) << 8;
+ result |= ((unsigned int)(cp[1]));
+
+ return (result);
+}
+
+/* Put an unsigned 16-bit integer. */
+void
+lwres_buffer_putuint16(lwres_buffer_t *b, lwres_uint16_t val)
+{
+ unsigned char *cp;
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used + 2 <= b->length);
+
+ cp = b->base;
+ cp += b->used;
+ b->used += 2;
+ cp[0] = (val & 0xff00) >> 8;
+ cp[1] = (val & 0x00ff);
+}
+
+/* Read an unsigned 32-bit integer in network byte order from 'b', convert it to host byte order, and return it. */
+lwres_uint32_t
+lwres_buffer_getuint32(lwres_buffer_t *b)
+{
+ unsigned char *cp;
+ lwres_uint32_t result;
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 4);
+
+ cp = b->base;
+ cp += b->current;
+ b->current += 4;
+ result = ((unsigned int)(cp[0])) << 24;
+ result |= ((unsigned int)(cp[1])) << 16;
+ result |= ((unsigned int)(cp[2])) << 8;
+ result |= ((unsigned int)(cp[3]));
+
+ return (result);
+}
+
+/* Put an unsigned 32-bit integer. */
+void
+lwres_buffer_putuint32(lwres_buffer_t *b, lwres_uint32_t val)
+{
+ unsigned char *cp;
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used + 4 <= b->length);
+
+ cp = b->base;
+ cp += b->used;
+ b->used += 4;
+ cp[0] = (unsigned char)((val & 0xff000000) >> 24);
+ cp[1] = (unsigned char)((val & 0x00ff0000) >> 16);
+ cp[2] = (unsigned char)((val & 0x0000ff00) >> 8);
+ cp[3] = (unsigned char)(val & 0x000000ff);
+}
+
+/* copies length bytes of memory at base to b */
+void
+lwres_buffer_putmem(lwres_buffer_t *b, const unsigned char *base,
+ unsigned int length)
+{
+ unsigned char *cp;
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used + length <= b->length);
+
+ cp = (unsigned char *)b->base + b->used;
+ memcpy(cp, base, length);
+ b->used += length;
+}
+
+/* copies length bytes of memory at b to base */
+void
+lwres_buffer_getmem(lwres_buffer_t *b, unsigned char *base,
+ unsigned int length)
+{
+ unsigned char *cp;
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= length);
+
+ cp = b->base;
+ cp += b->current;
+ b->current += length;
+
+ memcpy(base, cp, length);
+}
diff --git a/lib/lwres/lwconfig.c b/lib/lwres/lwconfig.c
new file mode 100644
index 0000000..cf4f6a7
--- /dev/null
+++ b/lib/lwres/lwconfig.c
@@ -0,0 +1,725 @@
+/*
+ * Copyright (C) 2004-2006 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: lwconfig.c,v 1.38.18.5 2006/10/03 23:50:51 marka Exp $ */
+
+/*! \file */
+
+/**
+ * Module for parsing resolv.conf files.
+ *
+ * lwres_conf_init() creates an empty lwres_conf_t structure for
+ * lightweight resolver context ctx.
+ *
+ * lwres_conf_clear() frees up all the internal memory used by that
+ * lwres_conf_t structure in resolver context ctx.
+ *
+ * lwres_conf_parse() opens the file filename and parses it to initialise
+ * the resolver context ctx's lwres_conf_t structure.
+ *
+ * lwres_conf_print() prints the lwres_conf_t structure for resolver
+ * context ctx to the FILE fp.
+ *
+ * \section lwconfig_return Return Values
+ *
+ * lwres_conf_parse() returns #LWRES_R_SUCCESS if it successfully read and
+ * parsed filename. It returns #LWRES_R_FAILURE if filename could not be
+ * opened or contained incorrect resolver statements.
+ *
+ * lwres_conf_print() returns #LWRES_R_SUCCESS unless an error occurred
+ * when converting the network addresses to a numeric host address
+ * string. If this happens, the function returns #LWRES_R_FAILURE.
+ *
+ * \section lwconfig_see See Also
+ *
+ * stdio(3), \link resolver resolver \endlink
+ *
+ * \section files Files
+ *
+ * /etc/resolv.conf
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/result.h>
+
+#include "assert_p.h"
+#include "context_p.h"
+
+
+#if ! defined(NS_INADDRSZ)
+#define NS_INADDRSZ 4
+#endif
+
+#if ! defined(NS_IN6ADDRSZ)
+#define NS_IN6ADDRSZ 16
+#endif
+
+static lwres_result_t
+lwres_conf_parsenameserver(lwres_context_t *ctx, FILE *fp);
+
+static lwres_result_t
+lwres_conf_parselwserver(lwres_context_t *ctx, FILE *fp);
+
+static lwres_result_t
+lwres_conf_parsedomain(lwres_context_t *ctx, FILE *fp);
+
+static lwres_result_t
+lwres_conf_parsesearch(lwres_context_t *ctx, FILE *fp);
+
+static lwres_result_t
+lwres_conf_parsesortlist(lwres_context_t *ctx, FILE *fp);
+
+static lwres_result_t
+lwres_conf_parseoption(lwres_context_t *ctx, FILE *fp);
+
+static void
+lwres_resetaddr(lwres_addr_t *addr);
+
+static lwres_result_t
+lwres_create_addr(const char *buff, lwres_addr_t *addr, int convert_zero);
+
+static int lwresaddr2af(int lwresaddrtype);
+
+
+static int
+lwresaddr2af(int lwresaddrtype)
+{
+ int af = 0;
+
+ switch (lwresaddrtype) {
+ case LWRES_ADDRTYPE_V4:
+ af = AF_INET;
+ break;
+
+ case LWRES_ADDRTYPE_V6:
+ af = AF_INET6;
+ break;
+ }
+
+ return (af);
+}
+
+
+/*!
+ * Eat characters from FP until EOL or EOF. Returns EOF or '\n'
+ */
+static int
+eatline(FILE *fp) {
+ int ch;
+
+ ch = fgetc(fp);
+ while (ch != '\n' && ch != EOF)
+ ch = fgetc(fp);
+
+ return (ch);
+}
+
+
+/*!
+ * Eats white space up to next newline or non-whitespace character (of
+ * EOF). Returns the last character read. Comments are considered white
+ * space.
+ */
+static int
+eatwhite(FILE *fp) {
+ int ch;
+
+ ch = fgetc(fp);
+ while (ch != '\n' && ch != EOF && isspace((unsigned char)ch))
+ ch = fgetc(fp);
+
+ if (ch == ';' || ch == '#')
+ ch = eatline(fp);
+
+ return (ch);
+}
+
+
+/*!
+ * Skip over any leading whitespace and then read in the next sequence of
+ * non-whitespace characters. In this context newline is not considered
+ * whitespace. Returns EOF on end-of-file, or the character
+ * that caused the reading to stop.
+ */
+static int
+getword(FILE *fp, char *buffer, size_t size) {
+ int ch;
+ char *p = buffer;
+
+ REQUIRE(buffer != NULL);
+ REQUIRE(size > 0U);
+
+ *p = '\0';
+
+ ch = eatwhite(fp);
+
+ if (ch == EOF)
+ return (EOF);
+
+ do {
+ *p = '\0';
+
+ if (ch == EOF || isspace((unsigned char)ch))
+ break;
+ else if ((size_t) (p - buffer) == size - 1)
+ return (EOF); /* Not enough space. */
+
+ *p++ = (char)ch;
+ ch = fgetc(fp);
+ } while (1);
+
+ return (ch);
+}
+
+static void
+lwres_resetaddr(lwres_addr_t *addr) {
+ REQUIRE(addr != NULL);
+
+ memset(addr->address, 0, LWRES_ADDR_MAXLEN);
+ addr->family = 0;
+ addr->length = 0;
+}
+
+static char *
+lwres_strdup(lwres_context_t *ctx, const char *str) {
+ char *p;
+
+ REQUIRE(str != NULL);
+ REQUIRE(strlen(str) > 0U);
+
+ p = CTXMALLOC(strlen(str) + 1);
+ if (p != NULL)
+ strcpy(p, str);
+
+ return (p);
+}
+
+/*% intializes data structure for subsequent config parsing. */
+void
+lwres_conf_init(lwres_context_t *ctx) {
+ int i;
+ lwres_conf_t *confdata;
+
+ REQUIRE(ctx != NULL);
+ confdata = &ctx->confdata;
+
+ confdata->nsnext = 0;
+ confdata->lwnext = 0;
+ confdata->domainname = NULL;
+ confdata->searchnxt = 0;
+ confdata->sortlistnxt = 0;
+ confdata->resdebug = 0;
+ confdata->ndots = 1;
+ confdata->no_tld_query = 0;
+
+ for (i = 0; i < LWRES_CONFMAXNAMESERVERS; i++)
+ lwres_resetaddr(&confdata->nameservers[i]);
+
+ for (i = 0; i < LWRES_CONFMAXSEARCH; i++)
+ confdata->search[i] = NULL;
+
+ for (i = 0; i < LWRES_CONFMAXSORTLIST; i++) {
+ lwres_resetaddr(&confdata->sortlist[i].addr);
+ lwres_resetaddr(&confdata->sortlist[i].mask);
+ }
+}
+
+/*% Frees up all the internal memory used by the config data structure, returning it to the lwres_context_t. */
+void
+lwres_conf_clear(lwres_context_t *ctx) {
+ int i;
+ lwres_conf_t *confdata;
+
+ REQUIRE(ctx != NULL);
+ confdata = &ctx->confdata;
+
+ for (i = 0; i < confdata->nsnext; i++)
+ lwres_resetaddr(&confdata->nameservers[i]);
+
+ if (confdata->domainname != NULL) {
+ CTXFREE(confdata->domainname,
+ strlen(confdata->domainname) + 1);
+ confdata->domainname = NULL;
+ }
+
+ for (i = 0; i < confdata->searchnxt; i++) {
+ if (confdata->search[i] != NULL) {
+ CTXFREE(confdata->search[i],
+ strlen(confdata->search[i]) + 1);
+ confdata->search[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < LWRES_CONFMAXSORTLIST; i++) {
+ lwres_resetaddr(&confdata->sortlist[i].addr);
+ lwres_resetaddr(&confdata->sortlist[i].mask);
+ }
+
+ confdata->nsnext = 0;
+ confdata->lwnext = 0;
+ confdata->domainname = NULL;
+ confdata->searchnxt = 0;
+ confdata->sortlistnxt = 0;
+ confdata->resdebug = 0;
+ confdata->ndots = 1;
+ confdata->no_tld_query = 0;
+}
+
+static lwres_result_t
+lwres_conf_parsenameserver(lwres_context_t *ctx, FILE *fp) {
+ char word[LWRES_CONFMAXLINELEN];
+ int res;
+ lwres_conf_t *confdata;
+ lwres_addr_t address;
+
+ confdata = &ctx->confdata;
+
+ if (confdata->nsnext == LWRES_CONFMAXNAMESERVERS)
+ return (LWRES_R_SUCCESS);
+
+ res = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0U)
+ return (LWRES_R_FAILURE); /* Nothing on line. */
+ else if (res == ' ' || res == '\t')
+ res = eatwhite(fp);
+
+ if (res != EOF && res != '\n')
+ return (LWRES_R_FAILURE); /* Extra junk on line. */
+
+ res = lwres_create_addr(word, &address, 1);
+ if (res == LWRES_R_SUCCESS)
+ confdata->nameservers[confdata->nsnext++] = address;
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_conf_parselwserver(lwres_context_t *ctx, FILE *fp) {
+ char word[LWRES_CONFMAXLINELEN];
+ int res;
+ lwres_conf_t *confdata;
+
+ confdata = &ctx->confdata;
+
+ if (confdata->lwnext == LWRES_CONFMAXLWSERVERS)
+ return (LWRES_R_SUCCESS);
+
+ res = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0U)
+ return (LWRES_R_FAILURE); /* Nothing on line. */
+ else if (res == ' ' || res == '\t')
+ res = eatwhite(fp);
+
+ if (res != EOF && res != '\n')
+ return (LWRES_R_FAILURE); /* Extra junk on line. */
+
+ res = lwres_create_addr(word,
+ &confdata->lwservers[confdata->lwnext++], 1);
+ if (res != LWRES_R_SUCCESS)
+ return (res);
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_conf_parsedomain(lwres_context_t *ctx, FILE *fp) {
+ char word[LWRES_CONFMAXLINELEN];
+ int res, i;
+ lwres_conf_t *confdata;
+
+ confdata = &ctx->confdata;
+
+ res = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0U)
+ return (LWRES_R_FAILURE); /* Nothing else on line. */
+ else if (res == ' ' || res == '\t')
+ res = eatwhite(fp);
+
+ if (res != EOF && res != '\n')
+ return (LWRES_R_FAILURE); /* Extra junk on line. */
+
+ if (confdata->domainname != NULL)
+ CTXFREE(confdata->domainname,
+ strlen(confdata->domainname) + 1); /* */
+
+ /*
+ * Search and domain are mutually exclusive.
+ */
+ for (i = 0; i < LWRES_CONFMAXSEARCH; i++) {
+ if (confdata->search[i] != NULL) {
+ CTXFREE(confdata->search[i],
+ strlen(confdata->search[i])+1);
+ confdata->search[i] = NULL;
+ }
+ }
+ confdata->searchnxt = 0;
+
+ confdata->domainname = lwres_strdup(ctx, word);
+
+ if (confdata->domainname == NULL)
+ return (LWRES_R_FAILURE);
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_conf_parsesearch(lwres_context_t *ctx, FILE *fp) {
+ int idx, delim;
+ char word[LWRES_CONFMAXLINELEN];
+ lwres_conf_t *confdata;
+
+ confdata = &ctx->confdata;
+
+ if (confdata->domainname != NULL) {
+ /*
+ * Search and domain are mutually exclusive.
+ */
+ CTXFREE(confdata->domainname,
+ strlen(confdata->domainname) + 1);
+ confdata->domainname = NULL;
+ }
+
+ /*
+ * Remove any previous search definitions.
+ */
+ for (idx = 0; idx < LWRES_CONFMAXSEARCH; idx++) {
+ if (confdata->search[idx] != NULL) {
+ CTXFREE(confdata->search[idx],
+ strlen(confdata->search[idx])+1);
+ confdata->search[idx] = NULL;
+ }
+ }
+ confdata->searchnxt = 0;
+
+ delim = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0U)
+ return (LWRES_R_FAILURE); /* Nothing else on line. */
+
+ idx = 0;
+ while (strlen(word) > 0U) {
+ if (confdata->searchnxt == LWRES_CONFMAXSEARCH)
+ goto ignore; /* Too many domains. */
+
+ confdata->search[idx] = lwres_strdup(ctx, word);
+ if (confdata->search[idx] == NULL)
+ return (LWRES_R_FAILURE);
+ idx++;
+ confdata->searchnxt++;
+
+ ignore:
+ if (delim == EOF || delim == '\n')
+ break;
+ else
+ delim = getword(fp, word, sizeof(word));
+ }
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_create_addr(const char *buffer, lwres_addr_t *addr, int convert_zero) {
+ struct in_addr v4;
+ struct in6_addr v6;
+
+ if (lwres_net_aton(buffer, &v4) == 1) {
+ if (convert_zero) {
+ unsigned char zeroaddress[] = {0, 0, 0, 0};
+ unsigned char loopaddress[] = {127, 0, 0, 1};
+ if (memcmp(&v4, zeroaddress, 4) == 0)
+ memcpy(&v4, loopaddress, 4);
+ }
+ addr->family = LWRES_ADDRTYPE_V4;
+ addr->length = NS_INADDRSZ;
+ memcpy((void *)addr->address, &v4, NS_INADDRSZ);
+
+ } else if (lwres_net_pton(AF_INET6, buffer, &v6) == 1) {
+ addr->family = LWRES_ADDRTYPE_V6;
+ addr->length = NS_IN6ADDRSZ;
+ memcpy((void *)addr->address, &v6, NS_IN6ADDRSZ);
+ } else {
+ return (LWRES_R_FAILURE); /* Unrecognised format. */
+ }
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_conf_parsesortlist(lwres_context_t *ctx, FILE *fp) {
+ int delim, res, idx;
+ char word[LWRES_CONFMAXLINELEN];
+ char *p;
+ lwres_conf_t *confdata;
+
+ confdata = &ctx->confdata;
+
+ delim = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0U)
+ return (LWRES_R_FAILURE); /* Empty line after keyword. */
+
+ while (strlen(word) > 0U) {
+ if (confdata->sortlistnxt == LWRES_CONFMAXSORTLIST)
+ return (LWRES_R_FAILURE); /* Too many values. */
+
+ p = strchr(word, '/');
+ if (p != NULL)
+ *p++ = '\0';
+
+ idx = confdata->sortlistnxt;
+ res = lwres_create_addr(word, &confdata->sortlist[idx].addr, 1);
+ if (res != LWRES_R_SUCCESS)
+ return (res);
+
+ if (p != NULL) {
+ res = lwres_create_addr(p,
+ &confdata->sortlist[idx].mask,
+ 0);
+ if (res != LWRES_R_SUCCESS)
+ return (res);
+ } else {
+ /*
+ * Make up a mask.
+ */
+ confdata->sortlist[idx].mask =
+ confdata->sortlist[idx].addr;
+
+ memset(&confdata->sortlist[idx].mask.address, 0xff,
+ confdata->sortlist[idx].addr.length);
+ }
+
+ confdata->sortlistnxt++;
+
+ if (delim == EOF || delim == '\n')
+ break;
+ else
+ delim = getword(fp, word, sizeof(word));
+ }
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_conf_parseoption(lwres_context_t *ctx, FILE *fp) {
+ int delim;
+ long ndots;
+ char *p;
+ char word[LWRES_CONFMAXLINELEN];
+ lwres_conf_t *confdata;
+
+ REQUIRE(ctx != NULL);
+ confdata = &ctx->confdata;
+
+ delim = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0U)
+ return (LWRES_R_FAILURE); /* Empty line after keyword. */
+
+ while (strlen(word) > 0U) {
+ if (strcmp("debug", word) == 0) {
+ confdata->resdebug = 1;
+ } else if (strcmp("no_tld_query", word) == 0) {
+ confdata->no_tld_query = 1;
+ } else if (strncmp("ndots:", word, 6) == 0) {
+ ndots = strtol(word + 6, &p, 10);
+ if (*p != '\0') /* Bad string. */
+ return (LWRES_R_FAILURE);
+ if (ndots < 0 || ndots > 0xff) /* Out of range. */
+ return (LWRES_R_FAILURE);
+ confdata->ndots = (lwres_uint8_t)ndots;
+ }
+
+ if (delim == EOF || delim == '\n')
+ break;
+ else
+ delim = getword(fp, word, sizeof(word));
+ }
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% parses a file and fills in the data structure. */
+lwres_result_t
+lwres_conf_parse(lwres_context_t *ctx, const char *filename) {
+ FILE *fp = NULL;
+ char word[256];
+ lwres_result_t rval, ret;
+ lwres_conf_t *confdata;
+ int stopchar;
+
+ REQUIRE(ctx != NULL);
+ confdata = &ctx->confdata;
+
+ REQUIRE(filename != NULL);
+ REQUIRE(strlen(filename) > 0U);
+ REQUIRE(confdata != NULL);
+
+ errno = 0;
+ if ((fp = fopen(filename, "r")) == NULL)
+ return (LWRES_R_NOTFOUND);
+
+ ret = LWRES_R_SUCCESS;
+ do {
+ stopchar = getword(fp, word, sizeof(word));
+ if (stopchar == EOF) {
+ rval = LWRES_R_SUCCESS;
+ break;
+ }
+
+ if (strlen(word) == 0U)
+ rval = LWRES_R_SUCCESS;
+ else if (strcmp(word, "nameserver") == 0)
+ rval = lwres_conf_parsenameserver(ctx, fp);
+ else if (strcmp(word, "lwserver") == 0)
+ rval = lwres_conf_parselwserver(ctx, fp);
+ else if (strcmp(word, "domain") == 0)
+ rval = lwres_conf_parsedomain(ctx, fp);
+ else if (strcmp(word, "search") == 0)
+ rval = lwres_conf_parsesearch(ctx, fp);
+ else if (strcmp(word, "sortlist") == 0)
+ rval = lwres_conf_parsesortlist(ctx, fp);
+ else if (strcmp(word, "options") == 0)
+ rval = lwres_conf_parseoption(ctx, fp);
+ else {
+ /* unrecognised word. Ignore entire line */
+ rval = LWRES_R_SUCCESS;
+ stopchar = eatline(fp);
+ if (stopchar == EOF) {
+ break;
+ }
+ }
+ if (ret == LWRES_R_SUCCESS && rval != LWRES_R_SUCCESS)
+ ret = rval;
+ } while (1);
+
+ fclose(fp);
+
+ return (ret);
+}
+
+/*% Prints the config data structure to the FILE. */
+lwres_result_t
+lwres_conf_print(lwres_context_t *ctx, FILE *fp) {
+ int i;
+ int af;
+ char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+ const char *p;
+ lwres_conf_t *confdata;
+ lwres_addr_t tmpaddr;
+
+ REQUIRE(ctx != NULL);
+ confdata = &ctx->confdata;
+
+ REQUIRE(confdata->nsnext <= LWRES_CONFMAXNAMESERVERS);
+
+ for (i = 0; i < confdata->nsnext; i++) {
+ af = lwresaddr2af(confdata->nameservers[i].family);
+
+ p = lwres_net_ntop(af, confdata->nameservers[i].address,
+ tmp, sizeof(tmp));
+ if (p != tmp)
+ return (LWRES_R_FAILURE);
+
+ fprintf(fp, "nameserver %s\n", tmp);
+ }
+
+ for (i = 0; i < confdata->lwnext; i++) {
+ af = lwresaddr2af(confdata->lwservers[i].family);
+
+ p = lwres_net_ntop(af, confdata->lwservers[i].address,
+ tmp, sizeof(tmp));
+ if (p != tmp)
+ return (LWRES_R_FAILURE);
+
+ fprintf(fp, "lwserver %s\n", tmp);
+ }
+
+ if (confdata->domainname != NULL) {
+ fprintf(fp, "domain %s\n", confdata->domainname);
+ } else if (confdata->searchnxt > 0) {
+ REQUIRE(confdata->searchnxt <= LWRES_CONFMAXSEARCH);
+
+ fprintf(fp, "search");
+ for (i = 0; i < confdata->searchnxt; i++)
+ fprintf(fp, " %s", confdata->search[i]);
+ fputc('\n', fp);
+ }
+
+ REQUIRE(confdata->sortlistnxt <= LWRES_CONFMAXSORTLIST);
+
+ if (confdata->sortlistnxt > 0) {
+ fputs("sortlist", fp);
+ for (i = 0; i < confdata->sortlistnxt; i++) {
+ af = lwresaddr2af(confdata->sortlist[i].addr.family);
+
+ p = lwres_net_ntop(af,
+ confdata->sortlist[i].addr.address,
+ tmp, sizeof(tmp));
+ if (p != tmp)
+ return (LWRES_R_FAILURE);
+
+ fprintf(fp, " %s", tmp);
+
+ tmpaddr = confdata->sortlist[i].mask;
+ memset(&tmpaddr.address, 0xff, tmpaddr.length);
+
+ if (memcmp(&tmpaddr.address,
+ confdata->sortlist[i].mask.address,
+ confdata->sortlist[i].mask.length) != 0) {
+ af = lwresaddr2af(
+ confdata->sortlist[i].mask.family);
+ p = lwres_net_ntop
+ (af,
+ confdata->sortlist[i].mask.address,
+ tmp, sizeof(tmp));
+ if (p != tmp)
+ return (LWRES_R_FAILURE);
+
+ fprintf(fp, "/%s", tmp);
+ }
+ }
+ fputc('\n', fp);
+ }
+
+ if (confdata->resdebug)
+ fprintf(fp, "options debug\n");
+
+ if (confdata->ndots > 0)
+ fprintf(fp, "options ndots:%d\n", confdata->ndots);
+
+ if (confdata->no_tld_query)
+ fprintf(fp, "options no_tld_query\n");
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Returns a pointer to the current config structure. */
+lwres_conf_t *
+lwres_conf_get(lwres_context_t *ctx) {
+ REQUIRE(ctx != NULL);
+
+ return (&ctx->confdata);
+}
diff --git a/lib/lwres/lwinetaton.c b/lib/lwres/lwinetaton.c
new file mode 100644
index 0000000..cc4b9bd
--- /dev/null
+++ b/lib/lwres/lwinetaton.c
@@ -0,0 +1,205 @@
+/*
+ * Portions Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-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.
+ */
+
+/*
+ * 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.
+ */
+
+/*! \file lwinetaton.c
+ */
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
+static char rcsid[] = "$Id: lwinetaton.c,v 1.12.18.2 2005/04/29 00:17:19 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <ctype.h>
+
+#include <stddef.h>
+
+#include <lwres/int.h>
+#include <lwres/net.h>
+
+#include "assert_p.h"
+
+/*!
+ * 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
+lwres_net_aton(const char *cp, struct in_addr *addr) {
+ unsigned long val;
+ int base, n;
+ unsigned char c;
+ lwres_uint8_t parts[4];
+ lwres_uint8_t *pp = parts;
+ int digit;
+
+ REQUIRE(cp != NULL);
+
+ c = *cp;
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, isdigit=decimal.
+ */
+ if (!isdigit(c & 0xff))
+ 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 (;;) {
+ /*
+ * isascii() is valid for all integer values, and
+ * when it is true, c is known to be in scope
+ * for isdigit(). No cast necessary. Similar
+ * comment applies for later ctype uses.
+ */
+ if (isascii(c) && isdigit(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(c)) {
+ val = (val << 4) |
+ (c + 10 - (islower(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++ = (lwres_uint8_t)val;
+ c = *++cp;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (c != '\0' && (!isascii(c) || !isspace(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/lib/lwres/lwinetntop.c b/lib/lwres/lwinetntop.c
new file mode 100644
index 0000000..e65656f
--- /dev/null
+++ b/lib/lwres/lwinetntop.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-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.
+ */
+
+/*! \file lwinetntop.c
+ */
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] =
+ "$Id: lwinetntop.c,v 1.12.18.4 2005/11/03 23:02:24 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <lwres/net.h>
+#include "print_p.h"
+
+#define NS_INT16SZ 2
+#define NS_IN6ADDRSZ 16
+
+/*
+ * 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(const unsigned char *src, char *dst,
+ size_t size);
+
+#ifdef AF_INET6
+static const char *inet_ntop6(const unsigned char *src, char *dst,
+ size_t size);
+#endif
+
+/*! char *
+ * lwres_net_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 *
+lwres_net_ntop(int af, const void *src, char *dst, size_t size) {
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+#ifdef AF_INET6
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+#endif
+ 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 unsigned char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, size_t size) {
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[sizeof("255.255.255.255")];
+ size_t len;
+
+ len = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
+ if (len >= 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.
+ */
+#ifdef AF_INET6
+static const char *
+inet_ntop6(const unsigned 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;
+ unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof(words));
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0;
+ cur.base = -1;
+ cur.len = 0;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 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]); /* XXX */
+ }
+ /* 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);
+}
+#endif /* AF_INET6 */
diff --git a/lib/lwres/lwinetpton.c b/lib/lwres/lwinetpton.c
new file mode 100644
index 0000000..5155fd1
--- /dev/null
+++ b/lib/lwres/lwinetpton.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-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.
+ */
+
+/*! \file lwinetpton.c
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$Id: lwinetpton.c,v 1.7.18.3 2005/04/27 05:02:48 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <lwres/net.h>
+
+#define NS_INT16SZ 2
+#define NS_INADDRSZ 4
+#define NS_IN6ADDRSZ 16
+
+/*
+ * 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(const char *src, unsigned char *dst);
+static int inet_pton6(const char *src, unsigned char *dst);
+
+/*!
+ * int
+ * lwres_net_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
+lwres_net_pton(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(const char *src, unsigned char *dst) {
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned 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) {
+ unsigned int new = *tp * 10 + (pch - digits);
+
+ 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(const char *src, unsigned char *dst) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, seen_xdigits;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ seen_xdigits = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (++seen_xdigits > 4)
+ return (0);
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!seen_xdigits) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ seen_xdigits = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ seen_xdigits = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (seen_xdigits) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned 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;
+
+ 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/lib/lwres/lwpacket.c b/lib/lwres/lwpacket.c
new file mode 100644
index 0000000..964b465
--- /dev/null
+++ b/lib/lwres/lwpacket.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2004, 2005 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: lwpacket.c,v 1.14.18.2 2005/04/29 00:17:19 marka Exp $ */
+
+/*! \file */
+
+/**
+ * These functions rely on a struct lwres_lwpacket which is defined in
+ * \link lwpacket.h lwres/lwpacket.h.\endlink
+ *
+ * The following opcodes are currently defined:
+ *
+ * \li #LWRES_OPCODE_NOOP
+ * Success is always returned and the packet contents are
+ * echoed. The \link lwres_noop.c lwres_noop_*()\endlink functions should be used for this
+ * type.
+ *
+ * \li #LWRES_OPCODE_GETADDRSBYNAME
+ * returns all known addresses for a given name. The
+ * \link lwres_gabn.c lwres_gabn_*()\endlink functions should be used for this type.
+ *
+ * \li #LWRES_OPCODE_GETNAMEBYADDR
+ * return the hostname for the given address. The
+ * \link lwres_gnba.c lwres_gnba_*() \endlink functions should be used for this type.
+ *
+ * lwres_lwpacket_renderheader() transfers the contents of lightweight
+ * resolver packet structure #lwres_lwpacket_t *pkt in network byte
+ * order to the lightweight resolver buffer, *b.
+ *
+ * lwres_lwpacket_parseheader() performs the converse operation. It
+ * transfers data in network byte order from buffer *b to resolver
+ * packet *pkt. The contents of the buffer b should correspond to a
+ * #lwres_lwpacket_t.
+ *
+ * \section lwpacket_return Return Values
+ *
+ * Successful calls to lwres_lwpacket_renderheader() and
+ * lwres_lwpacket_parseheader() return #LWRES_R_SUCCESS. If there is
+ * insufficient space to copy data between the buffer *b and
+ * lightweight resolver packet *pkt both functions return
+ * #LWRES_R_UNEXPECTEDEND.
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwpacket.h>
+#include <lwres/result.h>
+
+#include "assert_p.h"
+
+/*% Length of Packet */
+#define LWPACKET_LENGTH \
+ (sizeof(lwres_uint16_t) * 4 + sizeof(lwres_uint32_t) * 5)
+
+/*% transfers the contents of lightweight resolver packet structure lwres_lwpacket_t *pkt in network byte order to the lightweight resolver buffer, *b. */
+
+lwres_result_t
+lwres_lwpacket_renderheader(lwres_buffer_t *b, lwres_lwpacket_t *pkt) {
+ REQUIRE(b != NULL);
+ REQUIRE(pkt != NULL);
+
+ if (!SPACE_OK(b, LWPACKET_LENGTH))
+ return (LWRES_R_UNEXPECTEDEND);
+
+ lwres_buffer_putuint32(b, pkt->length);
+ lwres_buffer_putuint16(b, pkt->version);
+ lwres_buffer_putuint16(b, pkt->pktflags);
+ lwres_buffer_putuint32(b, pkt->serial);
+ lwres_buffer_putuint32(b, pkt->opcode);
+ lwres_buffer_putuint32(b, pkt->result);
+ lwres_buffer_putuint32(b, pkt->recvlength);
+ lwres_buffer_putuint16(b, pkt->authtype);
+ lwres_buffer_putuint16(b, pkt->authlength);
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% transfers data in network byte order from buffer *b to resolver packet *pkt. The contents of the buffer b should correspond to a lwres_lwpacket_t. */
+
+lwres_result_t
+lwres_lwpacket_parseheader(lwres_buffer_t *b, lwres_lwpacket_t *pkt) {
+ lwres_uint32_t space;
+
+ REQUIRE(b != NULL);
+ REQUIRE(pkt != NULL);
+
+ space = LWRES_BUFFER_REMAINING(b);
+ if (space < LWPACKET_LENGTH)
+ return (LWRES_R_UNEXPECTEDEND);
+
+ pkt->length = lwres_buffer_getuint32(b);
+ /*
+ * XXXBEW/MLG Checking that the buffer is long enough probably
+ * shouldn't be done here, since this function is supposed to just
+ * parse the header.
+ */
+ if (pkt->length > space)
+ return (LWRES_R_UNEXPECTEDEND);
+ pkt->version = lwres_buffer_getuint16(b);
+ pkt->pktflags = lwres_buffer_getuint16(b);
+ pkt->serial = lwres_buffer_getuint32(b);
+ pkt->opcode = lwres_buffer_getuint32(b);
+ pkt->result = lwres_buffer_getuint32(b);
+ pkt->recvlength = lwres_buffer_getuint32(b);
+ pkt->authtype = lwres_buffer_getuint16(b);
+ pkt->authlength = lwres_buffer_getuint16(b);
+
+ return (LWRES_R_SUCCESS);
+}
diff --git a/lib/lwres/lwres_gabn.c b/lib/lwres/lwres_gabn.c
new file mode 100644
index 0000000..c6f1139
--- /dev/null
+++ b/lib/lwres/lwres_gabn.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2004, 2005 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: lwres_gabn.c,v 1.29.18.2 2005/04/29 00:17:19 marka Exp $ */
+
+/*! \file lwres_gabn.c
+ These are low-level routines for creating and parsing lightweight
+ resolver name-to-address lookup request and response messages.
+
+ There are four main functions for the getaddrbyname opcode. One render
+ function converts a getaddrbyname request structure --
+ lwres_gabnrequest_t -- to the lighweight resolver's canonical format.
+ It is complemented by a parse function that converts a packet in this
+ canonical format to a getaddrbyname request structure. Another render
+ function converts the getaddrbyname response structure --
+ lwres_gabnresponse_t -- to the canonical format. This is complemented
+ by a parse function which converts a packet in canonical format to a
+ getaddrbyname response structure.
+
+ These structures are defined in \link lwres.h <lwres/lwres.h>.\endlink They are shown below.
+
+\code
+#define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
+
+typedef struct lwres_addr lwres_addr_t;
+typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint32_t addrtypes;
+ lwres_uint16_t namelen;
+ char *name;
+} lwres_gabnrequest_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+\endcode
+
+ lwres_gabnrequest_render() uses resolver context ctx to convert
+ getaddrbyname request structure req to canonical format. The packet
+ header structure pkt is initialised and transferred to buffer b. The
+ contents of *req are then appended to the buffer in canonical format.
+ lwres_gabnresponse_render() performs the same task, except it converts
+ a getaddrbyname response structure lwres_gabnresponse_t to the
+ lightweight resolver's canonical format.
+
+ lwres_gabnrequest_parse() uses context ctx to convert the contents of
+ packet pkt to a lwres_gabnrequest_t structure. Buffer b provides space
+ to be used for storing this structure. When the function succeeds, the
+ resulting lwres_gabnrequest_t is made available through *structp.
+ lwres_gabnresponse_parse() offers the same semantics as
+ lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t
+ structure.
+
+ lwres_gabnresponse_free() and lwres_gabnrequest_free() release the
+ memory in resolver context ctx that was allocated to the
+ lwres_gabnresponse_t or lwres_gabnrequest_t structures referenced via
+ structp. Any memory associated with ancillary buffers and strings for
+ those structures is also discarded.
+
+\section lwres_gabn_return Return Values
+
+ The getaddrbyname opcode functions lwres_gabnrequest_render(),
+ lwres_gabnresponse_render() lwres_gabnrequest_parse() and
+ lwres_gabnresponse_parse() all return #LWRES_R_SUCCESS on success. They
+ return #LWRES_R_NOMEMORY if memory allocation fails.
+ #LWRES_R_UNEXPECTEDEND is returned if the available space in the buffer
+ b is too small to accommodate the packet header or the
+ lwres_gabnrequest_t and lwres_gabnresponse_t structures.
+ lwres_gabnrequest_parse() and lwres_gabnresponse_parse() will return
+ #LWRES_R_UNEXPECTEDEND if the buffer is not empty after decoding the
+ received packet. These functions will return #LWRES_R_FAILURE if
+ pktflags in the packet header structure #lwres_lwpacket_t indicate that
+ the packet is not a response to an earlier query.
+
+\section lwres_gabn_see See Also
+
+ \link lwpacket.c lwres_lwpacket \endlink
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwpacket.h>
+#include <lwres/lwres.h>
+#include <lwres/result.h>
+
+#include "context_p.h"
+#include "assert_p.h"
+
+/*% uses resolver context ctx to convert getaddrbyname request structure req to canonical format. */
+lwres_result_t
+lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+ lwres_uint16_t datalen;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(req->name != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ datalen = strlen(req->name);
+
+ payload_length = 4 + 4 + 2 + req->namelen + 1;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
+ pkt->result = 0;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+
+ /*
+ * Flags.
+ */
+ lwres_buffer_putuint32(b, req->flags);
+
+ /*
+ * Address types we'll accept.
+ */
+ lwres_buffer_putuint32(b, req->addrtypes);
+
+ /*
+ * Put the length and the data. We know this will fit because we
+ * just checked for it.
+ */
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->name, datalen);
+ lwres_buffer_putuint8(b, 0); /* trailing NUL */
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+/*% converts a getaddrbyname response structure lwres_gabnresponse_t to the lightweight resolver's canonical format. */
+lwres_result_t
+lwres_gabnresponse_render(lwres_context_t *ctx, lwres_gabnresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+ lwres_uint16_t datalen;
+ lwres_addr_t *addr;
+ int x;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ /* naliases, naddrs */
+ payload_length = 4 + 2 + 2;
+ /* real name encoding */
+ payload_length += 2 + req->realnamelen + 1;
+ /* each alias */
+ for (x = 0; x < req->naliases; x++)
+ payload_length += 2 + req->aliaslen[x] + 1;
+ /* each address */
+ x = 0;
+ addr = LWRES_LIST_HEAD(req->addrs);
+ while (addr != NULL) {
+ payload_length += 4 + 2;
+ payload_length += addr->length;
+ addr = LWRES_LIST_NEXT(addr, link);
+ x++;
+ }
+ INSIST(x == req->naddrs);
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ /*
+ * Check space needed here.
+ */
+ INSIST(SPACE_OK(b, payload_length));
+
+ /* Flags. */
+ lwres_buffer_putuint32(b, req->flags);
+
+ /* encode naliases and naddrs */
+ lwres_buffer_putuint16(b, req->naliases);
+ lwres_buffer_putuint16(b, req->naddrs);
+
+ /* encode the real name */
+ datalen = req->realnamelen;
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
+ lwres_buffer_putuint8(b, 0);
+
+ /* encode the aliases */
+ for (x = 0; x < req->naliases; x++) {
+ datalen = req->aliaslen[x];
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->aliases[x],
+ datalen);
+ lwres_buffer_putuint8(b, 0);
+ }
+
+ /* encode the addresses */
+ addr = LWRES_LIST_HEAD(req->addrs);
+ while (addr != NULL) {
+ lwres_buffer_putuint32(b, addr->family);
+ lwres_buffer_putuint16(b, addr->length);
+ lwres_buffer_putmem(b, addr->address, addr->length);
+ addr = LWRES_LIST_NEXT(addr, link);
+ }
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+ INSIST(LWRES_BUFFER_USEDCOUNT(b) == pkt->length);
+
+ return (LWRES_R_SUCCESS);
+}
+/*% Uses context ctx to convert the contents of packet pkt to a lwres_gabnrequest_t structure. */
+lwres_result_t
+lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gabnrequest_t **structp)
+{
+ int ret;
+ char *name;
+ lwres_gabnrequest_t *gabn;
+ lwres_uint32_t addrtypes;
+ lwres_uint32_t flags;
+ lwres_uint16_t namelen;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
+ return (LWRES_R_FAILURE);
+
+ if (!SPACE_REMAINING(b, 4 + 4))
+ return (LWRES_R_UNEXPECTEDEND);
+
+ flags = lwres_buffer_getuint32(b);
+ addrtypes = lwres_buffer_getuint32(b);
+
+ /*
+ * Pull off the name itself
+ */
+ ret = lwres_string_parse(b, &name, &namelen);
+ if (ret != LWRES_R_SUCCESS)
+ return (ret);
+
+ if (LWRES_BUFFER_REMAINING(b) != 0)
+ return (LWRES_R_TRAILINGDATA);
+
+ gabn = CTXMALLOC(sizeof(lwres_gabnrequest_t));
+ if (gabn == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ gabn->flags = flags;
+ gabn->addrtypes = addrtypes;
+ gabn->name = name;
+ gabn->namelen = namelen;
+
+ *structp = gabn;
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Offers the same semantics as lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t structure. */
+
+lwres_result_t
+lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gabnresponse_t **structp)
+{
+ lwres_result_t ret;
+ unsigned int x;
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ lwres_gabnresponse_t *gabn;
+ lwres_addrlist_t addrlist;
+ lwres_addr_t *addr;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ gabn = NULL;
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
+ return (LWRES_R_FAILURE);
+
+ /*
+ * Pull off the name itself
+ */
+ if (!SPACE_REMAINING(b, 4 + 2 + 2))
+ return (LWRES_R_UNEXPECTEDEND);
+ flags = lwres_buffer_getuint32(b);
+ naliases = lwres_buffer_getuint16(b);
+ naddrs = lwres_buffer_getuint16(b);
+
+ gabn = CTXMALLOC(sizeof(lwres_gabnresponse_t));
+ if (gabn == NULL)
+ return (LWRES_R_NOMEMORY);
+ gabn->aliases = NULL;
+ gabn->aliaslen = NULL;
+ LWRES_LIST_INIT(gabn->addrs);
+ gabn->base = NULL;
+
+ gabn->flags = flags;
+ gabn->naliases = naliases;
+ gabn->naddrs = naddrs;
+
+ LWRES_LIST_INIT(addrlist);
+
+ if (naliases > 0) {
+ gabn->aliases = CTXMALLOC(sizeof(char *) * naliases);
+ if (gabn->aliases == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ gabn->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases);
+ if (gabn->aliaslen == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+ }
+
+ for (x = 0; x < naddrs; x++) {
+ addr = CTXMALLOC(sizeof(lwres_addr_t));
+ if (addr == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+ LWRES_LINK_INIT(addr, link);
+ LWRES_LIST_APPEND(addrlist, addr, link);
+ }
+
+ /*
+ * Now, pull off the real name.
+ */
+ ret = lwres_string_parse(b, &gabn->realname, &gabn->realnamelen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Parse off the aliases.
+ */
+ for (x = 0; x < gabn->naliases; x++) {
+ ret = lwres_string_parse(b, &gabn->aliases[x],
+ &gabn->aliaslen[x]);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ }
+
+ /*
+ * Pull off the addresses. We already strung the linked list
+ * up above.
+ */
+ addr = LWRES_LIST_HEAD(addrlist);
+ for (x = 0; x < gabn->naddrs; x++) {
+ INSIST(addr != NULL);
+ ret = lwres_addr_parse(b, addr);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ addr = LWRES_LIST_NEXT(addr, link);
+ }
+
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ gabn->addrs = addrlist;
+
+ *structp = gabn;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (gabn != NULL) {
+ if (gabn->aliases != NULL)
+ CTXFREE(gabn->aliases, sizeof(char *) * naliases);
+ if (gabn->aliaslen != NULL)
+ CTXFREE(gabn->aliaslen,
+ sizeof(lwres_uint16_t) * naliases);
+ addr = LWRES_LIST_HEAD(addrlist);
+ while (addr != NULL) {
+ LWRES_LIST_UNLINK(addrlist, addr, link);
+ CTXFREE(addr, sizeof(lwres_addr_t));
+ addr = LWRES_LIST_HEAD(addrlist);
+ }
+ CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
+ }
+
+ return (ret);
+}
+
+/*% Release the memory in resolver context ctx that was allocated to the lwres_gabnrequest_t. */
+void
+lwres_gabnrequest_free(lwres_context_t *ctx, lwres_gabnrequest_t **structp)
+{
+ lwres_gabnrequest_t *gabn;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ gabn = *structp;
+ *structp = NULL;
+
+ CTXFREE(gabn, sizeof(lwres_gabnrequest_t));
+}
+
+/*% Release the memory in resolver context ctx that was allocated to the lwres_gabnresponse_t. */
+void
+lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp)
+{
+ lwres_gabnresponse_t *gabn;
+ lwres_addr_t *addr;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ gabn = *structp;
+ *structp = NULL;
+
+ if (gabn->naliases > 0) {
+ CTXFREE(gabn->aliases, sizeof(char *) * gabn->naliases);
+ CTXFREE(gabn->aliaslen,
+ sizeof(lwres_uint16_t) * gabn->naliases);
+ }
+ addr = LWRES_LIST_HEAD(gabn->addrs);
+ while (addr != NULL) {
+ LWRES_LIST_UNLINK(gabn->addrs, addr, link);
+ CTXFREE(addr, sizeof(lwres_addr_t));
+ addr = LWRES_LIST_HEAD(gabn->addrs);
+ }
+ if (gabn->base != NULL)
+ CTXFREE(gabn->base, gabn->baselen);
+ CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
+}
diff --git a/lib/lwres/lwres_gnba.c b/lib/lwres/lwres_gnba.c
new file mode 100644
index 0000000..7627385
--- /dev/null
+++ b/lib/lwres/lwres_gnba.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2002 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwres_gnba.c,v 1.23.18.4 2007/09/26 23:46:34 tbox Exp $ */
+
+/*! \file lwres_gnba.c
+ These are low-level routines for creating and parsing lightweight
+ resolver address-to-name lookup request and response messages.
+
+ There are four main functions for the getnamebyaddr opcode. One
+ render function converts a getnamebyaddr request structure --
+ lwres_gnbarequest_t -- to the lightweight resolver's canonical
+ format. It is complemented by a parse function that converts a
+ packet in this canonical format to a getnamebyaddr request
+ structure. Another render function converts the getnamebyaddr
+ response structure -- lwres_gnbaresponse_t to the canonical format.
+ This is complemented by a parse function which converts a packet in
+ canonical format to a getnamebyaddr response structure.
+
+ These structures are defined in \link lwres.h <lwres/lwres.h.>\endlink They are shown
+ below.
+
+\code
+#define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_addr_t addr;
+} lwres_gnbarequest_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ void *base;
+ size_t baselen;
+} lwres_gnbaresponse_t;
+\endcode
+
+ lwres_gnbarequest_render() uses resolver context ctx to convert
+ getnamebyaddr request structure req to canonical format. The packet
+ header structure pkt is initialised and transferred to buffer b.
+ The contents of *req are then appended to the buffer in canonical
+ format. lwres_gnbaresponse_render() performs the same task, except
+ it converts a getnamebyaddr response structure lwres_gnbaresponse_t
+ to the lightweight resolver's canonical format.
+
+ lwres_gnbarequest_parse() uses context ctx to convert the contents
+ of packet pkt to a lwres_gnbarequest_t structure. Buffer b provides
+ space to be used for storing this structure. When the function
+ succeeds, the resulting lwres_gnbarequest_t is made available
+ through *structp. lwres_gnbaresponse_parse() offers the same
+semantics as lwres_gnbarequest_parse() except it yields a
+ lwres_gnbaresponse_t structure.
+
+ lwres_gnbaresponse_free() and lwres_gnbarequest_free() release the
+ memory in resolver context ctx that was allocated to the
+ lwres_gnbaresponse_t or lwres_gnbarequest_t structures referenced
+ via structp. Any memory associated with ancillary buffers and
+ strings for those structures is also discarded.
+
+\section lwres_gbna_return Return Values
+
+ The getnamebyaddr opcode functions lwres_gnbarequest_render(),
+ lwres_gnbaresponse_render() lwres_gnbarequest_parse() and
+ lwres_gnbaresponse_parse() all return #LWRES_R_SUCCESS on success.
+ They return #LWRES_R_NOMEMORY if memory allocation fails.
+ #LWRES_R_UNEXPECTEDEND is returned if the available space in the
+ buffer b is too small to accommodate the packet header or the
+ lwres_gnbarequest_t and lwres_gnbaresponse_t structures.
+ lwres_gnbarequest_parse() and lwres_gnbaresponse_parse() will
+ return #LWRES_R_UNEXPECTEDEND if the buffer is not empty after
+ decoding the received packet. These functions will return
+ #LWRES_R_FAILURE if pktflags in the packet header structure
+ #lwres_lwpacket_t indicate that the packet is not a response to an
+ earlier query.
+
+\section lwres_gbna_see See Also
+
+ \link lwpacket.c lwres_packet\endlink
+
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwpacket.h>
+#include <lwres/lwres.h>
+#include <lwres/result.h>
+
+#include "context_p.h"
+#include "assert_p.h"
+
+/*% Uses resolver context ctx to convert getnamebyaddr request structure req to canonical format. */
+lwres_result_t
+lwres_gnbarequest_render(lwres_context_t *ctx, lwres_gnbarequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(req->addr.family != 0);
+ REQUIRE(req->addr.length != 0);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ payload_length = 4 + 4 + 2 + + req->addr.length;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETNAMEBYADDR;
+ pkt->result = 0;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+
+ /*
+ * Put the length and the data. We know this will fit because we
+ * just checked for it.
+ */
+ lwres_buffer_putuint32(b, req->flags);
+ lwres_buffer_putuint32(b, req->addr.family);
+ lwres_buffer_putuint16(b, req->addr.length);
+ lwres_buffer_putmem(b, (unsigned char *)req->addr.address,
+ req->addr.length);
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Converts a getnamebyaddr response structure lwres_gnbaresponse_t to the lightweight resolver's canonical format. */
+lwres_result_t
+lwres_gnbaresponse_render(lwres_context_t *ctx, lwres_gnbaresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+ lwres_uint16_t datalen;
+ int x;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ /*
+ * Calculate packet size.
+ */
+ payload_length = 4; /* flags */
+ payload_length += 2; /* naliases */
+ payload_length += 2 + req->realnamelen + 1; /* real name encoding */
+ for (x = 0; x < req->naliases; x++) /* each alias */
+ payload_length += 2 + req->aliaslen[x] + 1;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETNAMEBYADDR;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+ lwres_buffer_putuint32(b, req->flags);
+
+ /* encode naliases */
+ lwres_buffer_putuint16(b, req->naliases);
+
+ /* encode the real name */
+ datalen = req->realnamelen;
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
+ lwres_buffer_putuint8(b, 0);
+
+ /* encode the aliases */
+ for (x = 0; x < req->naliases; x++) {
+ datalen = req->aliaslen[x];
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->aliases[x],
+ datalen);
+ lwres_buffer_putuint8(b, 0);
+ }
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Uses context ctx to convert the contents of packet pkt to a lwres_gnbarequest_t structure. */
+lwres_result_t
+lwres_gnbarequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gnbarequest_t **structp)
+{
+ int ret;
+ lwres_gnbarequest_t *gnba;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
+ return (LWRES_R_FAILURE);
+
+ if (!SPACE_REMAINING(b, 4))
+ return (LWRES_R_UNEXPECTEDEND);
+
+ gnba = CTXMALLOC(sizeof(lwres_gnbarequest_t));
+ if (gnba == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ gnba->flags = lwres_buffer_getuint32(b);
+
+ ret = lwres_addr_parse(b, &gnba->addr);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ *structp = gnba;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (gnba != NULL)
+ lwres_gnbarequest_free(ctx, &gnba);
+
+ return (ret);
+}
+
+/*% Offers the same semantics as lwres_gnbarequest_parse() except it yields a lwres_gnbaresponse_t structure. */
+
+lwres_result_t
+lwres_gnbaresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gnbaresponse_t **structp)
+{
+ int ret;
+ unsigned int x;
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_gnbaresponse_t *gnba;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ gnba = NULL;
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
+ return (LWRES_R_FAILURE);
+
+ /*
+ * Pull off flags & naliases
+ */
+ if (!SPACE_REMAINING(b, 4 + 2))
+ return (LWRES_R_UNEXPECTEDEND);
+ flags = lwres_buffer_getuint32(b);
+ naliases = lwres_buffer_getuint16(b);
+
+ gnba = CTXMALLOC(sizeof(lwres_gnbaresponse_t));
+ if (gnba == NULL)
+ return (LWRES_R_NOMEMORY);
+ gnba->base = NULL;
+ gnba->aliases = NULL;
+ gnba->aliaslen = NULL;
+
+ gnba->flags = flags;
+ gnba->naliases = naliases;
+
+ if (naliases > 0) {
+ gnba->aliases = CTXMALLOC(sizeof(char *) * naliases);
+ if (gnba->aliases == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ gnba->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases);
+ if (gnba->aliaslen == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+ }
+
+ /*
+ * Now, pull off the real name.
+ */
+ ret = lwres_string_parse(b, &gnba->realname, &gnba->realnamelen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Parse off the aliases.
+ */
+ for (x = 0; x < gnba->naliases; x++) {
+ ret = lwres_string_parse(b, &gnba->aliases[x],
+ &gnba->aliaslen[x]);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ }
+
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ *structp = gnba;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (gnba != NULL) {
+ if (gnba->aliases != NULL)
+ CTXFREE(gnba->aliases, sizeof(char *) * naliases);
+ if (gnba->aliaslen != NULL)
+ CTXFREE(gnba->aliaslen,
+ sizeof(lwres_uint16_t) * naliases);
+ CTXFREE(gnba, sizeof(lwres_gnbaresponse_t));
+ }
+
+ return (ret);
+}
+
+/*% Release the memory in resolver context ctx that was allocated to the lwres_gnbarequest_t. */
+void
+lwres_gnbarequest_free(lwres_context_t *ctx, lwres_gnbarequest_t **structp)
+{
+ lwres_gnbarequest_t *gnba;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ gnba = *structp;
+ *structp = NULL;
+
+ CTXFREE(gnba, sizeof(lwres_gnbarequest_t));
+}
+
+/*% Release the memory in resolver context ctx that was allocated to the lwres_gnbaresponse_t. */
+void
+lwres_gnbaresponse_free(lwres_context_t *ctx, lwres_gnbaresponse_t **structp)
+{
+ lwres_gnbaresponse_t *gnba;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ gnba = *structp;
+ *structp = NULL;
+
+ if (gnba->naliases > 0) {
+ CTXFREE(gnba->aliases, sizeof(char *) * gnba->naliases);
+ CTXFREE(gnba->aliaslen,
+ sizeof(lwres_uint16_t) * gnba->naliases);
+ }
+ if (gnba->base != NULL)
+ CTXFREE(gnba->base, gnba->baselen);
+ CTXFREE(gnba, sizeof(lwres_gnbaresponse_t));
+}
diff --git a/lib/lwres/lwres_grbn.c b/lib/lwres/lwres_grbn.c
new file mode 100644
index 0000000..976708e
--- /dev/null
+++ b/lib/lwres/lwres_grbn.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2004, 2005 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: lwres_grbn.c,v 1.6.18.2 2005/04/29 00:17:20 marka Exp $ */
+
+/*! \file lwres_grbn.c
+
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwpacket.h>
+#include <lwres/lwres.h>
+#include <lwres/result.h>
+
+#include "context_p.h"
+#include "assert_p.h"
+
+/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
+lwres_result_t
+lwres_grbnrequest_render(lwres_context_t *ctx, lwres_grbnrequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+ lwres_uint16_t datalen;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(req->name != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ datalen = strlen(req->name);
+
+ payload_length = 4 + 2 + 2 + 2 + req->namelen + 1;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETRDATABYNAME;
+ pkt->result = 0;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+
+ /*
+ * Flags.
+ */
+ lwres_buffer_putuint32(b, req->flags);
+
+ /*
+ * Class.
+ */
+ lwres_buffer_putuint16(b, req->rdclass);
+
+ /*
+ * Type.
+ */
+ lwres_buffer_putuint16(b, req->rdtype);
+
+ /*
+ * Put the length and the data. We know this will fit because we
+ * just checked for it.
+ */
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->name, datalen);
+ lwres_buffer_putuint8(b, 0); /* trailing NUL */
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
+lwres_result_t
+lwres_grbnresponse_render(lwres_context_t *ctx, lwres_grbnresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+ lwres_uint16_t datalen;
+ int x;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ /* flags, class, type, ttl, nrdatas, nsigs */
+ payload_length = 4 + 2 + 2 + 4 + 2 + 2;
+ /* real name encoding */
+ payload_length += 2 + req->realnamelen + 1;
+ /* each rr */
+ for (x = 0; x < req->nrdatas; x++)
+ payload_length += 2 + req->rdatalen[x];
+ for (x = 0; x < req->nsigs; x++)
+ payload_length += 2 + req->siglen[x];
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETRDATABYNAME;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ /*
+ * Check space needed here.
+ */
+ INSIST(SPACE_OK(b, payload_length));
+
+ /* Flags. */
+ lwres_buffer_putuint32(b, req->flags);
+
+ /* encode class, type, ttl, and nrdatas */
+ lwres_buffer_putuint16(b, req->rdclass);
+ lwres_buffer_putuint16(b, req->rdtype);
+ lwres_buffer_putuint32(b, req->ttl);
+ lwres_buffer_putuint16(b, req->nrdatas);
+ lwres_buffer_putuint16(b, req->nsigs);
+
+ /* encode the real name */
+ datalen = req->realnamelen;
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
+ lwres_buffer_putuint8(b, 0);
+
+ /* encode the rdatas */
+ for (x = 0; x < req->nrdatas; x++) {
+ datalen = req->rdatalen[x];
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, req->rdatas[x], datalen);
+ }
+
+ /* encode the signatures */
+ for (x = 0; x < req->nsigs; x++) {
+ datalen = req->siglen[x];
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, req->sigs[x], datalen);
+ }
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+ INSIST(LWRES_BUFFER_USEDCOUNT(b) == pkt->length);
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
+lwres_result_t
+lwres_grbnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_grbnrequest_t **structp)
+{
+ int ret;
+ char *name;
+ lwres_grbnrequest_t *grbn;
+ lwres_uint32_t flags;
+ lwres_uint16_t rdclass, rdtype;
+ lwres_uint16_t namelen;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
+ return (LWRES_R_FAILURE);
+
+ if (!SPACE_REMAINING(b, 4 + 2 + 2))
+ return (LWRES_R_UNEXPECTEDEND);
+
+ /*
+ * Pull off the flags, class, and type.
+ */
+ flags = lwres_buffer_getuint32(b);
+ rdclass = lwres_buffer_getuint16(b);
+ rdtype = lwres_buffer_getuint16(b);
+
+ /*
+ * Pull off the name itself
+ */
+ ret = lwres_string_parse(b, &name, &namelen);
+ if (ret != LWRES_R_SUCCESS)
+ return (ret);
+
+ if (LWRES_BUFFER_REMAINING(b) != 0)
+ return (LWRES_R_TRAILINGDATA);
+
+ grbn = CTXMALLOC(sizeof(lwres_grbnrequest_t));
+ if (grbn == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ grbn->flags = flags;
+ grbn->rdclass = rdclass;
+ grbn->rdtype = rdtype;
+ grbn->name = name;
+ grbn->namelen = namelen;
+
+ *structp = grbn;
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
+lwres_result_t
+lwres_grbnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_grbnresponse_t **structp)
+{
+ lwres_result_t ret;
+ unsigned int x;
+ lwres_uint32_t flags;
+ lwres_uint16_t rdclass, rdtype;
+ lwres_uint32_t ttl;
+ lwres_uint16_t nrdatas, nsigs;
+ lwres_grbnresponse_t *grbn;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ grbn = NULL;
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
+ return (LWRES_R_FAILURE);
+
+ /*
+ * Pull off the flags, class, type, ttl, nrdatas, and nsigs
+ */
+ if (!SPACE_REMAINING(b, 4 + 2 + 2 + 4 + 2 + 2))
+ return (LWRES_R_UNEXPECTEDEND);
+ flags = lwres_buffer_getuint32(b);
+ rdclass = lwres_buffer_getuint16(b);
+ rdtype = lwres_buffer_getuint16(b);
+ ttl = lwres_buffer_getuint32(b);
+ nrdatas = lwres_buffer_getuint16(b);
+ nsigs = lwres_buffer_getuint16(b);
+
+ /*
+ * Pull off the name itself
+ */
+
+ grbn = CTXMALLOC(sizeof(lwres_grbnresponse_t));
+ if (grbn == NULL)
+ return (LWRES_R_NOMEMORY);
+ grbn->rdatas = NULL;
+ grbn->rdatalen = NULL;
+ grbn->sigs = NULL;
+ grbn->siglen = NULL;
+ grbn->base = NULL;
+
+ grbn->flags = flags;
+ grbn->rdclass = rdclass;
+ grbn->rdtype = rdtype;
+ grbn->ttl = ttl;
+ grbn->nrdatas = nrdatas;
+ grbn->nsigs = nsigs;
+
+ if (nrdatas > 0) {
+ grbn->rdatas = CTXMALLOC(sizeof(char *) * nrdatas);
+ if (grbn->rdatas == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ grbn->rdatalen = CTXMALLOC(sizeof(lwres_uint16_t) * nrdatas);
+ if (grbn->rdatalen == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+ }
+
+ if (nsigs > 0) {
+ grbn->sigs = CTXMALLOC(sizeof(char *) * nsigs);
+ if (grbn->sigs == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ grbn->siglen = CTXMALLOC(sizeof(lwres_uint16_t) * nsigs);
+ if (grbn->siglen == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+ }
+
+ /*
+ * Now, pull off the real name.
+ */
+ ret = lwres_string_parse(b, &grbn->realname, &grbn->realnamelen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Parse off the rdatas.
+ */
+ for (x = 0; x < grbn->nrdatas; x++) {
+ ret = lwres_data_parse(b, &grbn->rdatas[x],
+ &grbn->rdatalen[x]);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ }
+
+ /*
+ * Parse off the signatures.
+ */
+ for (x = 0; x < grbn->nsigs; x++) {
+ ret = lwres_data_parse(b, &grbn->sigs[x], &grbn->siglen[x]);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ }
+
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ *structp = grbn;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (grbn != NULL) {
+ if (grbn->rdatas != NULL)
+ CTXFREE(grbn->rdatas, sizeof(char *) * nrdatas);
+ if (grbn->rdatalen != NULL)
+ CTXFREE(grbn->rdatalen,
+ sizeof(lwres_uint16_t) * nrdatas);
+ if (grbn->sigs != NULL)
+ CTXFREE(grbn->sigs, sizeof(char *) * nsigs);
+ if (grbn->siglen != NULL)
+ CTXFREE(grbn->siglen, sizeof(lwres_uint16_t) * nsigs);
+ CTXFREE(grbn, sizeof(lwres_grbnresponse_t));
+ }
+
+ return (ret);
+}
+
+/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
+void
+lwres_grbnrequest_free(lwres_context_t *ctx, lwres_grbnrequest_t **structp)
+{
+ lwres_grbnrequest_t *grbn;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ grbn = *structp;
+ *structp = NULL;
+
+ CTXFREE(grbn, sizeof(lwres_grbnrequest_t));
+}
+
+/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
+void
+lwres_grbnresponse_free(lwres_context_t *ctx, lwres_grbnresponse_t **structp)
+{
+ lwres_grbnresponse_t *grbn;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ grbn = *structp;
+ *structp = NULL;
+
+ if (grbn->nrdatas > 0) {
+ CTXFREE(grbn->rdatas, sizeof(char *) * grbn->nrdatas);
+ CTXFREE(grbn->rdatalen,
+ sizeof(lwres_uint16_t) * grbn->nrdatas);
+ }
+ if (grbn->nsigs > 0) {
+ CTXFREE(grbn->sigs, sizeof(char *) * grbn->nsigs);
+ CTXFREE(grbn->siglen, sizeof(lwres_uint16_t) * grbn->nsigs);
+ }
+ if (grbn->base != NULL)
+ CTXFREE(grbn->base, grbn->baselen);
+ CTXFREE(grbn, sizeof(lwres_grbnresponse_t));
+}
diff --git a/lib/lwres/lwres_noop.c b/lib/lwres/lwres_noop.c
new file mode 100644
index 0000000..e76bc4d
--- /dev/null
+++ b/lib/lwres/lwres_noop.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2004, 2005 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: lwres_noop.c,v 1.15.18.2 2005/04/29 00:17:20 marka Exp $ */
+
+/*! \file */
+
+/**
+ * These are low-level routines for creating and parsing lightweight
+ * resolver no-op request and response messages.
+ *
+ * The no-op message is analogous to a ping packet: a packet is sent to
+ * the resolver daemon and is simply echoed back. The opcode is intended
+ * to allow a client to determine if the server is operational or not.
+ *
+ * There are four main functions for the no-op opcode. One render
+ * function converts a no-op request structure -- lwres_nooprequest_t --
+ * to the lighweight resolver's canonical format. It is complemented by a
+ * parse function that converts a packet in this canonical format to a
+ * no-op request structure. Another render function converts the no-op
+ * response structure -- lwres_noopresponse_t to the canonical format.
+ * This is complemented by a parse function which converts a packet in
+ * canonical format to a no-op response structure.
+ *
+ * These structures are defined in \link lwres.h <lwres/lwres.h.> \endlink They are shown below.
+ *
+ * \code
+ * #define LWRES_OPCODE_NOOP 0x00000000U
+ *
+ * typedef struct {
+ * lwres_uint16_t datalength;
+ * unsigned char *data;
+ * } lwres_nooprequest_t;
+ *
+ * typedef struct {
+ * lwres_uint16_t datalength;
+ * unsigned char *data;
+ * } lwres_noopresponse_t;
+ * \endcode
+ *
+ * Although the structures have different types, they are identical. This
+ * is because the no-op opcode simply echos whatever data was sent: the
+ * response is therefore identical to the request.
+ *
+ * lwres_nooprequest_render() uses resolver context ctx to convert no-op
+ * request structure req to canonical format. The packet header structure
+ * pkt is initialised and transferred to buffer b. The contents of *req
+ * are then appended to the buffer in canonical format.
+ * lwres_noopresponse_render() performs the same task, except it converts
+ * a no-op response structure lwres_noopresponse_t to the lightweight
+ * resolver's canonical format.
+ *
+ * lwres_nooprequest_parse() uses context ctx to convert the contents of
+ * packet pkt to a lwres_nooprequest_t structure. Buffer b provides space
+ * to be used for storing this structure. When the function succeeds, the
+ * resulting lwres_nooprequest_t is made available through *structp.
+ * lwres_noopresponse_parse() offers the same semantics as
+ * lwres_nooprequest_parse() except it yields a lwres_noopresponse_t
+ * structure.
+ *
+ * lwres_noopresponse_free() and lwres_nooprequest_free() release the
+ * memory in resolver context ctx that was allocated to the
+ * lwres_noopresponse_t or lwres_nooprequest_t structures referenced via
+ * structp.
+ *
+ * \section lwres_noop_return Return Values
+ *
+ * The no-op opcode functions lwres_nooprequest_render(),
+ * lwres_noopresponse_render() lwres_nooprequest_parse() and
+ * lwres_noopresponse_parse() all return #LWRES_R_SUCCESS on success. They
+ * return #LWRES_R_NOMEMORY if memory allocation fails.
+ * #LWRES_R_UNEXPECTEDEND is returned if the available space in the buffer
+ * b is too small to accommodate the packet header or the
+ * lwres_nooprequest_t and lwres_noopresponse_t structures.
+ * lwres_nooprequest_parse() and lwres_noopresponse_parse() will return
+ * #LWRES_R_UNEXPECTEDEND if the buffer is not empty after decoding the
+ * received packet. These functions will return #LWRES_R_FAILURE if
+ * pktflags in the packet header structure #lwres_lwpacket_t indicate that
+ * the packet is not a response to an earlier query.
+ *
+ * \section lwres_noop_see See Also
+ *
+ * lwpacket.c
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwpacket.h>
+#include <lwres/lwres.h>
+#include <lwres/result.h>
+
+#include "context_p.h"
+#include "assert_p.h"
+
+/*% Uses resolver context ctx to convert no-op request structure req to canonical format. */
+lwres_result_t
+lwres_nooprequest_render(lwres_context_t *ctx, lwres_nooprequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ payload_length = sizeof(lwres_uint16_t) + req->datalength;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_NOOP;
+ pkt->result = 0;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+
+ /*
+ * Put the length and the data. We know this will fit because we
+ * just checked for it.
+ */
+ lwres_buffer_putuint16(b, req->datalength);
+ lwres_buffer_putmem(b, req->data, req->datalength);
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Converts a no-op response structure lwres_noopresponse_t to the lightweight resolver's canonical format. */
+
+lwres_result_t
+lwres_noopresponse_render(lwres_context_t *ctx, lwres_noopresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ payload_length = sizeof(lwres_uint16_t) + req->datalength;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_NOOP;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+
+ /*
+ * Put the length and the data. We know this will fit because we
+ * just checked for it.
+ */
+ lwres_buffer_putuint16(b, req->datalength);
+ lwres_buffer_putmem(b, req->data, req->datalength);
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Uses context ctx to convert the contents of packet pkt to a lwres_nooprequest_t structure. */
+lwres_result_t
+lwres_nooprequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_nooprequest_t **structp)
+{
+ int ret;
+ lwres_nooprequest_t *req;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
+ return (LWRES_R_FAILURE);
+
+ req = CTXMALLOC(sizeof(lwres_nooprequest_t));
+ if (req == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ if (!SPACE_REMAINING(b, sizeof(lwres_uint16_t))) {
+ ret = LWRES_R_UNEXPECTEDEND;
+ goto out;
+ }
+ req->datalength = lwres_buffer_getuint16(b);
+
+ if (!SPACE_REMAINING(b, req->datalength)) {
+ ret = LWRES_R_UNEXPECTEDEND;
+ goto out;
+ }
+ req->data = b->base + b->current;
+ lwres_buffer_forward(b, req->datalength);
+
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ /* success! */
+ *structp = req;
+ return (LWRES_R_SUCCESS);
+
+ /* Error return */
+ out:
+ CTXFREE(req, sizeof(lwres_nooprequest_t));
+ return (ret);
+}
+
+/*% Offers the same semantics as lwres_nooprequest_parse() except it yields a lwres_noopresponse_t structure. */
+lwres_result_t
+lwres_noopresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_noopresponse_t **structp)
+{
+ int ret;
+ lwres_noopresponse_t *req;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
+ return (LWRES_R_FAILURE);
+
+ req = CTXMALLOC(sizeof(lwres_noopresponse_t));
+ if (req == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ if (!SPACE_REMAINING(b, sizeof(lwres_uint16_t))) {
+ ret = LWRES_R_UNEXPECTEDEND;
+ goto out;
+ }
+ req->datalength = lwres_buffer_getuint16(b);
+
+ if (!SPACE_REMAINING(b, req->datalength)) {
+ ret = LWRES_R_UNEXPECTEDEND;
+ goto out;
+ }
+ req->data = b->base + b->current;
+
+ lwres_buffer_forward(b, req->datalength);
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ /* success! */
+ *structp = req;
+ return (LWRES_R_SUCCESS);
+
+ /* Error return */
+ out:
+ CTXFREE(req, sizeof(lwres_noopresponse_t));
+ return (ret);
+}
+
+/*% Release the memory in resolver context ctx. */
+void
+lwres_noopresponse_free(lwres_context_t *ctx, lwres_noopresponse_t **structp)
+{
+ lwres_noopresponse_t *noop;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ noop = *structp;
+ *structp = NULL;
+
+ CTXFREE(noop, sizeof(lwres_noopresponse_t));
+}
+
+/*% Release the memory in resolver context ctx. */
+void
+lwres_nooprequest_free(lwres_context_t *ctx, lwres_nooprequest_t **structp)
+{
+ lwres_nooprequest_t *noop;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ noop = *structp;
+ *structp = NULL;
+
+ CTXFREE(noop, sizeof(lwres_nooprequest_t));
+}
diff --git a/lib/lwres/lwresutil.c b/lib/lwres/lwresutil.c
new file mode 100644
index 0000000..6d6764f
--- /dev/null
+++ b/lib/lwres/lwresutil.c
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2004, 2005 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: lwresutil.c,v 1.30.18.2 2005/04/29 00:17:20 marka Exp $ */
+
+/*! \file */
+
+/**
+ * lwres_string_parse() retrieves a DNS-encoded string starting the
+ * current pointer of lightweight resolver buffer b: i.e. b->current.
+ * When the function returns, the address of the first byte of the
+ * encoded string is returned via *c and the length of that string is
+ * given by *len. The buffer's current pointer is advanced to point at
+ * the character following the string length, the encoded string, and
+ * the trailing NULL character.
+ *
+ * lwres_addr_parse() extracts an address from the buffer b. The
+ * buffer's current pointer b->current is presumed to point at an
+ * encoded address: the address preceded by a 32-bit protocol family
+ * identifier and a 16-bit length field. The encoded address is copied
+ * to addr->address and addr->length indicates the size in bytes of
+ * the address that was copied. b->current is advanced to point at the
+ * next byte of available data in the buffer following the encoded
+ * address.
+ *
+ * lwres_getaddrsbyname() and lwres_getnamebyaddr() use the
+ * lwres_gnbaresponse_t structure defined below:
+ *
+ * \code
+ * typedef struct {
+ * lwres_uint32_t flags;
+ * lwres_uint16_t naliases;
+ * lwres_uint16_t naddrs;
+ * char *realname;
+ * char **aliases;
+ * lwres_uint16_t realnamelen;
+ * lwres_uint16_t *aliaslen;
+ * lwres_addrlist_t addrs;
+ * void *base;
+ * size_t baselen;
+ * } lwres_gabnresponse_t;
+ * \endcode
+ *
+ * The contents of this structure are not manipulated directly but
+ * they are controlled through the \link lwres_gabn.c lwres_gabn*\endlink functions.
+ *
+ * The lightweight resolver uses lwres_getaddrsbyname() to perform
+ * foward lookups. Hostname name is looked up using the resolver
+ * context ctx for memory allocation. addrtypes is a bitmask
+ * indicating which type of addresses are to be looked up. Current
+ * values for this bitmask are #LWRES_ADDRTYPE_V4 for IPv4 addresses
+ * and #LWRES_ADDRTYPE_V6 for IPv6 addresses. Results of the lookup are
+ * returned in *structp.
+ *
+ * lwres_getnamebyaddr() performs reverse lookups. Resolver context
+ * ctx is used for memory allocation. The address type is indicated by
+ * addrtype: #LWRES_ADDRTYPE_V4 or #LWRES_ADDRTYPE_V6. The address to be
+ * looked up is given by addr and its length is addrlen bytes. The
+ * result of the function call is made available through *structp.
+ *
+ * \section lwresutil_return Return Values
+ *
+ * Successful calls to lwres_string_parse() and lwres_addr_parse()
+ * return #LWRES_R_SUCCESS. Both functions return #LWRES_R_FAILURE if
+ * the buffer is corrupt or #LWRES_R_UNEXPECTEDEND if the buffer has
+ * less space than expected for the components of the encoded string
+ * or address.
+ *
+ * lwres_getaddrsbyname() returns #LWRES_R_SUCCESS on success and it
+ * returns #LWRES_R_NOTFOUND if the hostname name could not be found.
+ *
+ * #LWRES_R_SUCCESS is returned by a successful call to
+ * lwres_getnamebyaddr().
+ *
+ * Both lwres_getaddrsbyname() and lwres_getnamebyaddr() return
+ * #LWRES_R_NOMEMORY when memory allocation requests fail and
+ * #LWRES_R_UNEXPECTEDEND if the buffers used for sending queries and
+ * receiving replies are too small.
+ *
+ * \section lwresutil_see See Also
+ *
+ * lwbuffer.c, lwres_gabn.c
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwres.h>
+#include <lwres/result.h>
+
+#include "assert_p.h"
+#include "context_p.h"
+
+/*% Parse data. */
+/*!
+ * Requires:
+ *
+ * The "current" pointer in "b" points to encoded raw data.
+ *
+ * Ensures:
+ *
+ * The address of the first byte of the data is returned via "p",
+ * and the length is returned via "len". If NULL, they are not
+ * set.
+ *
+ * On return, the current pointer of "b" will point to the character
+ * following the data length and the data.
+ *
+ */
+lwres_result_t
+lwres_data_parse(lwres_buffer_t *b, unsigned char **p, lwres_uint16_t *len)
+{
+ lwres_uint16_t datalen;
+ unsigned char *data;
+
+ REQUIRE(b != NULL);
+
+ /*
+ * Pull off the length (2 bytes)
+ */
+ if (!SPACE_REMAINING(b, 2))
+ return (LWRES_R_UNEXPECTEDEND);
+ datalen = lwres_buffer_getuint16(b);
+
+ /*
+ * Set the pointer to this string to the right place, then
+ * advance the buffer pointer.
+ */
+ if (!SPACE_REMAINING(b, datalen))
+ return (LWRES_R_UNEXPECTEDEND);
+ data = b->base + b->current;
+ lwres_buffer_forward(b, datalen);
+
+ if (len != NULL)
+ *len = datalen;
+ if (p != NULL)
+ *p = data;
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Retrieves a DNS-encoded string. */
+/*!
+ * Requires:
+ *
+ * The "current" pointer in "b" point to an encoded string.
+ *
+ * Ensures:
+ *
+ * The address of the first byte of the string is returned via "c",
+ * and the length is returned via "len". If NULL, they are not
+ * set.
+ *
+ * On return, the current pointer of "b" will point to the character
+ * following the string length, the string, and the trailing NULL.
+ *
+ */
+lwres_result_t
+lwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len)
+{
+ lwres_uint16_t datalen;
+ char *string;
+
+ REQUIRE(b != NULL);
+
+ /*
+ * Pull off the length (2 bytes)
+ */
+ if (!SPACE_REMAINING(b, 2))
+ return (LWRES_R_UNEXPECTEDEND);
+ datalen = lwres_buffer_getuint16(b);
+
+ /*
+ * Set the pointer to this string to the right place, then
+ * advance the buffer pointer.
+ */
+ if (!SPACE_REMAINING(b, datalen))
+ return (LWRES_R_UNEXPECTEDEND);
+ string = (char *)b->base + b->current;
+ lwres_buffer_forward(b, datalen);
+
+ /*
+ * Skip the "must be zero" byte.
+ */
+ if (!SPACE_REMAINING(b, 1))
+ return (LWRES_R_UNEXPECTEDEND);
+ if (0 != lwres_buffer_getuint8(b))
+ return (LWRES_R_FAILURE);
+
+ if (len != NULL)
+ *len = datalen;
+ if (c != NULL)
+ *c = string;
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Extracts an address from the buffer b. */
+lwres_result_t
+lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr)
+{
+ REQUIRE(addr != NULL);
+
+ if (!SPACE_REMAINING(b, 6))
+ return (LWRES_R_UNEXPECTEDEND);
+
+ addr->family = lwres_buffer_getuint32(b);
+ addr->length = lwres_buffer_getuint16(b);
+
+ if (!SPACE_REMAINING(b, addr->length))
+ return (LWRES_R_UNEXPECTEDEND);
+ if (addr->length > LWRES_ADDR_MAXLEN)
+ return (LWRES_R_FAILURE);
+
+ lwres_buffer_getmem(b, addr->address, addr->length);
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*% Used to perform forward lookups. */
+lwres_result_t
+lwres_getaddrsbyname(lwres_context_t *ctx, const char *name,
+ lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp)
+{
+ lwres_gabnrequest_t request;
+ lwres_gabnresponse_t *response;
+ int ret;
+ int recvlen;
+ lwres_buffer_t b_in, b_out;
+ lwres_lwpacket_t pkt;
+ lwres_uint32_t serial;
+ char *buffer;
+ char target_name[1024];
+ unsigned int target_length;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(addrtypes != 0);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ b_in.base = NULL;
+ b_out.base = NULL;
+ response = NULL;
+ buffer = NULL;
+ serial = lwres_context_nextserial(ctx);
+
+ buffer = CTXMALLOC(LWRES_RECVLENGTH);
+ if (buffer == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ target_length = strlen(name);
+ if (target_length >= sizeof(target_name))
+ return (LWRES_R_FAILURE);
+ strcpy(target_name, name); /* strcpy is safe */
+
+ /*
+ * Set up our request and render it to a buffer.
+ */
+ request.flags = 0;
+ request.addrtypes = addrtypes;
+ request.name = target_name;
+ request.namelen = target_length;
+ pkt.pktflags = 0;
+ pkt.serial = serial;
+ pkt.result = 0;
+ pkt.recvlength = LWRES_RECVLENGTH;
+
+ again:
+ ret = lwres_gabnrequest_render(ctx, &request, &pkt, &b_out);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
+ LWRES_RECVLENGTH, &recvlen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ lwres_buffer_init(&b_in, buffer, recvlen);
+ b_in.used = recvlen;
+
+ /*
+ * Parse the packet header.
+ */
+ ret = lwres_lwpacket_parseheader(&b_in, &pkt);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Sanity check.
+ */
+ if (pkt.serial != serial)
+ goto again;
+ if (pkt.opcode != LWRES_OPCODE_GETADDRSBYNAME)
+ goto again;
+
+ /*
+ * Free what we've transmitted
+ */
+ CTXFREE(b_out.base, b_out.length);
+ b_out.base = NULL;
+ b_out.length = 0;
+
+ if (pkt.result != LWRES_R_SUCCESS) {
+ ret = pkt.result;
+ goto out;
+ }
+
+ /*
+ * Parse the response.
+ */
+ ret = lwres_gabnresponse_parse(ctx, &b_in, &pkt, &response);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ response->base = buffer;
+ response->baselen = LWRES_RECVLENGTH;
+ buffer = NULL; /* don't free this below */
+
+ *structp = response;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (b_out.base != NULL)
+ CTXFREE(b_out.base, b_out.length);
+ if (buffer != NULL)
+ CTXFREE(buffer, LWRES_RECVLENGTH);
+ if (response != NULL)
+ lwres_gabnresponse_free(ctx, &response);
+
+ return (ret);
+}
+
+
+/*% Used to perform reverse lookups. */
+lwres_result_t
+lwres_getnamebyaddr(lwres_context_t *ctx, lwres_uint32_t addrtype,
+ lwres_uint16_t addrlen, const unsigned char *addr,
+ lwres_gnbaresponse_t **structp)
+{
+ lwres_gnbarequest_t request;
+ lwres_gnbaresponse_t *response;
+ int ret;
+ int recvlen;
+ lwres_buffer_t b_in, b_out;
+ lwres_lwpacket_t pkt;
+ lwres_uint32_t serial;
+ char *buffer;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(addrtype != 0);
+ REQUIRE(addrlen != 0);
+ REQUIRE(addr != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ b_in.base = NULL;
+ b_out.base = NULL;
+ response = NULL;
+ buffer = NULL;
+ serial = lwres_context_nextserial(ctx);
+
+ buffer = CTXMALLOC(LWRES_RECVLENGTH);
+ if (buffer == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ /*
+ * Set up our request and render it to a buffer.
+ */
+ request.flags = 0;
+ request.addr.family = addrtype;
+ request.addr.length = addrlen;
+ memcpy(request.addr.address, addr, addrlen);
+ pkt.pktflags = 0;
+ pkt.serial = serial;
+ pkt.result = 0;
+ pkt.recvlength = LWRES_RECVLENGTH;
+
+ again:
+ ret = lwres_gnbarequest_render(ctx, &request, &pkt, &b_out);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
+ LWRES_RECVLENGTH, &recvlen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ lwres_buffer_init(&b_in, buffer, recvlen);
+ b_in.used = recvlen;
+
+ /*
+ * Parse the packet header.
+ */
+ ret = lwres_lwpacket_parseheader(&b_in, &pkt);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Sanity check.
+ */
+ if (pkt.serial != serial)
+ goto again;
+ if (pkt.opcode != LWRES_OPCODE_GETNAMEBYADDR)
+ goto again;
+
+ /*
+ * Free what we've transmitted
+ */
+ CTXFREE(b_out.base, b_out.length);
+ b_out.base = NULL;
+ b_out.length = 0;
+
+ if (pkt.result != LWRES_R_SUCCESS) {
+ ret = pkt.result;
+ goto out;
+ }
+
+ /*
+ * Parse the response.
+ */
+ ret = lwres_gnbaresponse_parse(ctx, &b_in, &pkt, &response);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ response->base = buffer;
+ response->baselen = LWRES_RECVLENGTH;
+ buffer = NULL; /* don't free this below */
+
+ *structp = response;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (b_out.base != NULL)
+ CTXFREE(b_out.base, b_out.length);
+ if (buffer != NULL)
+ CTXFREE(buffer, LWRES_RECVLENGTH);
+ if (response != NULL)
+ lwres_gnbaresponse_free(ctx, &response);
+
+ return (ret);
+}
+
+/*% Get rdata by name. */
+lwres_result_t
+lwres_getrdatabyname(lwres_context_t *ctx, const char *name,
+ lwres_uint16_t rdclass, lwres_uint16_t rdtype,
+ lwres_uint32_t flags, lwres_grbnresponse_t **structp)
+{
+ int ret;
+ int recvlen;
+ lwres_buffer_t b_in, b_out;
+ lwres_lwpacket_t pkt;
+ lwres_uint32_t serial;
+ char *buffer;
+ lwres_grbnrequest_t request;
+ lwres_grbnresponse_t *response;
+ char target_name[1024];
+ unsigned int target_length;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ b_in.base = NULL;
+ b_out.base = NULL;
+ response = NULL;
+ buffer = NULL;
+ serial = lwres_context_nextserial(ctx);
+
+ buffer = CTXMALLOC(LWRES_RECVLENGTH);
+ if (buffer == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ target_length = strlen(name);
+ if (target_length >= sizeof(target_name))
+ return (LWRES_R_FAILURE);
+ strcpy(target_name, name); /* strcpy is safe */
+
+ /*
+ * Set up our request and render it to a buffer.
+ */
+ request.rdclass = rdclass;
+ request.rdtype = rdtype;
+ request.flags = flags;
+ request.name = target_name;
+ request.namelen = target_length;
+ pkt.pktflags = 0;
+ pkt.serial = serial;
+ pkt.result = 0;
+ pkt.recvlength = LWRES_RECVLENGTH;
+
+ again:
+ ret = lwres_grbnrequest_render(ctx, &request, &pkt, &b_out);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
+ LWRES_RECVLENGTH, &recvlen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ lwres_buffer_init(&b_in, buffer, recvlen);
+ b_in.used = recvlen;
+
+ /*
+ * Parse the packet header.
+ */
+ ret = lwres_lwpacket_parseheader(&b_in, &pkt);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Sanity check.
+ */
+ if (pkt.serial != serial)
+ goto again;
+ if (pkt.opcode != LWRES_OPCODE_GETRDATABYNAME)
+ goto again;
+
+ /*
+ * Free what we've transmitted
+ */
+ CTXFREE(b_out.base, b_out.length);
+ b_out.base = NULL;
+ b_out.length = 0;
+
+ if (pkt.result != LWRES_R_SUCCESS) {
+ ret = pkt.result;
+ goto out;
+ }
+
+ /*
+ * Parse the response.
+ */
+ ret = lwres_grbnresponse_parse(ctx, &b_in, &pkt, &response);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ response->base = buffer;
+ response->baselen = LWRES_RECVLENGTH;
+ buffer = NULL; /* don't free this below */
+
+ *structp = response;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (b_out.base != NULL)
+ CTXFREE(b_out.base, b_out.length);
+ if (buffer != NULL)
+ CTXFREE(buffer, LWRES_RECVLENGTH);
+ if (response != NULL)
+ lwres_grbnresponse_free(ctx, &response);
+
+ return (ret);
+}
diff --git a/lib/lwres/man/Makefile.in b/lib/lwres/man/Makefile.in
new file mode 100644
index 0000000..e28123c
--- /dev/null
+++ b/lib/lwres/man/Makefile.in
@@ -0,0 +1,232 @@
+# 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: Makefile.in,v 1.7 2004/03/05 05:12:55 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+@BIND9_MAKE_RULES@
+
+# Alphabetically
+#MANPAGES = lwres.3 lwres_addr_parse.3 lwres_buffer.3 \
+# lwres_buffer_add.3 lwres_buffer_back.3 lwres_buffer_clear.3 \
+# lwres_buffer_first.3 lwres_buffer_forward.3 \
+# lwres_buffer_getmem.3 lwres_buffer_getuint16.3 \
+# lwres_buffer_getuint32.3 lwres_buffer_getuint8.3 \
+# lwres_buffer_init.3 lwres_buffer_invalidate.3 \
+# lwres_buffer_putmem.3 lwres_buffer_putuint16.3 \
+# lwres_buffer_putuint32.3 lwres_buffer_putuint8.3 \
+# lwres_buffer_subtract.3 lwres_conf_clear.3 \
+# lwres_conf_get.3 lwres_conf_init.3 \
+# lwres_conf_parse.3 lwres_conf_print.3 \
+# lwres_config.3 lwres_context.3 \
+# lwres_context_allocmem.3 lwres_context_create.3 \
+# lwres_context_destroy.3 lwres_context_freemem.3 \
+# lwres_context_initserial.3 lwres_context_nextserial.3 \
+# lwres_context_sendrecv.3 lwres_endhostent.3 \
+# lwres_endhostent_r.3 lwres_freeaddrinfo.3 \
+# lwres_freehostent.3 lwres_gabn.3 \
+# lwres_gabnrequest_free.3 lwres_gabnrequest_parse.3 \
+# lwres_gabnrequest_render.3 lwres_gabnresponse_free.3 \
+# lwres_gabnresponse_parse.3 lwres_gabnresponse_render.3 \
+# lwres_gai_strerror.3 lwres_getaddrinfo.3 \
+# lwres_getaddrsbyname.3 lwres_gethostbyaddr.3 \
+# lwres_gethostbyaddr_r.3 lwres_gethostbyname.3 \
+# lwres_gethostbyname2.3 lwres_gethostbyname_r.3 \
+# lwres_gethostent.3 lwres_gethostent_r.3 \
+# lwres_getipnode.3 lwres_getipnodebyaddr.3 \
+# lwres_getipnodebyname.3 lwres_getnamebyaddr.3 \
+# lwres_getnameinfo.3 lwres_getrrsetbyname.3 \
+# lwres_gnba.3 lwres_gnbarequest_free.3 \
+# lwres_gnbarequest_parse.3 lwres_gnbarequest_render.3 \
+# lwres_gnbaresponse_free.3 lwres_gnbaresponse_parse.3 \
+# lwres_gnbaresponse_render.3 lwres_herror.3 \
+# lwres_hstrerror.3 lwres_inetntop.3 \
+# lwres_lwpacket_parseheader.3 lwres_lwpacket_renderheader.3 \
+# lwres_net_ntop.3 lwres_noop.3 \
+# lwres_nooprequest_free.3 lwres_nooprequest_parse.3 \
+# lwres_nooprequest_render.3 lwres_noopresponse_free.3 \
+# lwres_noopresponse_parse.3 lwres_noopresponse_render.3 \
+# lwres_packet.3 lwres_resutil.3 \
+# lwres_sethostent.3 lwres_sethostent_r.3 \
+# lwres_string_parse.3
+
+
+MANPAGES = lwres.3 lwres_buffer.3 lwres_config.3 lwres_context.3 \
+ lwres_gabn.3 lwres_gai_strerror.3 lwres_getaddrinfo.3 \
+ lwres_gethostent.3 lwres_getipnode.3 lwres_getnameinfo.3 \
+ lwres_getrrsetbyname.3 lwres_gnba.3 lwres_hstrerror.3 lwres_inetntop.3 \
+ lwres_noop.3 lwres_packet.3 lwres_resutil.3
+
+HTMLPAGES = lwres.html lwres_buffer.html lwres_config.html lwres_context.html \
+ lwres_gabn.html lwres_gai_strerror.html lwres_getaddrinfo.html \
+ lwres_gethostent.html lwres_getipnode.html lwres_getnameinfo.html \
+ lwres_getrrsetbyname.html lwres_gnba.html lwres_hstrerror.html lwres_inetntop.html \
+ lwres_noop.html lwres_packet.html lwres_resutil.html
+
+MANOBJS = ${MANPAGES} ${HTMLPAGES}
+
+doc man:: ${MANOBJS}
+
+docclean manclean maintainer-clean::
+ rm -f ${MANOBJS}
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man3
+
+man3 = ${DESTDIR}${mandir}/man3
+
+install:: installdirs
+ for m in ${MANPAGES}; do ${INSTALL_DATA} ${srcdir}/$$m ${DESTDIR}${mandir}/man3; done
+ rm -f ${man3}/lwres_addr_parse.3
+ @LN@ ${man3}/lwres_resutil.3 ${man3}/lwres_addr_parse.3
+ rm -f ${man3}/lwres_buffer_add.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_add.3
+ rm -f ${man3}/lwres_buffer_back.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_back.3
+ rm -f ${man3}/lwres_buffer_clear.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_clear.3
+ rm -f ${man3}/lwres_buffer_first.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_first.3
+ rm -f ${man3}/lwres_buffer_forward.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_forward.3
+ rm -f ${man3}/lwres_buffer_getmem.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_getmem.3
+ rm -f ${man3}/lwres_buffer_getuint16.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_getuint16.3
+ rm -f ${man3}/lwres_buffer_getuint32.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_getuint32.3
+ rm -f ${man3}/lwres_buffer_getuint8.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_getuint8.3
+ rm -f ${man3}/lwres_buffer_init.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_init.3
+ rm -f ${man3}/lwres_buffer_invalidate.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_invalidate.3
+ rm -f ${man3}/lwres_buffer_putmem.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_putmem.3
+ rm -f ${man3}/lwres_buffer_putuint16.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_putuint16.3
+ rm -f ${man3}/lwres_buffer_putuint32.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_putuint32.3
+ rm -f ${man3}/lwres_buffer_putuint8.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_putuint8.3
+ rm -f ${man3}/lwres_buffer_subtract.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_subtract.3
+ rm -f ${man3}/lwres_conf_clear.3
+ @LN@ ${man3}/lwres_config.3 ${man3}/lwres_conf_clear.3
+ rm -f ${man3}/lwres_conf_get.3
+ @LN@ ${man3}/lwres_config.3 ${man3}/lwres_conf_get.3
+ rm -f ${man3}/lwres_conf_init.3
+ @LN@ ${man3}/lwres_config.3 ${man3}/lwres_conf_init.3
+ rm -f ${man3}/lwres_conf_parse.3
+ @LN@ ${man3}/lwres_config.3 ${man3}/lwres_conf_parse.3
+ rm -f ${man3}/lwres_conf_print.3
+ @LN@ ${man3}/lwres_config.3 ${man3}/lwres_conf_print.3
+ rm -f ${man3}/lwres_context_allocmem.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_allocmem.3
+ rm -f ${man3}/lwres_context_create.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_create.3
+ rm -f ${man3}/lwres_context_destroy.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_destroy.3
+ rm -f ${man3}/lwres_context_freemem.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_freemem.3
+ rm -f ${man3}/lwres_context_initserial.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_initserial.3
+ rm -f ${man3}/lwres_context_nextserial.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_nextserial.3
+ rm -f ${man3}/lwres_context_sendrecv.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_sendrecv.3
+ rm -f ${man3}/lwres_endhostent.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_endhostent.3
+ rm -f ${man3}/lwres_endhostent_r.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_endhostent_r.3
+ rm -f ${man3}/lwres_freeaddrinfo.3
+ @LN@ ${man3}/lwres_getaddrinfo.3 ${man3}/lwres_freeaddrinfo.3
+ rm -f ${man3}/lwres_freehostent.3
+ @LN@ ${man3}/lwres_getipnode.3 ${man3}/lwres_freehostent.3
+ rm -f ${man3}/lwres_gabnrequest_free.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnrequest_free.3
+ rm -f ${man3}/lwres_gabnrequest_parse.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnrequest_parse.3
+ rm -f ${man3}/lwres_gabnrequest_render.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnrequest_render.3
+ rm -f ${man3}/lwres_gabnresponse_free.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnresponse_free.3
+ rm -f ${man3}/lwres_gabnresponse_parse.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnresponse_parse.3
+ rm -f ${man3}/lwres_gabnresponse_render.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnresponse_render.3
+ rm -f ${man3}/lwres_getaddrsbyname.3
+ @LN@ ${man3}/lwres_resutil.3 ${man3}/lwres_getaddrsbyname.3
+ rm -f ${man3}/lwres_gethostbyaddr.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostbyaddr.3
+ rm -f ${man3}/lwres_gethostbyaddr_r.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostbyaddr_r.3
+ rm -f ${man3}/lwres_gethostbyname.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostbyname.3
+ rm -f ${man3}/lwres_gethostbyname2.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostbyname2.3
+ rm -f ${man3}/lwres_gethostbyname_r.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostbyname_r.3
+ rm -f ${man3}/lwres_gethostent_r.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostent_r.3
+ rm -f ${man3}/lwres_getipnodebyaddr.3
+ @LN@ ${man3}/lwres_getipnode.3 ${man3}/lwres_getipnodebyaddr.3
+ rm -f ${man3}/lwres_getipnodebyname.3
+ @LN@ ${man3}/lwres_getipnode.3 ${man3}/lwres_getipnodebyname.3
+ rm -f ${man3}/lwres_getnamebyaddr.3
+ @LN@ ${man3}/lwres_resutil.3 ${man3}/lwres_getnamebyaddr.3
+ rm -f ${man3}/lwres_gnbarequest_free.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbarequest_free.3
+ rm -f ${man3}/lwres_gnbarequest_parse.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbarequest_parse.3
+ rm -f ${man3}/lwres_gnbarequest_render.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbarequest_render.3
+ rm -f ${man3}/lwres_gnbaresponse_free.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbaresponse_free.3
+ rm -f ${man3}/lwres_gnbaresponse_parse.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbaresponse_parse.3
+ rm -f ${man3}/lwres_gnbaresponse_render.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbaresponse_render.3
+ rm -f ${man3}/lwres_herror.3
+ @LN@ ${man3}/lwres_hstrerror.3 ${man3}/lwres_herror.3
+ rm -f ${man3}/lwres_lwpacket_parseheader.3
+ @LN@ ${man3}/lwres_packet.3 ${man3}/lwres_lwpacket_parseheader.3
+ rm -f ${man3}/lwres_lwpacket_renderheader.3
+ @LN@ ${man3}/lwres_packet.3 ${man3}/lwres_lwpacket_renderheader.3
+ rm -f ${man3}/lwres_net_ntop.3
+ @LN@ ${man3}/lwres_inetntop.3 ${man3}/lwres_net_ntop.3
+ rm -f ${man3}/lwres_nooprequest_free.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_nooprequest_free.3
+ rm -f ${man3}/lwres_nooprequest_parse.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_nooprequest_parse.3
+ rm -f ${man3}/lwres_nooprequest_render.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_nooprequest_render.3
+ rm -f ${man3}/lwres_noopresponse_free.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_noopresponse_free.3
+ rm -f ${man3}/lwres_noopresponse_parse.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_noopresponse_parse.3
+ rm -f ${man3}/lwres_noopresponse_render.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_noopresponse_render.3
+ rm -f ${man3}/lwres_sethostent.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_sethostent.3
+ rm -f ${man3}/lwres_sethostent_r.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_sethostent_r.3
+ rm -f ${man3}/lwres_string_parse.3
+ @LN@ ${man3}/lwres_resutil.3 ${man3}/lwres_string_parse.3
diff --git a/lib/lwres/man/lwres.3 b/lib/lwres/man/lwres.3
new file mode 100644
index 0000000..968e8f8
--- /dev/null
+++ b/lib/lwres/man/lwres.3
@@ -0,0 +1,165 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres.3,v 1.17.18.11 2007/01/30 00:23:44 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres \- introduction to the lightweight resolver library
+.SH "SYNOPSIS"
+.nf
+#include <lwres/lwres.h>
+.fi
+.SH "DESCRIPTION"
+.PP
+The BIND 9 lightweight resolver library is a simple, name service independent stub resolver library. It provides hostname\-to\-address and address\-to\-hostname lookup services to applications by transmitting lookup requests to a resolver daemon
+\fBlwresd\fR
+running on the local host. The resover daemon performs the lookup using the DNS or possibly other name service protocols, and returns the results to the application through the library. The library and resolver daemon communicate using a simple UDP\-based protocol.
+.SH "OVERVIEW"
+.PP
+The lwresd library implements multiple name service APIs. The standard
+\fBgethostbyname()\fR,
+\fBgethostbyaddr()\fR,
+\fBgethostbyname_r()\fR,
+\fBgethostbyaddr_r()\fR,
+\fBgetaddrinfo()\fR,
+\fBgetipnodebyname()\fR, and
+\fBgetipnodebyaddr()\fR
+functions are all supported. To allow the lwres library to coexist with system libraries that define functions of the same name, the library defines these functions with names prefixed by
+lwres_. To define the standard names, applications must include the header file
+\fI<lwres/netdb.h>\fR
+which contains macro definitions mapping the standard function names into
+lwres_
+prefixed ones. Operating system vendors who integrate the lwres library into their base distributions should rename the functions in the library proper so that the renaming macros are not needed.
+.PP
+The library also provides a native API consisting of the functions
+\fBlwres_getaddrsbyname()\fR
+and
+\fBlwres_getnamebyaddr()\fR. These may be called by applications that require more detailed control over the lookup process than the standard functions provide.
+.PP
+In addition to these name service independent address lookup functions, the library implements a new, experimental API for looking up arbitrary DNS resource records, using the
+\fBlwres_getaddrsbyname()\fR
+function.
+.PP
+Finally, there is a low\-level API for converting lookup requests and responses to and from raw lwres protocol packets. This API can be used by clients requiring nonblocking operation, and is also used when implementing the server side of the lwres protocol, for example in the
+\fBlwresd\fR
+resolver daemon. The use of this low\-level API in clients and servers is outlined in the following sections.
+.SH "CLIENT\-SIDE LOW\-LEVEL API CALL FLOW"
+.PP
+When a client program wishes to make an lwres request using the native low\-level API, it typically performs the following sequence of actions.
+.PP
+(1) Allocate or use an existing
+\fBlwres_packet_t\fR, called
+\fIpkt\fR
+below.
+.PP
+(2) Set
+pkt.recvlength
+to the maximum length we will accept. This is done so the receiver of our packets knows how large our receive buffer is. The "default" is a constant in
+\fIlwres.h\fR:
+\fBLWRES_RECVLENGTH = 4096\fR.
+.PP
+(3) Set
+pkt.serial
+to a unique serial number. This value is echoed back to the application by the remote server.
+.PP
+(4) Set
+pkt.pktflags. Usually this is set to 0.
+.PP
+(5) Set
+pkt.result
+to 0.
+.PP
+(6) Call
+\fBlwres_*request_render()\fR, or marshall in the data using the primitives such as
+\fBlwres_packet_render()\fR
+and storing the packet data.
+.PP
+(7) Transmit the resulting buffer.
+.PP
+(8) Call
+\fBlwres_*response_parse()\fR
+to parse any packets received.
+.PP
+(9) Verify that the opcode and serial match a request, and process the packet specific information contained in the body.
+.SH "SERVER\-SIDE LOW\-LEVEL API CALL FLOW"
+.PP
+When implementing the server side of the lightweight resolver protocol using the lwres library, a sequence of actions like the following is typically involved in processing each request packet.
+.PP
+Note that the same
+\fBlwres_packet_t\fR
+is used in both the
+\fB_parse()\fR
+and
+\fB_render()\fR
+calls, with only a few modifications made to the packet header's contents between uses. This method is recommended as it keeps the serial, opcode, and other fields correct.
+.PP
+(1) When a packet is received, call
+\fBlwres_*request_parse()\fR
+to unmarshall it. This returns a
+\fBlwres_packet_t\fR
+(also called
+\fIpkt\fR, below) as well as a data specific type, such as
+\fBlwres_gabnrequest_t\fR.
+.PP
+(2) Process the request in the data specific type.
+.PP
+(3) Set the
+pkt.result,
+pkt.recvlength
+as above. All other fields can be left untouched since they were filled in by the
+\fB*_parse()\fR
+call above. If using
+\fBlwres_*response_render()\fR,
+pkt.pktflags
+will be set up properly. Otherwise, the
+\fBLWRES_LWPACKETFLAG_RESPONSE\fR
+bit should be set.
+.PP
+(4) Call the data specific rendering function, such as
+\fBlwres_gabnresponse_render()\fR.
+.PP
+(5) Send the resulting packet to the client.
+.PP
+.SH "SEE ALSO"
+.PP
+\fBlwres_gethostent\fR(3),
+\fBlwres_getipnode\fR(3),
+\fBlwres_getnameinfo\fR(3),
+\fBlwres_noop\fR(3),
+\fBlwres_gabn\fR(3),
+\fBlwres_gnba\fR(3),
+\fBlwres_context\fR(3),
+\fBlwres_config\fR(3),
+\fBresolver\fR(5),
+\fBlwresd\fR(8).
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres.docbook b/lib/lwres/man/lwres.docbook
new file mode 100644
index 0000000..cf1c154
--- /dev/null
+++ b/lib/lwres/man/lwres.docbook
@@ -0,0 +1,266 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres.docbook,v 1.4.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname>lwres</refname>
+ <refpurpose>introduction to the lightweight resolver library</refpurpose>
+ </refnamediv>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+</funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+ <para>
+ The BIND 9 lightweight resolver library is a simple, name service
+ independent stub resolver library. It provides hostname-to-address
+ and address-to-hostname lookup services to applications by
+ transmitting lookup requests to a resolver daemon
+ <command>lwresd</command>
+ running on the local host. The resover daemon performs the
+ lookup using the DNS or possibly other name service protocols,
+ and returns the results to the application through the library.
+ The library and resolver daemon communicate using a simple
+ UDP-based protocol.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>OVERVIEW</title>
+ <para>
+ The lwresd library implements multiple name service APIs.
+ The standard
+ <function>gethostbyname()</function>,
+ <function>gethostbyaddr()</function>,
+ <function>gethostbyname_r()</function>,
+ <function>gethostbyaddr_r()</function>,
+ <function>getaddrinfo()</function>,
+ <function>getipnodebyname()</function>,
+ and
+ <function>getipnodebyaddr()</function>
+ functions are all supported. To allow the lwres library to coexist
+ with system libraries that define functions of the same name,
+ the library defines these functions with names prefixed by
+ <literal>lwres_</literal>.
+ To define the standard names, applications must include the
+ header file
+ <filename>&lt;lwres/netdb.h&gt;</filename>
+ which contains macro definitions mapping the standard function names
+ into
+ <literal>lwres_</literal>
+ prefixed ones. Operating system vendors who integrate the lwres
+ library into their base distributions should rename the functions
+ in the library proper so that the renaming macros are not needed.
+ </para>
+ <para>
+ The library also provides a native API consisting of the functions
+ <function>lwres_getaddrsbyname()</function>
+ and
+ <function>lwres_getnamebyaddr()</function>.
+ These may be called by applications that require more detailed
+ control over the lookup process than the standard functions
+ provide.
+ </para>
+ <para>
+ In addition to these name service independent address lookup
+ functions, the library implements a new, experimental API
+ for looking up arbitrary DNS resource records, using the
+ <function>lwres_getaddrsbyname()</function>
+ function.
+ </para>
+ <para>
+ Finally, there is a low-level API for converting lookup
+ requests and responses to and from raw lwres protocol packets.
+ This API can be used by clients requiring nonblocking operation,
+ and is also used when implementing the server side of the lwres
+ protocol, for example in the
+ <command>lwresd</command>
+ resolver daemon. The use of this low-level API in clients
+ and servers is outlined in the following sections.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>CLIENT-SIDE LOW-LEVEL API CALL FLOW</title>
+ <para>
+ When a client program wishes to make an lwres request using the
+ native low-level API, it typically performs the following
+ sequence of actions.
+ </para>
+ <para>
+ (1) Allocate or use an existing <type>lwres_packet_t</type>,
+ called <varname>pkt</varname> below.
+ </para>
+ <para>
+ (2) Set <structfield>pkt.recvlength</structfield> to the maximum length
+ we will accept.
+ This is done so the receiver of our packets knows how large our receive
+ buffer is. The "default" is a constant in
+ <filename>lwres.h</filename>: <constant>LWRES_RECVLENGTH = 4096</constant>.
+ </para>
+ <para>
+ (3) Set <structfield>pkt.serial</structfield>
+ to a unique serial number. This value is echoed
+ back to the application by the remote server.
+ </para>
+ <para>
+ (4) Set <structfield>pkt.pktflags</structfield>. Usually this is set to
+ 0.
+ </para>
+ <para>
+ (5) Set <structfield>pkt.result</structfield> to 0.
+ </para>
+ <para>
+ (6) Call <function>lwres_*request_render()</function>,
+ or marshall in the data using the primitives
+ such as <function>lwres_packet_render()</function>
+ and storing the packet data.
+ </para>
+ <para>
+ (7) Transmit the resulting buffer.
+ </para>
+ <para>
+ (8) Call <function>lwres_*response_parse()</function>
+ to parse any packets received.
+ </para>
+ <para>
+ (9) Verify that the opcode and serial match a request, and process the
+ packet specific information contained in the body.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>SERVER-SIDE LOW-LEVEL API CALL FLOW</title>
+ <para>
+ When implementing the server side of the lightweight resolver
+ protocol using the lwres library, a sequence of actions like the
+ following is typically involved in processing each request packet.
+ </para>
+ <para>
+ Note that the same <type>lwres_packet_t</type> is used
+ in both the <function>_parse()</function> and <function>_render()</function> calls,
+ with only a few modifications made
+ to the packet header's contents between uses. This method is
+ recommended
+ as it keeps the serial, opcode, and other fields correct.
+ </para>
+ <para>
+ (1) When a packet is received, call <function>lwres_*request_parse()</function> to
+ unmarshall it. This returns a <type>lwres_packet_t</type> (also called <varname>pkt</varname>, below)
+ as well as a data specific type, such as <type>lwres_gabnrequest_t</type>.
+ </para>
+ <para>
+ (2) Process the request in the data specific type.
+ </para>
+ <para>
+ (3) Set the <structfield>pkt.result</structfield>,
+ <structfield>pkt.recvlength</structfield> as above. All other fields
+ can
+ be left untouched since they were filled in by the <function>*_parse()</function> call
+ above. If using <function>lwres_*response_render()</function>,
+ <structfield>pkt.pktflags</structfield> will be set up
+ properly. Otherwise, the <constant>LWRES_LWPACKETFLAG_RESPONSE</constant> bit should be
+ set.
+ </para>
+ <para>
+ (4) Call the data specific rendering function, such as
+ <function>lwres_gabnresponse_render()</function>.
+ </para>
+ <para>
+ (5) Send the resulting packet to the client.
+ </para>
+ <para></para>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>lwres_gethostent</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_getipnode</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_getnameinfo</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_noop</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_gabn</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_gnba</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_context</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_config</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>resolver</refentrytitle><manvolnum>5</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwresd</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>.
+
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres.html b/lib/lwres/man/lwres.html
new file mode 100644
index 0000000..e4bbc09
--- /dev/null
+++ b/lib/lwres/man/lwres.html
@@ -0,0 +1,218 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres.html,v 1.5.18.18 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres &#8212; introduction to the lightweight resolver library</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis"><pre class="funcsynopsisinfo">#include &lt;lwres/lwres.h&gt;</pre></div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543348"></a><h2>DESCRIPTION</h2>
+<p>
+ The BIND 9 lightweight resolver library is a simple, name service
+ independent stub resolver library. It provides hostname-to-address
+ and address-to-hostname lookup services to applications by
+ transmitting lookup requests to a resolver daemon
+ <span><strong class="command">lwresd</strong></span>
+ running on the local host. The resover daemon performs the
+ lookup using the DNS or possibly other name service protocols,
+ and returns the results to the application through the library.
+ The library and resolver daemon communicate using a simple
+ UDP-based protocol.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543361"></a><h2>OVERVIEW</h2>
+<p>
+ The lwresd library implements multiple name service APIs.
+ The standard
+ <code class="function">gethostbyname()</code>,
+ <code class="function">gethostbyaddr()</code>,
+ <code class="function">gethostbyname_r()</code>,
+ <code class="function">gethostbyaddr_r()</code>,
+ <code class="function">getaddrinfo()</code>,
+ <code class="function">getipnodebyname()</code>,
+ and
+ <code class="function">getipnodebyaddr()</code>
+ functions are all supported. To allow the lwres library to coexist
+ with system libraries that define functions of the same name,
+ the library defines these functions with names prefixed by
+ <code class="literal">lwres_</code>.
+ To define the standard names, applications must include the
+ header file
+ <code class="filename">&lt;lwres/netdb.h&gt;</code>
+ which contains macro definitions mapping the standard function names
+ into
+ <code class="literal">lwres_</code>
+ prefixed ones. Operating system vendors who integrate the lwres
+ library into their base distributions should rename the functions
+ in the library proper so that the renaming macros are not needed.
+ </p>
+<p>
+ The library also provides a native API consisting of the functions
+ <code class="function">lwres_getaddrsbyname()</code>
+ and
+ <code class="function">lwres_getnamebyaddr()</code>.
+ These may be called by applications that require more detailed
+ control over the lookup process than the standard functions
+ provide.
+ </p>
+<p>
+ In addition to these name service independent address lookup
+ functions, the library implements a new, experimental API
+ for looking up arbitrary DNS resource records, using the
+ <code class="function">lwres_getaddrsbyname()</code>
+ function.
+ </p>
+<p>
+ Finally, there is a low-level API for converting lookup
+ requests and responses to and from raw lwres protocol packets.
+ This API can be used by clients requiring nonblocking operation,
+ and is also used when implementing the server side of the lwres
+ protocol, for example in the
+ <span><strong class="command">lwresd</strong></span>
+ resolver daemon. The use of this low-level API in clients
+ and servers is outlined in the following sections.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543425"></a><h2>CLIENT-SIDE LOW-LEVEL API CALL FLOW</h2>
+<p>
+ When a client program wishes to make an lwres request using the
+ native low-level API, it typically performs the following
+ sequence of actions.
+ </p>
+<p>
+ (1) Allocate or use an existing <span class="type">lwres_packet_t</span>,
+ called <code class="varname">pkt</code> below.
+ </p>
+<p>
+ (2) Set <em class="structfield"><code>pkt.recvlength</code></em> to the maximum length
+ we will accept.
+ This is done so the receiver of our packets knows how large our receive
+ buffer is. The "default" is a constant in
+ <code class="filename">lwres.h</code>: <code class="constant">LWRES_RECVLENGTH = 4096</code>.
+ </p>
+<p>
+ (3) Set <em class="structfield"><code>pkt.serial</code></em>
+ to a unique serial number. This value is echoed
+ back to the application by the remote server.
+ </p>
+<p>
+ (4) Set <em class="structfield"><code>pkt.pktflags</code></em>. Usually this is set to
+ 0.
+ </p>
+<p>
+ (5) Set <em class="structfield"><code>pkt.result</code></em> to 0.
+ </p>
+<p>
+ (6) Call <code class="function">lwres_*request_render()</code>,
+ or marshall in the data using the primitives
+ such as <code class="function">lwres_packet_render()</code>
+ and storing the packet data.
+ </p>
+<p>
+ (7) Transmit the resulting buffer.
+ </p>
+<p>
+ (8) Call <code class="function">lwres_*response_parse()</code>
+ to parse any packets received.
+ </p>
+<p>
+ (9) Verify that the opcode and serial match a request, and process the
+ packet specific information contained in the body.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543573"></a><h2>SERVER-SIDE LOW-LEVEL API CALL FLOW</h2>
+<p>
+ When implementing the server side of the lightweight resolver
+ protocol using the lwres library, a sequence of actions like the
+ following is typically involved in processing each request packet.
+ </p>
+<p>
+ Note that the same <span class="type">lwres_packet_t</span> is used
+ in both the <code class="function">_parse()</code> and <code class="function">_render()</code> calls,
+ with only a few modifications made
+ to the packet header's contents between uses. This method is
+ recommended
+ as it keeps the serial, opcode, and other fields correct.
+ </p>
+<p>
+ (1) When a packet is received, call <code class="function">lwres_*request_parse()</code> to
+ unmarshall it. This returns a <span class="type">lwres_packet_t</span> (also called <code class="varname">pkt</code>, below)
+ as well as a data specific type, such as <span class="type">lwres_gabnrequest_t</span>.
+ </p>
+<p>
+ (2) Process the request in the data specific type.
+ </p>
+<p>
+ (3) Set the <em class="structfield"><code>pkt.result</code></em>,
+ <em class="structfield"><code>pkt.recvlength</code></em> as above. All other fields
+ can
+ be left untouched since they were filled in by the <code class="function">*_parse()</code> call
+ above. If using <code class="function">lwres_*response_render()</code>,
+ <em class="structfield"><code>pkt.pktflags</code></em> will be set up
+ properly. Otherwise, the <code class="constant">LWRES_LWPACKETFLAG_RESPONSE</code> bit should be
+ set.
+ </p>
+<p>
+ (4) Call the data specific rendering function, such as
+ <code class="function">lwres_gabnresponse_render()</code>.
+ </p>
+<p>
+ (5) Send the resulting packet to the client.
+ </p>
+<p></p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543656"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">lwres_gethostent</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_getipnode</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_getnameinfo</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_noop</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_gabn</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_gnba</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_context</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_config</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">resolver</span>(5)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwresd</span>(8)</span>.
+
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_buffer.3 b/lib/lwres/man/lwres_buffer.3
new file mode 100644
index 0000000..4bebafa
--- /dev/null
+++ b/lib/lwres/man/lwres_buffer.3
@@ -0,0 +1,233 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_buffer.3,v 1.15.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_buffer
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_BUFFER" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_buffer_init, lwres_buffer_invalidate, lwres_buffer_add, lwres_buffer_subtract, lwres_buffer_clear, lwres_buffer_first, lwres_buffer_forward, lwres_buffer_back, lwres_buffer_getuint8, lwres_buffer_putuint8, lwres_buffer_getuint16, lwres_buffer_putuint16, lwres_buffer_getuint32, lwres_buffer_putuint32, lwres_buffer_putmem, lwres_buffer_getmem \- lightweight resolver buffer management
+.SH "SYNOPSIS"
+.nf
+#include <lwres/lwbuffer.h>
+.fi
+.HP 23
+.BI "void lwres_buffer_init(lwres_buffer_t\ *" "b" ", void\ *" "base" ", unsigned\ int\ " "length" ");"
+.HP 29
+.BI "void lwres_buffer_invalidate(lwres_buffer_t\ *" "b" ");"
+.HP 22
+.BI "void lwres_buffer_add(lwres_buffer_t\ *" "b" ", unsigned\ int\ " "n" ");"
+.HP 27
+.BI "void lwres_buffer_subtract(lwres_buffer_t\ *" "b" ", unsigned\ int\ " "n" ");"
+.HP 24
+.BI "void lwres_buffer_clear(lwres_buffer_t\ *" "b" ");"
+.HP 24
+.BI "void lwres_buffer_first(lwres_buffer_t\ *" "b" ");"
+.HP 26
+.BI "void lwres_buffer_forward(lwres_buffer_t\ *" "b" ", unsigned\ int\ " "n" ");"
+.HP 23
+.BI "void lwres_buffer_back(lwres_buffer_t\ *" "b" ", unsigned\ int\ " "n" ");"
+.HP 36
+.BI "lwres_uint8_t lwres_buffer_getuint8(lwres_buffer_t\ *" "b" ");"
+.HP 27
+.BI "void lwres_buffer_putuint8(lwres_buffer_t\ *" "b" ", lwres_uint8_t\ " "val" ");"
+.HP 38
+.BI "lwres_uint16_t lwres_buffer_getuint16(lwres_buffer_t\ *" "b" ");"
+.HP 28
+.BI "void lwres_buffer_putuint16(lwres_buffer_t\ *" "b" ", lwres_uint16_t\ " "val" ");"
+.HP 38
+.BI "lwres_uint32_t lwres_buffer_getuint32(lwres_buffer_t\ *" "b" ");"
+.HP 28
+.BI "void lwres_buffer_putuint32(lwres_buffer_t\ *" "b" ", lwres_uint32_t\ " "val" ");"
+.HP 25
+.BI "void lwres_buffer_putmem(lwres_buffer_t\ *" "b" ", const\ unsigned\ char\ *" "base" ", unsigned\ int\ " "length" ");"
+.HP 25
+.BI "void lwres_buffer_getmem(lwres_buffer_t\ *" "b" ", unsigned\ char\ *" "base" ", unsigned\ int\ " "length" ");"
+.SH "DESCRIPTION"
+.PP
+These functions provide bounds checked access to a region of memory where data is being read or written. They are based on, and similar to, the
+isc_buffer_
+functions in the ISC library.
+.PP
+A buffer is a region of memory, together with a set of related subregions. The
+\fIused region\fR
+and the
+\fIavailable\fR
+region are disjoint, and their union is the buffer's region. The used region extends from the beginning of the buffer region to the last used byte. The available region extends from one byte greater than the last used byte to the end of the buffer's region. The size of the used region can be changed using various buffer commands. Initially, the used region is empty.
+.PP
+The used region is further subdivided into two disjoint regions: the
+\fIconsumed region\fR
+and the
+\fIremaining region\fR. The union of these two regions is the used region. The consumed region extends from the beginning of the used region to the byte before the
+\fIcurrent\fR
+offset (if any). The
+\fIremaining\fR
+region the current pointer to the end of the used region. The size of the consumed region can be changed using various buffer commands. Initially, the consumed region is empty.
+.PP
+The
+\fIactive region\fR
+is an (optional) subregion of the remaining region. It extends from the current offset to an offset in the remaining region. Initially, the active region is empty. If the current offset advances beyond the chosen offset, the active region will also be empty.
+.PP
+.RS 4
+.nf
+ /\-\-\-\-\-\-\-\-\-\-\-\-entire length\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\\\\
+ /\-\-\-\-\- used region \-\-\-\-\-\\\\/\-\- available \-\-\\\\
+ +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
+ | consumed | remaining | |
+ +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
+ a b c d e
+.fi
+.RE
+.sp
+.PP
+.RS 4
+.nf
+ a == base of buffer.
+ b == current pointer. Can be anywhere between a and d.
+ c == active pointer. Meaningful between b and d.
+ d == used pointer.
+ e == length of buffer.
+.fi
+.RE
+.sp
+.PP
+.RS 4
+.nf
+ a\-e == entire length of buffer.
+ a\-d == used region.
+ a\-b == consumed region.
+ b\-d == remaining region.
+ b\-c == optional active region.
+.fi
+.RE
+.sp
+.PP
+\fBlwres_buffer_init()\fR
+initializes the
+\fBlwres_buffer_t\fR
+\fI*b\fR
+and assocates it with the memory region of size
+\fIlength\fR
+bytes starting at location
+\fIbase.\fR
+.PP
+\fBlwres_buffer_invalidate()\fR
+marks the buffer
+\fI*b\fR
+as invalid. Invalidating a buffer after use is not required, but makes it possible to catch its possible accidental use.
+.PP
+The functions
+\fBlwres_buffer_add()\fR
+and
+\fBlwres_buffer_subtract()\fR
+respectively increase and decrease the used space in buffer
+\fI*b\fR
+by
+\fIn\fR
+bytes.
+\fBlwres_buffer_add()\fR
+checks for buffer overflow and
+\fBlwres_buffer_subtract()\fR
+checks for underflow. These functions do not allocate or deallocate memory. They just change the value of
+used.
+.PP
+A buffer is re\-initialised by
+\fBlwres_buffer_clear()\fR. The function sets
+used,
+current
+and
+active
+to zero.
+.PP
+\fBlwres_buffer_first\fR
+makes the consumed region of buffer
+\fI*p\fR
+empty by setting
+current
+to zero (the start of the buffer).
+.PP
+\fBlwres_buffer_forward()\fR
+increases the consumed region of buffer
+\fI*b\fR
+by
+\fIn\fR
+bytes, checking for overflow. Similarly,
+\fBlwres_buffer_back()\fR
+decreases buffer
+\fIb\fR's consumed region by
+\fIn\fR
+bytes and checks for underflow.
+.PP
+\fBlwres_buffer_getuint8()\fR
+reads an unsigned 8\-bit integer from
+\fI*b\fR
+and returns it.
+\fBlwres_buffer_putuint8()\fR
+writes the unsigned 8\-bit integer
+\fIval\fR
+to buffer
+\fI*b\fR.
+.PP
+\fBlwres_buffer_getuint16()\fR
+and
+\fBlwres_buffer_getuint32()\fR
+are identical to
+\fBlwres_buffer_putuint8()\fR
+except that they respectively read an unsigned 16\-bit or 32\-bit integer in network byte order from
+\fIb\fR. Similarly,
+\fBlwres_buffer_putuint16()\fR
+and
+\fBlwres_buffer_putuint32()\fR
+writes the unsigned 16\-bit or 32\-bit integer
+\fIval\fR
+to buffer
+\fIb\fR, in network byte order.
+.PP
+Arbitrary amounts of data are read or written from a lightweight resolver buffer with
+\fBlwres_buffer_getmem()\fR
+and
+\fBlwres_buffer_putmem()\fR
+respectively.
+\fBlwres_buffer_putmem()\fR
+copies
+\fIlength\fR
+bytes of memory at
+\fIbase\fR
+to
+\fIb\fR. Conversely,
+\fBlwres_buffer_getmem()\fR
+copies
+\fIlength\fR
+bytes of memory from
+\fIb\fR
+to
+\fIbase\fR.
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_buffer.docbook b/lib/lwres/man/lwres_buffer.docbook
new file mode 100644
index 0000000..f0b7a9f
--- /dev/null
+++ b/lib/lwres/man/lwres_buffer.docbook
@@ -0,0 +1,394 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_buffer.docbook,v 1.4.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_buffer</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_buffer_init</refname>
+ <refname>lwres_buffer_invalidate</refname>
+ <refname>lwres_buffer_add</refname>
+ <refname>lwres_buffer_subtract</refname>
+ <refname>lwres_buffer_clear</refname>
+ <refname>lwres_buffer_first</refname>
+ <refname>lwres_buffer_forward</refname>
+ <refname>lwres_buffer_back</refname>
+ <refname>lwres_buffer_getuint8</refname>
+ <refname>lwres_buffer_putuint8</refname>
+ <refname>lwres_buffer_getuint16</refname>
+ <refname>lwres_buffer_putuint16</refname>
+ <refname>lwres_buffer_getuint32</refname>
+ <refname>lwres_buffer_putuint32</refname>
+ <refname>lwres_buffer_putmem</refname>
+ <refname>lwres_buffer_getmem</refname>
+ <refpurpose>lightweight resolver buffer management</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+
+ <funcsynopsis>
+<funcsynopsisinfo>
+#include &lt;lwres/lwbuffer.h&gt;
+</funcsynopsisinfo>
+
+<funcprototype>
+
+ <funcdef>
+void
+<function>lwres_buffer_init</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>void *<parameter>base</parameter></paramdef>
+ <paramdef>unsigned int <parameter>length</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_buffer_invalidate</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_buffer_add</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>unsigned int <parameter>n</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_buffer_subtract</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>unsigned int <parameter>n</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_buffer_clear</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_buffer_first</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_buffer_forward</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>unsigned int <parameter>n</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+
+ <funcdef>
+void
+<function>lwres_buffer_back</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>unsigned int <parameter>n</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+lwres_uint8_t
+<function>lwres_buffer_getuint8</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_buffer_putuint8</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_uint8_t <parameter>val</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+lwres_uint16_t
+<function>lwres_buffer_getuint16</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_buffer_putuint16</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_uint16_t <parameter>val</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+lwres_uint32_t
+<function>lwres_buffer_getuint32</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_buffer_putuint32</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_uint32_t <parameter>val</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_buffer_putmem</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>const unsigned char *<parameter>base</parameter></paramdef>
+ <paramdef>unsigned int <parameter>length</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_buffer_getmem</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>unsigned char *<parameter>base</parameter></paramdef>
+ <paramdef>unsigned int <parameter>length</parameter></paramdef>
+ </funcprototype>
+
+</funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+
+ <title>DESCRIPTION</title>
+ <para>
+ These functions provide bounds checked access to a region of memory
+ where data is being read or written.
+ They are based on, and similar to, the
+ <literal>isc_buffer_</literal>
+ functions in the ISC library.
+ </para>
+ <para>
+ A buffer is a region of memory, together with a set of related
+ subregions.
+ The <emphasis>used region</emphasis> and the
+ <emphasis>available</emphasis> region are disjoint, and
+ their union is the buffer's region.
+ The used region extends from the beginning of the buffer region to the
+ last used byte.
+ The available region extends from one byte greater than the last used
+ byte to the end of the buffer's region.
+ The size of the used region can be changed using various
+ buffer commands.
+ Initially, the used region is empty.
+ </para>
+ <para>
+ The used region is further subdivided into two disjoint regions: the
+ <emphasis>consumed region</emphasis> and the <emphasis>remaining region</emphasis>.
+ The union of these two regions is the used region.
+ The consumed region extends from the beginning of the used region to
+ the byte before the <emphasis>current</emphasis> offset (if any).
+ The <emphasis>remaining</emphasis> region the current pointer to the end
+ of the used
+ region.
+ The size of the consumed region can be changed using various
+ buffer commands.
+ Initially, the consumed region is empty.
+ </para>
+ <para>
+ The <emphasis>active region</emphasis> is an (optional) subregion of the
+ remaining
+ region.
+ It extends from the current offset to an offset in the
+ remaining region.
+ Initially, the active region is empty.
+ If the current offset advances beyond the chosen offset,
+ the active region will also be empty.
+ </para>
+ <para><programlisting>
+ /------------entire length---------------\\
+ /----- used region -----\\/-- available --\\
+ +----------------------------------------+
+ | consumed | remaining | |
+ +----------------------------------------+
+ a b c d e
+ </programlisting>
+ </para>
+ <para><programlisting>
+ a == base of buffer.
+ b == current pointer. Can be anywhere between a and d.
+ c == active pointer. Meaningful between b and d.
+ d == used pointer.
+ e == length of buffer.
+ </programlisting>
+ </para>
+ <para><programlisting>
+ a-e == entire length of buffer.
+ a-d == used region.
+ a-b == consumed region.
+ b-d == remaining region.
+ b-c == optional active region.
+</programlisting>
+ </para>
+ <para><function>lwres_buffer_init()</function>
+ initializes the
+ <type>lwres_buffer_t</type>
+ <parameter>*b</parameter>
+ and assocates it with the memory region of size
+ <parameter>length</parameter>
+ bytes starting at location
+ <parameter>base.</parameter>
+ </para>
+ <para><function>lwres_buffer_invalidate()</function>
+ marks the buffer <parameter>*b</parameter>
+ as invalid. Invalidating a buffer after use is not required,
+ but makes it possible to catch its possible accidental use.
+ </para>
+ <para>
+ The functions
+ <function>lwres_buffer_add()</function>
+ and
+ <function>lwres_buffer_subtract()</function>
+ respectively increase and decrease the used space in
+ buffer
+ <parameter>*b</parameter>
+ by
+ <parameter>n</parameter>
+ bytes.
+ <function>lwres_buffer_add()</function>
+ checks for buffer overflow and
+ <function>lwres_buffer_subtract()</function>
+ checks for underflow.
+ These functions do not allocate or deallocate memory.
+ They just change the value of
+ <structfield>used</structfield>.
+ </para>
+ <para>
+ A buffer is re-initialised by
+ <function>lwres_buffer_clear()</function>.
+ The function sets
+ <structfield>used</structfield>,
+ <structfield>current</structfield>
+ and
+ <structfield>active</structfield>
+ to zero.
+ </para>
+ <para><function>lwres_buffer_first</function>
+ makes the consumed region of buffer
+ <parameter>*p</parameter>
+ empty by setting
+ <structfield>current</structfield>
+ to zero (the start of the buffer).
+ </para>
+ <para><function>lwres_buffer_forward()</function>
+ increases the consumed region of buffer
+ <parameter>*b</parameter>
+ by
+ <parameter>n</parameter>
+ bytes, checking for overflow.
+ Similarly,
+ <function>lwres_buffer_back()</function>
+ decreases buffer
+ <parameter>b</parameter>'s
+ consumed region by
+ <parameter>n</parameter>
+ bytes and checks for underflow.
+ </para>
+ <para><function>lwres_buffer_getuint8()</function>
+ reads an unsigned 8-bit integer from
+ <parameter>*b</parameter>
+ and returns it.
+ <function>lwres_buffer_putuint8()</function>
+ writes the unsigned 8-bit integer
+ <parameter>val</parameter>
+ to buffer
+ <parameter>*b</parameter>.
+ </para>
+ <para><function>lwres_buffer_getuint16()</function>
+ and
+ <function>lwres_buffer_getuint32()</function>
+ are identical to
+ <function>lwres_buffer_putuint8()</function>
+ except that they respectively read an unsigned 16-bit or 32-bit integer
+ in network byte order from
+ <parameter>b</parameter>.
+ Similarly,
+ <function>lwres_buffer_putuint16()</function>
+ and
+ <function>lwres_buffer_putuint32()</function>
+ writes the unsigned 16-bit or 32-bit integer
+ <parameter>val</parameter>
+ to buffer
+ <parameter>b</parameter>,
+ in network byte order.
+ </para>
+ <para>
+ Arbitrary amounts of data are read or written from a lightweight
+ resolver buffer with
+ <function>lwres_buffer_getmem()</function>
+ and
+ <function>lwres_buffer_putmem()</function>
+ respectively.
+ <function>lwres_buffer_putmem()</function>
+ copies
+ <parameter>length</parameter>
+ bytes of memory at
+ <parameter>base</parameter>
+ to
+ <parameter>b</parameter>.
+ Conversely,
+ <function>lwres_buffer_getmem()</function>
+ copies
+ <parameter>length</parameter>
+ bytes of memory from
+ <parameter>b</parameter>
+ to
+ <parameter>base</parameter>.
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_buffer.html b/lib/lwres/man/lwres_buffer.html
new file mode 100644
index 0000000..ed3e427
--- /dev/null
+++ b/lib/lwres/man/lwres_buffer.html
@@ -0,0 +1,455 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_buffer.html,v 1.5.18.16 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_buffer</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_buffer_init, lwres_buffer_invalidate, lwres_buffer_add, lwres_buffer_subtract, lwres_buffer_clear, lwres_buffer_first, lwres_buffer_forward, lwres_buffer_back, lwres_buffer_getuint8, lwres_buffer_putuint8, lwres_buffer_getuint16, lwres_buffer_putuint16, lwres_buffer_getuint32, lwres_buffer_putuint32, lwres_buffer_putmem, lwres_buffer_getmem &#8212; lightweight resolver buffer management</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">
+#include &lt;lwres/lwbuffer.h&gt;
+</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_init</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>void * </td>
+<td>
+<var class="pdparam">base</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>unsigned int  </td>
+<td>
+<var class="pdparam">length</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_invalidate</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_add</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>unsigned int  </td>
+<td>
+<var class="pdparam">n</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_subtract</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>unsigned int  </td>
+<td>
+<var class="pdparam">n</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_clear</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_first</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_forward</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>unsigned int  </td>
+<td>
+<var class="pdparam">n</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_back</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>unsigned int  </td>
+<td>
+<var class="pdparam">n</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+lwres_uint8_t
+<b class="fsfunc">lwres_buffer_getuint8</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_putuint8</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_uint8_t  </td>
+<td>
+<var class="pdparam">val</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+lwres_uint16_t
+<b class="fsfunc">lwres_buffer_getuint16</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_putuint16</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_uint16_t  </td>
+<td>
+<var class="pdparam">val</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+lwres_uint32_t
+<b class="fsfunc">lwres_buffer_getuint32</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_putuint32</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_uint32_t  </td>
+<td>
+<var class="pdparam">val</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_putmem</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>const unsigned char * </td>
+<td>
+<var class="pdparam">base</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>unsigned int  </td>
+<td>
+<var class="pdparam">length</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_buffer_getmem</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>unsigned char * </td>
+<td>
+<var class="pdparam">base</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>unsigned int  </td>
+<td>
+<var class="pdparam">length</var><code>)</code>;</td>
+</tr>
+</table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543892"></a><h2>DESCRIPTION</h2>
+<p>
+ These functions provide bounds checked access to a region of memory
+ where data is being read or written.
+ They are based on, and similar to, the
+ <code class="literal">isc_buffer_</code>
+ functions in the ISC library.
+ </p>
+<p>
+ A buffer is a region of memory, together with a set of related
+ subregions.
+ The <span class="emphasis"><em>used region</em></span> and the
+ <span class="emphasis"><em>available</em></span> region are disjoint, and
+ their union is the buffer's region.
+ The used region extends from the beginning of the buffer region to the
+ last used byte.
+ The available region extends from one byte greater than the last used
+ byte to the end of the buffer's region.
+ The size of the used region can be changed using various
+ buffer commands.
+ Initially, the used region is empty.
+ </p>
+<p>
+ The used region is further subdivided into two disjoint regions: the
+ <span class="emphasis"><em>consumed region</em></span> and the <span class="emphasis"><em>remaining region</em></span>.
+ The union of these two regions is the used region.
+ The consumed region extends from the beginning of the used region to
+ the byte before the <span class="emphasis"><em>current</em></span> offset (if any).
+ The <span class="emphasis"><em>remaining</em></span> region the current pointer to the end
+ of the used
+ region.
+ The size of the consumed region can be changed using various
+ buffer commands.
+ Initially, the consumed region is empty.
+ </p>
+<p>
+ The <span class="emphasis"><em>active region</em></span> is an (optional) subregion of the
+ remaining
+ region.
+ It extends from the current offset to an offset in the
+ remaining region.
+ Initially, the active region is empty.
+ If the current offset advances beyond the chosen offset,
+ the active region will also be empty.
+ </p>
+<pre class="programlisting">
+ /------------entire length---------------\\
+ /----- used region -----\\/-- available --\\
+ +----------------------------------------+
+ | consumed | remaining | |
+ +----------------------------------------+
+ a b c d e
+ </pre>
+<p>
+ </p>
+<pre class="programlisting">
+ a == base of buffer.
+ b == current pointer. Can be anywhere between a and d.
+ c == active pointer. Meaningful between b and d.
+ d == used pointer.
+ e == length of buffer.
+ </pre>
+<p>
+ </p>
+<pre class="programlisting">
+ a-e == entire length of buffer.
+ a-d == used region.
+ a-b == consumed region.
+ b-d == remaining region.
+ b-c == optional active region.
+</pre>
+<p>
+ </p>
+<p><code class="function">lwres_buffer_init()</code>
+ initializes the
+ <span class="type">lwres_buffer_t</span>
+ <em class="parameter"><code>*b</code></em>
+ and assocates it with the memory region of size
+ <em class="parameter"><code>length</code></em>
+ bytes starting at location
+ <em class="parameter"><code>base.</code></em>
+ </p>
+<p><code class="function">lwres_buffer_invalidate()</code>
+ marks the buffer <em class="parameter"><code>*b</code></em>
+ as invalid. Invalidating a buffer after use is not required,
+ but makes it possible to catch its possible accidental use.
+ </p>
+<p>
+ The functions
+ <code class="function">lwres_buffer_add()</code>
+ and
+ <code class="function">lwres_buffer_subtract()</code>
+ respectively increase and decrease the used space in
+ buffer
+ <em class="parameter"><code>*b</code></em>
+ by
+ <em class="parameter"><code>n</code></em>
+ bytes.
+ <code class="function">lwres_buffer_add()</code>
+ checks for buffer overflow and
+ <code class="function">lwres_buffer_subtract()</code>
+ checks for underflow.
+ These functions do not allocate or deallocate memory.
+ They just change the value of
+ <em class="structfield"><code>used</code></em>.
+ </p>
+<p>
+ A buffer is re-initialised by
+ <code class="function">lwres_buffer_clear()</code>.
+ The function sets
+ <em class="structfield"><code>used</code></em>,
+ <em class="structfield"><code>current</code></em>
+ and
+ <em class="structfield"><code>active</code></em>
+ to zero.
+ </p>
+<p><code class="function">lwres_buffer_first</code>
+ makes the consumed region of buffer
+ <em class="parameter"><code>*p</code></em>
+ empty by setting
+ <em class="structfield"><code>current</code></em>
+ to zero (the start of the buffer).
+ </p>
+<p><code class="function">lwres_buffer_forward()</code>
+ increases the consumed region of buffer
+ <em class="parameter"><code>*b</code></em>
+ by
+ <em class="parameter"><code>n</code></em>
+ bytes, checking for overflow.
+ Similarly,
+ <code class="function">lwres_buffer_back()</code>
+ decreases buffer
+ <em class="parameter"><code>b</code></em>'s
+ consumed region by
+ <em class="parameter"><code>n</code></em>
+ bytes and checks for underflow.
+ </p>
+<p><code class="function">lwres_buffer_getuint8()</code>
+ reads an unsigned 8-bit integer from
+ <em class="parameter"><code>*b</code></em>
+ and returns it.
+ <code class="function">lwres_buffer_putuint8()</code>
+ writes the unsigned 8-bit integer
+ <em class="parameter"><code>val</code></em>
+ to buffer
+ <em class="parameter"><code>*b</code></em>.
+ </p>
+<p><code class="function">lwres_buffer_getuint16()</code>
+ and
+ <code class="function">lwres_buffer_getuint32()</code>
+ are identical to
+ <code class="function">lwres_buffer_putuint8()</code>
+ except that they respectively read an unsigned 16-bit or 32-bit integer
+ in network byte order from
+ <em class="parameter"><code>b</code></em>.
+ Similarly,
+ <code class="function">lwres_buffer_putuint16()</code>
+ and
+ <code class="function">lwres_buffer_putuint32()</code>
+ writes the unsigned 16-bit or 32-bit integer
+ <em class="parameter"><code>val</code></em>
+ to buffer
+ <em class="parameter"><code>b</code></em>,
+ in network byte order.
+ </p>
+<p>
+ Arbitrary amounts of data are read or written from a lightweight
+ resolver buffer with
+ <code class="function">lwres_buffer_getmem()</code>
+ and
+ <code class="function">lwres_buffer_putmem()</code>
+ respectively.
+ <code class="function">lwres_buffer_putmem()</code>
+ copies
+ <em class="parameter"><code>length</code></em>
+ bytes of memory at
+ <em class="parameter"><code>base</code></em>
+ to
+ <em class="parameter"><code>b</code></em>.
+ Conversely,
+ <code class="function">lwres_buffer_getmem()</code>
+ copies
+ <em class="parameter"><code>length</code></em>
+ bytes of memory from
+ <em class="parameter"><code>b</code></em>
+ to
+ <em class="parameter"><code>base</code></em>.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_config.3 b/lib/lwres/man/lwres_config.3
new file mode 100644
index 0000000..5a4123d
--- /dev/null
+++ b/lib/lwres/man/lwres_config.3
@@ -0,0 +1,106 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_config.3,v 1.15.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_config
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_CONFIG" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_conf_init, lwres_conf_clear, lwres_conf_parse, lwres_conf_print, lwres_conf_get \- lightweight resolver configuration
+.SH "SYNOPSIS"
+.nf
+#include <lwres/lwres.h>
+.fi
+.HP 21
+.BI "void lwres_conf_init(lwres_context_t\ *" "ctx" ");"
+.HP 22
+.BI "void lwres_conf_clear(lwres_context_t\ *" "ctx" ");"
+.HP 32
+.BI "lwres_result_t lwres_conf_parse(lwres_context_t\ *" "ctx" ", const\ char\ *" "filename" ");"
+.HP 32
+.BI "lwres_result_t lwres_conf_print(lwres_context_t\ *" "ctx" ", FILE\ *" "fp" ");"
+.HP 30
+.BI "lwres_conf_t * lwres_conf_get(lwres_context_t\ *" "ctx" ");"
+.SH "DESCRIPTION"
+.PP
+\fBlwres_conf_init()\fR
+creates an empty
+\fBlwres_conf_t\fR
+structure for lightweight resolver context
+\fIctx\fR.
+.PP
+\fBlwres_conf_clear()\fR
+frees up all the internal memory used by that
+\fBlwres_conf_t\fR
+structure in resolver context
+\fIctx\fR.
+.PP
+\fBlwres_conf_parse()\fR
+opens the file
+\fIfilename\fR
+and parses it to initialise the resolver context
+\fIctx\fR's
+\fBlwres_conf_t\fR
+structure.
+.PP
+\fBlwres_conf_print()\fR
+prints the
+\fBlwres_conf_t\fR
+structure for resolver context
+\fIctx\fR
+to the
+\fBFILE\fR
+\fIfp\fR.
+.SH "RETURN VALUES"
+.PP
+\fBlwres_conf_parse()\fR
+returns
+\fBLWRES_R_SUCCESS\fR
+if it successfully read and parsed
+\fIfilename\fR. It returns
+\fBLWRES_R_FAILURE\fR
+if
+\fIfilename\fR
+could not be opened or contained incorrect resolver statements.
+.PP
+\fBlwres_conf_print()\fR
+returns
+\fBLWRES_R_SUCCESS\fR
+unless an error occurred when converting the network addresses to a numeric host address string. If this happens, the function returns
+\fBLWRES_R_FAILURE\fR.
+.SH "SEE ALSO"
+.PP
+\fBstdio\fR(3),
+\fBresolver\fR(5).
+.SH "FILES"
+.PP
+\fI/etc/resolv.conf\fR
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_config.docbook b/lib/lwres/man/lwres_config.docbook
new file mode 100644
index 0000000..eba0c44
--- /dev/null
+++ b/lib/lwres/man/lwres_config.docbook
@@ -0,0 +1,173 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_config.docbook,v 1.3.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+ <refentryinfo>
+
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_config</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_conf_init</refname>
+ <refname>lwres_conf_clear</refname>
+ <refname>lwres_conf_parse</refname>
+ <refname>lwres_conf_print</refname>
+ <refname>lwres_conf_get</refname>
+ <refpurpose>lightweight resolver configuration</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_conf_init</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_conf_clear</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_conf_parse</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>const char *<parameter>filename</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_conf_print</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>FILE *<parameter>fp</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_conf_t *
+<function>lwres_conf_get</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><function>lwres_conf_init()</function>
+ creates an empty
+ <type>lwres_conf_t</type>
+ structure for lightweight resolver context
+ <parameter>ctx</parameter>.
+ </para>
+
+ <para><function>lwres_conf_clear()</function>
+ frees up all the internal memory used by
+ that
+ <type>lwres_conf_t</type>
+ structure in resolver context
+ <parameter>ctx</parameter>.
+ </para>
+
+ <para><function>lwres_conf_parse()</function>
+ opens the file
+ <parameter>filename</parameter>
+ and parses it to initialise the resolver context
+ <parameter>ctx</parameter>'s
+ <type>lwres_conf_t</type>
+ structure.
+ </para>
+
+ <para><function>lwres_conf_print()</function>
+ prints the
+ <type>lwres_conf_t</type>
+ structure for resolver context
+ <parameter>ctx</parameter>
+ to the
+ <type>FILE</type>
+ <parameter>fp</parameter>.
+ </para>
+ </refsect1>
+ <refsect1>
+
+ <title>RETURN VALUES</title>
+
+ <para><function>lwres_conf_parse()</function>
+ returns <errorcode>LWRES_R_SUCCESS</errorcode>
+ if it successfully read and parsed
+ <parameter>filename</parameter>.
+ It returns <errorcode>LWRES_R_FAILURE</errorcode>
+ if <parameter>filename</parameter>
+ could not be opened or contained incorrect
+ resolver statements.
+ </para>
+
+ <para><function>lwres_conf_print()</function>
+ returns <errorcode>LWRES_R_SUCCESS</errorcode>
+ unless an error occurred when converting the network addresses to a
+ numeric host address string.
+ If this happens, the function returns
+ <errorcode>LWRES_R_FAILURE</errorcode>.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>stdio</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>resolver</refentrytitle><manvolnum>5</manvolnum>
+ </citerefentry>.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>FILES</title>
+ <para><filename>/etc/resolv.conf</filename>
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_config.html b/lib/lwres/man/lwres_config.html
new file mode 100644
index 0000000..efa33d8
--- /dev/null
+++ b/lib/lwres/man/lwres_config.html
@@ -0,0 +1,156 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_config.html,v 1.5.18.17 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_config</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_conf_init, lwres_conf_clear, lwres_conf_parse, lwres_conf_print, lwres_conf_get &#8212; lightweight resolver configuration</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/lwres.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_conf_init</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_conf_clear</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_conf_parse</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>const char * </td>
+<td>
+<var class="pdparam">filename</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_conf_print</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>FILE * </td>
+<td>
+<var class="pdparam">fp</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0"><tr>
+<td><code class="funcdef">
+lwres_conf_t *
+<b class="fsfunc">lwres_conf_get</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var><code>)</code>;</td>
+</tr></table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543441"></a><h2>DESCRIPTION</h2>
+<p><code class="function">lwres_conf_init()</code>
+ creates an empty
+ <span class="type">lwres_conf_t</span>
+ structure for lightweight resolver context
+ <em class="parameter"><code>ctx</code></em>.
+ </p>
+<p><code class="function">lwres_conf_clear()</code>
+ frees up all the internal memory used by
+ that
+ <span class="type">lwres_conf_t</span>
+ structure in resolver context
+ <em class="parameter"><code>ctx</code></em>.
+ </p>
+<p><code class="function">lwres_conf_parse()</code>
+ opens the file
+ <em class="parameter"><code>filename</code></em>
+ and parses it to initialise the resolver context
+ <em class="parameter"><code>ctx</code></em>'s
+ <span class="type">lwres_conf_t</span>
+ structure.
+ </p>
+<p><code class="function">lwres_conf_print()</code>
+ prints the
+ <span class="type">lwres_conf_t</span>
+ structure for resolver context
+ <em class="parameter"><code>ctx</code></em>
+ to the
+ <span class="type">FILE</span>
+ <em class="parameter"><code>fp</code></em>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543508"></a><h2>RETURN VALUES</h2>
+<p><code class="function">lwres_conf_parse()</code>
+ returns <span class="errorcode">LWRES_R_SUCCESS</span>
+ if it successfully read and parsed
+ <em class="parameter"><code>filename</code></em>.
+ It returns <span class="errorcode">LWRES_R_FAILURE</span>
+ if <em class="parameter"><code>filename</code></em>
+ could not be opened or contained incorrect
+ resolver statements.
+ </p>
+<p><code class="function">lwres_conf_print()</code>
+ returns <span class="errorcode">LWRES_R_SUCCESS</span>
+ unless an error occurred when converting the network addresses to a
+ numeric host address string.
+ If this happens, the function returns
+ <span class="errorcode">LWRES_R_FAILURE</span>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543545"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">stdio</span>(3)</span>,
+ <span class="citerefentry"><span class="refentrytitle">resolver</span>(5)</span>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543571"></a><h2>FILES</h2>
+<p><code class="filename">/etc/resolv.conf</code>
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_context.3 b/lib/lwres/man/lwres_context.3
new file mode 100644
index 0000000..8883a01
--- /dev/null
+++ b/lib/lwres/man/lwres_context.3
@@ -0,0 +1,170 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_context.3,v 1.17.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_context
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_CONTEXT" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_context_create, lwres_context_destroy, lwres_context_nextserial, lwres_context_initserial, lwres_context_freemem, lwres_context_allocmem, lwres_context_sendrecv \- lightweight resolver context management
+.SH "SYNOPSIS"
+.nf
+#include <lwres/lwres.h>
+.fi
+.HP 36
+.BI "lwres_result_t lwres_context_create(lwres_context_t\ **" "contextp" ", void\ *" "arg" ", lwres_malloc_t\ " "malloc_function" ", lwres_free_t\ " "free_function" ");"
+.HP 37
+.BI "lwres_result_t lwres_context_destroy(lwres_context_t\ **" "contextp" ");"
+.HP 30
+.BI "void lwres_context_initserial(lwres_context_t\ *" "ctx" ", lwres_uint32_t\ " "serial" ");"
+.HP 40
+.BI "lwres_uint32_t lwres_context_nextserial(lwres_context_t\ *" "ctx" ");"
+.HP 27
+.BI "void lwres_context_freemem(lwres_context_t\ *" "ctx" ", void\ *" "mem" ", size_t\ " "len" ");"
+.HP 28
+.BI "void lwres_context_allocmem(lwres_context_t\ *" "ctx" ", size_t\ " "len" ");"
+.HP 30
+.BI "void * lwres_context_sendrecv(lwres_context_t\ *" "ctx" ", void\ *" "sendbase" ", int\ " "sendlen" ", void\ *" "recvbase" ", int\ " "recvlen" ", int\ *" "recvd_len" ");"
+.SH "DESCRIPTION"
+.PP
+\fBlwres_context_create()\fR
+creates a
+\fBlwres_context_t\fR
+structure for use in lightweight resolver operations. It holds a socket and other data needed for communicating with a resolver daemon. The new
+\fBlwres_context_t\fR
+is returned through
+\fIcontextp\fR, a pointer to a
+\fBlwres_context_t\fR
+pointer. This
+\fBlwres_context_t\fR
+pointer must initially be NULL, and is modified to point to the newly created
+\fBlwres_context_t\fR.
+.PP
+When the lightweight resolver needs to perform dynamic memory allocation, it will call
+\fImalloc_function\fR
+to allocate memory and
+\fIfree_function\fR
+to free it. If
+\fImalloc_function\fR
+and
+\fIfree_function\fR
+are NULL, memory is allocated using
+\fBmalloc\fR(3). and
+\fBfree\fR(3). It is not permitted to have a NULL
+\fImalloc_function\fR
+and a non\-NULL
+\fIfree_function\fR
+or vice versa.
+\fIarg\fR
+is passed as the first parameter to the memory allocation functions. If
+\fImalloc_function\fR
+and
+\fIfree_function\fR
+are NULL,
+\fIarg\fR
+is unused and should be passed as NULL.
+.PP
+Once memory for the structure has been allocated, it is initialized using
+\fBlwres_conf_init\fR(3)
+and returned via
+\fI*contextp\fR.
+.PP
+\fBlwres_context_destroy()\fR
+destroys a
+\fBlwres_context_t\fR, closing its socket.
+\fIcontextp\fR
+is a pointer to a pointer to the context that is to be destroyed. The pointer will be set to NULL when the context has been destroyed.
+.PP
+The context holds a serial number that is used to identify resolver request packets and associate responses with the corresponding requests. This serial number is controlled using
+\fBlwres_context_initserial()\fR
+and
+\fBlwres_context_nextserial()\fR.
+\fBlwres_context_initserial()\fR
+sets the serial number for context
+\fI*ctx\fR
+to
+\fIserial\fR.
+\fBlwres_context_nextserial()\fR
+increments the serial number and returns the previous value.
+.PP
+Memory for a lightweight resolver context is allocated and freed using
+\fBlwres_context_allocmem()\fR
+and
+\fBlwres_context_freemem()\fR. These use whatever allocations were defined when the context was created with
+\fBlwres_context_create()\fR.
+\fBlwres_context_allocmem()\fR
+allocates
+\fIlen\fR
+bytes of memory and if successful returns a pointer to the allocated storage.
+\fBlwres_context_freemem()\fR
+frees
+\fIlen\fR
+bytes of space starting at location
+\fImem\fR.
+.PP
+\fBlwres_context_sendrecv()\fR
+performs I/O for the context
+\fIctx\fR. Data are read and written from the context's socket. It writes data from
+\fIsendbase\fR
+\(em typically a lightweight resolver query packet \(em and waits for a reply which is copied to the receive buffer at
+\fIrecvbase\fR. The number of bytes that were written to this receive buffer is returned in
+\fI*recvd_len\fR.
+.SH "RETURN VALUES"
+.PP
+\fBlwres_context_create()\fR
+returns
+\fBLWRES_R_NOMEMORY\fR
+if memory for the
+\fBstruct lwres_context\fR
+could not be allocated,
+\fBLWRES_R_SUCCESS\fR
+otherwise.
+.PP
+Successful calls to the memory allocator
+\fBlwres_context_allocmem()\fR
+return a pointer to the start of the allocated space. It returns NULL if memory could not be allocated.
+.PP
+\fBLWRES_R_SUCCESS\fR
+is returned when
+\fBlwres_context_sendrecv()\fR
+completes successfully.
+\fBLWRES_R_IOERROR\fR
+is returned if an I/O error occurs and
+\fBLWRES_R_TIMEOUT\fR
+is returned if
+\fBlwres_context_sendrecv()\fR
+times out waiting for a response.
+.SH "SEE ALSO"
+.PP
+\fBlwres_conf_init\fR(3),
+\fBmalloc\fR(3),
+\fBfree\fR(3).
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001, 2003 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_context.docbook b/lib/lwres/man/lwres_context.docbook
new file mode 100644
index 0000000..b965374
--- /dev/null
+++ b/lib/lwres/man/lwres_context.docbook
@@ -0,0 +1,262 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_context.docbook,v 1.5.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_context</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <year>2003</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_context_create</refname>
+ <refname>lwres_context_destroy</refname>
+ <refname>lwres_context_nextserial</refname>
+ <refname>lwres_context_initserial</refname>
+ <refname>lwres_context_freemem</refname>
+ <refname>lwres_context_allocmem</refname>
+ <refname>lwres_context_sendrecv</refname>
+ <refpurpose>lightweight resolver context management</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_context_create</function></funcdef>
+ <paramdef>lwres_context_t **<parameter>contextp</parameter></paramdef>
+ <paramdef>void *<parameter>arg</parameter></paramdef>
+ <paramdef>lwres_malloc_t <parameter>malloc_function</parameter></paramdef>
+ <paramdef>lwres_free_t <parameter>free_function</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_context_destroy</function></funcdef>
+ <paramdef>lwres_context_t **<parameter>contextp</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_context_initserial</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_uint32_t <parameter>serial</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_uint32_t
+<function>lwres_context_nextserial</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_context_freemem</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>void *<parameter>mem</parameter></paramdef>
+ <paramdef>size_t <parameter>len</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_context_allocmem</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>size_t <parameter>len</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void *
+<function>lwres_context_sendrecv</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>void *<parameter>sendbase</parameter></paramdef>
+ <paramdef>int <parameter>sendlen</parameter></paramdef>
+ <paramdef>void *<parameter>recvbase</parameter></paramdef>
+ <paramdef>int <parameter>recvlen</parameter></paramdef>
+ <paramdef>int *<parameter>recvd_len</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><function>lwres_context_create()</function>
+ creates a <type>lwres_context_t</type> structure for use in
+ lightweight resolver operations. It holds a socket and other
+ data needed for communicating with a resolver daemon. The new
+ <type>lwres_context_t</type> is returned through
+ <parameter>contextp</parameter>, a pointer to a
+ <type>lwres_context_t</type> pointer. This
+ <type>lwres_context_t</type> pointer must initially be NULL, and
+ is modified to point to the newly created
+ <type>lwres_context_t</type>.
+ </para>
+ <para>
+ When the lightweight resolver needs to perform dynamic memory
+ allocation, it will call
+ <parameter>malloc_function</parameter>
+ to allocate memory and
+ <parameter>free_function</parameter>
+ to free it. If
+ <parameter>malloc_function</parameter>
+ and
+ <parameter>free_function</parameter>
+ are NULL, memory is allocated using
+ <citerefentry>
+ <refentrytitle>malloc</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ and
+ <citerefentry>
+ <refentrytitle>free</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+
+ It is not permitted to have a NULL
+ <parameter>malloc_function</parameter> and a non-NULL
+ <parameter>free_function</parameter> or vice versa.
+ <parameter>arg</parameter> is passed as the first parameter to
+ the memory allocation functions. If
+ <parameter>malloc_function</parameter> and
+ <parameter>free_function</parameter> are NULL,
+ <parameter>arg</parameter> is unused and should be passed as
+ NULL.
+ </para>
+
+ <para>
+ Once memory for the structure has been allocated,
+ it is initialized using
+ <citerefentry>
+ <refentrytitle>lwres_conf_init</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>
+ and returned via <parameter>*contextp</parameter>.
+ </para>
+
+ <para><function>lwres_context_destroy()</function>
+ destroys a <type>lwres_context_t</type>, closing its socket.
+ <parameter>contextp</parameter> is a pointer to a pointer to the
+ context that is to be destroyed. The pointer will be set to
+ NULL when the context has been destroyed.
+ </para>
+
+ <para>
+ The context holds a serial number that is used to identify
+ resolver request packets and associate responses with the
+ corresponding requests. This serial number is controlled using
+ <function>lwres_context_initserial()</function> and
+ <function>lwres_context_nextserial()</function>.
+ <function>lwres_context_initserial()</function> sets the serial
+ number for context <parameter>*ctx</parameter> to
+ <parameter>serial</parameter>.
+ <function>lwres_context_nextserial()</function> increments the
+ serial number and returns the previous value.
+ </para>
+
+ <para>
+ Memory for a lightweight resolver context is allocated and freed
+ using <function>lwres_context_allocmem()</function> and
+ <function>lwres_context_freemem()</function>. These use
+ whatever allocations were defined when the context was created
+ with <function>lwres_context_create()</function>.
+ <function>lwres_context_allocmem()</function> allocates
+ <parameter>len</parameter> bytes of memory and if successful
+ returns a pointer to the allocated storage.
+ <function>lwres_context_freemem()</function> frees
+ <parameter>len</parameter> bytes of space starting at location
+ <parameter>mem</parameter>.
+ </para>
+
+ <para><function>lwres_context_sendrecv()</function>
+ performs I/O for the context <parameter>ctx</parameter>. Data
+ are read and written from the context's socket. It writes data
+ from <parameter>sendbase</parameter> &mdash; typically a
+ lightweight resolver query packet &mdash; and waits for a reply
+ which is copied to the receive buffer at
+ <parameter>recvbase</parameter>. The number of bytes that were
+ written to this receive buffer is returned in
+ <parameter>*recvd_len</parameter>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>RETURN VALUES</title>
+
+ <para><function>lwres_context_create()</function>
+ returns <errorcode>LWRES_R_NOMEMORY</errorcode> if memory for
+ the <type>struct lwres_context</type> could not be allocated,
+ <errorcode>LWRES_R_SUCCESS</errorcode> otherwise.
+ </para>
+ <para>
+ Successful calls to the memory allocator
+ <function>lwres_context_allocmem()</function>
+ return a pointer to the start of the allocated space.
+ It returns NULL if memory could not be allocated.
+ </para>
+ <para><errorcode>LWRES_R_SUCCESS</errorcode>
+ is returned when
+ <function>lwres_context_sendrecv()</function>
+ completes successfully.
+ <errorcode>LWRES_R_IOERROR</errorcode>
+ is returned if an I/O error occurs and
+ <errorcode>LWRES_R_TIMEOUT</errorcode>
+ is returned if
+ <function>lwres_context_sendrecv()</function>
+ times out waiting for a response.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>lwres_conf_init</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>malloc</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>free</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_context.html b/lib/lwres/man/lwres_context.html
new file mode 100644
index 0000000..f2aa7e1
--- /dev/null
+++ b/lib/lwres/man/lwres_context.html
@@ -0,0 +1,295 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_context.html,v 1.7.18.16 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_context</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_context_create, lwres_context_destroy, lwres_context_nextserial, lwres_context_initserial, lwres_context_freemem, lwres_context_allocmem, lwres_context_sendrecv &#8212; lightweight resolver context management</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/lwres.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_context_create</b>(</code></td>
+<td>lwres_context_t ** </td>
+<td>
+<var class="pdparam">contextp</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>void * </td>
+<td>
+<var class="pdparam">arg</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_malloc_t  </td>
+<td>
+<var class="pdparam">malloc_function</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_free_t  </td>
+<td>
+<var class="pdparam">free_function</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_context_destroy</b>(</code></td>
+<td>lwres_context_t ** </td>
+<td>
+<var class="pdparam">contextp</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_context_initserial</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_uint32_t  </td>
+<td>
+<var class="pdparam">serial</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+lwres_uint32_t
+<b class="fsfunc">lwres_context_nextserial</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_context_freemem</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>void * </td>
+<td>
+<var class="pdparam">mem</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>size_t  </td>
+<td>
+<var class="pdparam">len</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_context_allocmem</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>size_t  </td>
+<td>
+<var class="pdparam">len</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0">
+<tr>
+<td><code class="funcdef">
+void *
+<b class="fsfunc">lwres_context_sendrecv</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>void * </td>
+<td>
+<var class="pdparam">sendbase</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">sendlen</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>void * </td>
+<td>
+<var class="pdparam">recvbase</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">recvlen</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int * </td>
+<td>
+<var class="pdparam">recvd_len</var><code>)</code>;</td>
+</tr>
+</table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543531"></a><h2>DESCRIPTION</h2>
+<p><code class="function">lwres_context_create()</code>
+ creates a <span class="type">lwres_context_t</span> structure for use in
+ lightweight resolver operations. It holds a socket and other
+ data needed for communicating with a resolver daemon. The new
+ <span class="type">lwres_context_t</span> is returned through
+ <em class="parameter"><code>contextp</code></em>, a pointer to a
+ <span class="type">lwres_context_t</span> pointer. This
+ <span class="type">lwres_context_t</span> pointer must initially be NULL, and
+ is modified to point to the newly created
+ <span class="type">lwres_context_t</span>.
+ </p>
+<p>
+ When the lightweight resolver needs to perform dynamic memory
+ allocation, it will call
+ <em class="parameter"><code>malloc_function</code></em>
+ to allocate memory and
+ <em class="parameter"><code>free_function</code></em>
+ to free it. If
+ <em class="parameter"><code>malloc_function</code></em>
+ and
+ <em class="parameter"><code>free_function</code></em>
+ are NULL, memory is allocated using
+ <span class="citerefentry"><span class="refentrytitle">malloc</span>(3)</span>.
+ and
+ <span class="citerefentry"><span class="refentrytitle">free</span>(3)</span>.
+
+ It is not permitted to have a NULL
+ <em class="parameter"><code>malloc_function</code></em> and a non-NULL
+ <em class="parameter"><code>free_function</code></em> or vice versa.
+ <em class="parameter"><code>arg</code></em> is passed as the first parameter to
+ the memory allocation functions. If
+ <em class="parameter"><code>malloc_function</code></em> and
+ <em class="parameter"><code>free_function</code></em> are NULL,
+ <em class="parameter"><code>arg</code></em> is unused and should be passed as
+ NULL.
+ </p>
+<p>
+ Once memory for the structure has been allocated,
+ it is initialized using
+ <span class="citerefentry"><span class="refentrytitle">lwres_conf_init</span>(3)</span>
+ and returned via <em class="parameter"><code>*contextp</code></em>.
+ </p>
+<p><code class="function">lwres_context_destroy()</code>
+ destroys a <span class="type">lwres_context_t</span>, closing its socket.
+ <em class="parameter"><code>contextp</code></em> is a pointer to a pointer to the
+ context that is to be destroyed. The pointer will be set to
+ NULL when the context has been destroyed.
+ </p>
+<p>
+ The context holds a serial number that is used to identify
+ resolver request packets and associate responses with the
+ corresponding requests. This serial number is controlled using
+ <code class="function">lwres_context_initserial()</code> and
+ <code class="function">lwres_context_nextserial()</code>.
+ <code class="function">lwres_context_initserial()</code> sets the serial
+ number for context <em class="parameter"><code>*ctx</code></em> to
+ <em class="parameter"><code>serial</code></em>.
+ <code class="function">lwres_context_nextserial()</code> increments the
+ serial number and returns the previous value.
+ </p>
+<p>
+ Memory for a lightweight resolver context is allocated and freed
+ using <code class="function">lwres_context_allocmem()</code> and
+ <code class="function">lwres_context_freemem()</code>. These use
+ whatever allocations were defined when the context was created
+ with <code class="function">lwres_context_create()</code>.
+ <code class="function">lwres_context_allocmem()</code> allocates
+ <em class="parameter"><code>len</code></em> bytes of memory and if successful
+ returns a pointer to the allocated storage.
+ <code class="function">lwres_context_freemem()</code> frees
+ <em class="parameter"><code>len</code></em> bytes of space starting at location
+ <em class="parameter"><code>mem</code></em>.
+ </p>
+<p><code class="function">lwres_context_sendrecv()</code>
+ performs I/O for the context <em class="parameter"><code>ctx</code></em>. Data
+ are read and written from the context's socket. It writes data
+ from <em class="parameter"><code>sendbase</code></em> &#8212; typically a
+ lightweight resolver query packet &#8212; and waits for a reply
+ which is copied to the receive buffer at
+ <em class="parameter"><code>recvbase</code></em>. The number of bytes that were
+ written to this receive buffer is returned in
+ <em class="parameter"><code>*recvd_len</code></em>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543719"></a><h2>RETURN VALUES</h2>
+<p><code class="function">lwres_context_create()</code>
+ returns <span class="errorcode">LWRES_R_NOMEMORY</span> if memory for
+ the <span class="type">struct lwres_context</span> could not be allocated,
+ <span class="errorcode">LWRES_R_SUCCESS</span> otherwise.
+ </p>
+<p>
+ Successful calls to the memory allocator
+ <code class="function">lwres_context_allocmem()</code>
+ return a pointer to the start of the allocated space.
+ It returns NULL if memory could not be allocated.
+ </p>
+<p><span class="errorcode">LWRES_R_SUCCESS</span>
+ is returned when
+ <code class="function">lwres_context_sendrecv()</code>
+ completes successfully.
+ <span class="errorcode">LWRES_R_IOERROR</span>
+ is returned if an I/O error occurs and
+ <span class="errorcode">LWRES_R_TIMEOUT</span>
+ is returned if
+ <code class="function">lwres_context_sendrecv()</code>
+ times out waiting for a response.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543769"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">lwres_conf_init</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">malloc</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">free</span>(3)</span>.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_gabn.3 b/lib/lwres/man/lwres_gabn.3
new file mode 100644
index 0000000..69d311f
--- /dev/null
+++ b/lib/lwres/man/lwres_gabn.3
@@ -0,0 +1,195 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_gabn.3,v 1.16.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_gabn
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_GABN" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_gabnrequest_render, lwres_gabnresponse_render, lwres_gabnrequest_parse, lwres_gabnresponse_parse, lwres_gabnresponse_free, lwres_gabnrequest_free \- lightweight resolver getaddrbyname message handling
+.SH "SYNOPSIS"
+.nf
+#include <lwres/lwres.h>
+.fi
+.HP 40
+.BI "lwres_result_t lwres_gabnrequest_render(lwres_context_t\ *" "ctx" ", lwres_gabnrequest_t\ *" "req" ", lwres_lwpacket_t\ *" "pkt" ", lwres_buffer_t\ *" "b" ");"
+.HP 41
+.BI "lwres_result_t lwres_gabnresponse_render(lwres_context_t\ *" "ctx" ", lwres_gabnresponse_t\ *" "req" ", lwres_lwpacket_t\ *" "pkt" ", lwres_buffer_t\ *" "b" ");"
+.HP 39
+.BI "lwres_result_t lwres_gabnrequest_parse(lwres_context_t\ *" "ctx" ", lwres_buffer_t\ *" "b" ", lwres_lwpacket_t\ *" "pkt" ", lwres_gabnrequest_t\ **" "structp" ");"
+.HP 40
+.BI "lwres_result_t lwres_gabnresponse_parse(lwres_context_t\ *" "ctx" ", lwres_buffer_t\ *" "b" ", lwres_lwpacket_t\ *" "pkt" ", lwres_gabnresponse_t\ **" "structp" ");"
+.HP 29
+.BI "void lwres_gabnresponse_free(lwres_context_t\ *" "ctx" ", lwres_gabnresponse_t\ **" "structp" ");"
+.HP 28
+.BI "void lwres_gabnrequest_free(lwres_context_t\ *" "ctx" ", lwres_gabnrequest_t\ **" "structp" ");"
+.SH "DESCRIPTION"
+.PP
+These are low\-level routines for creating and parsing lightweight resolver name\-to\-address lookup request and response messages.
+.PP
+There are four main functions for the getaddrbyname opcode. One render function converts a getaddrbyname request structure \(em
+\fBlwres_gabnrequest_t\fR
+\(em to the lighweight resolver's canonical format. It is complemented by a parse function that converts a packet in this canonical format to a getaddrbyname request structure. Another render function converts the getaddrbyname response structure \(em
+\fBlwres_gabnresponse_t\fR
+\(em to the canonical format. This is complemented by a parse function which converts a packet in canonical format to a getaddrbyname response structure.
+.PP
+These structures are defined in
+\fI<lwres/lwres.h>\fR. They are shown below.
+.PP
+.RS 4
+.nf
+#define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
+.fi
+.RE
+.sp
+.PP
+.RS 4
+.nf
+typedef struct lwres_addr lwres_addr_t;
+typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
+.fi
+.RE
+.sp
+.PP
+.RS 4
+.nf
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint32_t addrtypes;
+ lwres_uint16_t namelen;
+ char *name;
+} lwres_gabnrequest_t;
+.fi
+.RE
+.sp
+.PP
+.RS 4
+.nf
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+.fi
+.RE
+.sp
+.PP
+\fBlwres_gabnrequest_render()\fR
+uses resolver context
+\fIctx\fR
+to convert getaddrbyname request structure
+\fIreq\fR
+to canonical format. The packet header structure
+\fIpkt\fR
+is initialised and transferred to buffer
+\fIb\fR. The contents of
+\fI*req\fR
+are then appended to the buffer in canonical format.
+\fBlwres_gabnresponse_render()\fR
+performs the same task, except it converts a getaddrbyname response structure
+\fBlwres_gabnresponse_t\fR
+to the lightweight resolver's canonical format.
+.PP
+\fBlwres_gabnrequest_parse()\fR
+uses context
+\fIctx\fR
+to convert the contents of packet
+\fIpkt\fR
+to a
+\fBlwres_gabnrequest_t\fR
+structure. Buffer
+\fIb\fR
+provides space to be used for storing this structure. When the function succeeds, the resulting
+\fBlwres_gabnrequest_t\fR
+is made available through
+\fI*structp\fR.
+\fBlwres_gabnresponse_parse()\fR
+offers the same semantics as
+\fBlwres_gabnrequest_parse()\fR
+except it yields a
+\fBlwres_gabnresponse_t\fR
+structure.
+.PP
+\fBlwres_gabnresponse_free()\fR
+and
+\fBlwres_gabnrequest_free()\fR
+release the memory in resolver context
+\fIctx\fR
+that was allocated to the
+\fBlwres_gabnresponse_t\fR
+or
+\fBlwres_gabnrequest_t\fR
+structures referenced via
+\fIstructp\fR. Any memory associated with ancillary buffers and strings for those structures is also discarded.
+.SH "RETURN VALUES"
+.PP
+The getaddrbyname opcode functions
+\fBlwres_gabnrequest_render()\fR,
+\fBlwres_gabnresponse_render()\fR
+\fBlwres_gabnrequest_parse()\fR
+and
+\fBlwres_gabnresponse_parse()\fR
+all return
+\fBLWRES_R_SUCCESS\fR
+on success. They return
+\fBLWRES_R_NOMEMORY\fR
+if memory allocation fails.
+\fBLWRES_R_UNEXPECTEDEND\fR
+is returned if the available space in the buffer
+\fIb\fR
+is too small to accommodate the packet header or the
+\fBlwres_gabnrequest_t\fR
+and
+\fBlwres_gabnresponse_t\fR
+structures.
+\fBlwres_gabnrequest_parse()\fR
+and
+\fBlwres_gabnresponse_parse()\fR
+will return
+\fBLWRES_R_UNEXPECTEDEND\fR
+if the buffer is not empty after decoding the received packet. These functions will return
+\fBLWRES_R_FAILURE\fR
+if
+pktflags
+in the packet header structure
+\fBlwres_lwpacket_t\fR
+indicate that the packet is not a response to an earlier query.
+.SH "SEE ALSO"
+.PP
+\fBlwres_packet\fR(3)
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_gabn.docbook b/lib/lwres/man/lwres_gabn.docbook
new file mode 100644
index 0000000..c719420
--- /dev/null
+++ b/lib/lwres/man/lwres_gabn.docbook
@@ -0,0 +1,260 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_gabn.docbook,v 1.4.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_gabn</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_gabnrequest_render</refname>
+ <refname>lwres_gabnresponse_render</refname>
+ <refname>lwres_gabnrequest_parse</refname>
+ <refname>lwres_gabnresponse_parse</refname>
+ <refname>lwres_gabnresponse_free</refname>
+ <refname>lwres_gabnrequest_free</refname>
+ <refpurpose>lightweight resolver getaddrbyname message handling</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_gabnrequest_render</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_gabnrequest_t *<parameter>req</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_gabnresponse_render</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_gabnresponse_t *<parameter>req</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_gabnrequest_parse</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_gabnrequest_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_gabnresponse_parse</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_gabnresponse_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_gabnresponse_free</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_gabnresponse_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_gabnrequest_free</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_gabnrequest_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+ <refsect1>
+ <title>DESCRIPTION</title>
+ <para>
+ These are low-level routines for creating and parsing
+ lightweight resolver name-to-address lookup request and
+ response messages.
+ </para>
+ <para>
+ There are four main functions for the getaddrbyname opcode.
+ One render function converts a getaddrbyname request structure &mdash;
+ <type>lwres_gabnrequest_t</type> &mdash;
+ to the lighweight resolver's canonical format.
+ It is complemented by a parse function that converts a packet in this
+ canonical format to a getaddrbyname request structure.
+ Another render function converts the getaddrbyname response structure
+ &mdash; <type>lwres_gabnresponse_t</type> &mdash;
+ to the canonical format.
+ This is complemented by a parse function which converts a packet in
+ canonical format to a getaddrbyname response structure.
+ </para>
+ <para>
+ These structures are defined in
+ <filename>&lt;lwres/lwres.h&gt;</filename>.
+ They are shown below.
+ </para>
+ <para><programlisting>
+#define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
+</programlisting>
+ </para>
+ <para><programlisting>
+typedef struct lwres_addr lwres_addr_t;
+typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
+</programlisting>
+ </para>
+ <para><programlisting>
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint32_t addrtypes;
+ lwres_uint16_t namelen;
+ char *name;
+} lwres_gabnrequest_t;
+</programlisting>
+ </para>
+ <para><programlisting>
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+</programlisting>
+ </para>
+
+ <para><function>lwres_gabnrequest_render()</function>
+ uses resolver context <parameter>ctx</parameter> to convert
+ getaddrbyname request structure <parameter>req</parameter> to
+ canonical format. The packet header structure
+ <parameter>pkt</parameter> is initialised and transferred to
+ buffer <parameter>b</parameter>.
+
+ The contents of <parameter>*req</parameter> are then appended to
+ the buffer in canonical format.
+ <function>lwres_gabnresponse_render()</function> performs the
+ same task, except it converts a getaddrbyname response structure
+ <type>lwres_gabnresponse_t</type> to the lightweight resolver's
+ canonical format.
+ </para>
+
+ <para><function>lwres_gabnrequest_parse()</function>
+ uses context <parameter>ctx</parameter> to convert the contents
+ of packet <parameter>pkt</parameter> to a
+ <type>lwres_gabnrequest_t</type> structure. Buffer
+ <parameter>b</parameter> provides space to be used for storing
+ this structure. When the function succeeds, the resulting
+ <type>lwres_gabnrequest_t</type> is made available through
+ <parameter>*structp</parameter>.
+
+ <function>lwres_gabnresponse_parse()</function> offers the same
+ semantics as <function>lwres_gabnrequest_parse()</function>
+ except it yields a <type>lwres_gabnresponse_t</type> structure.
+ </para>
+
+ <para><function>lwres_gabnresponse_free()</function>
+ and <function>lwres_gabnrequest_free()</function> release the
+ memory in resolver context <parameter>ctx</parameter> that was
+ allocated to the <type>lwres_gabnresponse_t</type> or
+ <type>lwres_gabnrequest_t</type> structures referenced via
+ <parameter>structp</parameter>.
+
+ Any memory associated with ancillary buffers and strings for
+ those structures is also discarded.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>RETURN VALUES</title>
+ <para>
+ The getaddrbyname opcode functions
+ <function>lwres_gabnrequest_render()</function>,
+ <function>lwres_gabnresponse_render()</function>
+ <function>lwres_gabnrequest_parse()</function>
+ and
+ <function>lwres_gabnresponse_parse()</function>
+ all return
+ <errorcode>LWRES_R_SUCCESS</errorcode>
+ on success.
+ They return
+ <errorcode>LWRES_R_NOMEMORY</errorcode>
+ if memory allocation fails.
+ <errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+ is returned if the available space in the buffer
+ <parameter>b</parameter>
+ is too small to accommodate the packet header or the
+ <type>lwres_gabnrequest_t</type>
+ and
+ <type>lwres_gabnresponse_t</type>
+ structures.
+ <function>lwres_gabnrequest_parse()</function>
+ and
+ <function>lwres_gabnresponse_parse()</function>
+ will return
+ <errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+ if the buffer is not empty after decoding the received packet.
+ These functions will return
+ <errorcode>LWRES_R_FAILURE</errorcode>
+ if
+ <structfield>pktflags</structfield>
+ in the packet header structure
+ <type>lwres_lwpacket_t</type>
+ indicate that the packet is not a response to an earlier query.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>lwres_packet</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_gabn.html b/lib/lwres/man/lwres_gabn.html
new file mode 100644
index 0000000..e27954b
--- /dev/null
+++ b/lib/lwres/man/lwres_gabn.html
@@ -0,0 +1,324 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_gabn.html,v 1.7.18.17 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_gabn</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_gabnrequest_render, lwres_gabnresponse_render, lwres_gabnrequest_parse, lwres_gabnresponse_parse, lwres_gabnresponse_free, lwres_gabnrequest_free &#8212; lightweight resolver getaddrbyname message handling</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/lwres.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_gabnrequest_render</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gabnrequest_t * </td>
+<td>
+<var class="pdparam">req</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_gabnresponse_render</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gabnresponse_t * </td>
+<td>
+<var class="pdparam">req</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_gabnrequest_parse</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gabnrequest_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_gabnresponse_parse</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gabnresponse_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_gabnresponse_free</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gabnresponse_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_gabnrequest_free</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gabnrequest_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543522"></a><h2>DESCRIPTION</h2>
+<p>
+ These are low-level routines for creating and parsing
+ lightweight resolver name-to-address lookup request and
+ response messages.
+ </p>
+<p>
+ There are four main functions for the getaddrbyname opcode.
+ One render function converts a getaddrbyname request structure &#8212;
+ <span class="type">lwres_gabnrequest_t</span> &#8212;
+ to the lighweight resolver's canonical format.
+ It is complemented by a parse function that converts a packet in this
+ canonical format to a getaddrbyname request structure.
+ Another render function converts the getaddrbyname response structure
+ &#8212; <span class="type">lwres_gabnresponse_t</span> &#8212;
+ to the canonical format.
+ This is complemented by a parse function which converts a packet in
+ canonical format to a getaddrbyname response structure.
+ </p>
+<p>
+ These structures are defined in
+ <code class="filename">&lt;lwres/lwres.h&gt;</code>.
+ They are shown below.
+ </p>
+<pre class="programlisting">
+#define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
+</pre>
+<p>
+ </p>
+<pre class="programlisting">
+typedef struct lwres_addr lwres_addr_t;
+typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
+</pre>
+<p>
+ </p>
+<pre class="programlisting">
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint32_t addrtypes;
+ lwres_uint16_t namelen;
+ char *name;
+} lwres_gabnrequest_t;
+</pre>
+<p>
+ </p>
+<pre class="programlisting">
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+</pre>
+<p>
+ </p>
+<p><code class="function">lwres_gabnrequest_render()</code>
+ uses resolver context <em class="parameter"><code>ctx</code></em> to convert
+ getaddrbyname request structure <em class="parameter"><code>req</code></em> to
+ canonical format. The packet header structure
+ <em class="parameter"><code>pkt</code></em> is initialised and transferred to
+ buffer <em class="parameter"><code>b</code></em>.
+
+ The contents of <em class="parameter"><code>*req</code></em> are then appended to
+ the buffer in canonical format.
+ <code class="function">lwres_gabnresponse_render()</code> performs the
+ same task, except it converts a getaddrbyname response structure
+ <span class="type">lwres_gabnresponse_t</span> to the lightweight resolver's
+ canonical format.
+ </p>
+<p><code class="function">lwres_gabnrequest_parse()</code>
+ uses context <em class="parameter"><code>ctx</code></em> to convert the contents
+ of packet <em class="parameter"><code>pkt</code></em> to a
+ <span class="type">lwres_gabnrequest_t</span> structure. Buffer
+ <em class="parameter"><code>b</code></em> provides space to be used for storing
+ this structure. When the function succeeds, the resulting
+ <span class="type">lwres_gabnrequest_t</span> is made available through
+ <em class="parameter"><code>*structp</code></em>.
+
+ <code class="function">lwres_gabnresponse_parse()</code> offers the same
+ semantics as <code class="function">lwres_gabnrequest_parse()</code>
+ except it yields a <span class="type">lwres_gabnresponse_t</span> structure.
+ </p>
+<p><code class="function">lwres_gabnresponse_free()</code>
+ and <code class="function">lwres_gabnrequest_free()</code> release the
+ memory in resolver context <em class="parameter"><code>ctx</code></em> that was
+ allocated to the <span class="type">lwres_gabnresponse_t</span> or
+ <span class="type">lwres_gabnrequest_t</span> structures referenced via
+ <em class="parameter"><code>structp</code></em>.
+
+ Any memory associated with ancillary buffers and strings for
+ those structures is also discarded.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543667"></a><h2>RETURN VALUES</h2>
+<p>
+ The getaddrbyname opcode functions
+ <code class="function">lwres_gabnrequest_render()</code>,
+ <code class="function">lwres_gabnresponse_render()</code>
+ <code class="function">lwres_gabnrequest_parse()</code>
+ and
+ <code class="function">lwres_gabnresponse_parse()</code>
+ all return
+ <span class="errorcode">LWRES_R_SUCCESS</span>
+ on success.
+ They return
+ <span class="errorcode">LWRES_R_NOMEMORY</span>
+ if memory allocation fails.
+ <span class="errorcode">LWRES_R_UNEXPECTEDEND</span>
+ is returned if the available space in the buffer
+ <em class="parameter"><code>b</code></em>
+ is too small to accommodate the packet header or the
+ <span class="type">lwres_gabnrequest_t</span>
+ and
+ <span class="type">lwres_gabnresponse_t</span>
+ structures.
+ <code class="function">lwres_gabnrequest_parse()</code>
+ and
+ <code class="function">lwres_gabnresponse_parse()</code>
+ will return
+ <span class="errorcode">LWRES_R_UNEXPECTEDEND</span>
+ if the buffer is not empty after decoding the received packet.
+ These functions will return
+ <span class="errorcode">LWRES_R_FAILURE</span>
+ if
+ <em class="structfield"><code>pktflags</code></em>
+ in the packet header structure
+ <span class="type">lwres_lwpacket_t</span>
+ indicate that the packet is not a response to an earlier query.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543733"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">lwres_packet</span>(3)</span>
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_gai_strerror.3 b/lib/lwres/man/lwres_gai_strerror.3
new file mode 100644
index 0000000..4fd03e2
--- /dev/null
+++ b/lib/lwres/man/lwres_gai_strerror.3
@@ -0,0 +1,129 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_gai_strerror.3,v 1.16.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_gai_strerror
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_GAI_STRERROR" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_gai_strerror \- print suitable error string
+.SH "SYNOPSIS"
+.nf
+#include <lwres/netdb.h>
+.fi
+.HP 20
+.BI "char * gai_strerror(int\ " "ecode" ");"
+.SH "DESCRIPTION"
+.PP
+\fBlwres_gai_strerror()\fR
+returns an error message corresponding to an error code returned by
+\fBgetaddrinfo()\fR. The following error codes and their meaning are defined in
+\fIinclude/lwres/netdb.h\fR.
+.PP
+\fBEAI_ADDRFAMILY\fR
+.RS 4
+address family for hostname not supported
+.RE
+.PP
+\fBEAI_AGAIN\fR
+.RS 4
+temporary failure in name resolution
+.RE
+.PP
+\fBEAI_BADFLAGS\fR
+.RS 4
+invalid value for
+\fBai_flags\fR
+.RE
+.PP
+\fBEAI_FAIL\fR
+.RS 4
+non\-recoverable failure in name resolution
+.RE
+.PP
+\fBEAI_FAMILY\fR
+.RS 4
+\fBai_family\fR
+not supported
+.RE
+.PP
+\fBEAI_MEMORY\fR
+.RS 4
+memory allocation failure
+.RE
+.PP
+\fBEAI_NODATA\fR
+.RS 4
+no address associated with hostname
+.RE
+.PP
+\fBEAI_NONAME\fR
+.RS 4
+hostname or servname not provided, or not known
+.RE
+.PP
+\fBEAI_SERVICE\fR
+.RS 4
+servname not supported for
+\fBai_socktype\fR
+.RE
+.PP
+\fBEAI_SOCKTYPE\fR
+.RS 4
+\fBai_socktype\fR
+not supported
+.RE
+.PP
+\fBEAI_SYSTEM\fR
+.RS 4
+system error returned in errno
+.RE
+The message
+invalid error code
+is returned if
+\fIecode\fR
+is out of range.
+.PP
+\fBai_flags\fR,
+\fBai_family\fR
+and
+\fBai_socktype\fR
+are elements of the
+\fBstruct addrinfo\fR
+used by
+\fBlwres_getaddrinfo()\fR.
+.SH "SEE ALSO"
+.PP
+\fBstrerror\fR(3),
+\fBlwres_getaddrinfo\fR(3),
+\fBgetaddrinfo\fR(3),
+\fBRFC2133\fR().
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_gai_strerror.docbook b/lib/lwres/man/lwres_gai_strerror.docbook
new file mode 100644
index 0000000..0b0338b
--- /dev/null
+++ b/lib/lwres/man/lwres_gai_strerror.docbook
@@ -0,0 +1,200 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_gai_strerror.docbook,v 1.4.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_gai_strerror</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_gai_strerror</refname>
+ <refpurpose>print suitable error string</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+char *
+<function>gai_strerror</function></funcdef>
+ <paramdef>int <parameter>ecode</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><function>lwres_gai_strerror()</function>
+ returns an error message corresponding to an error code returned by
+ <function>getaddrinfo()</function>.
+ The following error codes and their meaning are defined in
+ <filename>include/lwres/netdb.h</filename>.
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EAI_ADDRFAMILY</errorcode></term>
+ <listitem>
+ <para>
+ address family for hostname not supported
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EAI_AGAIN</errorcode></term>
+ <listitem>
+ <para>
+ temporary failure in name resolution
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EAI_BADFLAGS</errorcode></term>
+ <listitem>
+ <para>
+ invalid value for
+ <constant>ai_flags</constant>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EAI_FAIL</errorcode></term>
+ <listitem>
+ <para>
+ non-recoverable failure in name resolution
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EAI_FAMILY</errorcode></term>
+ <listitem>
+ <para><constant>ai_family</constant> not supported
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EAI_MEMORY</errorcode></term>
+ <listitem>
+ <para>
+ memory allocation failure
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EAI_NODATA</errorcode></term>
+ <listitem>
+ <para>
+ no address associated with hostname
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EAI_NONAME</errorcode></term>
+ <listitem>
+ <para>
+ hostname or servname not provided, or not known
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EAI_SERVICE</errorcode></term>
+ <listitem>
+ <para>
+ servname not supported for <constant>ai_socktype</constant>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EAI_SOCKTYPE</errorcode></term>
+ <listitem>
+ <para><constant>ai_socktype</constant> not supported
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EAI_SYSTEM</errorcode></term>
+ <listitem>
+ <para>
+ system error returned in errno
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ The message <errorname>invalid error code</errorname> is returned if
+ <parameter>ecode</parameter>
+ is out of range.
+ </para>
+ <para><constant>ai_flags</constant>,
+ <constant>ai_family</constant>
+ and
+ <constant>ai_socktype</constant>
+ are elements of the
+ <type>struct addrinfo</type>
+ used by
+ <function>lwres_getaddrinfo()</function>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>strerror</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_getaddrinfo</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>getaddrinfo</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>RFC2133</refentrytitle>
+ </citerefentry>.
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_gai_strerror.html b/lib/lwres/man/lwres_gai_strerror.html
new file mode 100644
index 0000000..9673253
--- /dev/null
+++ b/lib/lwres/man/lwres_gai_strerror.html
@@ -0,0 +1,124 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_gai_strerror.html,v 1.6.18.18 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_gai_strerror</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_gai_strerror &#8212; print suitable error string</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/netdb.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0"><tr>
+<td><code class="funcdef">
+char *
+<b class="fsfunc">gai_strerror</b>(</code></td>
+<td>int  </td>
+<td>
+<var class="pdparam">ecode</var><code>)</code>;</td>
+</tr></table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543361"></a><h2>DESCRIPTION</h2>
+<p><code class="function">lwres_gai_strerror()</code>
+ returns an error message corresponding to an error code returned by
+ <code class="function">getaddrinfo()</code>.
+ The following error codes and their meaning are defined in
+ <code class="filename">include/lwres/netdb.h</code>.
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><span class="errorcode">EAI_ADDRFAMILY</span></span></dt>
+<dd><p>
+ address family for hostname not supported
+ </p></dd>
+<dt><span class="term"><span class="errorcode">EAI_AGAIN</span></span></dt>
+<dd><p>
+ temporary failure in name resolution
+ </p></dd>
+<dt><span class="term"><span class="errorcode">EAI_BADFLAGS</span></span></dt>
+<dd><p>
+ invalid value for
+ <code class="constant">ai_flags</code>
+ </p></dd>
+<dt><span class="term"><span class="errorcode">EAI_FAIL</span></span></dt>
+<dd><p>
+ non-recoverable failure in name resolution
+ </p></dd>
+<dt><span class="term"><span class="errorcode">EAI_FAMILY</span></span></dt>
+<dd><p><code class="constant">ai_family</code> not supported
+ </p></dd>
+<dt><span class="term"><span class="errorcode">EAI_MEMORY</span></span></dt>
+<dd><p>
+ memory allocation failure
+ </p></dd>
+<dt><span class="term"><span class="errorcode">EAI_NODATA</span></span></dt>
+<dd><p>
+ no address associated with hostname
+ </p></dd>
+<dt><span class="term"><span class="errorcode">EAI_NONAME</span></span></dt>
+<dd><p>
+ hostname or servname not provided, or not known
+ </p></dd>
+<dt><span class="term"><span class="errorcode">EAI_SERVICE</span></span></dt>
+<dd><p>
+ servname not supported for <code class="constant">ai_socktype</code>
+ </p></dd>
+<dt><span class="term"><span class="errorcode">EAI_SOCKTYPE</span></span></dt>
+<dd><p><code class="constant">ai_socktype</code> not supported
+ </p></dd>
+<dt><span class="term"><span class="errorcode">EAI_SYSTEM</span></span></dt>
+<dd><p>
+ system error returned in errno
+ </p></dd>
+</dl></div>
+<p>
+ The message <span class="errorname">invalid error code</span> is returned if
+ <em class="parameter"><code>ecode</code></em>
+ is out of range.
+ </p>
+<p><code class="constant">ai_flags</code>,
+ <code class="constant">ai_family</code>
+ and
+ <code class="constant">ai_socktype</code>
+ are elements of the
+ <span class="type">struct addrinfo</span>
+ used by
+ <code class="function">lwres_getaddrinfo()</code>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543576"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">strerror</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_getaddrinfo</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">getaddrinfo</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">RFC2133</span></span>.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_getaddrinfo.3 b/lib/lwres/man/lwres_getaddrinfo.3
new file mode 100644
index 0000000..9d198d6
--- /dev/null
+++ b/lib/lwres/man/lwres_getaddrinfo.3
@@ -0,0 +1,246 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_getaddrinfo.3,v 1.20.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_getaddrinfo
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_GETADDRINFO" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_getaddrinfo, lwres_freeaddrinfo \- socket address structure to host and service name
+.SH "SYNOPSIS"
+.nf
+#include <lwres/netdb.h>
+.fi
+.HP 22
+.BI "int lwres_getaddrinfo(const\ char\ *" "hostname" ", const\ char\ *" "servname" ", const\ struct\ addrinfo\ *" "hints" ", struct\ addrinfo\ **" "res" ");"
+.HP 24
+.BI "void lwres_freeaddrinfo(struct\ addrinfo\ *" "ai" ");"
+.PP
+If the operating system does not provide a
+\fBstruct addrinfo\fR, the following structure is used:
+.PP
+.RS 4
+.nf
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+.fi
+.RE
+.sp
+.SH "DESCRIPTION"
+.PP
+\fBlwres_getaddrinfo()\fR
+is used to get a list of IP addresses and port numbers for host
+\fIhostname\fR
+and service
+\fIservname\fR. The function is the lightweight resolver's implementation of
+\fBgetaddrinfo()\fR
+as defined in RFC2133.
+\fIhostname\fR
+and
+\fIservname\fR
+are pointers to null\-terminated strings or
+\fBNULL\fR.
+\fIhostname\fR
+is either a host name or a numeric host address string: a dotted decimal IPv4 address or an IPv6 address.
+\fIservname\fR
+is either a decimal port number or a service name as listed in
+\fI/etc/services\fR.
+.PP
+\fIhints\fR
+is an optional pointer to a
+\fBstruct addrinfo\fR. This structure can be used to provide hints concerning the type of socket that the caller supports or wishes to use. The caller can supply the following structure elements in
+\fI*hints\fR:
+.PP
+\fBai_family\fR
+.RS 4
+The protocol family that should be used. When
+\fBai_family\fR
+is set to
+\fBPF_UNSPEC\fR, it means the caller will accept any protocol family supported by the operating system.
+.RE
+.PP
+\fBai_socktype\fR
+.RS 4
+denotes the type of socket \(em
+\fBSOCK_STREAM\fR,
+\fBSOCK_DGRAM\fR
+or
+\fBSOCK_RAW\fR
+\(em that is wanted. When
+\fBai_socktype\fR
+is zero the caller will accept any socket type.
+.RE
+.PP
+\fBai_protocol\fR
+.RS 4
+indicates which transport protocol is wanted: IPPROTO_UDP or IPPROTO_TCP. If
+\fBai_protocol\fR
+is zero the caller will accept any protocol.
+.RE
+.PP
+\fBai_flags\fR
+.RS 4
+Flag bits. If the
+\fBAI_CANONNAME\fR
+bit is set, a successful call to
+\fBlwres_getaddrinfo()\fR
+will return a null\-terminated string containing the canonical name of the specified hostname in
+\fBai_canonname\fR
+of the first
+\fBaddrinfo\fR
+structure returned. Setting the
+\fBAI_PASSIVE\fR
+bit indicates that the returned socket address structure is intended for used in a call to
+\fBbind\fR(2). In this case, if the hostname argument is a
+\fBNULL\fR
+pointer, then the IP address portion of the socket address structure will be set to
+\fBINADDR_ANY\fR
+for an IPv4 address or
+\fBIN6ADDR_ANY_INIT\fR
+for an IPv6 address.
+.sp
+When
+\fBai_flags\fR
+does not set the
+\fBAI_PASSIVE\fR
+bit, the returned socket address structure will be ready for use in a call to
+\fBconnect\fR(2)
+for a connection\-oriented protocol or
+\fBconnect\fR(2),
+\fBsendto\fR(2), or
+\fBsendmsg\fR(2)
+if a connectionless protocol was chosen. The IP address portion of the socket address structure will be set to the loopback address if
+\fIhostname\fR
+is a
+\fBNULL\fR
+pointer and
+\fBAI_PASSIVE\fR
+is not set in
+\fBai_flags\fR.
+.sp
+If
+\fBai_flags\fR
+is set to
+\fBAI_NUMERICHOST\fR
+it indicates that
+\fIhostname\fR
+should be treated as a numeric string defining an IPv4 or IPv6 address and no name resolution should be attempted.
+.RE
+.PP
+All other elements of the
+\fBstruct addrinfo\fR
+passed via
+\fIhints\fR
+must be zero.
+.PP
+A
+\fIhints\fR
+of
+\fBNULL\fR
+is treated as if the caller provided a
+\fBstruct addrinfo\fR
+initialized to zero with
+\fBai_family\fRset to
+\fBPF_UNSPEC\fR.
+.PP
+After a successful call to
+\fBlwres_getaddrinfo()\fR,
+\fI*res\fR
+is a pointer to a linked list of one or more
+\fBaddrinfo\fR
+structures. Each
+\fBstruct addrinfo\fR
+in this list cn be processed by following the
+\fBai_next\fR
+pointer, until a
+\fBNULL\fR
+pointer is encountered. The three members
+\fBai_family\fR,
+\fBai_socktype\fR, and
+\fBai_protocol\fR
+in each returned
+\fBaddrinfo\fR
+structure contain the corresponding arguments for a call to
+\fBsocket\fR(2). For each
+\fBaddrinfo\fR
+structure in the list, the
+\fBai_addr\fR
+member points to a filled\-in socket address structure of length
+\fBai_addrlen\fR.
+.PP
+All of the information returned by
+\fBlwres_getaddrinfo()\fR
+is dynamically allocated: the addrinfo structures, and the socket address structures and canonical host name strings pointed to by the
+\fBaddrinfo\fRstructures. Memory allocated for the dynamically allocated structures created by a successful call to
+\fBlwres_getaddrinfo()\fR
+is released by
+\fBlwres_freeaddrinfo()\fR.
+\fIai\fR
+is a pointer to a
+\fBstruct addrinfo\fR
+created by a call to
+\fBlwres_getaddrinfo()\fR.
+.SH "RETURN VALUES"
+.PP
+\fBlwres_getaddrinfo()\fR
+returns zero on success or one of the error codes listed in
+\fBgai_strerror\fR(3)
+if an error occurs. If both
+\fIhostname\fR
+and
+\fIservname\fR
+are
+\fBNULL\fR
+\fBlwres_getaddrinfo()\fR
+returns
+\fBEAI_NONAME\fR.
+.SH "SEE ALSO"
+.PP
+\fBlwres\fR(3),
+\fBlwres_getaddrinfo\fR(3),
+\fBlwres_freeaddrinfo\fR(3),
+\fBlwres_gai_strerror\fR(3),
+\fBRFC2133\fR(),
+\fBgetservbyname\fR(3),
+\fBbind\fR(2),
+\fBconnect\fR(2),
+\fBsendto\fR(2),
+\fBsendmsg\fR(2),
+\fBsocket\fR(2).
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001, 2003 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_getaddrinfo.docbook b/lib/lwres/man/lwres_getaddrinfo.docbook
new file mode 100644
index 0000000..52d9387
--- /dev/null
+++ b/lib/lwres/man/lwres_getaddrinfo.docbook
@@ -0,0 +1,387 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_getaddrinfo.docbook,v 1.7.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_getaddrinfo</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <year>2003</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_getaddrinfo</refname>
+ <refname>lwres_freeaddrinfo</refname>
+ <refpurpose>socket address structure to host and service name</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+int
+<function>lwres_getaddrinfo</function></funcdef>
+ <paramdef>const char *<parameter>hostname</parameter></paramdef>
+ <paramdef>const char *<parameter>servname</parameter></paramdef>
+ <paramdef>const struct addrinfo *<parameter>hints</parameter></paramdef>
+ <paramdef>struct addrinfo **<parameter>res</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_freeaddrinfo</function></funcdef>
+ <paramdef>struct addrinfo *<parameter>ai</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+
+ <para>
+ If the operating system does not provide a
+ <type>struct addrinfo</type>,
+ the following structure is used:
+ </para>
+ <para><programlisting>
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+</programlisting>
+ </para>
+
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><function>lwres_getaddrinfo()</function>
+ is used to get a list of IP addresses and port numbers for host
+ <parameter>hostname</parameter> and service
+ <parameter>servname</parameter>.
+
+ The function is the lightweight resolver's implementation of
+ <function>getaddrinfo()</function> as defined in RFC2133.
+ <parameter>hostname</parameter> and
+ <parameter>servname</parameter> are pointers to null-terminated
+ strings or <type>NULL</type>.
+
+ <parameter>hostname</parameter> is either a host name or a
+ numeric host address string: a dotted decimal IPv4 address or an
+ IPv6 address. <parameter>servname</parameter> is either a
+ decimal port number or a service name as listed in
+ <filename>/etc/services</filename>.
+ </para>
+
+ <para><parameter>hints</parameter>
+ is an optional pointer to a
+ <type>struct addrinfo</type>.
+ This structure can be used to provide hints concerning the type of
+ socket
+ that the caller supports or wishes to use.
+ The caller can supply the following structure elements in
+ <parameter>*hints</parameter>:
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>ai_family</constant></term>
+ <listitem>
+ <para>
+ The protocol family that should be used.
+ When
+ <constant>ai_family</constant>
+ is set to
+ <type>PF_UNSPEC</type>,
+ it means the caller will accept any protocol family supported by
+ the
+ operating system.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>ai_socktype</constant></term>
+ <listitem>
+ <para>
+ denotes the type of socket &mdash;
+ <type>SOCK_STREAM</type>,
+ <type>SOCK_DGRAM</type>
+ or
+ <type>SOCK_RAW</type>
+ &mdash; that is wanted.
+ When
+ <constant>ai_socktype</constant>
+ is zero the caller will accept any socket type.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>ai_protocol</constant></term>
+ <listitem>
+ <para>
+ indicates which transport protocol is wanted: IPPROTO_UDP or
+ IPPROTO_TCP.
+ If
+ <constant>ai_protocol</constant>
+ is zero the caller will accept any protocol.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>ai_flags</constant></term>
+ <listitem>
+ <para>
+ Flag bits.
+ If the
+ <type>AI_CANONNAME</type>
+ bit is set, a successful call to
+ <function>lwres_getaddrinfo()</function>
+ will return a null-terminated string containing the canonical
+ name
+ of the specified hostname in
+ <constant>ai_canonname</constant>
+ of the first
+ <type>addrinfo</type>
+ structure returned.
+ Setting the
+ <type>AI_PASSIVE</type>
+ bit indicates that the returned socket address structure is
+ intended
+ for used in a call to
+ <citerefentry>
+ <refentrytitle>bind</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>.
+
+ In this case, if the hostname argument is a
+ <type>NULL</type>
+ pointer, then the IP address portion of the socket
+ address structure will be set to
+ <type>INADDR_ANY</type>
+ for an IPv4 address or
+ <type>IN6ADDR_ANY_INIT</type>
+ for an IPv6 address.
+ </para>
+ <para>
+ When
+ <constant>ai_flags</constant>
+ does not set the
+ <type>AI_PASSIVE</type>
+ bit, the returned socket address structure will be ready
+ for use in a call to
+ <citerefentry>
+ <refentrytitle>connect</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>
+ for a connection-oriented protocol or
+ <citerefentry>
+ <refentrytitle>connect</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>sendto</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>,
+
+ or
+ <citerefentry>
+ <refentrytitle>sendmsg</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>
+ if a connectionless protocol was chosen.
+ The IP address portion of the socket address structure will be
+ set to the loopback address if
+ <parameter>hostname</parameter>
+ is a
+ <type>NULL</type>
+ pointer and
+ <type>AI_PASSIVE</type>
+ is not set in
+ <constant>ai_flags</constant>.
+ </para>
+ <para>
+ If
+ <constant>ai_flags</constant>
+ is set to
+ <type>AI_NUMERICHOST</type>
+ it indicates that
+ <parameter>hostname</parameter>
+ should be treated as a numeric string defining an IPv4 or IPv6
+ address
+ and no name resolution should be attempted.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para>
+ All other elements of the <type>struct addrinfo</type> passed
+ via <parameter>hints</parameter> must be zero.
+ </para>
+
+ <para>
+ A <parameter>hints</parameter> of <type>NULL</type> is
+ treated as if
+ the caller provided a <type>struct addrinfo</type> initialized to zero
+ with <constant>ai_family</constant>set to
+ <constant>PF_UNSPEC</constant>.
+ </para>
+
+ <para>
+ After a successful call to
+ <function>lwres_getaddrinfo()</function>,
+ <parameter>*res</parameter>
+ is a pointer to a linked list of one or more
+ <type>addrinfo</type>
+ structures.
+ Each
+ <type>struct addrinfo</type>
+ in this list cn be processed by following
+ the
+ <constant>ai_next</constant>
+ pointer, until a
+ <type>NULL</type>
+ pointer is encountered.
+ The three members
+ <constant>ai_family</constant>,
+ <constant>ai_socktype</constant>,
+ and
+ <constant>ai_protocol</constant>
+ in each
+ returned
+ <type>addrinfo</type>
+ structure contain the corresponding arguments for a call to
+ <citerefentry>
+ <refentrytitle>socket</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>.
+ For each
+ <type>addrinfo</type>
+ structure in the list, the
+ <constant>ai_addr</constant>
+ member points to a filled-in socket address structure of length
+ <constant>ai_addrlen</constant>.
+ </para>
+
+ <para>
+ All of the information returned by
+ <function>lwres_getaddrinfo()</function>
+ is dynamically allocated: the addrinfo structures, and the socket
+ address structures and canonical host name strings pointed to by the
+ <constant>addrinfo</constant>structures.
+ Memory allocated for the dynamically allocated structures created by
+ a successful call to
+ <function>lwres_getaddrinfo()</function>
+ is released by
+ <function>lwres_freeaddrinfo()</function>.
+ <parameter>ai</parameter>
+ is a pointer to a
+ <type>struct addrinfo</type>
+ created by a call to
+ <function>lwres_getaddrinfo()</function>.
+ </para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>RETURN VALUES</title>
+
+ <para><function>lwres_getaddrinfo()</function>
+ returns zero on success or one of the error codes listed in
+ <citerefentry>
+ <refentrytitle>gai_strerror</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>
+ if an error occurs. If both <parameter>hostname</parameter> and
+ <parameter>servname</parameter> are <type>NULL</type>
+ <function>lwres_getaddrinfo()</function> returns
+ <errorcode>EAI_NONAME</errorcode>.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>lwres</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_getaddrinfo</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_freeaddrinfo</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_gai_strerror</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>RFC2133</refentrytitle>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>getservbyname</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>bind</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>connect</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>sendto</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>sendmsg</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>socket</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>.
+ </para>
+
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_getaddrinfo.html b/lib/lwres/man/lwres_getaddrinfo.html
new file mode 100644
index 0000000..d2dcdd9
--- /dev/null
+++ b/lib/lwres/man/lwres_getaddrinfo.html
@@ -0,0 +1,322 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_getaddrinfo.html,v 1.10.18.17 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_getaddrinfo</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_getaddrinfo, lwres_freeaddrinfo &#8212; socket address structure to host and service name</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/netdb.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+int
+<b class="fsfunc">lwres_getaddrinfo</b>(</code></td>
+<td>const char * </td>
+<td>
+<var class="pdparam">hostname</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>const char * </td>
+<td>
+<var class="pdparam">servname</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>const struct addrinfo * </td>
+<td>
+<var class="pdparam">hints</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>struct addrinfo ** </td>
+<td>
+<var class="pdparam">res</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_freeaddrinfo</b>(</code></td>
+<td>struct addrinfo * </td>
+<td>
+<var class="pdparam">ai</var><code>)</code>;</td>
+</tr></table>
+</div>
+<p>
+ If the operating system does not provide a
+ <span class="type">struct addrinfo</span>,
+ the following structure is used:
+ </p>
+<pre class="programlisting">
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+</pre>
+<p>
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543412"></a><h2>DESCRIPTION</h2>
+<p><code class="function">lwres_getaddrinfo()</code>
+ is used to get a list of IP addresses and port numbers for host
+ <em class="parameter"><code>hostname</code></em> and service
+ <em class="parameter"><code>servname</code></em>.
+
+ The function is the lightweight resolver's implementation of
+ <code class="function">getaddrinfo()</code> as defined in RFC2133.
+ <em class="parameter"><code>hostname</code></em> and
+ <em class="parameter"><code>servname</code></em> are pointers to null-terminated
+ strings or <span class="type">NULL</span>.
+
+ <em class="parameter"><code>hostname</code></em> is either a host name or a
+ numeric host address string: a dotted decimal IPv4 address or an
+ IPv6 address. <em class="parameter"><code>servname</code></em> is either a
+ decimal port number or a service name as listed in
+ <code class="filename">/etc/services</code>.
+ </p>
+<p><em class="parameter"><code>hints</code></em>
+ is an optional pointer to a
+ <span class="type">struct addrinfo</span>.
+ This structure can be used to provide hints concerning the type of
+ socket
+ that the caller supports or wishes to use.
+ The caller can supply the following structure elements in
+ <em class="parameter"><code>*hints</code></em>:
+
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><code class="constant">ai_family</code></span></dt>
+<dd><p>
+ The protocol family that should be used.
+ When
+ <code class="constant">ai_family</code>
+ is set to
+ <span class="type">PF_UNSPEC</span>,
+ it means the caller will accept any protocol family supported by
+ the
+ operating system.
+ </p></dd>
+<dt><span class="term"><code class="constant">ai_socktype</code></span></dt>
+<dd><p>
+ denotes the type of socket &#8212;
+ <span class="type">SOCK_STREAM</span>,
+ <span class="type">SOCK_DGRAM</span>
+ or
+ <span class="type">SOCK_RAW</span>
+ &#8212; that is wanted.
+ When
+ <code class="constant">ai_socktype</code>
+ is zero the caller will accept any socket type.
+ </p></dd>
+<dt><span class="term"><code class="constant">ai_protocol</code></span></dt>
+<dd><p>
+ indicates which transport protocol is wanted: IPPROTO_UDP or
+ IPPROTO_TCP.
+ If
+ <code class="constant">ai_protocol</code>
+ is zero the caller will accept any protocol.
+ </p></dd>
+<dt><span class="term"><code class="constant">ai_flags</code></span></dt>
+<dd>
+<p>
+ Flag bits.
+ If the
+ <span class="type">AI_CANONNAME</span>
+ bit is set, a successful call to
+ <code class="function">lwres_getaddrinfo()</code>
+ will return a null-terminated string containing the canonical
+ name
+ of the specified hostname in
+ <code class="constant">ai_canonname</code>
+ of the first
+ <span class="type">addrinfo</span>
+ structure returned.
+ Setting the
+ <span class="type">AI_PASSIVE</span>
+ bit indicates that the returned socket address structure is
+ intended
+ for used in a call to
+ <span class="citerefentry"><span class="refentrytitle">bind</span>(2)</span>.
+
+ In this case, if the hostname argument is a
+ <span class="type">NULL</span>
+ pointer, then the IP address portion of the socket
+ address structure will be set to
+ <span class="type">INADDR_ANY</span>
+ for an IPv4 address or
+ <span class="type">IN6ADDR_ANY_INIT</span>
+ for an IPv6 address.
+ </p>
+<p>
+ When
+ <code class="constant">ai_flags</code>
+ does not set the
+ <span class="type">AI_PASSIVE</span>
+ bit, the returned socket address structure will be ready
+ for use in a call to
+ <span class="citerefentry"><span class="refentrytitle">connect</span>(2)</span>
+ for a connection-oriented protocol or
+ <span class="citerefentry"><span class="refentrytitle">connect</span>(2)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">sendto</span>(2)</span>,
+
+ or
+ <span class="citerefentry"><span class="refentrytitle">sendmsg</span>(2)</span>
+ if a connectionless protocol was chosen.
+ The IP address portion of the socket address structure will be
+ set to the loopback address if
+ <em class="parameter"><code>hostname</code></em>
+ is a
+ <span class="type">NULL</span>
+ pointer and
+ <span class="type">AI_PASSIVE</span>
+ is not set in
+ <code class="constant">ai_flags</code>.
+ </p>
+<p>
+ If
+ <code class="constant">ai_flags</code>
+ is set to
+ <span class="type">AI_NUMERICHOST</span>
+ it indicates that
+ <em class="parameter"><code>hostname</code></em>
+ should be treated as a numeric string defining an IPv4 or IPv6
+ address
+ and no name resolution should be attempted.
+ </p>
+</dd>
+</dl></div>
+<p>
+ </p>
+<p>
+ All other elements of the <span class="type">struct addrinfo</span> passed
+ via <em class="parameter"><code>hints</code></em> must be zero.
+ </p>
+<p>
+ A <em class="parameter"><code>hints</code></em> of <span class="type">NULL</span> is
+ treated as if
+ the caller provided a <span class="type">struct addrinfo</span> initialized to zero
+ with <code class="constant">ai_family</code>set to
+ <code class="constant">PF_UNSPEC</code>.
+ </p>
+<p>
+ After a successful call to
+ <code class="function">lwres_getaddrinfo()</code>,
+ <em class="parameter"><code>*res</code></em>
+ is a pointer to a linked list of one or more
+ <span class="type">addrinfo</span>
+ structures.
+ Each
+ <span class="type">struct addrinfo</span>
+ in this list cn be processed by following
+ the
+ <code class="constant">ai_next</code>
+ pointer, until a
+ <span class="type">NULL</span>
+ pointer is encountered.
+ The three members
+ <code class="constant">ai_family</code>,
+ <code class="constant">ai_socktype</code>,
+ and
+ <code class="constant">ai_protocol</code>
+ in each
+ returned
+ <span class="type">addrinfo</span>
+ structure contain the corresponding arguments for a call to
+ <span class="citerefentry"><span class="refentrytitle">socket</span>(2)</span>.
+ For each
+ <span class="type">addrinfo</span>
+ structure in the list, the
+ <code class="constant">ai_addr</code>
+ member points to a filled-in socket address structure of length
+ <code class="constant">ai_addrlen</code>.
+ </p>
+<p>
+ All of the information returned by
+ <code class="function">lwres_getaddrinfo()</code>
+ is dynamically allocated: the addrinfo structures, and the socket
+ address structures and canonical host name strings pointed to by the
+ <code class="constant">addrinfo</code>structures.
+ Memory allocated for the dynamically allocated structures created by
+ a successful call to
+ <code class="function">lwres_getaddrinfo()</code>
+ is released by
+ <code class="function">lwres_freeaddrinfo()</code>.
+ <em class="parameter"><code>ai</code></em>
+ is a pointer to a
+ <span class="type">struct addrinfo</span>
+ created by a call to
+ <code class="function">lwres_getaddrinfo()</code>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543789"></a><h2>RETURN VALUES</h2>
+<p><code class="function">lwres_getaddrinfo()</code>
+ returns zero on success or one of the error codes listed in
+ <span class="citerefentry"><span class="refentrytitle">gai_strerror</span>(3)</span>
+ if an error occurs. If both <em class="parameter"><code>hostname</code></em> and
+ <em class="parameter"><code>servname</code></em> are <span class="type">NULL</span>
+ <code class="function">lwres_getaddrinfo()</code> returns
+ <span class="errorcode">EAI_NONAME</span>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543827"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">lwres</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_getaddrinfo</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_freeaddrinfo</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_gai_strerror</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">RFC2133</span></span>,
+
+ <span class="citerefentry"><span class="refentrytitle">getservbyname</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">bind</span>(2)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">connect</span>(2)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">sendto</span>(2)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">sendmsg</span>(2)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">socket</span>(2)</span>.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_gethostent.3 b/lib/lwres/man/lwres_gethostent.3
new file mode 100644
index 0000000..e6fbcd7
--- /dev/null
+++ b/lib/lwres/man/lwres_gethostent.3
@@ -0,0 +1,315 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_gethostent.3,v 1.19.18.10 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_gethostent
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_GETHOSTENT" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_gethostbyname, lwres_gethostbyname2, lwres_gethostbyaddr, lwres_gethostent, lwres_sethostent, lwres_endhostent, lwres_gethostbyname_r, lwres_gethostbyaddr_r, lwres_gethostent_r, lwres_sethostent_r, lwres_endhostent_r \- lightweight resolver get network host entry
+.SH "SYNOPSIS"
+.nf
+#include <lwres/netdb.h>
+.fi
+.HP 37
+.BI "struct hostent * lwres_gethostbyname(const\ char\ *" "name" ");"
+.HP 38
+.BI "struct hostent * lwres_gethostbyname2(const\ char\ *" "name" ", int\ " "af" ");"
+.HP 37
+.BI "struct hostent * lwres_gethostbyaddr(const\ char\ *" "addr" ", int\ " "len" ", int\ " "type" ");"
+.HP 34
+.BI "struct hostent * lwres_gethostent(void);"
+.HP 22
+.BI "void lwres_sethostent(int\ " "stayopen" ");"
+.HP 22
+.BI "void lwres_endhostent(void);"
+.HP 39
+.BI "struct hostent * lwres_gethostbyname_r(const\ char\ *" "name" ", struct\ hostent\ *" "resbuf" ", char\ *" "buf" ", int\ " "buflen" ", int\ *" "error" ");"
+.HP 39
+.BI "struct hostent * lwres_gethostbyaddr_r(const\ char\ *" "addr" ", int\ " "len" ", int\ " "type" ", struct\ hostent\ *" "resbuf" ", char\ *" "buf" ", int\ " "buflen" ", int\ *" "error" ");"
+.HP 36
+.BI "struct hostent * lwres_gethostent_r(struct\ hostent\ *" "resbuf" ", char\ *" "buf" ", int\ " "buflen" ", int\ *" "error" ");"
+.HP 24
+.BI "void lwres_sethostent_r(int\ " "stayopen" ");"
+.HP 24
+.BI "void lwres_endhostent_r(void);"
+.SH "DESCRIPTION"
+.PP
+These functions provide hostname\-to\-address and address\-to\-hostname lookups by means of the lightweight resolver. They are similar to the standard
+\fBgethostent\fR(3)
+functions provided by most operating systems. They use a
+\fBstruct hostent\fR
+which is usually defined in
+\fI<namedb.h>\fR.
+.PP
+.RS 4
+.nf
+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 compatibility */
+.fi
+.RE
+.sp
+.PP
+The members of this structure are:
+.PP
+\fBh_name\fR
+.RS 4
+The official (canonical) name of the host.
+.RE
+.PP
+\fBh_aliases\fR
+.RS 4
+A NULL\-terminated array of alternate names (nicknames) for the host.
+.RE
+.PP
+\fBh_addrtype\fR
+.RS 4
+The type of address being returned \(em
+\fBPF_INET\fR
+or
+\fBPF_INET6\fR.
+.RE
+.PP
+\fBh_length\fR
+.RS 4
+The length of the address in bytes.
+.RE
+.PP
+\fBh_addr_list\fR
+.RS 4
+A
+\fBNULL\fR
+terminated array of network addresses for the host. Host addresses are returned in network byte order.
+.RE
+.PP
+For backward compatibility with very old software,
+\fBh_addr\fR
+is the first address in
+\fBh_addr_list.\fR
+.PP
+\fBlwres_gethostent()\fR,
+\fBlwres_sethostent()\fR,
+\fBlwres_endhostent()\fR,
+\fBlwres_gethostent_r()\fR,
+\fBlwres_sethostent_r()\fR
+and
+\fBlwres_endhostent_r()\fR
+provide iteration over the known host entries on systems that provide such functionality through facilities like
+\fI/etc/hosts\fR
+or NIS. The lightweight resolver does not currently implement these functions; it only provides them as stub functions that always return failure.
+.PP
+\fBlwres_gethostbyname()\fR
+and
+\fBlwres_gethostbyname2()\fR
+look up the hostname
+\fIname\fR.
+\fBlwres_gethostbyname()\fR
+always looks for an IPv4 address while
+\fBlwres_gethostbyname2()\fR
+looks for an address of protocol family
+\fIaf\fR: either
+\fBPF_INET\fR
+or
+\fBPF_INET6\fR
+\(em IPv4 or IPV6 addresses respectively. Successful calls of the functions return a
+\fBstruct hostent\fRfor the name that was looked up.
+\fBNULL\fR
+is returned if the lookups by
+\fBlwres_gethostbyname()\fR
+or
+\fBlwres_gethostbyname2()\fR
+fail.
+.PP
+Reverse lookups of addresses are performed by
+\fBlwres_gethostbyaddr()\fR.
+\fIaddr\fR
+is an address of length
+\fIlen\fR
+bytes and protocol family
+\fItype\fR
+\(em
+\fBPF_INET\fR
+or
+\fBPF_INET6\fR.
+\fBlwres_gethostbyname_r()\fR
+is a thread\-safe function for forward lookups. If an error occurs, an error code is returned in
+\fI*error\fR.
+\fIresbuf\fR
+is a pointer to a
+\fBstruct hostent\fR
+which is initialised by a successful call to
+\fBlwres_gethostbyname_r()\fR.
+\fIbuf\fR
+is a buffer of length
+\fIlen\fR
+bytes which is used to store the
+\fBh_name\fR,
+\fBh_aliases\fR, and
+\fBh_addr_list\fR
+elements of the
+\fBstruct hostent\fR
+returned in
+\fIresbuf\fR. Successful calls to
+\fBlwres_gethostbyname_r()\fR
+return
+\fIresbuf\fR, which is a pointer to the
+\fBstruct hostent\fR
+it created.
+.PP
+\fBlwres_gethostbyaddr_r()\fR
+is a thread\-safe function that performs a reverse lookup of address
+\fIaddr\fR
+which is
+\fIlen\fR
+bytes long and is of protocol family
+\fItype\fR
+\(em
+\fBPF_INET\fR
+or
+\fBPF_INET6\fR. If an error occurs, the error code is returned in
+\fI*error\fR. The other function parameters are identical to those in
+\fBlwres_gethostbyname_r()\fR.
+\fIresbuf\fR
+is a pointer to a
+\fBstruct hostent\fR
+which is initialised by a successful call to
+\fBlwres_gethostbyaddr_r()\fR.
+\fIbuf\fR
+is a buffer of length
+\fIlen\fR
+bytes which is used to store the
+\fBh_name\fR,
+\fBh_aliases\fR, and
+\fBh_addr_list\fR
+elements of the
+\fBstruct hostent\fR
+returned in
+\fIresbuf\fR. Successful calls to
+\fBlwres_gethostbyaddr_r()\fR
+return
+\fIresbuf\fR, which is a pointer to the
+\fBstruct hostent()\fR
+it created.
+.SH "RETURN VALUES"
+.PP
+The functions
+\fBlwres_gethostbyname()\fR,
+\fBlwres_gethostbyname2()\fR,
+\fBlwres_gethostbyaddr()\fR, and
+\fBlwres_gethostent()\fR
+return NULL to indicate an error. In this case the global variable
+\fBlwres_h_errno\fR
+will contain one of the following error codes defined in
+\fI<lwres/netdb.h>\fR:
+.PP
+\fBHOST_NOT_FOUND\fR
+.RS 4
+The host or address was not found.
+.RE
+.PP
+\fBTRY_AGAIN\fR
+.RS 4
+A recoverable error occurred, e.g., a timeout. Retrying the lookup may succeed.
+.RE
+.PP
+\fBNO_RECOVERY\fR
+.RS 4
+A non\-recoverable error occurred.
+.RE
+.PP
+\fBNO_DATA\fR
+.RS 4
+The name exists, but has no address information associated with it (or vice versa in the case of a reverse lookup). The code NO_ADDRESS is accepted as a synonym for NO_DATA for backwards compatibility.
+.RE
+.PP
+\fBlwres_hstrerror\fR(3)
+translates these error codes to suitable error messages.
+.PP
+\fBlwres_gethostent()\fR
+and
+\fBlwres_gethostent_r()\fR
+always return
+\fBNULL\fR.
+.PP
+Successful calls to
+\fBlwres_gethostbyname_r()\fR
+and
+\fBlwres_gethostbyaddr_r()\fR
+return
+\fIresbuf\fR, a pointer to the
+\fBstruct hostent\fR
+that was initialised by these functions. They return
+\fBNULL\fR
+if the lookups fail or if
+\fIbuf\fR
+was too small to hold the list of addresses and names referenced by the
+\fBh_name\fR,
+\fBh_aliases\fR, and
+\fBh_addr_list\fR
+elements of the
+\fBstruct hostent\fR. If
+\fIbuf\fR
+was too small, both
+\fBlwres_gethostbyname_r()\fR
+and
+\fBlwres_gethostbyaddr_r()\fR
+set the global variable
+\fBerrno\fR
+to
+\fBERANGE\fR.
+.SH "SEE ALSO"
+.PP
+\fBgethostent\fR(3),
+\fBlwres_getipnode\fR(3),
+\fBlwres_hstrerror\fR(3)
+.SH "BUGS"
+.PP
+\fBlwres_gethostbyname()\fR,
+\fBlwres_gethostbyname2()\fR,
+\fBlwres_gethostbyaddr()\fR
+and
+\fBlwres_endhostent()\fR
+are not thread safe; they return pointers to static data and provide error codes through a global variable. Thread\-safe versions for name and address lookup are provided by
+\fBlwres_gethostbyname_r()\fR, and
+\fBlwres_gethostbyaddr_r()\fR
+respectively.
+.PP
+The resolver daemon does not currently support any non\-DNS name services such as
+\fI/etc/hosts\fR
+or
+\fBNIS\fR, consequently the above functions don't, either.
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_gethostent.docbook b/lib/lwres/man/lwres_gethostent.docbook
new file mode 100644
index 0000000..4ed7393
--- /dev/null
+++ b/lib/lwres/man/lwres_gethostent.docbook
@@ -0,0 +1,439 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_gethostent.docbook,v 1.6.18.5 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_gethostent</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_gethostbyname</refname>
+ <refname>lwres_gethostbyname2</refname>
+ <refname>lwres_gethostbyaddr</refname>
+ <refname>lwres_gethostent</refname>
+ <refname>lwres_sethostent</refname>
+ <refname>lwres_endhostent</refname>
+ <refname>lwres_gethostbyname_r</refname>
+ <refname>lwres_gethostbyaddr_r</refname>
+ <refname>lwres_gethostent_r</refname>
+ <refname>lwres_sethostent_r</refname>
+ <refname>lwres_endhostent_r</refname>
+ <refpurpose>lightweight resolver get network host entry</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+struct hostent *
+<function>lwres_gethostbyname</function></funcdef>
+ <paramdef>const char *<parameter>name</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+struct hostent *
+<function>lwres_gethostbyname2</function></funcdef>
+ <paramdef>const char *<parameter>name</parameter></paramdef>
+ <paramdef>int <parameter>af</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+struct hostent *
+<function>lwres_gethostbyaddr</function></funcdef>
+ <paramdef>const char *<parameter>addr</parameter></paramdef>
+ <paramdef>int <parameter>len</parameter></paramdef>
+ <paramdef>int <parameter>type</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+struct hostent *
+<function>lwres_gethostent</function></funcdef>
+ <paramdef>void</paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_sethostent</function></funcdef>
+ <paramdef>int <parameter>stayopen</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_endhostent</function></funcdef>
+ <paramdef>void</paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+struct hostent *
+<function>lwres_gethostbyname_r</function></funcdef>
+ <paramdef>const char *<parameter>name</parameter></paramdef>
+ <paramdef>struct hostent *<parameter>resbuf</parameter></paramdef>
+ <paramdef>char *<parameter>buf</parameter></paramdef>
+ <paramdef>int <parameter>buflen</parameter></paramdef>
+ <paramdef>int *<parameter>error</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+struct hostent *
+<function>lwres_gethostbyaddr_r</function></funcdef>
+ <paramdef>const char *<parameter>addr</parameter></paramdef>
+ <paramdef>int <parameter>len</parameter></paramdef>
+ <paramdef>int <parameter>type</parameter></paramdef>
+ <paramdef>struct hostent *<parameter>resbuf</parameter></paramdef>
+ <paramdef>char *<parameter>buf</parameter></paramdef>
+ <paramdef>int <parameter>buflen</parameter></paramdef>
+ <paramdef>int *<parameter>error</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+struct hostent *
+<function>lwres_gethostent_r</function></funcdef>
+ <paramdef>struct hostent *<parameter>resbuf</parameter></paramdef>
+ <paramdef>char *<parameter>buf</parameter></paramdef>
+ <paramdef>int <parameter>buflen</parameter></paramdef>
+ <paramdef>int *<parameter>error</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_sethostent_r</function></funcdef>
+ <paramdef>int <parameter>stayopen</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_endhostent_r</function></funcdef>
+ <paramdef>void</paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+ <para>
+ These functions provide hostname-to-address and
+ address-to-hostname lookups by means of the lightweight resolver.
+ They are similar to the standard
+ <citerefentry>
+ <refentrytitle>gethostent</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>
+ functions provided by most operating systems.
+ They use a
+ <type>struct hostent</type>
+ which is usually defined in
+ <filename>&lt;namedb.h&gt;</filename>.
+ </para>
+ <para><programlisting>
+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 compatibility */
+</programlisting>
+ </para>
+ <para>
+ The members of this structure are:
+ <variablelist>
+ <varlistentry>
+ <term><constant>h_name</constant></term>
+ <listitem>
+ <para>
+ The official (canonical) name of the host.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>h_aliases</constant></term>
+ <listitem>
+ <para>
+ A NULL-terminated array of alternate names (nicknames) for the
+ host.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>h_addrtype</constant></term>
+ <listitem>
+ <para>
+ The type of address being returned &mdash;
+ <type>PF_INET</type>
+ or
+ <type>PF_INET6</type>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>h_length</constant></term>
+ <listitem>
+ <para>
+ The length of the address in bytes.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>h_addr_list</constant></term>
+ <listitem>
+ <para>
+ A <type>NULL</type>
+ terminated array of network addresses for the host.
+ Host addresses are returned in network byte order.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para>
+ For backward compatibility with very old software,
+ <constant>h_addr</constant>
+ is the first address in
+ <constant>h_addr_list.</constant>
+ </para>
+ <para><function>lwres_gethostent()</function>,
+ <function>lwres_sethostent()</function>,
+ <function>lwres_endhostent()</function>,
+ <function>lwres_gethostent_r()</function>,
+ <function>lwres_sethostent_r()</function>
+ and
+ <function>lwres_endhostent_r()</function>
+ provide iteration over the known host entries on systems that
+ provide such functionality through facilities like
+ <filename>/etc/hosts</filename>
+ or NIS. The lightweight resolver does not currently implement
+ these functions; it only provides them as stub functions that always
+ return failure.
+ </para>
+
+ <para><function>lwres_gethostbyname()</function>
+ and <function>lwres_gethostbyname2()</function> look up the
+ hostname <parameter>name</parameter>.
+ <function>lwres_gethostbyname()</function> always looks for an
+ IPv4 address while <function>lwres_gethostbyname2()</function>
+ looks for an address of protocol family
+ <parameter>af</parameter>: either <type>PF_INET</type> or
+ <type>PF_INET6</type> &mdash; IPv4 or IPV6 addresses
+ respectively. Successful calls of the functions return a
+ <type>struct hostent</type>for the name that was looked up.
+ <type>NULL</type> is returned if the lookups by
+ <function>lwres_gethostbyname()</function> or
+ <function>lwres_gethostbyname2()</function> fail.
+ </para>
+
+ <para>
+ Reverse lookups of addresses are performed by
+ <function>lwres_gethostbyaddr()</function>.
+ <parameter>addr</parameter> is an address of length
+ <parameter>len</parameter> bytes and protocol family
+ <parameter>type</parameter> &mdash; <type>PF_INET</type> or
+ <type>PF_INET6</type>.
+ <function>lwres_gethostbyname_r()</function> is a
+ thread-safe function
+ for forward lookups. If an error occurs, an error code is returned in
+ <parameter>*error</parameter>.
+ <parameter>resbuf</parameter> is a pointer to a
+ <type>struct hostent</type> which is initialised by a successful call to
+ <function>lwres_gethostbyname_r()</function>.
+ <parameter>buf</parameter> is a buffer of length
+ <parameter>len</parameter> bytes which is used to store the
+ <constant>h_name</constant>, <constant>h_aliases</constant>, and
+ <constant>h_addr_list</constant> elements of the
+ <type>struct hostent</type> returned in <parameter>resbuf</parameter>.
+ Successful calls to <function>lwres_gethostbyname_r()</function>
+ return <parameter>resbuf</parameter>,
+ which is a pointer to the <type>struct hostent</type> it created.
+ </para>
+
+ <para><function>lwres_gethostbyaddr_r()</function>
+ is a thread-safe function
+ that performs a reverse lookup of address <parameter>addr</parameter>
+ which is <parameter>len</parameter> bytes long and is of
+ protocol
+ family <parameter>type</parameter> &mdash; <type>PF_INET</type> or
+ <type>PF_INET6</type>. If an error occurs, the error code is returned
+ in <parameter>*error</parameter>. The other function
+ parameters are
+ identical to those in <function>lwres_gethostbyname_r()</function>.
+ <parameter>resbuf</parameter> is a pointer to a
+ <type>struct hostent</type> which is initialised by a successful call to
+ <function>lwres_gethostbyaddr_r()</function>.
+ <parameter>buf</parameter> is a buffer of length
+ <parameter>len</parameter> bytes which is used to store the
+ <constant>h_name</constant>, <constant>h_aliases</constant>, and
+ <constant>h_addr_list</constant> elements of the
+ <type>struct hostent</type> returned in <parameter>resbuf</parameter>.
+ Successful calls to <function>lwres_gethostbyaddr_r()</function> return
+ <parameter>resbuf</parameter>, which is a pointer to the
+ <function>struct hostent()</function> it created.
+ </para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>RETURN VALUES</title>
+ <para>
+ The functions
+ <function>lwres_gethostbyname()</function>,
+ <function>lwres_gethostbyname2()</function>,
+ <function>lwres_gethostbyaddr()</function>,
+ and
+ <function>lwres_gethostent()</function>
+ return NULL to indicate an error. In this case the global variable
+ <type>lwres_h_errno</type>
+ will contain one of the following error codes defined in
+ <filename>&lt;lwres/netdb.h&gt;</filename>:
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>HOST_NOT_FOUND</constant></term>
+ <listitem>
+ <para>
+ The host or address was not found.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>TRY_AGAIN</constant></term>
+ <listitem>
+ <para>
+ A recoverable error occurred, e.g., a timeout.
+ Retrying the lookup may succeed.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>NO_RECOVERY</constant></term>
+ <listitem>
+ <para>
+ A non-recoverable error occurred.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>NO_DATA</constant></term>
+ <listitem>
+ <para>
+ The name exists, but has no address information
+ associated with it (or vice versa in the case
+ of a reverse lookup). The code NO_ADDRESS
+ is accepted as a synonym for NO_DATA for backwards
+ compatibility.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para><citerefentry>
+ <refentrytitle>lwres_hstrerror</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>
+ translates these error codes to suitable error messages.
+ </para>
+
+ <para><function>lwres_gethostent()</function>
+ and <function>lwres_gethostent_r()</function>
+ always return <type>NULL</type>.
+ </para>
+
+ <para>
+ Successful calls to <function>lwres_gethostbyname_r()</function> and
+ <function>lwres_gethostbyaddr_r()</function> return
+ <parameter>resbuf</parameter>, a pointer to the
+ <type>struct hostent</type> that was initialised by these functions. They return
+ <type>NULL</type> if the lookups fail or if <parameter>buf</parameter>
+ was too small to hold the list of addresses and names referenced by
+ the <constant>h_name</constant>, <constant>h_aliases</constant>, and
+ <constant>h_addr_list</constant> elements of the
+ <type>struct hostent</type>.
+ If <parameter>buf</parameter> was too small, both
+ <function>lwres_gethostbyname_r()</function> and
+ <function>lwres_gethostbyaddr_r()</function> set the global
+ variable
+ <type>errno</type> to <errorcode>ERANGE</errorcode>.
+ </para>
+
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>gethostent</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_getipnode</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_hstrerror</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>BUGS</title>
+ <para><function>lwres_gethostbyname()</function>,
+ <function>lwres_gethostbyname2()</function>,
+ <function>lwres_gethostbyaddr()</function>
+ and
+ <function>lwres_endhostent()</function>
+ are not thread safe; they return pointers to static data and
+ provide error codes through a global variable.
+ Thread-safe versions for name and address lookup are provided by
+ <function>lwres_gethostbyname_r()</function>,
+ and
+ <function>lwres_gethostbyaddr_r()</function>
+ respectively.
+ </para>
+ <para>
+ The resolver daemon does not currently support any non-DNS
+ name services such as
+ <filename>/etc/hosts</filename>
+ or
+ <type>NIS</type>,
+ consequently the above functions don't, either.
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_gethostent.html b/lib/lwres/man/lwres_gethostent.html
new file mode 100644
index 0000000..0b7ba442
--- /dev/null
+++ b/lib/lwres/man/lwres_gethostent.html
@@ -0,0 +1,466 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_gethostent.html,v 1.9.18.15 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_gethostent</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_gethostbyname, lwres_gethostbyname2, lwres_gethostbyaddr, lwres_gethostent, lwres_sethostent, lwres_endhostent, lwres_gethostbyname_r, lwres_gethostbyaddr_r, lwres_gethostent_r, lwres_sethostent_r, lwres_endhostent_r &#8212; lightweight resolver get network host entry</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/netdb.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+struct hostent *
+<b class="fsfunc">lwres_gethostbyname</b>(</code></td>
+<td>const char * </td>
+<td>
+<var class="pdparam">name</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+struct hostent *
+<b class="fsfunc">lwres_gethostbyname2</b>(</code></td>
+<td>const char * </td>
+<td>
+<var class="pdparam">name</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">af</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+struct hostent *
+<b class="fsfunc">lwres_gethostbyaddr</b>(</code></td>
+<td>const char * </td>
+<td>
+<var class="pdparam">addr</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">len</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">type</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+struct hostent *
+<b class="fsfunc">lwres_gethostent</b>(</code></td>
+<td> </td>
+<td>
+<code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_sethostent</b>(</code></td>
+<td>int  </td>
+<td>
+<var class="pdparam">stayopen</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_endhostent</b>(</code></td>
+<td> </td>
+<td>
+<code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+struct hostent *
+<b class="fsfunc">lwres_gethostbyname_r</b>(</code></td>
+<td>const char * </td>
+<td>
+<var class="pdparam">name</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>struct hostent * </td>
+<td>
+<var class="pdparam">resbuf</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>char * </td>
+<td>
+<var class="pdparam">buf</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">buflen</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int * </td>
+<td>
+<var class="pdparam">error</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+struct hostent *
+<b class="fsfunc">lwres_gethostbyaddr_r</b>(</code></td>
+<td>const char * </td>
+<td>
+<var class="pdparam">addr</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">len</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">type</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>struct hostent * </td>
+<td>
+<var class="pdparam">resbuf</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>char * </td>
+<td>
+<var class="pdparam">buf</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">buflen</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int * </td>
+<td>
+<var class="pdparam">error</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+struct hostent *
+<b class="fsfunc">lwres_gethostent_r</b>(</code></td>
+<td>struct hostent * </td>
+<td>
+<var class="pdparam">resbuf</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>char * </td>
+<td>
+<var class="pdparam">buf</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">buflen</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int * </td>
+<td>
+<var class="pdparam">error</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_sethostent_r</b>(</code></td>
+<td>int  </td>
+<td>
+<var class="pdparam">stayopen</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_endhostent_r</b>(</code></td>
+<td> </td>
+<td>
+<code>)</code>;</td>
+</tr></table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543608"></a><h2>DESCRIPTION</h2>
+<p>
+ These functions provide hostname-to-address and
+ address-to-hostname lookups by means of the lightweight resolver.
+ They are similar to the standard
+ <span class="citerefentry"><span class="refentrytitle">gethostent</span>(3)</span>
+ functions provided by most operating systems.
+ They use a
+ <span class="type">struct hostent</span>
+ which is usually defined in
+ <code class="filename">&lt;namedb.h&gt;</code>.
+ </p>
+<pre class="programlisting">
+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 compatibility */
+</pre>
+<p>
+ </p>
+<p>
+ The members of this structure are:
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><code class="constant">h_name</code></span></dt>
+<dd><p>
+ The official (canonical) name of the host.
+ </p></dd>
+<dt><span class="term"><code class="constant">h_aliases</code></span></dt>
+<dd><p>
+ A NULL-terminated array of alternate names (nicknames) for the
+ host.
+ </p></dd>
+<dt><span class="term"><code class="constant">h_addrtype</code></span></dt>
+<dd><p>
+ The type of address being returned &#8212;
+ <span class="type">PF_INET</span>
+ or
+ <span class="type">PF_INET6</span>.
+ </p></dd>
+<dt><span class="term"><code class="constant">h_length</code></span></dt>
+<dd><p>
+ The length of the address in bytes.
+ </p></dd>
+<dt><span class="term"><code class="constant">h_addr_list</code></span></dt>
+<dd><p>
+ A <span class="type">NULL</span>
+ terminated array of network addresses for the host.
+ Host addresses are returned in network byte order.
+ </p></dd>
+</dl></div>
+<p>
+ </p>
+<p>
+ For backward compatibility with very old software,
+ <code class="constant">h_addr</code>
+ is the first address in
+ <code class="constant">h_addr_list.</code>
+ </p>
+<p><code class="function">lwres_gethostent()</code>,
+ <code class="function">lwres_sethostent()</code>,
+ <code class="function">lwres_endhostent()</code>,
+ <code class="function">lwres_gethostent_r()</code>,
+ <code class="function">lwres_sethostent_r()</code>
+ and
+ <code class="function">lwres_endhostent_r()</code>
+ provide iteration over the known host entries on systems that
+ provide such functionality through facilities like
+ <code class="filename">/etc/hosts</code>
+ or NIS. The lightweight resolver does not currently implement
+ these functions; it only provides them as stub functions that always
+ return failure.
+ </p>
+<p><code class="function">lwres_gethostbyname()</code>
+ and <code class="function">lwres_gethostbyname2()</code> look up the
+ hostname <em class="parameter"><code>name</code></em>.
+ <code class="function">lwres_gethostbyname()</code> always looks for an
+ IPv4 address while <code class="function">lwres_gethostbyname2()</code>
+ looks for an address of protocol family
+ <em class="parameter"><code>af</code></em>: either <span class="type">PF_INET</span> or
+ <span class="type">PF_INET6</span> &#8212; IPv4 or IPV6 addresses
+ respectively. Successful calls of the functions return a
+ <span class="type">struct hostent</span>for the name that was looked up.
+ <span class="type">NULL</span> is returned if the lookups by
+ <code class="function">lwres_gethostbyname()</code> or
+ <code class="function">lwres_gethostbyname2()</code> fail.
+ </p>
+<p>
+ Reverse lookups of addresses are performed by
+ <code class="function">lwres_gethostbyaddr()</code>.
+ <em class="parameter"><code>addr</code></em> is an address of length
+ <em class="parameter"><code>len</code></em> bytes and protocol family
+ <em class="parameter"><code>type</code></em> &#8212; <span class="type">PF_INET</span> or
+ <span class="type">PF_INET6</span>.
+ <code class="function">lwres_gethostbyname_r()</code> is a
+ thread-safe function
+ for forward lookups. If an error occurs, an error code is returned in
+ <em class="parameter"><code>*error</code></em>.
+ <em class="parameter"><code>resbuf</code></em> is a pointer to a
+ <span class="type">struct hostent</span> which is initialised by a successful call to
+ <code class="function">lwres_gethostbyname_r()</code>.
+ <em class="parameter"><code>buf</code></em> is a buffer of length
+ <em class="parameter"><code>len</code></em> bytes which is used to store the
+ <code class="constant">h_name</code>, <code class="constant">h_aliases</code>, and
+ <code class="constant">h_addr_list</code> elements of the
+ <span class="type">struct hostent</span> returned in <em class="parameter"><code>resbuf</code></em>.
+ Successful calls to <code class="function">lwres_gethostbyname_r()</code>
+ return <em class="parameter"><code>resbuf</code></em>,
+ which is a pointer to the <span class="type">struct hostent</span> it created.
+ </p>
+<p><code class="function">lwres_gethostbyaddr_r()</code>
+ is a thread-safe function
+ that performs a reverse lookup of address <em class="parameter"><code>addr</code></em>
+ which is <em class="parameter"><code>len</code></em> bytes long and is of
+ protocol
+ family <em class="parameter"><code>type</code></em> &#8212; <span class="type">PF_INET</span> or
+ <span class="type">PF_INET6</span>. If an error occurs, the error code is returned
+ in <em class="parameter"><code>*error</code></em>. The other function
+ parameters are
+ identical to those in <code class="function">lwres_gethostbyname_r()</code>.
+ <em class="parameter"><code>resbuf</code></em> is a pointer to a
+ <span class="type">struct hostent</span> which is initialised by a successful call to
+ <code class="function">lwres_gethostbyaddr_r()</code>.
+ <em class="parameter"><code>buf</code></em> is a buffer of length
+ <em class="parameter"><code>len</code></em> bytes which is used to store the
+ <code class="constant">h_name</code>, <code class="constant">h_aliases</code>, and
+ <code class="constant">h_addr_list</code> elements of the
+ <span class="type">struct hostent</span> returned in <em class="parameter"><code>resbuf</code></em>.
+ Successful calls to <code class="function">lwres_gethostbyaddr_r()</code> return
+ <em class="parameter"><code>resbuf</code></em>, which is a pointer to the
+ <code class="function">struct hostent()</code> it created.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543959"></a><h2>RETURN VALUES</h2>
+<p>
+ The functions
+ <code class="function">lwres_gethostbyname()</code>,
+ <code class="function">lwres_gethostbyname2()</code>,
+ <code class="function">lwres_gethostbyaddr()</code>,
+ and
+ <code class="function">lwres_gethostent()</code>
+ return NULL to indicate an error. In this case the global variable
+ <span class="type">lwres_h_errno</span>
+ will contain one of the following error codes defined in
+ <code class="filename">&lt;lwres/netdb.h&gt;</code>:
+
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><code class="constant">HOST_NOT_FOUND</code></span></dt>
+<dd><p>
+ The host or address was not found.
+ </p></dd>
+<dt><span class="term"><code class="constant">TRY_AGAIN</code></span></dt>
+<dd><p>
+ A recoverable error occurred, e.g., a timeout.
+ Retrying the lookup may succeed.
+ </p></dd>
+<dt><span class="term"><code class="constant">NO_RECOVERY</code></span></dt>
+<dd><p>
+ A non-recoverable error occurred.
+ </p></dd>
+<dt><span class="term"><code class="constant">NO_DATA</code></span></dt>
+<dd><p>
+ The name exists, but has no address information
+ associated with it (or vice versa in the case
+ of a reverse lookup). The code NO_ADDRESS
+ is accepted as a synonym for NO_DATA for backwards
+ compatibility.
+ </p></dd>
+</dl></div>
+<p>
+ </p>
+<p><span class="citerefentry"><span class="refentrytitle">lwres_hstrerror</span>(3)</span>
+ translates these error codes to suitable error messages.
+ </p>
+<p><code class="function">lwres_gethostent()</code>
+ and <code class="function">lwres_gethostent_r()</code>
+ always return <span class="type">NULL</span>.
+ </p>
+<p>
+ Successful calls to <code class="function">lwres_gethostbyname_r()</code> and
+ <code class="function">lwres_gethostbyaddr_r()</code> return
+ <em class="parameter"><code>resbuf</code></em>, a pointer to the
+ <span class="type">struct hostent</span> that was initialised by these functions. They return
+ <span class="type">NULL</span> if the lookups fail or if <em class="parameter"><code>buf</code></em>
+ was too small to hold the list of addresses and names referenced by
+ the <code class="constant">h_name</code>, <code class="constant">h_aliases</code>, and
+ <code class="constant">h_addr_list</code> elements of the
+ <span class="type">struct hostent</span>.
+ If <em class="parameter"><code>buf</code></em> was too small, both
+ <code class="function">lwres_gethostbyname_r()</code> and
+ <code class="function">lwres_gethostbyaddr_r()</code> set the global
+ variable
+ <span class="type">errno</span> to <span class="errorcode">ERANGE</span>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2544193"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">gethostent</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_getipnode</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_hstrerror</span>(3)</span>
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2544227"></a><h2>BUGS</h2>
+<p><code class="function">lwres_gethostbyname()</code>,
+ <code class="function">lwres_gethostbyname2()</code>,
+ <code class="function">lwres_gethostbyaddr()</code>
+ and
+ <code class="function">lwres_endhostent()</code>
+ are not thread safe; they return pointers to static data and
+ provide error codes through a global variable.
+ Thread-safe versions for name and address lookup are provided by
+ <code class="function">lwres_gethostbyname_r()</code>,
+ and
+ <code class="function">lwres_gethostbyaddr_r()</code>
+ respectively.
+ </p>
+<p>
+ The resolver daemon does not currently support any non-DNS
+ name services such as
+ <code class="filename">/etc/hosts</code>
+ or
+ <span class="type">NIS</span>,
+ consequently the above functions don't, either.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_getipnode.3 b/lib/lwres/man/lwres_getipnode.3
new file mode 100644
index 0000000..9c9f374
--- /dev/null
+++ b/lib/lwres/man/lwres_getipnode.3
@@ -0,0 +1,206 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_getipnode.3,v 1.17.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_getipnode
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_GETIPNODE" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_getipnodebyname, lwres_getipnodebyaddr, lwres_freehostent \- lightweight resolver nodename / address translation API
+.SH "SYNOPSIS"
+.nf
+#include <lwres/netdb.h>
+.fi
+.HP 39
+.BI "struct hostent * lwres_getipnodebyname(const\ char\ *" "name" ", int\ " "af" ", int\ " "flags" ", int\ *" "error_num" ");"
+.HP 39
+.BI "struct hostent * lwres_getipnodebyaddr(const\ void\ *" "src" ", size_t\ " "len" ", int\ " "af" ", int\ *" "error_num" ");"
+.HP 23
+.BI "void lwres_freehostent(struct\ hostent\ *" "he" ");"
+.SH "DESCRIPTION"
+.PP
+These functions perform thread safe, protocol independent nodename\-to\-address and address\-to\-nodename translation as defined in RFC2553.
+.PP
+They use a
+\fBstruct hostent\fR
+which is defined in
+\fInamedb.h\fR:
+.PP
+.RS 4
+.nf
+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 compatibility */
+.fi
+.RE
+.sp
+.PP
+The members of this structure are:
+.PP
+\fBh_name\fR
+.RS 4
+The official (canonical) name of the host.
+.RE
+.PP
+\fBh_aliases\fR
+.RS 4
+A NULL\-terminated array of alternate names (nicknames) for the host.
+.RE
+.PP
+\fBh_addrtype\fR
+.RS 4
+The type of address being returned \- usually
+\fBPF_INET\fR
+or
+\fBPF_INET6\fR.
+.RE
+.PP
+\fBh_length\fR
+.RS 4
+The length of the address in bytes.
+.RE
+.PP
+\fBh_addr_list\fR
+.RS 4
+A
+\fBNULL\fR
+terminated array of network addresses for the host. Host addresses are returned in network byte order.
+.RE
+.PP
+\fBlwres_getipnodebyname()\fR
+looks up addresses of protocol family
+\fIaf\fR
+for the hostname
+\fIname\fR. The
+\fIflags\fR
+parameter contains ORed flag bits to specify the types of addresses that are searched for, and the types of addresses that are returned. The flag bits are:
+.PP
+\fBAI_V4MAPPED\fR
+.RS 4
+This is used with an
+\fIaf\fR
+of AF_INET6, and causes IPv4 addresses to be returned as IPv4\-mapped IPv6 addresses.
+.RE
+.PP
+\fBAI_ALL\fR
+.RS 4
+This is used with an
+\fIaf\fR
+of AF_INET6, and causes all known addresses (IPv6 and IPv4) to be returned. If AI_V4MAPPED is also set, the IPv4 addresses are return as mapped IPv6 addresses.
+.RE
+.PP
+\fBAI_ADDRCONFIG\fR
+.RS 4
+Only return an IPv6 or IPv4 address if here is an active network interface of that type. This is not currently implemented in the BIND 9 lightweight resolver, and the flag is ignored.
+.RE
+.PP
+\fBAI_DEFAULT\fR
+.RS 4
+This default sets the
+\fBAI_V4MAPPED\fR
+and
+\fBAI_ADDRCONFIG\fR
+flag bits.
+.RE
+.PP
+\fBlwres_getipnodebyaddr()\fR
+performs a reverse lookup of address
+\fIsrc\fR
+which is
+\fIlen\fR
+bytes long.
+\fIaf\fR
+denotes the protocol family, typically
+\fBPF_INET\fR
+or
+\fBPF_INET6\fR.
+.PP
+\fBlwres_freehostent()\fR
+releases all the memory associated with the
+\fBstruct hostent\fR
+pointer
+\fIhe\fR. Any memory allocated for the
+\fBh_name\fR,
+\fBh_addr_list\fR
+and
+\fBh_aliases\fR
+is freed, as is the memory for the
+\fBhostent\fR
+structure itself.
+.SH "RETURN VALUES"
+.PP
+If an error occurs,
+\fBlwres_getipnodebyname()\fR
+and
+\fBlwres_getipnodebyaddr()\fR
+set
+\fI*error_num\fR
+to an appropriate error code and the function returns a
+\fBNULL\fR
+pointer. The error codes and their meanings are defined in
+\fI<lwres/netdb.h>\fR:
+.PP
+\fBHOST_NOT_FOUND\fR
+.RS 4
+No such host is known.
+.RE
+.PP
+\fBNO_ADDRESS\fR
+.RS 4
+The server recognised the request and the name but no address is available. Another type of request to the name server for the domain might return an answer.
+.RE
+.PP
+\fBTRY_AGAIN\fR
+.RS 4
+A temporary and possibly transient error occurred, such as a failure of a server to respond. The request may succeed if retried.
+.RE
+.PP
+\fBNO_RECOVERY\fR
+.RS 4
+An unexpected failure occurred, and retrying the request is pointless.
+.RE
+.PP
+\fBlwres_hstrerror\fR(3)
+translates these error codes to suitable error messages.
+.SH "SEE ALSO"
+.PP
+\fBRFC2553\fR(),
+\fBlwres\fR(3),
+\fBlwres_gethostent\fR(3),
+\fBlwres_getaddrinfo\fR(3),
+\fBlwres_getnameinfo\fR(3),
+\fBlwres_hstrerror\fR(3).
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001, 2003 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_getipnode.docbook b/lib/lwres/man/lwres_getipnode.docbook
new file mode 100644
index 0000000..a748920
--- /dev/null
+++ b/lib/lwres/man/lwres_getipnode.docbook
@@ -0,0 +1,331 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_getipnode.docbook,v 1.6.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_getipnode</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <year>2003</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_getipnodebyname</refname>
+ <refname>lwres_getipnodebyaddr</refname>
+ <refname>lwres_freehostent</refname>
+ <refpurpose>lightweight resolver nodename / address translation API</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+struct hostent *
+<function>lwres_getipnodebyname</function></funcdef>
+ <paramdef>const char *<parameter>name</parameter></paramdef>
+ <paramdef>int <parameter>af</parameter></paramdef>
+ <paramdef>int <parameter>flags</parameter></paramdef>
+ <paramdef>int *<parameter>error_num</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+struct hostent *
+<function>lwres_getipnodebyaddr</function></funcdef>
+ <paramdef>const void *<parameter>src</parameter></paramdef>
+ <paramdef>size_t <parameter>len</parameter></paramdef>
+ <paramdef>int <parameter>af</parameter></paramdef>
+ <paramdef>int *<parameter>error_num</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_freehostent</function></funcdef>
+ <paramdef>struct hostent *<parameter>he</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>
+ These functions perform thread safe, protocol independent
+ nodename-to-address and address-to-nodename
+ translation as defined in RFC2553.
+ </para>
+
+ <para>
+ They use a
+ <type>struct hostent</type>
+ which is defined in
+ <filename>namedb.h</filename>:
+ </para>
+ <para><programlisting>
+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 compatibility */
+</programlisting>
+ </para>
+
+ <para>
+ The members of this structure are:
+ <variablelist>
+ <varlistentry>
+ <term><constant>h_name</constant></term>
+ <listitem>
+ <para>
+ The official (canonical) name of the host.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>h_aliases</constant></term>
+ <listitem>
+ <para>
+ A NULL-terminated array of alternate names (nicknames) for the
+ host.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>h_addrtype</constant></term>
+ <listitem>
+ <para>
+ The type of address being returned - usually
+ <type>PF_INET</type>
+ or
+ <type>PF_INET6</type>.
+
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>h_length</constant></term>
+ <listitem>
+ <para>
+ The length of the address in bytes.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>h_addr_list</constant></term>
+ <listitem>
+ <para>
+ A
+ <type>NULL</type>
+ terminated array of network addresses for the host.
+ Host addresses are returned in network byte order.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para><function>lwres_getipnodebyname()</function>
+ looks up addresses of protocol family <parameter>af</parameter>
+ for the hostname <parameter>name</parameter>. The
+ <parameter>flags</parameter> parameter contains ORed flag bits
+ to specify the types of addresses that are searched for, and the
+ types of addresses that are returned. The flag bits are:
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>AI_V4MAPPED</constant></term>
+ <listitem>
+ <para>
+ This is used with an
+ <parameter>af</parameter>
+ of AF_INET6, and causes IPv4 addresses to be returned as
+ IPv4-mapped
+ IPv6 addresses.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>AI_ALL</constant></term>
+ <listitem>
+ <para>
+ This is used with an
+ <parameter>af</parameter>
+ of AF_INET6, and causes all known addresses (IPv6 and IPv4) to
+ be returned.
+ If AI_V4MAPPED is also set, the IPv4 addresses are return as
+ mapped
+ IPv6 addresses.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>AI_ADDRCONFIG</constant></term>
+ <listitem>
+ <para>
+ Only return an IPv6 or IPv4 address if here is an active network
+ interface of that type. This is not currently implemented
+ in the BIND 9 lightweight resolver, and the flag is ignored.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>AI_DEFAULT</constant></term>
+ <listitem>
+ <para>
+ This default sets the
+ <constant>AI_V4MAPPED</constant>
+ and
+ <constant>AI_ADDRCONFIG</constant>
+ flag bits.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para><function>lwres_getipnodebyaddr()</function>
+ performs a reverse lookup of address <parameter>src</parameter>
+ which is <parameter>len</parameter> bytes long.
+ <parameter>af</parameter> denotes the protocol family, typically
+ <type>PF_INET</type> or <type>PF_INET6</type>.
+ </para>
+ <para><function>lwres_freehostent()</function>
+ releases all the memory associated with the <type>struct
+ hostent</type> pointer <parameter>he</parameter>. Any memory
+ allocated for the <constant>h_name</constant>,
+ <constant>h_addr_list</constant> and
+ <constant>h_aliases</constant> is freed, as is the memory for
+ the <type>hostent</type> structure itself.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>RETURN VALUES</title>
+ <para>
+ If an error occurs,
+ <function>lwres_getipnodebyname()</function>
+ and
+ <function>lwres_getipnodebyaddr()</function>
+ set
+ <parameter>*error_num</parameter>
+ to an appropriate error code and the function returns a
+ <type>NULL</type>
+ pointer.
+ The error codes and their meanings are defined in
+ <filename>&lt;lwres/netdb.h&gt;</filename>:
+ <variablelist>
+ <varlistentry>
+ <term><constant>HOST_NOT_FOUND</constant></term>
+ <listitem>
+ <para>
+ No such host is known.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>NO_ADDRESS</constant></term>
+ <listitem>
+ <para>
+ The server recognised the request and the name but no address is
+ available. Another type of request to the name server for the
+ domain might return an answer.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>TRY_AGAIN</constant></term>
+ <listitem>
+ <para>
+ A temporary and possibly transient error occurred, such as a
+ failure of a server to respond. The request may succeed if
+ retried.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>NO_RECOVERY</constant></term>
+ <listitem>
+ <para>
+ An unexpected failure occurred, and retrying the request
+ is pointless.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para><citerefentry>
+ <refentrytitle>lwres_hstrerror</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>
+ translates these error codes to suitable error messages.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>RFC2553</refentrytitle>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_gethostent</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_getaddrinfo</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_getnameinfo</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_hstrerror</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_getipnode.html b/lib/lwres/man/lwres_getipnode.html
new file mode 100644
index 0000000..a585f1d
--- /dev/null
+++ b/lib/lwres/man/lwres_getipnode.html
@@ -0,0 +1,279 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_getipnode.html,v 1.9.18.16 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_getipnode</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_getipnodebyname, lwres_getipnodebyaddr, lwres_freehostent &#8212; lightweight resolver nodename / address translation API</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/netdb.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+struct hostent *
+<b class="fsfunc">lwres_getipnodebyname</b>(</code></td>
+<td>const char * </td>
+<td>
+<var class="pdparam">name</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">af</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">flags</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int * </td>
+<td>
+<var class="pdparam">error_num</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+struct hostent *
+<b class="fsfunc">lwres_getipnodebyaddr</b>(</code></td>
+<td>const void * </td>
+<td>
+<var class="pdparam">src</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>size_t  </td>
+<td>
+<var class="pdparam">len</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">af</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int * </td>
+<td>
+<var class="pdparam">error_num</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_freehostent</b>(</code></td>
+<td>struct hostent * </td>
+<td>
+<var class="pdparam">he</var><code>)</code>;</td>
+</tr></table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543431"></a><h2>DESCRIPTION</h2>
+<p>
+ These functions perform thread safe, protocol independent
+ nodename-to-address and address-to-nodename
+ translation as defined in RFC2553.
+ </p>
+<p>
+ They use a
+ <span class="type">struct hostent</span>
+ which is defined in
+ <code class="filename">namedb.h</code>:
+ </p>
+<pre class="programlisting">
+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 compatibility */
+</pre>
+<p>
+ </p>
+<p>
+ The members of this structure are:
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><code class="constant">h_name</code></span></dt>
+<dd><p>
+ The official (canonical) name of the host.
+ </p></dd>
+<dt><span class="term"><code class="constant">h_aliases</code></span></dt>
+<dd><p>
+ A NULL-terminated array of alternate names (nicknames) for the
+ host.
+ </p></dd>
+<dt><span class="term"><code class="constant">h_addrtype</code></span></dt>
+<dd><p>
+ The type of address being returned - usually
+ <span class="type">PF_INET</span>
+ or
+ <span class="type">PF_INET6</span>.
+
+ </p></dd>
+<dt><span class="term"><code class="constant">h_length</code></span></dt>
+<dd><p>
+ The length of the address in bytes.
+ </p></dd>
+<dt><span class="term"><code class="constant">h_addr_list</code></span></dt>
+<dd><p>
+ A
+ <span class="type">NULL</span>
+ terminated array of network addresses for the host.
+ Host addresses are returned in network byte order.
+ </p></dd>
+</dl></div>
+<p>
+ </p>
+<p><code class="function">lwres_getipnodebyname()</code>
+ looks up addresses of protocol family <em class="parameter"><code>af</code></em>
+ for the hostname <em class="parameter"><code>name</code></em>. The
+ <em class="parameter"><code>flags</code></em> parameter contains ORed flag bits
+ to specify the types of addresses that are searched for, and the
+ types of addresses that are returned. The flag bits are:
+
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><code class="constant">AI_V4MAPPED</code></span></dt>
+<dd><p>
+ This is used with an
+ <em class="parameter"><code>af</code></em>
+ of AF_INET6, and causes IPv4 addresses to be returned as
+ IPv4-mapped
+ IPv6 addresses.
+ </p></dd>
+<dt><span class="term"><code class="constant">AI_ALL</code></span></dt>
+<dd><p>
+ This is used with an
+ <em class="parameter"><code>af</code></em>
+ of AF_INET6, and causes all known addresses (IPv6 and IPv4) to
+ be returned.
+ If AI_V4MAPPED is also set, the IPv4 addresses are return as
+ mapped
+ IPv6 addresses.
+ </p></dd>
+<dt><span class="term"><code class="constant">AI_ADDRCONFIG</code></span></dt>
+<dd><p>
+ Only return an IPv6 or IPv4 address if here is an active network
+ interface of that type. This is not currently implemented
+ in the BIND 9 lightweight resolver, and the flag is ignored.
+ </p></dd>
+<dt><span class="term"><code class="constant">AI_DEFAULT</code></span></dt>
+<dd><p>
+ This default sets the
+ <code class="constant">AI_V4MAPPED</code>
+ and
+ <code class="constant">AI_ADDRCONFIG</code>
+ flag bits.
+ </p></dd>
+</dl></div>
+<p>
+ </p>
+<p><code class="function">lwres_getipnodebyaddr()</code>
+ performs a reverse lookup of address <em class="parameter"><code>src</code></em>
+ which is <em class="parameter"><code>len</code></em> bytes long.
+ <em class="parameter"><code>af</code></em> denotes the protocol family, typically
+ <span class="type">PF_INET</span> or <span class="type">PF_INET6</span>.
+ </p>
+<p><code class="function">lwres_freehostent()</code>
+ releases all the memory associated with the <span class="type">struct
+ hostent</span> pointer <em class="parameter"><code>he</code></em>. Any memory
+ allocated for the <code class="constant">h_name</code>,
+ <code class="constant">h_addr_list</code> and
+ <code class="constant">h_aliases</code> is freed, as is the memory for
+ the <span class="type">hostent</span> structure itself.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543689"></a><h2>RETURN VALUES</h2>
+<p>
+ If an error occurs,
+ <code class="function">lwres_getipnodebyname()</code>
+ and
+ <code class="function">lwres_getipnodebyaddr()</code>
+ set
+ <em class="parameter"><code>*error_num</code></em>
+ to an appropriate error code and the function returns a
+ <span class="type">NULL</span>
+ pointer.
+ The error codes and their meanings are defined in
+ <code class="filename">&lt;lwres/netdb.h&gt;</code>:
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><code class="constant">HOST_NOT_FOUND</code></span></dt>
+<dd><p>
+ No such host is known.
+ </p></dd>
+<dt><span class="term"><code class="constant">NO_ADDRESS</code></span></dt>
+<dd><p>
+ The server recognised the request and the name but no address is
+ available. Another type of request to the name server for the
+ domain might return an answer.
+ </p></dd>
+<dt><span class="term"><code class="constant">TRY_AGAIN</code></span></dt>
+<dd><p>
+ A temporary and possibly transient error occurred, such as a
+ failure of a server to respond. The request may succeed if
+ retried.
+ </p></dd>
+<dt><span class="term"><code class="constant">NO_RECOVERY</code></span></dt>
+<dd><p>
+ An unexpected failure occurred, and retrying the request
+ is pointless.
+ </p></dd>
+</dl></div>
+<p>
+ </p>
+<p><span class="citerefentry"><span class="refentrytitle">lwres_hstrerror</span>(3)</span>
+ translates these error codes to suitable error messages.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543786"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">RFC2553</span></span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_gethostent</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_getaddrinfo</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_getnameinfo</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_hstrerror</span>(3)</span>.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_getnameinfo.3 b/lib/lwres/man/lwres_getnameinfo.3
new file mode 100644
index 0000000..449f591
--- /dev/null
+++ b/lib/lwres/man/lwres_getnameinfo.3
@@ -0,0 +1,117 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_getnameinfo.3,v 1.18.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_getnameinfo
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_GETNAMEINFO" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_getnameinfo \- lightweight resolver socket address structure to hostname and service name
+.SH "SYNOPSIS"
+.nf
+#include <lwres/netdb.h>
+.fi
+.HP 22
+.BI "int lwres_getnameinfo(const\ struct\ sockaddr\ *" "sa" ", size_t\ " "salen" ", char\ *" "host" ", size_t\ " "hostlen" ", char\ *" "serv" ", size_t\ " "servlen" ", int\ " "flags" ");"
+.SH "DESCRIPTION"
+.PP
+This function is equivalent to the
+\fBgetnameinfo\fR(3)
+function defined in RFC2133.
+\fBlwres_getnameinfo()\fR
+returns the hostname for the
+\fBstruct sockaddr\fR
+\fIsa\fR
+which is
+\fIsalen\fR
+bytes long. The hostname is of length
+\fIhostlen\fR
+and is returned via
+\fI*host.\fR
+The maximum length of the hostname is 1025 bytes:
+\fBNI_MAXHOST\fR.
+.PP
+The name of the service associated with the port number in
+\fIsa\fR
+is returned in
+\fI*serv.\fR
+It is
+\fIservlen\fR
+bytes long. The maximum length of the service name is
+\fBNI_MAXSERV\fR
+\- 32 bytes.
+.PP
+The
+\fIflags\fR
+argument sets the following bits:
+.PP
+\fBNI_NOFQDN\fR
+.RS 4
+A fully qualified domain name is not required for local hosts. The local part of the fully qualified domain name is returned instead.
+.RE
+.PP
+\fBNI_NUMERICHOST\fR
+.RS 4
+Return the address in numeric form, as if calling inet_ntop(), instead of a host name.
+.RE
+.PP
+\fBNI_NAMEREQD\fR
+.RS 4
+A name is required. If the hostname cannot be found in the DNS and this flag is set, a non\-zero error code is returned. If the hostname is not found and the flag is not set, the address is returned in numeric form.
+.RE
+.PP
+\fBNI_NUMERICSERV\fR
+.RS 4
+The service name is returned as a digit string representing the port number.
+.RE
+.PP
+\fBNI_DGRAM\fR
+.RS 4
+Specifies that the service being looked up is a datagram service, and causes getservbyport() to be called with a second argument of "udp" instead of its default of "tcp". This is required for the few ports (512\-514) that have different services for UDP and TCP.
+.RE
+.SH "RETURN VALUES"
+.PP
+\fBlwres_getnameinfo()\fR
+returns 0 on success or a non\-zero error code if an error occurs.
+.SH "SEE ALSO"
+.PP
+\fBRFC2133\fR(),
+\fBgetservbyport\fR(3),
+\fBlwres\fR(3),
+\fBlwres_getnameinfo\fR(3),
+\fBlwres_getnamebyaddr\fR(3).
+\fBlwres_net_ntop\fR(3).
+.SH "BUGS"
+.PP
+RFC2133 fails to define what the nonzero return values of
+\fBgetnameinfo\fR(3)
+are.
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_getnameinfo.docbook b/lib/lwres/man/lwres_getnameinfo.docbook
new file mode 100644
index 0000000..d0b0df5
--- /dev/null
+++ b/lib/lwres/man/lwres_getnameinfo.docbook
@@ -0,0 +1,205 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_getnameinfo.docbook,v 1.4.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_getnameinfo</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_getnameinfo</refname>
+ <refpurpose>lightweight resolver socket address structure to hostname and
+ service name
+ </refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+int
+<function>lwres_getnameinfo</function></funcdef>
+ <paramdef>const struct sockaddr *<parameter>sa</parameter></paramdef>
+ <paramdef>size_t <parameter>salen</parameter></paramdef>
+ <paramdef>char *<parameter>host</parameter></paramdef>
+ <paramdef>size_t <parameter>hostlen</parameter></paramdef>
+ <paramdef>char *<parameter>serv</parameter></paramdef>
+ <paramdef>size_t <parameter>servlen</parameter></paramdef>
+ <paramdef>int <parameter>flags</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>
+ This function is equivalent to the
+ <citerefentry>
+ <refentrytitle>getnameinfo</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry> function defined in RFC2133.
+ <function>lwres_getnameinfo()</function> returns the
+ hostname for the
+ <type>struct sockaddr</type> <parameter>sa</parameter> which
+ is
+ <parameter>salen</parameter> bytes long. The hostname is of
+ length
+ <parameter>hostlen</parameter> and is returned via
+ <parameter>*host.</parameter> The maximum length of the
+ hostname is
+ 1025 bytes: <constant>NI_MAXHOST</constant>.
+ </para>
+
+ <para> The name of the service associated with the port number in
+ <parameter>sa</parameter> is returned in <parameter>*serv.</parameter>
+ It is <parameter>servlen</parameter> bytes long. The
+ maximum length
+ of the service name is <constant>NI_MAXSERV</constant> - 32
+ bytes.
+ </para>
+
+ <para>
+ The <parameter>flags</parameter> argument sets the
+ following
+ bits:
+ <variablelist>
+ <varlistentry>
+ <term><constant>NI_NOFQDN</constant></term>
+ <listitem>
+ <para>
+ A fully qualified domain name is not required for local hosts.
+ The local part of the fully qualified domain name is returned
+ instead.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>NI_NUMERICHOST</constant></term>
+ <listitem>
+ <para>
+ Return the address in numeric form, as if calling inet_ntop(),
+ instead of a host name.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>NI_NAMEREQD</constant></term>
+ <listitem>
+ <para>
+ A name is required. If the hostname cannot be found in the DNS
+ and
+ this flag is set, a non-zero error code is returned.
+ If the hostname is not found and the flag is not set, the
+ address is returned in numeric form.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>NI_NUMERICSERV</constant></term>
+ <listitem>
+ <para>
+ The service name is returned as a digit string representing the
+ port number.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>NI_DGRAM</constant></term>
+ <listitem>
+ <para>
+ Specifies that the service being looked up is a datagram
+ service, and causes getservbyport() to be called with a second
+ argument of "udp" instead of its default of "tcp". This is
+ required
+ for the few ports (512-514) that have different services for UDP
+ and
+ TCP.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>RETURN VALUES</title>
+ <para><function>lwres_getnameinfo()</function>
+ returns 0 on success or a non-zero error code if an error occurs.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>RFC2133</refentrytitle>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>getservbyport</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>lwres</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>lwres_getnameinfo</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>lwres_getnamebyaddr</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ <citerefentry>
+ <refentrytitle>lwres_net_ntop</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>BUGS</title>
+ <para>
+ RFC2133 fails to define what the nonzero return values of
+ <citerefentry>
+ <refentrytitle>getnameinfo</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>
+ are.
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_getnameinfo.html b/lib/lwres/man/lwres_getnameinfo.html
new file mode 100644
index 0000000..312cfe5
--- /dev/null
+++ b/lib/lwres/man/lwres_getnameinfo.html
@@ -0,0 +1,176 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_getnameinfo.html,v 1.6.18.17 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_getnameinfo</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_getnameinfo &#8212; lightweight resolver socket address structure to hostname and
+ service name
+ </p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/netdb.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0">
+<tr>
+<td><code class="funcdef">
+int
+<b class="fsfunc">lwres_getnameinfo</b>(</code></td>
+<td>const struct sockaddr * </td>
+<td>
+<var class="pdparam">sa</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>size_t  </td>
+<td>
+<var class="pdparam">salen</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>char * </td>
+<td>
+<var class="pdparam">host</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>size_t  </td>
+<td>
+<var class="pdparam">hostlen</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>char * </td>
+<td>
+<var class="pdparam">serv</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>size_t  </td>
+<td>
+<var class="pdparam">servlen</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>int  </td>
+<td>
+<var class="pdparam">flags</var><code>)</code>;</td>
+</tr>
+</table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543393"></a><h2>DESCRIPTION</h2>
+<p>
+ This function is equivalent to the
+ <span class="citerefentry"><span class="refentrytitle">getnameinfo</span>(3)</span> function defined in RFC2133.
+ <code class="function">lwres_getnameinfo()</code> returns the
+ hostname for the
+ <span class="type">struct sockaddr</span> <em class="parameter"><code>sa</code></em> which
+ is
+ <em class="parameter"><code>salen</code></em> bytes long. The hostname is of
+ length
+ <em class="parameter"><code>hostlen</code></em> and is returned via
+ <em class="parameter"><code>*host.</code></em> The maximum length of the
+ hostname is
+ 1025 bytes: <code class="constant">NI_MAXHOST</code>.
+ </p>
+<p> The name of the service associated with the port number in
+ <em class="parameter"><code>sa</code></em> is returned in <em class="parameter"><code>*serv.</code></em>
+ It is <em class="parameter"><code>servlen</code></em> bytes long. The
+ maximum length
+ of the service name is <code class="constant">NI_MAXSERV</code> - 32
+ bytes.
+ </p>
+<p>
+ The <em class="parameter"><code>flags</code></em> argument sets the
+ following
+ bits:
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><code class="constant">NI_NOFQDN</code></span></dt>
+<dd><p>
+ A fully qualified domain name is not required for local hosts.
+ The local part of the fully qualified domain name is returned
+ instead.
+ </p></dd>
+<dt><span class="term"><code class="constant">NI_NUMERICHOST</code></span></dt>
+<dd><p>
+ Return the address in numeric form, as if calling inet_ntop(),
+ instead of a host name.
+ </p></dd>
+<dt><span class="term"><code class="constant">NI_NAMEREQD</code></span></dt>
+<dd><p>
+ A name is required. If the hostname cannot be found in the DNS
+ and
+ this flag is set, a non-zero error code is returned.
+ If the hostname is not found and the flag is not set, the
+ address is returned in numeric form.
+ </p></dd>
+<dt><span class="term"><code class="constant">NI_NUMERICSERV</code></span></dt>
+<dd><p>
+ The service name is returned as a digit string representing the
+ port number.
+ </p></dd>
+<dt><span class="term"><code class="constant">NI_DGRAM</code></span></dt>
+<dd><p>
+ Specifies that the service being looked up is a datagram
+ service, and causes getservbyport() to be called with a second
+ argument of "udp" instead of its default of "tcp". This is
+ required
+ for the few ports (512-514) that have different services for UDP
+ and
+ TCP.
+ </p></dd>
+</dl></div>
+<p>
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543534"></a><h2>RETURN VALUES</h2>
+<p><code class="function">lwres_getnameinfo()</code>
+ returns 0 on success or a non-zero error code if an error occurs.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543546"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">RFC2133</span></span>,
+ <span class="citerefentry"><span class="refentrytitle">getservbyport</span>(3)</span>,
+ <span class="citerefentry"><span class="refentrytitle">lwres</span>(3)</span>,
+ <span class="citerefentry"><span class="refentrytitle">lwres_getnameinfo</span>(3)</span>,
+ <span class="citerefentry"><span class="refentrytitle">lwres_getnamebyaddr</span>(3)</span>.
+ <span class="citerefentry"><span class="refentrytitle">lwres_net_ntop</span>(3)</span>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543604"></a><h2>BUGS</h2>
+<p>
+ RFC2133 fails to define what the nonzero return values of
+ <span class="citerefentry"><span class="refentrytitle">getnameinfo</span>(3)</span>
+ are.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_getrrsetbyname.3 b/lib/lwres/man/lwres_getrrsetbyname.3
new file mode 100644
index 0000000..548b8e7
--- /dev/null
+++ b/lib/lwres/man/lwres_getrrsetbyname.3
@@ -0,0 +1,164 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_getrrsetbyname.3,v 1.14.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_getrrsetbyname
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Oct 18, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_GETRRSETBYNAME" "3" "Oct 18, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_getrrsetbyname, lwres_freerrset \- retrieve DNS records
+.SH "SYNOPSIS"
+.nf
+#include <lwres/netdb.h>
+.fi
+.HP 25
+.BI "int lwres_getrrsetbyname(const\ char\ *" "hostname" ", unsigned\ int\ " "rdclass" ", unsigned\ int\ " "rdtype" ", unsigned\ int\ " "flags" ", struct\ rrsetinfo\ **" "res" ");"
+.HP 21
+.BI "void lwres_freerrset(struct\ rrsetinfo\ *" "rrset" ");"
+.PP
+The following structures are used:
+.PP
+.RS 4
+.nf
+struct rdatainfo {
+ unsigned int rdi_length; /* length of data */
+ unsigned char *rdi_data; /* record data */
+};
+.fi
+.RE
+.sp
+.PP
+.RS 4
+.nf
+struct rrsetinfo {
+ unsigned int rri_flags; /* RRSET_VALIDATED... */
+ unsigned int rri_rdclass; /* class number */
+ unsigned int rri_rdtype; /* RR type number */
+ unsigned int rri_ttl; /* time to live */
+ unsigned int rri_nrdatas; /* size of rdatas array */
+ unsigned int rri_nsigs; /* size of sigs array */
+ char *rri_name; /* canonical name */
+ struct rdatainfo *rri_rdatas; /* individual records */
+ struct rdatainfo *rri_sigs; /* individual signatures */
+};
+.fi
+.RE
+.sp
+.SH "DESCRIPTION"
+.PP
+\fBlwres_getrrsetbyname()\fR
+gets a set of resource records associated with a
+\fIhostname\fR,
+\fIclass\fR, and
+\fItype\fR.
+\fIhostname\fR
+is a pointer a to null\-terminated string. The
+\fIflags\fR
+field is currently unused and must be zero.
+.PP
+After a successful call to
+\fBlwres_getrrsetbyname()\fR,
+\fI*res\fR
+is a pointer to an
+\fBrrsetinfo\fR
+structure, containing a list of one or more
+\fBrdatainfo\fR
+structures containing resource records and potentially another list of
+\fBrdatainfo\fR
+structures containing SIG resource records associated with those records. The members
+\fBrri_rdclass\fR
+and
+\fBrri_rdtype\fR
+are copied from the parameters.
+\fBrri_ttl\fR
+and
+\fBrri_name\fR
+are properties of the obtained rrset. The resource records contained in
+\fBrri_rdatas\fR
+and
+\fBrri_sigs\fR
+are in uncompressed DNS wire format. Properties of the rdataset are represented in the
+\fBrri_flags\fR
+bitfield. If the RRSET_VALIDATED bit is set, the data has been DNSSEC validated and the signatures verified.
+.PP
+All of the information returned by
+\fBlwres_getrrsetbyname()\fR
+is dynamically allocated: the
+\fBrrsetinfo\fR
+and
+\fBrdatainfo\fR
+structures, and the canonical host name strings pointed to by the
+\fBrrsetinfo\fRstructure. Memory allocated for the dynamically allocated structures created by a successful call to
+\fBlwres_getrrsetbyname()\fR
+is released by
+\fBlwres_freerrset()\fR.
+\fIrrset\fR
+is a pointer to a
+\fBstruct rrset\fR
+created by a call to
+\fBlwres_getrrsetbyname()\fR.
+.PP
+.SH "RETURN VALUES"
+.PP
+\fBlwres_getrrsetbyname()\fR
+returns zero on success, and one of the following error codes if an error occurred:
+.PP
+\fBERRSET_NONAME\fR
+.RS 4
+the name does not exist
+.RE
+.PP
+\fBERRSET_NODATA\fR
+.RS 4
+the name exists, but does not have data of the desired type
+.RE
+.PP
+\fBERRSET_NOMEMORY\fR
+.RS 4
+memory could not be allocated
+.RE
+.PP
+\fBERRSET_INVAL\fR
+.RS 4
+a parameter is invalid
+.RE
+.PP
+\fBERRSET_FAIL\fR
+.RS 4
+other failure
+.RE
+.PP
+.RS 4
+.RE
+.SH "SEE ALSO"
+.PP
+\fBlwres\fR(3).
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_getrrsetbyname.docbook b/lib/lwres/man/lwres_getrrsetbyname.docbook
new file mode 100644
index 0000000..746d8bf
--- /dev/null
+++ b/lib/lwres/man/lwres_getrrsetbyname.docbook
@@ -0,0 +1,223 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_getrrsetbyname.docbook,v 1.4.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Oct 18, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_getrrsetbyname</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_getrrsetbyname</refname>
+ <refname>lwres_freerrset</refname>
+ <refpurpose>retrieve DNS records</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+int
+<function>lwres_getrrsetbyname</function></funcdef>
+ <paramdef>const char *<parameter>hostname</parameter></paramdef>
+ <paramdef>unsigned int <parameter>rdclass</parameter></paramdef>
+ <paramdef>unsigned int <parameter>rdtype</parameter></paramdef>
+ <paramdef>unsigned int <parameter>flags</parameter></paramdef>
+ <paramdef>struct rrsetinfo **<parameter>res</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_freerrset</function></funcdef>
+ <paramdef>struct rrsetinfo *<parameter>rrset</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+
+ <para>
+ The following structures are used:
+ </para>
+ <para><programlisting>
+struct rdatainfo {
+ unsigned int rdi_length; /* length of data */
+ unsigned char *rdi_data; /* record data */
+};
+</programlisting>
+ </para>
+ <para><programlisting>
+struct rrsetinfo {
+ unsigned int rri_flags; /* RRSET_VALIDATED... */
+ unsigned int rri_rdclass; /* class number */
+ unsigned int rri_rdtype; /* RR type number */
+ unsigned int rri_ttl; /* time to live */
+ unsigned int rri_nrdatas; /* size of rdatas array */
+ unsigned int rri_nsigs; /* size of sigs array */
+ char *rri_name; /* canonical name */
+ struct rdatainfo *rri_rdatas; /* individual records */
+ struct rdatainfo *rri_sigs; /* individual signatures */
+};
+</programlisting>
+ </para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+ <para><function>lwres_getrrsetbyname()</function>
+ gets a set of resource records associated with a
+ <parameter>hostname</parameter>, <parameter>class</parameter>,
+ and <parameter>type</parameter>.
+ <parameter>hostname</parameter> is a pointer a to
+ null-terminated string. The <parameter>flags</parameter> field
+ is currently unused and must be zero.
+ </para>
+ <para>
+ After a successful call to
+ <function>lwres_getrrsetbyname()</function>,
+ <parameter>*res</parameter> is a pointer to an
+ <type>rrsetinfo</type> structure, containing a list of one or
+ more <type>rdatainfo</type> structures containing resource
+ records and potentially another list of <type>rdatainfo</type>
+ structures containing SIG resource records associated with those
+ records. The members <constant>rri_rdclass</constant> and
+ <constant>rri_rdtype</constant> are copied from the parameters.
+ <constant>rri_ttl</constant> and <constant>rri_name</constant>
+ are properties of the obtained rrset. The resource records
+ contained in <constant>rri_rdatas</constant> and
+ <constant>rri_sigs</constant> are in uncompressed DNS wire
+ format. Properties of the rdataset are represented in the
+ <constant>rri_flags</constant> bitfield. If the RRSET_VALIDATED
+ bit is set, the data has been DNSSEC validated and the
+ signatures verified.
+ </para>
+ <para>
+ All of the information returned by
+ <function>lwres_getrrsetbyname()</function> is dynamically
+ allocated: the <constant>rrsetinfo</constant> and
+ <constant>rdatainfo</constant> structures, and the canonical
+ host name strings pointed to by the
+ <constant>rrsetinfo</constant>structure.
+
+ Memory allocated for the dynamically allocated structures
+ created by a successful call to
+ <function>lwres_getrrsetbyname()</function> is released by
+ <function>lwres_freerrset()</function>.
+
+ <parameter>rrset</parameter> is a pointer to a <type>struct
+ rrset</type> created by a call to
+ <function>lwres_getrrsetbyname()</function>.
+ </para>
+ <para></para>
+ </refsect1>
+ <refsect1>
+ <title>RETURN VALUES</title>
+ <para><function>lwres_getrrsetbyname()</function>
+ returns zero on success, and one of the following error codes if
+ an error occurred:
+ <variablelist>
+
+ <varlistentry>
+ <term><constant>ERRSET_NONAME</constant></term>
+ <listitem>
+ <para>
+ the name does not exist
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>ERRSET_NODATA</constant></term>
+ <listitem>
+ <para>
+ the name exists, but does not have data of the desired type
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>ERRSET_NOMEMORY</constant></term>
+ <listitem>
+ <para>
+ memory could not be allocated
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>ERRSET_INVAL</constant></term>
+ <listitem>
+ <para>
+ a parameter is invalid
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>ERRSET_FAIL</constant></term>
+ <listitem>
+ <para>
+ other failure
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant/></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>lwres</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ </para>
+
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_getrrsetbyname.html b/lib/lwres/man/lwres_getrrsetbyname.html
new file mode 100644
index 0000000..0925367
--- /dev/null
+++ b/lib/lwres/man/lwres_getrrsetbyname.html
@@ -0,0 +1,192 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_getrrsetbyname.html,v 1.6.18.17 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_getrrsetbyname</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_getrrsetbyname, lwres_freerrset &#8212; retrieve DNS records</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/netdb.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+int
+<b class="fsfunc">lwres_getrrsetbyname</b>(</code></td>
+<td>const char * </td>
+<td>
+<var class="pdparam">hostname</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>unsigned int  </td>
+<td>
+<var class="pdparam">rdclass</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>unsigned int  </td>
+<td>
+<var class="pdparam">rdtype</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>unsigned int  </td>
+<td>
+<var class="pdparam">flags</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>struct rrsetinfo ** </td>
+<td>
+<var class="pdparam">res</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_freerrset</b>(</code></td>
+<td>struct rrsetinfo * </td>
+<td>
+<var class="pdparam">rrset</var><code>)</code>;</td>
+</tr></table>
+</div>
+<p>
+ The following structures are used:
+ </p>
+<pre class="programlisting">
+struct rdatainfo {
+ unsigned int rdi_length; /* length of data */
+ unsigned char *rdi_data; /* record data */
+};
+</pre>
+<p>
+ </p>
+<pre class="programlisting">
+struct rrsetinfo {
+ unsigned int rri_flags; /* RRSET_VALIDATED... */
+ unsigned int rri_rdclass; /* class number */
+ unsigned int rri_rdtype; /* RR type number */
+ unsigned int rri_ttl; /* time to live */
+ unsigned int rri_nrdatas; /* size of rdatas array */
+ unsigned int rri_nsigs; /* size of sigs array */
+ char *rri_name; /* canonical name */
+ struct rdatainfo *rri_rdatas; /* individual records */
+ struct rdatainfo *rri_sigs; /* individual signatures */
+};
+</pre>
+<p>
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543414"></a><h2>DESCRIPTION</h2>
+<p><code class="function">lwres_getrrsetbyname()</code>
+ gets a set of resource records associated with a
+ <em class="parameter"><code>hostname</code></em>, <em class="parameter"><code>class</code></em>,
+ and <em class="parameter"><code>type</code></em>.
+ <em class="parameter"><code>hostname</code></em> is a pointer a to
+ null-terminated string. The <em class="parameter"><code>flags</code></em> field
+ is currently unused and must be zero.
+ </p>
+<p>
+ After a successful call to
+ <code class="function">lwres_getrrsetbyname()</code>,
+ <em class="parameter"><code>*res</code></em> is a pointer to an
+ <span class="type">rrsetinfo</span> structure, containing a list of one or
+ more <span class="type">rdatainfo</span> structures containing resource
+ records and potentially another list of <span class="type">rdatainfo</span>
+ structures containing SIG resource records associated with those
+ records. The members <code class="constant">rri_rdclass</code> and
+ <code class="constant">rri_rdtype</code> are copied from the parameters.
+ <code class="constant">rri_ttl</code> and <code class="constant">rri_name</code>
+ are properties of the obtained rrset. The resource records
+ contained in <code class="constant">rri_rdatas</code> and
+ <code class="constant">rri_sigs</code> are in uncompressed DNS wire
+ format. Properties of the rdataset are represented in the
+ <code class="constant">rri_flags</code> bitfield. If the RRSET_VALIDATED
+ bit is set, the data has been DNSSEC validated and the
+ signatures verified.
+ </p>
+<p>
+ All of the information returned by
+ <code class="function">lwres_getrrsetbyname()</code> is dynamically
+ allocated: the <code class="constant">rrsetinfo</code> and
+ <code class="constant">rdatainfo</code> structures, and the canonical
+ host name strings pointed to by the
+ <code class="constant">rrsetinfo</code>structure.
+
+ Memory allocated for the dynamically allocated structures
+ created by a successful call to
+ <code class="function">lwres_getrrsetbyname()</code> is released by
+ <code class="function">lwres_freerrset()</code>.
+
+ <em class="parameter"><code>rrset</code></em> is a pointer to a <span class="type">struct
+ rrset</span> created by a call to
+ <code class="function">lwres_getrrsetbyname()</code>.
+ </p>
+<p></p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543526"></a><h2>RETURN VALUES</h2>
+<p><code class="function">lwres_getrrsetbyname()</code>
+ returns zero on success, and one of the following error codes if
+ an error occurred:
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><code class="constant">ERRSET_NONAME</code></span></dt>
+<dd><p>
+ the name does not exist
+ </p></dd>
+<dt><span class="term"><code class="constant">ERRSET_NODATA</code></span></dt>
+<dd><p>
+ the name exists, but does not have data of the desired type
+ </p></dd>
+<dt><span class="term"><code class="constant">ERRSET_NOMEMORY</code></span></dt>
+<dd><p>
+ memory could not be allocated
+ </p></dd>
+<dt><span class="term"><code class="constant">ERRSET_INVAL</code></span></dt>
+<dd><p>
+ a parameter is invalid
+ </p></dd>
+<dt><span class="term"><code class="constant">ERRSET_FAIL</code></span></dt>
+<dd><p>
+ other failure
+ </p></dd>
+<dt><span class="term"><code class="constant"></code></span></dt>
+<dd><p></p></dd>
+</dl></div>
+<p>
+
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543626"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">lwres</span>(3)</span>.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_gnba.3 b/lib/lwres/man/lwres_gnba.3
new file mode 100644
index 0000000..1c6574f
--- /dev/null
+++ b/lib/lwres/man/lwres_gnba.3
@@ -0,0 +1,183 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_gnba.3,v 1.16.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_gnba
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_GNBA" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_gnbarequest_render, lwres_gnbaresponse_render, lwres_gnbarequest_parse, lwres_gnbaresponse_parse, lwres_gnbaresponse_free, lwres_gnbarequest_free \- lightweight resolver getnamebyaddress message handling
+.SH "SYNOPSIS"
+.nf
+#include <lwres/lwres.h>
+.fi
+.HP 40
+.BI "lwres_result_t lwres_gnbarequest_render(lwres_context_t\ *" "ctx" ", lwres_gnbarequest_t\ *" "req" ", lwres_lwpacket_t\ *" "pkt" ", lwres_buffer_t\ *" "b" ");"
+.HP 41
+.BI "lwres_result_t lwres_gnbaresponse_render(lwres_context_t\ *" "ctx" ", lwres_gnbaresponse_t\ *" "req" ", lwres_lwpacket_t\ *" "pkt" ", lwres_buffer_t\ *" "b" ");"
+.HP 39
+.BI "lwres_result_t lwres_gnbarequest_parse(lwres_context_t\ *" "ctx" ", lwres_buffer_t\ *" "b" ", lwres_lwpacket_t\ *" "pkt" ", lwres_gnbarequest_t\ **" "structp" ");"
+.HP 40
+.BI "lwres_result_t lwres_gnbaresponse_parse(lwres_context_t\ *" "ctx" ", lwres_buffer_t\ *" "b" ", lwres_lwpacket_t\ *" "pkt" ", lwres_gnbaresponse_t\ **" "structp" ");"
+.HP 29
+.BI "void lwres_gnbaresponse_free(lwres_context_t\ *" "ctx" ", lwres_gnbaresponse_t\ **" "structp" ");"
+.HP 28
+.BI "void lwres_gnbarequest_free(lwres_context_t\ *" "ctx" ", lwres_gnbarequest_t\ **" "structp" ");"
+.SH "DESCRIPTION"
+.PP
+These are low\-level routines for creating and parsing lightweight resolver address\-to\-name lookup request and response messages.
+.PP
+There are four main functions for the getnamebyaddr opcode. One render function converts a getnamebyaddr request structure \(em
+\fBlwres_gnbarequest_t\fR
+\(em to the lightweight resolver's canonical format. It is complemented by a parse function that converts a packet in this canonical format to a getnamebyaddr request structure. Another render function converts the getnamebyaddr response structure \(em
+\fBlwres_gnbaresponse_t\fR
+to the canonical format. This is complemented by a parse function which converts a packet in canonical format to a getnamebyaddr response structure.
+.PP
+These structures are defined in
+\fIlwres/lwres.h\fR. They are shown below.
+.PP
+.RS 4
+.nf
+#define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
+.fi
+.RE
+.sp
+.PP
+.RS 4
+.nf
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_addr_t addr;
+} lwres_gnbarequest_t;
+.fi
+.RE
+.sp
+.PP
+.RS 4
+.nf
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ void *base;
+ size_t baselen;
+} lwres_gnbaresponse_t;
+.fi
+.RE
+.sp
+.PP
+\fBlwres_gnbarequest_render()\fR
+uses resolver context
+\fIctx\fR
+to convert getnamebyaddr request structure
+\fIreq\fR
+to canonical format. The packet header structure
+\fIpkt\fR
+is initialised and transferred to buffer
+\fIb\fR. The contents of
+\fI*req\fR
+are then appended to the buffer in canonical format.
+\fBlwres_gnbaresponse_render()\fR
+performs the same task, except it converts a getnamebyaddr response structure
+\fBlwres_gnbaresponse_t\fR
+to the lightweight resolver's canonical format.
+.PP
+\fBlwres_gnbarequest_parse()\fR
+uses context
+\fIctx\fR
+to convert the contents of packet
+\fIpkt\fR
+to a
+\fBlwres_gnbarequest_t\fR
+structure. Buffer
+\fIb\fR
+provides space to be used for storing this structure. When the function succeeds, the resulting
+\fBlwres_gnbarequest_t\fR
+is made available through
+\fI*structp\fR.
+\fBlwres_gnbaresponse_parse()\fR
+offers the same semantics as
+\fBlwres_gnbarequest_parse()\fR
+except it yields a
+\fBlwres_gnbaresponse_t\fR
+structure.
+.PP
+\fBlwres_gnbaresponse_free()\fR
+and
+\fBlwres_gnbarequest_free()\fR
+release the memory in resolver context
+\fIctx\fR
+that was allocated to the
+\fBlwres_gnbaresponse_t\fR
+or
+\fBlwres_gnbarequest_t\fR
+structures referenced via
+\fIstructp\fR. Any memory associated with ancillary buffers and strings for those structures is also discarded.
+.SH "RETURN VALUES"
+.PP
+The getnamebyaddr opcode functions
+\fBlwres_gnbarequest_render()\fR,
+\fBlwres_gnbaresponse_render()\fR
+\fBlwres_gnbarequest_parse()\fR
+and
+\fBlwres_gnbaresponse_parse()\fR
+all return
+\fBLWRES_R_SUCCESS\fR
+on success. They return
+\fBLWRES_R_NOMEMORY\fR
+if memory allocation fails.
+\fBLWRES_R_UNEXPECTEDEND\fR
+is returned if the available space in the buffer
+\fIb\fR
+is too small to accommodate the packet header or the
+\fBlwres_gnbarequest_t\fR
+and
+\fBlwres_gnbaresponse_t\fR
+structures.
+\fBlwres_gnbarequest_parse()\fR
+and
+\fBlwres_gnbaresponse_parse()\fR
+will return
+\fBLWRES_R_UNEXPECTEDEND\fR
+if the buffer is not empty after decoding the received packet. These functions will return
+\fBLWRES_R_FAILURE\fR
+if
+pktflags
+in the packet header structure
+\fBlwres_lwpacket_t\fR
+indicate that the packet is not a response to an earlier query.
+.SH "SEE ALSO"
+.PP
+\fBlwres_packet\fR(3).
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_gnba.docbook b/lib/lwres/man/lwres_gnba.docbook
new file mode 100644
index 0000000..a22ce89
--- /dev/null
+++ b/lib/lwres/man/lwres_gnba.docbook
@@ -0,0 +1,261 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_gnba.docbook,v 1.5.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_gnba</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_gnbarequest_render</refname>
+ <refname>lwres_gnbaresponse_render</refname>
+ <refname>lwres_gnbarequest_parse</refname>
+ <refname>lwres_gnbaresponse_parse</refname>
+ <refname>lwres_gnbaresponse_free</refname>
+ <refname>lwres_gnbarequest_free</refname>
+ <refpurpose>lightweight resolver getnamebyaddress message handling</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+
+ <funcsynopsis>
+<funcsynopsisinfo>
+#include &lt;lwres/lwres.h&gt;
+</funcsynopsisinfo>
+
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_gnbarequest_render</function>
+</funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_gnbarequest_t *<parameter>req</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_gnbaresponse_render</function>
+</funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_gnbaresponse_t *<parameter>req</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_gnbarequest_parse</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_gnbarequest_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_gnbaresponse_parse</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_gnbaresponse_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_gnbaresponse_free</function>
+</funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_gnbaresponse_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_gnbarequest_free</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_gnbarequest_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+ <para>
+ These are low-level routines for creating and parsing
+ lightweight resolver address-to-name lookup request and
+ response messages.
+ </para>
+ <para>
+ There are four main functions for the getnamebyaddr opcode.
+ One render function converts a getnamebyaddr request structure &mdash;
+ <type>lwres_gnbarequest_t</type> &mdash;
+ to the lightweight resolver's canonical format.
+ It is complemented by a parse function that converts a packet in this
+ canonical format to a getnamebyaddr request structure.
+ Another render function converts the getnamebyaddr response structure
+ &mdash;
+ <type>lwres_gnbaresponse_t</type>
+ to the canonical format.
+ This is complemented by a parse function which converts a packet in
+ canonical format to a getnamebyaddr response structure.
+ </para>
+ <para>
+ These structures are defined in
+ <filename>lwres/lwres.h</filename>.
+ They are shown below.
+ </para>
+ <para><programlisting>
+#define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
+</programlisting>
+ </para>
+ <para><programlisting>
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_addr_t addr;
+} lwres_gnbarequest_t;
+</programlisting>
+ </para>
+ <para><programlisting>
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ void *base;
+ size_t baselen;
+} lwres_gnbaresponse_t;
+</programlisting>
+ </para>
+
+ <para><function>lwres_gnbarequest_render()</function>
+ uses resolver context <varname>ctx</varname> to convert
+ getnamebyaddr request structure <varname>req</varname> to
+ canonical format. The packet header structure
+ <varname>pkt</varname> is initialised and transferred to buffer
+ <varname>b</varname>. The contents of <varname>*req</varname>
+ are then appended to the buffer in canonical format.
+ <function>lwres_gnbaresponse_render()</function> performs the
+ same task, except it converts a getnamebyaddr response structure
+ <type>lwres_gnbaresponse_t</type> to the lightweight resolver's
+ canonical format.
+ </para>
+
+ <para><function>lwres_gnbarequest_parse()</function>
+ uses context <varname>ctx</varname> to convert the contents of
+ packet <varname>pkt</varname> to a
+ <type>lwres_gnbarequest_t</type> structure. Buffer
+ <varname>b</varname> provides space to be used for storing this
+ structure. When the function succeeds, the resulting
+ <type>lwres_gnbarequest_t</type> is made available through
+ <varname>*structp</varname>.
+ <function>lwres_gnbaresponse_parse()</function> offers the same
+ semantics as <function>lwres_gnbarequest_parse()</function>
+ except it yields a <type>lwres_gnbaresponse_t</type> structure.
+ </para>
+
+ <para><function>lwres_gnbaresponse_free()</function>
+ and <function>lwres_gnbarequest_free()</function> release the
+ memory in resolver context <varname>ctx</varname> that was
+ allocated to the <type>lwres_gnbaresponse_t</type> or
+ <type>lwres_gnbarequest_t</type> structures referenced via
+ <varname>structp</varname>. Any memory associated with
+ ancillary buffers and strings for those structures is also
+ discarded.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>RETURN VALUES</title>
+ <para>
+ The getnamebyaddr opcode functions
+ <function>lwres_gnbarequest_render()</function>,
+ <function>lwres_gnbaresponse_render()</function>
+ <function>lwres_gnbarequest_parse()</function>
+ and
+ <function>lwres_gnbaresponse_parse()</function>
+ all return
+ <errorcode>LWRES_R_SUCCESS</errorcode>
+ on success.
+ They return
+ <errorcode>LWRES_R_NOMEMORY</errorcode>
+ if memory allocation fails.
+ <errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+ is returned if the available space in the buffer
+ <varname>b</varname>
+ is too small to accommodate the packet header or the
+ <type>lwres_gnbarequest_t</type>
+ and
+ <type>lwres_gnbaresponse_t</type>
+ structures.
+ <function>lwres_gnbarequest_parse()</function>
+ and
+ <function>lwres_gnbaresponse_parse()</function>
+ will return
+ <errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+ if the buffer is not empty after decoding the received packet.
+ These functions will return
+ <errorcode>LWRES_R_FAILURE</errorcode>
+ if
+ <structfield>pktflags</structfield>
+ in the packet header structure
+ <type>lwres_lwpacket_t</type>
+ indicate that the packet is not a response to an earlier query.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>lwres_packet</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_gnba.html b/lib/lwres/man/lwres_gnba.html
new file mode 100644
index 0000000..aac60c6
--- /dev/null
+++ b/lib/lwres/man/lwres_gnba.html
@@ -0,0 +1,316 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_gnba.html,v 1.7.18.17 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_gnba</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_gnbarequest_render, lwres_gnbaresponse_render, lwres_gnbarequest_parse, lwres_gnbaresponse_parse, lwres_gnbaresponse_free, lwres_gnbarequest_free &#8212; lightweight resolver getnamebyaddress message handling</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">
+#include &lt;lwres/lwres.h&gt;
+</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_gnbarequest_render</b>
+(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gnbarequest_t * </td>
+<td>
+<var class="pdparam">req</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_gnbaresponse_render</b>
+(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gnbaresponse_t * </td>
+<td>
+<var class="pdparam">req</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_gnbarequest_parse</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gnbarequest_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_gnbaresponse_parse</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gnbaresponse_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_gnbaresponse_free</b>
+(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gnbaresponse_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_gnbarequest_free</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gnbarequest_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543525"></a><h2>DESCRIPTION</h2>
+<p>
+ These are low-level routines for creating and parsing
+ lightweight resolver address-to-name lookup request and
+ response messages.
+ </p>
+<p>
+ There are four main functions for the getnamebyaddr opcode.
+ One render function converts a getnamebyaddr request structure &#8212;
+ <span class="type">lwres_gnbarequest_t</span> &#8212;
+ to the lightweight resolver's canonical format.
+ It is complemented by a parse function that converts a packet in this
+ canonical format to a getnamebyaddr request structure.
+ Another render function converts the getnamebyaddr response structure
+ &#8212;
+ <span class="type">lwres_gnbaresponse_t</span>
+ to the canonical format.
+ This is complemented by a parse function which converts a packet in
+ canonical format to a getnamebyaddr response structure.
+ </p>
+<p>
+ These structures are defined in
+ <code class="filename">lwres/lwres.h</code>.
+ They are shown below.
+ </p>
+<pre class="programlisting">
+#define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
+</pre>
+<p>
+ </p>
+<pre class="programlisting">
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_addr_t addr;
+} lwres_gnbarequest_t;
+</pre>
+<p>
+ </p>
+<pre class="programlisting">
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ void *base;
+ size_t baselen;
+} lwres_gnbaresponse_t;
+</pre>
+<p>
+ </p>
+<p><code class="function">lwres_gnbarequest_render()</code>
+ uses resolver context <code class="varname">ctx</code> to convert
+ getnamebyaddr request structure <code class="varname">req</code> to
+ canonical format. The packet header structure
+ <code class="varname">pkt</code> is initialised and transferred to buffer
+ <code class="varname">b</code>. The contents of <code class="varname">*req</code>
+ are then appended to the buffer in canonical format.
+ <code class="function">lwres_gnbaresponse_render()</code> performs the
+ same task, except it converts a getnamebyaddr response structure
+ <span class="type">lwres_gnbaresponse_t</span> to the lightweight resolver's
+ canonical format.
+ </p>
+<p><code class="function">lwres_gnbarequest_parse()</code>
+ uses context <code class="varname">ctx</code> to convert the contents of
+ packet <code class="varname">pkt</code> to a
+ <span class="type">lwres_gnbarequest_t</span> structure. Buffer
+ <code class="varname">b</code> provides space to be used for storing this
+ structure. When the function succeeds, the resulting
+ <span class="type">lwres_gnbarequest_t</span> is made available through
+ <code class="varname">*structp</code>.
+ <code class="function">lwres_gnbaresponse_parse()</code> offers the same
+ semantics as <code class="function">lwres_gnbarequest_parse()</code>
+ except it yields a <span class="type">lwres_gnbaresponse_t</span> structure.
+ </p>
+<p><code class="function">lwres_gnbaresponse_free()</code>
+ and <code class="function">lwres_gnbarequest_free()</code> release the
+ memory in resolver context <code class="varname">ctx</code> that was
+ allocated to the <span class="type">lwres_gnbaresponse_t</span> or
+ <span class="type">lwres_gnbarequest_t</span> structures referenced via
+ <code class="varname">structp</code>. Any memory associated with
+ ancillary buffers and strings for those structures is also
+ discarded.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543665"></a><h2>RETURN VALUES</h2>
+<p>
+ The getnamebyaddr opcode functions
+ <code class="function">lwres_gnbarequest_render()</code>,
+ <code class="function">lwres_gnbaresponse_render()</code>
+ <code class="function">lwres_gnbarequest_parse()</code>
+ and
+ <code class="function">lwres_gnbaresponse_parse()</code>
+ all return
+ <span class="errorcode">LWRES_R_SUCCESS</span>
+ on success.
+ They return
+ <span class="errorcode">LWRES_R_NOMEMORY</span>
+ if memory allocation fails.
+ <span class="errorcode">LWRES_R_UNEXPECTEDEND</span>
+ is returned if the available space in the buffer
+ <code class="varname">b</code>
+ is too small to accommodate the packet header or the
+ <span class="type">lwres_gnbarequest_t</span>
+ and
+ <span class="type">lwres_gnbaresponse_t</span>
+ structures.
+ <code class="function">lwres_gnbarequest_parse()</code>
+ and
+ <code class="function">lwres_gnbaresponse_parse()</code>
+ will return
+ <span class="errorcode">LWRES_R_UNEXPECTEDEND</span>
+ if the buffer is not empty after decoding the received packet.
+ These functions will return
+ <span class="errorcode">LWRES_R_FAILURE</span>
+ if
+ <em class="structfield"><code>pktflags</code></em>
+ in the packet header structure
+ <span class="type">lwres_lwpacket_t</span>
+ indicate that the packet is not a response to an earlier query.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543731"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">lwres_packet</span>(3)</span>.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_hstrerror.3 b/lib/lwres/man/lwres_hstrerror.3
new file mode 100644
index 0000000..6fa744e
--- /dev/null
+++ b/lib/lwres/man/lwres_hstrerror.3
@@ -0,0 +1,99 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_hstrerror.3,v 1.16.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_hstrerror
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_HSTRERROR" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_herror, lwres_hstrerror \- lightweight resolver error message generation
+.SH "SYNOPSIS"
+.nf
+#include <lwres/netdb.h>
+.fi
+.HP 18
+.BI "void lwres_herror(const\ char\ *" "s" ");"
+.HP 29
+.BI "const char * lwres_hstrerror(int\ " "err" ");"
+.SH "DESCRIPTION"
+.PP
+\fBlwres_herror()\fR
+prints the string
+\fIs\fR
+on
+\fBstderr\fR
+followed by the string generated by
+\fBlwres_hstrerror()\fR
+for the error code stored in the global variable
+\fBlwres_h_errno\fR.
+.PP
+\fBlwres_hstrerror()\fR
+returns an appropriate string for the error code gievn by
+\fIerr\fR. The values of the error codes and messages are as follows:
+.PP
+\fBNETDB_SUCCESS\fR
+.RS 4
+Resolver Error 0 (no error)
+.RE
+.PP
+\fBHOST_NOT_FOUND\fR
+.RS 4
+Unknown host
+.RE
+.PP
+\fBTRY_AGAIN\fR
+.RS 4
+Host name lookup failure
+.RE
+.PP
+\fBNO_RECOVERY\fR
+.RS 4
+Unknown server error
+.RE
+.PP
+\fBNO_DATA\fR
+.RS 4
+No address associated with name
+.RE
+.SH "RETURN VALUES"
+.PP
+The string
+Unknown resolver error
+is returned by
+\fBlwres_hstrerror()\fR
+when the value of
+\fBlwres_h_errno\fR
+is not a valid error code.
+.SH "SEE ALSO"
+.PP
+\fBherror\fR(3),
+\fBlwres_hstrerror\fR(3).
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_hstrerror.docbook b/lib/lwres/man/lwres_hstrerror.docbook
new file mode 100644
index 0000000..aae00a9
--- /dev/null
+++ b/lib/lwres/man/lwres_hstrerror.docbook
@@ -0,0 +1,152 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_hstrerror.docbook,v 1.5.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_hstrerror</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_herror</refname>
+ <refname>lwres_hstrerror</refname>
+ <refpurpose>lightweight resolver error message generation</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_herror</function></funcdef>
+ <paramdef>const char *<parameter>s</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+const char *
+<function>lwres_hstrerror</function></funcdef>
+ <paramdef>int <parameter>err</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><function>lwres_herror()</function>
+ prints the string <parameter>s</parameter> on
+ <type>stderr</type> followed by the string generated by
+ <function>lwres_hstrerror()</function> for the error code stored
+ in the global variable <constant>lwres_h_errno</constant>.
+ </para>
+
+ <para><function>lwres_hstrerror()</function>
+ returns an appropriate string for the error code gievn by
+ <parameter>err</parameter>. The values of the error codes and
+ messages are as follows:
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>NETDB_SUCCESS</errorcode></term>
+ <listitem>
+ <para><errorname>Resolver Error 0 (no error)</errorname>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>HOST_NOT_FOUND</errorcode></term>
+ <listitem>
+ <para><errorname>Unknown host</errorname>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>TRY_AGAIN</errorcode></term>
+ <listitem>
+ <para><errorname>Host name lookup failure</errorname>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>NO_RECOVERY</errorcode></term>
+ <listitem>
+ <para><errorname>Unknown server error</errorname>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>NO_DATA</errorcode></term>
+ <listitem>
+ <para><errorname>No address associated with name</errorname>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>RETURN VALUES</title>
+ <para>
+ The string <errorname>Unknown resolver error</errorname> is returned by
+ <function>lwres_hstrerror()</function>
+ when the value of
+ <constant>lwres_h_errno</constant>
+ is not a valid error code.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>herror</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_hstrerror</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ </para>
+
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_hstrerror.html b/lib/lwres/man/lwres_hstrerror.html
new file mode 100644
index 0000000..b52ff06
--- /dev/null
+++ b/lib/lwres/man/lwres_hstrerror.html
@@ -0,0 +1,104 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_hstrerror.html,v 1.6.18.17 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_hstrerror</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_herror, lwres_hstrerror &#8212; lightweight resolver error message generation</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/netdb.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em"><tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_herror</b>(</code></td>
+<td>const char * </td>
+<td>
+<var class="pdparam">s</var><code>)</code>;</td>
+</tr></table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0"><tr>
+<td><code class="funcdef">
+const char *
+<b class="fsfunc">lwres_hstrerror</b>(</code></td>
+<td>int  </td>
+<td>
+<var class="pdparam">err</var><code>)</code>;</td>
+</tr></table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543379"></a><h2>DESCRIPTION</h2>
+<p><code class="function">lwres_herror()</code>
+ prints the string <em class="parameter"><code>s</code></em> on
+ <span class="type">stderr</span> followed by the string generated by
+ <code class="function">lwres_hstrerror()</code> for the error code stored
+ in the global variable <code class="constant">lwres_h_errno</code>.
+ </p>
+<p><code class="function">lwres_hstrerror()</code>
+ returns an appropriate string for the error code gievn by
+ <em class="parameter"><code>err</code></em>. The values of the error codes and
+ messages are as follows:
+
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><span class="errorcode">NETDB_SUCCESS</span></span></dt>
+<dd><p><span class="errorname">Resolver Error 0 (no error)</span>
+ </p></dd>
+<dt><span class="term"><span class="errorcode">HOST_NOT_FOUND</span></span></dt>
+<dd><p><span class="errorname">Unknown host</span>
+ </p></dd>
+<dt><span class="term"><span class="errorcode">TRY_AGAIN</span></span></dt>
+<dd><p><span class="errorname">Host name lookup failure</span>
+ </p></dd>
+<dt><span class="term"><span class="errorcode">NO_RECOVERY</span></span></dt>
+<dd><p><span class="errorname">Unknown server error</span>
+ </p></dd>
+<dt><span class="term"><span class="errorcode">NO_DATA</span></span></dt>
+<dd><p><span class="errorname">No address associated with name</span>
+ </p></dd>
+</dl></div>
+<p>
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543497"></a><h2>RETURN VALUES</h2>
+<p>
+ The string <span class="errorname">Unknown resolver error</span> is returned by
+ <code class="function">lwres_hstrerror()</code>
+ when the value of
+ <code class="constant">lwres_h_errno</code>
+ is not a valid error code.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543517"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">herror</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_hstrerror</span>(3)</span>.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_inetntop.3 b/lib/lwres/man/lwres_inetntop.3
new file mode 100644
index 0000000..4cb09f8
--- /dev/null
+++ b/lib/lwres/man/lwres_inetntop.3
@@ -0,0 +1,77 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_inetntop.3,v 1.15.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_inetntop
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_INETNTOP" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_net_ntop \- lightweight resolver IP address presentation
+.SH "SYNOPSIS"
+.nf
+#include <lwres/net.h>
+.fi
+.HP 28
+.BI "const char * lwres_net_ntop(int\ " "af" ", const\ void\ *" "src" ", char\ *" "dst" ", size_t\ " "size" ");"
+.SH "DESCRIPTION"
+.PP
+\fBlwres_net_ntop()\fR
+converts an IP address of protocol family
+\fIaf\fR
+\(em IPv4 or IPv6 \(em at location
+\fIsrc\fR
+from network format to its conventional representation as a string. For IPv4 addresses, that string would be a dotted\-decimal. An IPv6 address would be represented in colon notation as described in RFC1884.
+.PP
+The generated string is copied to
+\fIdst\fR
+provided
+\fIsize\fR
+indicates it is long enough to store the ASCII representation of the address.
+.SH "RETURN VALUES"
+.PP
+If successful, the function returns
+\fIdst\fR: a pointer to a string containing the presentation format of the address.
+\fBlwres_net_ntop()\fR
+returns
+\fBNULL\fR
+and sets the global variable
+\fBerrno\fR
+to
+\fBEAFNOSUPPORT\fR
+if the protocol family given in
+\fIaf\fR
+is not supported.
+.SH "SEE ALSO"
+.PP
+\fBRFC1884\fR(),
+\fBinet_ntop\fR(3),
+\fBerrno\fR(3).
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_inetntop.docbook b/lib/lwres/man/lwres_inetntop.docbook
new file mode 100644
index 0000000..db2c652
--- /dev/null
+++ b/lib/lwres/man/lwres_inetntop.docbook
@@ -0,0 +1,120 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_inetntop.docbook,v 1.4.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_inetntop</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_net_ntop</refname>
+ <refpurpose>lightweight resolver IP address presentation</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/net.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+const char *
+<function>lwres_net_ntop</function></funcdef>
+ <paramdef>int <parameter>af</parameter></paramdef>
+ <paramdef>const void *<parameter>src</parameter></paramdef>
+ <paramdef>char *<parameter>dst</parameter></paramdef>
+ <paramdef>size_t <parameter>size</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><function>lwres_net_ntop()</function>
+ converts an IP address of protocol family
+ <parameter>af</parameter> &mdash; IPv4 or IPv6 &mdash; at
+ location <parameter>src</parameter> from network format to its
+ conventional representation as a string. For IPv4 addresses,
+ that string would be a dotted-decimal. An IPv6 address would be
+ represented in colon notation as described in RFC1884.
+ </para>
+
+ <para>
+ The generated string is copied to <parameter>dst</parameter>
+ provided
+ <parameter>size</parameter> indicates it is long enough to
+ store the
+ ASCII representation of the address.
+ </para>
+
+ </refsect1>
+ <refsect1>
+ <title>RETURN VALUES</title>
+
+ <para>
+ If successful, the function returns <parameter>dst</parameter>:
+ a pointer to a string containing the presentation format of the
+ address. <function>lwres_net_ntop()</function> returns
+ <type>NULL</type> and sets the global variable
+ <constant>errno</constant> to <errorcode>EAFNOSUPPORT</errorcode> if
+ the protocol family given in <parameter>af</parameter> is
+ not
+ supported.
+ </para>
+
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>RFC1884</refentrytitle>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>inet_ntop</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_inetntop.html b/lib/lwres/man/lwres_inetntop.html
new file mode 100644
index 0000000..532d500
--- /dev/null
+++ b/lib/lwres/man/lwres_inetntop.html
@@ -0,0 +1,103 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_inetntop.html,v 1.6.18.17 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_inetntop</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_net_ntop &#8212; lightweight resolver IP address presentation</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/net.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0">
+<tr>
+<td><code class="funcdef">
+const char *
+<b class="fsfunc">lwres_net_ntop</b>(</code></td>
+<td>int  </td>
+<td>
+<var class="pdparam">af</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>const void * </td>
+<td>
+<var class="pdparam">src</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>char * </td>
+<td>
+<var class="pdparam">dst</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>size_t  </td>
+<td>
+<var class="pdparam">size</var><code>)</code>;</td>
+</tr>
+</table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543379"></a><h2>DESCRIPTION</h2>
+<p><code class="function">lwres_net_ntop()</code>
+ converts an IP address of protocol family
+ <em class="parameter"><code>af</code></em> &#8212; IPv4 or IPv6 &#8212; at
+ location <em class="parameter"><code>src</code></em> from network format to its
+ conventional representation as a string. For IPv4 addresses,
+ that string would be a dotted-decimal. An IPv6 address would be
+ represented in colon notation as described in RFC1884.
+ </p>
+<p>
+ The generated string is copied to <em class="parameter"><code>dst</code></em>
+ provided
+ <em class="parameter"><code>size</code></em> indicates it is long enough to
+ store the
+ ASCII representation of the address.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543411"></a><h2>RETURN VALUES</h2>
+<p>
+ If successful, the function returns <em class="parameter"><code>dst</code></em>:
+ a pointer to a string containing the presentation format of the
+ address. <code class="function">lwres_net_ntop()</code> returns
+ <span class="type">NULL</span> and sets the global variable
+ <code class="constant">errno</code> to <span class="errorcode">EAFNOSUPPORT</span> if
+ the protocol family given in <em class="parameter"><code>af</code></em> is
+ not
+ supported.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543444"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">RFC1884</span></span>,
+ <span class="citerefentry"><span class="refentrytitle">inet_ntop</span>(3)</span>,
+ <span class="citerefentry"><span class="refentrytitle">errno</span>(3)</span>.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_noop.3 b/lib/lwres/man/lwres_noop.3
new file mode 100644
index 0000000..7884109
--- /dev/null
+++ b/lib/lwres/man/lwres_noop.3
@@ -0,0 +1,183 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_noop.3,v 1.17.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_noop
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_NOOP" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_nooprequest_render, lwres_noopresponse_render, lwres_nooprequest_parse, lwres_noopresponse_parse, lwres_noopresponse_free, lwres_nooprequest_free \- lightweight resolver no\-op message handling
+.SH "SYNOPSIS"
+.nf
+#include <lwres/lwres.h>
+.fi
+.HP 40
+.BI "lwres_result_t lwres_nooprequest_render(lwres_context_t\ *" "ctx" ", lwres_nooprequest_t\ *" "req" ", lwres_lwpacket_t\ *" "pkt" ", lwres_buffer_t\ *" "b" ");"
+.HP 41
+.BI "lwres_result_t lwres_noopresponse_render(lwres_context_t\ *" "ctx" ", lwres_noopresponse_t\ *" "req" ", lwres_lwpacket_t\ *" "pkt" ", lwres_buffer_t\ *" "b" ");"
+.HP 39
+.BI "lwres_result_t lwres_nooprequest_parse(lwres_context_t\ *" "ctx" ", lwres_buffer_t\ *" "b" ", lwres_lwpacket_t\ *" "pkt" ", lwres_nooprequest_t\ **" "structp" ");"
+.HP 40
+.BI "lwres_result_t lwres_noopresponse_parse(lwres_context_t\ *" "ctx" ", lwres_buffer_t\ *" "b" ", lwres_lwpacket_t\ *" "pkt" ", lwres_noopresponse_t\ **" "structp" ");"
+.HP 29
+.BI "void lwres_noopresponse_free(lwres_context_t\ *" "ctx" ", lwres_noopresponse_t\ **" "structp" ");"
+.HP 28
+.BI "void lwres_nooprequest_free(lwres_context_t\ *" "ctx" ", lwres_nooprequest_t\ **" "structp" ");"
+.SH "DESCRIPTION"
+.PP
+These are low\-level routines for creating and parsing lightweight resolver no\-op request and response messages.
+.PP
+The no\-op message is analogous to a
+\fBping\fR
+packet: a packet is sent to the resolver daemon and is simply echoed back. The opcode is intended to allow a client to determine if the server is operational or not.
+.PP
+There are four main functions for the no\-op opcode. One render function converts a no\-op request structure \(em
+\fBlwres_nooprequest_t\fR
+\(em to the lighweight resolver's canonical format. It is complemented by a parse function that converts a packet in this canonical format to a no\-op request structure. Another render function converts the no\-op response structure \(em
+\fBlwres_noopresponse_t\fR
+to the canonical format. This is complemented by a parse function which converts a packet in canonical format to a no\-op response structure.
+.PP
+These structures are defined in
+\fIlwres/lwres.h\fR. They are shown below.
+.PP
+.RS 4
+.nf
+#define LWRES_OPCODE_NOOP 0x00000000U
+.fi
+.RE
+.sp
+.PP
+.RS 4
+.nf
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_nooprequest_t;
+.fi
+.RE
+.sp
+.PP
+.RS 4
+.nf
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_noopresponse_t;
+.fi
+.RE
+.sp
+.PP
+Although the structures have different types, they are identical. This is because the no\-op opcode simply echos whatever data was sent: the response is therefore identical to the request.
+.PP
+\fBlwres_nooprequest_render()\fR
+uses resolver context
+\fIctx\fR
+to convert no\-op request structure
+\fIreq\fR
+to canonical format. The packet header structure
+\fIpkt\fR
+is initialised and transferred to buffer
+\fIb\fR. The contents of
+\fI*req\fR
+are then appended to the buffer in canonical format.
+\fBlwres_noopresponse_render()\fR
+performs the same task, except it converts a no\-op response structure
+\fBlwres_noopresponse_t\fR
+to the lightweight resolver's canonical format.
+.PP
+\fBlwres_nooprequest_parse()\fR
+uses context
+\fIctx\fR
+to convert the contents of packet
+\fIpkt\fR
+to a
+\fBlwres_nooprequest_t\fR
+structure. Buffer
+\fIb\fR
+provides space to be used for storing this structure. When the function succeeds, the resulting
+\fBlwres_nooprequest_t\fR
+is made available through
+\fI*structp\fR.
+\fBlwres_noopresponse_parse()\fR
+offers the same semantics as
+\fBlwres_nooprequest_parse()\fR
+except it yields a
+\fBlwres_noopresponse_t\fR
+structure.
+.PP
+\fBlwres_noopresponse_free()\fR
+and
+\fBlwres_nooprequest_free()\fR
+release the memory in resolver context
+\fIctx\fR
+that was allocated to the
+\fBlwres_noopresponse_t\fR
+or
+\fBlwres_nooprequest_t\fR
+structures referenced via
+\fIstructp\fR.
+.SH "RETURN VALUES"
+.PP
+The no\-op opcode functions
+\fBlwres_nooprequest_render()\fR,
+\fBlwres_noopresponse_render()\fR
+\fBlwres_nooprequest_parse()\fR
+and
+\fBlwres_noopresponse_parse()\fR
+all return
+\fBLWRES_R_SUCCESS\fR
+on success. They return
+\fBLWRES_R_NOMEMORY\fR
+if memory allocation fails.
+\fBLWRES_R_UNEXPECTEDEND\fR
+is returned if the available space in the buffer
+\fIb\fR
+is too small to accommodate the packet header or the
+\fBlwres_nooprequest_t\fR
+and
+\fBlwres_noopresponse_t\fR
+structures.
+\fBlwres_nooprequest_parse()\fR
+and
+\fBlwres_noopresponse_parse()\fR
+will return
+\fBLWRES_R_UNEXPECTEDEND\fR
+if the buffer is not empty after decoding the received packet. These functions will return
+\fBLWRES_R_FAILURE\fR
+if
+\fBpktflags\fR
+in the packet header structure
+\fBlwres_lwpacket_t\fR
+indicate that the packet is not a response to an earlier query.
+.SH "SEE ALSO"
+.PP
+\fBlwres_packet\fR(3)
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_noop.docbook b/lib/lwres/man/lwres_noop.docbook
new file mode 100644
index 0000000..a2b0699
--- /dev/null
+++ b/lib/lwres/man/lwres_noop.docbook
@@ -0,0 +1,255 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_noop.docbook,v 1.5.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_noop</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_nooprequest_render</refname>
+ <refname>lwres_noopresponse_render</refname>
+ <refname>lwres_nooprequest_parse</refname>
+ <refname>lwres_noopresponse_parse</refname>
+ <refname>lwres_noopresponse_free</refname>
+ <refname>lwres_nooprequest_free</refname>
+ <refpurpose>lightweight resolver no-op message handling</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>
+#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_nooprequest_render</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_nooprequest_t *<parameter>req</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_noopresponse_render</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_noopresponse_t *<parameter>req</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_nooprequest_parse</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_nooprequest_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_noopresponse_parse</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ <paramdef>lwres_noopresponse_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_noopresponse_free</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_noopresponse_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+void
+<function>lwres_nooprequest_free</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_nooprequest_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+ <refsect1>
+ <title>DESCRIPTION</title>
+ <para>
+ These are low-level routines for creating and parsing
+ lightweight resolver no-op request and response messages.
+ </para>
+ <para>
+ The no-op message is analogous to a <command>ping</command>
+ packet:
+ a packet is sent to the resolver daemon and is simply echoed back.
+ The opcode is intended to allow a client to determine if the server is
+ operational or not.
+ </para>
+ <para>
+ There are four main functions for the no-op opcode.
+ One render function converts a no-op request structure &mdash;
+ <type>lwres_nooprequest_t</type> &mdash;
+ to the lighweight resolver's canonical format.
+ It is complemented by a parse function that converts a packet in this
+ canonical format to a no-op request structure.
+ Another render function converts the no-op response structure &mdash;
+ <type>lwres_noopresponse_t</type>
+ to the canonical format.
+ This is complemented by a parse function which converts a packet in
+ canonical format to a no-op response structure.
+ </para>
+ <para>
+ These structures are defined in
+ <filename>lwres/lwres.h</filename>.
+
+ They are shown below.
+ </para>
+ <para><programlisting>
+#define LWRES_OPCODE_NOOP 0x00000000U
+</programlisting>
+ </para>
+ <para><programlisting>
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_nooprequest_t;
+</programlisting>
+ </para>
+ <para><programlisting>
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_noopresponse_t;
+</programlisting>
+ </para>
+ <para>
+ Although the structures have different types, they are identical.
+ This is because the no-op opcode simply echos whatever data was sent:
+ the response is therefore identical to the request.
+ </para>
+
+ <para><function>lwres_nooprequest_render()</function>
+ uses resolver context <parameter>ctx</parameter> to convert
+ no-op request structure <parameter>req</parameter> to canonical
+ format. The packet header structure <parameter>pkt</parameter>
+ is initialised and transferred to buffer
+ <parameter>b</parameter>. The contents of
+ <parameter>*req</parameter> are then appended to the buffer in
+ canonical format.
+ <function>lwres_noopresponse_render()</function> performs the
+ same task, except it converts a no-op response structure
+ <type>lwres_noopresponse_t</type> to the lightweight resolver's
+ canonical format.
+ </para>
+
+ <para><function>lwres_nooprequest_parse()</function>
+ uses context <parameter>ctx</parameter> to convert the contents
+ of packet <parameter>pkt</parameter> to a
+ <type>lwres_nooprequest_t</type> structure. Buffer
+ <parameter>b</parameter> provides space to be used for storing
+ this structure. When the function succeeds, the resulting
+ <type>lwres_nooprequest_t</type> is made available through
+ <parameter>*structp</parameter>.
+ <function>lwres_noopresponse_parse()</function> offers the same
+ semantics as <function>lwres_nooprequest_parse()</function>
+ except it yields a <type>lwres_noopresponse_t</type> structure.
+ </para>
+
+ <para><function>lwres_noopresponse_free()</function>
+ and <function>lwres_nooprequest_free()</function> release the
+ memory in resolver context <parameter>ctx</parameter> that was
+ allocated to the <type>lwres_noopresponse_t</type> or
+ <type>lwres_nooprequest_t</type> structures referenced via
+ <parameter>structp</parameter>.
+ </para>
+
+ </refsect1>
+ <refsect1>
+ <title>RETURN VALUES</title>
+ <para>
+ The no-op opcode functions
+ <function>lwres_nooprequest_render()</function>,
+
+ <function>lwres_noopresponse_render()</function>
+ <function>lwres_nooprequest_parse()</function>
+ and
+ <function>lwres_noopresponse_parse()</function>
+ all return
+ <errorcode>LWRES_R_SUCCESS</errorcode>
+ on success.
+ They return
+ <errorcode>LWRES_R_NOMEMORY</errorcode>
+ if memory allocation fails.
+ <errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+ is returned if the available space in the buffer
+ <parameter>b</parameter>
+ is too small to accommodate the packet header or the
+ <type>lwres_nooprequest_t</type>
+ and
+ <type>lwres_noopresponse_t</type>
+ structures.
+ <function>lwres_nooprequest_parse()</function>
+ and
+ <function>lwres_noopresponse_parse()</function>
+ will return
+ <errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+ if the buffer is not empty after decoding the received packet.
+ These functions will return
+ <errorcode>LWRES_R_FAILURE</errorcode>
+ if
+ <constant>pktflags</constant>
+ in the packet header structure
+ <type>lwres_lwpacket_t</type>
+ indicate that the packet is not a response to an earlier query.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>lwres_packet</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_noop.html b/lib/lwres/man/lwres_noop.html
new file mode 100644
index 0000000..4705ecb
--- /dev/null
+++ b/lib/lwres/man/lwres_noop.html
@@ -0,0 +1,317 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_noop.html,v 1.8.18.17 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_noop</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_nooprequest_render, lwres_noopresponse_render, lwres_nooprequest_parse, lwres_noopresponse_parse, lwres_noopresponse_free, lwres_nooprequest_free &#8212; lightweight resolver no-op message handling</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">
+#include &lt;lwres/lwres.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_nooprequest_render</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_nooprequest_t * </td>
+<td>
+<var class="pdparam">req</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_noopresponse_render</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_noopresponse_t * </td>
+<td>
+<var class="pdparam">req</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_nooprequest_parse</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_nooprequest_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_noopresponse_parse</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_noopresponse_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_noopresponse_free</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_noopresponse_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0">
+<tr>
+<td><code class="funcdef">
+void
+<b class="fsfunc">lwres_nooprequest_free</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_nooprequest_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543522"></a><h2>DESCRIPTION</h2>
+<p>
+ These are low-level routines for creating and parsing
+ lightweight resolver no-op request and response messages.
+ </p>
+<p>
+ The no-op message is analogous to a <span><strong class="command">ping</strong></span>
+ packet:
+ a packet is sent to the resolver daemon and is simply echoed back.
+ The opcode is intended to allow a client to determine if the server is
+ operational or not.
+ </p>
+<p>
+ There are four main functions for the no-op opcode.
+ One render function converts a no-op request structure &#8212;
+ <span class="type">lwres_nooprequest_t</span> &#8212;
+ to the lighweight resolver's canonical format.
+ It is complemented by a parse function that converts a packet in this
+ canonical format to a no-op request structure.
+ Another render function converts the no-op response structure &#8212;
+ <span class="type">lwres_noopresponse_t</span>
+ to the canonical format.
+ This is complemented by a parse function which converts a packet in
+ canonical format to a no-op response structure.
+ </p>
+<p>
+ These structures are defined in
+ <code class="filename">lwres/lwres.h</code>.
+
+ They are shown below.
+ </p>
+<pre class="programlisting">
+#define LWRES_OPCODE_NOOP 0x00000000U
+</pre>
+<p>
+ </p>
+<pre class="programlisting">
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_nooprequest_t;
+</pre>
+<p>
+ </p>
+<pre class="programlisting">
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_noopresponse_t;
+</pre>
+<p>
+ </p>
+<p>
+ Although the structures have different types, they are identical.
+ This is because the no-op opcode simply echos whatever data was sent:
+ the response is therefore identical to the request.
+ </p>
+<p><code class="function">lwres_nooprequest_render()</code>
+ uses resolver context <em class="parameter"><code>ctx</code></em> to convert
+ no-op request structure <em class="parameter"><code>req</code></em> to canonical
+ format. The packet header structure <em class="parameter"><code>pkt</code></em>
+ is initialised and transferred to buffer
+ <em class="parameter"><code>b</code></em>. The contents of
+ <em class="parameter"><code>*req</code></em> are then appended to the buffer in
+ canonical format.
+ <code class="function">lwres_noopresponse_render()</code> performs the
+ same task, except it converts a no-op response structure
+ <span class="type">lwres_noopresponse_t</span> to the lightweight resolver's
+ canonical format.
+ </p>
+<p><code class="function">lwres_nooprequest_parse()</code>
+ uses context <em class="parameter"><code>ctx</code></em> to convert the contents
+ of packet <em class="parameter"><code>pkt</code></em> to a
+ <span class="type">lwres_nooprequest_t</span> structure. Buffer
+ <em class="parameter"><code>b</code></em> provides space to be used for storing
+ this structure. When the function succeeds, the resulting
+ <span class="type">lwres_nooprequest_t</span> is made available through
+ <em class="parameter"><code>*structp</code></em>.
+ <code class="function">lwres_noopresponse_parse()</code> offers the same
+ semantics as <code class="function">lwres_nooprequest_parse()</code>
+ except it yields a <span class="type">lwres_noopresponse_t</span> structure.
+ </p>
+<p><code class="function">lwres_noopresponse_free()</code>
+ and <code class="function">lwres_nooprequest_free()</code> release the
+ memory in resolver context <em class="parameter"><code>ctx</code></em> that was
+ allocated to the <span class="type">lwres_noopresponse_t</span> or
+ <span class="type">lwres_nooprequest_t</span> structures referenced via
+ <em class="parameter"><code>structp</code></em>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543672"></a><h2>RETURN VALUES</h2>
+<p>
+ The no-op opcode functions
+ <code class="function">lwres_nooprequest_render()</code>,
+
+ <code class="function">lwres_noopresponse_render()</code>
+ <code class="function">lwres_nooprequest_parse()</code>
+ and
+ <code class="function">lwres_noopresponse_parse()</code>
+ all return
+ <span class="errorcode">LWRES_R_SUCCESS</span>
+ on success.
+ They return
+ <span class="errorcode">LWRES_R_NOMEMORY</span>
+ if memory allocation fails.
+ <span class="errorcode">LWRES_R_UNEXPECTEDEND</span>
+ is returned if the available space in the buffer
+ <em class="parameter"><code>b</code></em>
+ is too small to accommodate the packet header or the
+ <span class="type">lwres_nooprequest_t</span>
+ and
+ <span class="type">lwres_noopresponse_t</span>
+ structures.
+ <code class="function">lwres_nooprequest_parse()</code>
+ and
+ <code class="function">lwres_noopresponse_parse()</code>
+ will return
+ <span class="errorcode">LWRES_R_UNEXPECTEDEND</span>
+ if the buffer is not empty after decoding the received packet.
+ These functions will return
+ <span class="errorcode">LWRES_R_FAILURE</span>
+ if
+ <code class="constant">pktflags</code>
+ in the packet header structure
+ <span class="type">lwres_lwpacket_t</span>
+ indicate that the packet is not a response to an earlier query.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543738"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">lwres_packet</span>(3)</span>
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_packet.3 b/lib/lwres/man/lwres_packet.3
new file mode 100644
index 0000000..14109085
--- /dev/null
+++ b/lib/lwres/man/lwres_packet.3
@@ -0,0 +1,170 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_packet.3,v 1.18.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_packet
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_PACKET" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_lwpacket_renderheader, lwres_lwpacket_parseheader \- lightweight resolver packet handling functions
+.SH "SYNOPSIS"
+.nf
+#include <lwres/lwpacket.h>
+.fi
+.HP 43
+.BI "lwres_result_t lwres_lwpacket_renderheader(lwres_buffer_t\ *" "b" ", lwres_lwpacket_t\ *" "pkt" ");"
+.HP 42
+.BI "lwres_result_t lwres_lwpacket_parseheader(lwres_buffer_t\ *" "b" ", lwres_lwpacket_t\ *" "pkt" ");"
+.SH "DESCRIPTION"
+.PP
+These functions rely on a
+\fBstruct lwres_lwpacket\fR
+which is defined in
+\fIlwres/lwpacket.h\fR.
+.PP
+.RS 4
+.nf
+typedef struct lwres_lwpacket lwres_lwpacket_t;
+.fi
+.RE
+.sp
+.PP
+.RS 4
+.nf
+struct lwres_lwpacket {
+ lwres_uint32_t length;
+ lwres_uint16_t version;
+ lwres_uint16_t pktflags;
+ lwres_uint32_t serial;
+ lwres_uint32_t opcode;
+ lwres_uint32_t result;
+ lwres_uint32_t recvlength;
+ lwres_uint16_t authtype;
+ lwres_uint16_t authlength;
+};
+.fi
+.RE
+.sp
+.PP
+The elements of this structure are:
+.PP
+\fBlength\fR
+.RS 4
+the overall packet length, including the entire packet header. This field is filled in by the lwres_gabn_*() and lwres_gnba_*() calls.
+.RE
+.PP
+\fBversion\fR
+.RS 4
+the header format. There is currently only one format,
+\fBLWRES_LWPACKETVERSION_0\fR. This field is filled in by the lwres_gabn_*() and lwres_gnba_*() calls.
+.RE
+.PP
+\fBpktflags\fR
+.RS 4
+library\-defined flags for this packet: for instance whether the packet is a request or a reply. Flag values can be set, but not defined by the caller. This field is filled in by the application wit the exception of the LWRES_LWPACKETFLAG_RESPONSE bit, which is set by the library in the lwres_gabn_*() and lwres_gnba_*() calls.
+.RE
+.PP
+\fBserial\fR
+.RS 4
+is set by the requestor and is returned in all replies. If two or more packets from the same source have the same serial number and are from the same source, they are assumed to be duplicates and the latter ones may be dropped. This field must be set by the application.
+.RE
+.PP
+\fBopcode\fR
+.RS 4
+indicates the operation. Opcodes between 0x00000000 and 0x03ffffff are reserved for use by the lightweight resolver library. Opcodes between 0x04000000 and 0xffffffff are application defined. This field is filled in by the lwres_gabn_*() and lwres_gnba_*() calls.
+.RE
+.PP
+\fBresult\fR
+.RS 4
+is only valid for replies. Results between 0x04000000 and 0xffffffff are application defined. Results between 0x00000000 and 0x03ffffff are reserved for library use. This field is filled in by the lwres_gabn_*() and lwres_gnba_*() calls.
+.RE
+.PP
+\fBrecvlength\fR
+.RS 4
+is the maximum buffer size that the receiver can handle on requests and the size of the buffer needed to satisfy a request when the buffer is too large for replies. This field is supplied by the application.
+.RE
+.PP
+\fBauthtype\fR
+.RS 4
+defines the packet level authentication that is used. Authorisation types between 0x1000 and 0xffff are application defined and types between 0x0000 and 0x0fff are reserved for library use. Currently these are not used and must be zero.
+.RE
+.PP
+\fBauthlen\fR
+.RS 4
+gives the length of the authentication data. Since packet authentication is currently not used, this must be zero.
+.RE
+.PP
+The following opcodes are currently defined:
+.PP
+\fBNOOP\fR
+.RS 4
+Success is always returned and the packet contents are echoed. The lwres_noop_*() functions should be used for this type.
+.RE
+.PP
+\fBGETADDRSBYNAME\fR
+.RS 4
+returns all known addresses for a given name. The lwres_gabn_*() functions should be used for this type.
+.RE
+.PP
+\fBGETNAMEBYADDR\fR
+.RS 4
+return the hostname for the given address. The lwres_gnba_*() functions should be used for this type.
+.RE
+.PP
+\fBlwres_lwpacket_renderheader()\fR
+transfers the contents of lightweight resolver packet structure
+\fBlwres_lwpacket_t\fR
+\fI*pkt\fR
+in network byte order to the lightweight resolver buffer,
+\fI*b\fR.
+.PP
+\fBlwres_lwpacket_parseheader()\fR
+performs the converse operation. It transfers data in network byte order from buffer
+\fI*b\fR
+to resolver packet
+\fI*pkt\fR. The contents of the buffer
+\fIb\fR
+should correspond to a
+\fBlwres_lwpacket_t\fR.
+.SH "RETURN VALUES"
+.PP
+Successful calls to
+\fBlwres_lwpacket_renderheader()\fR
+and
+\fBlwres_lwpacket_parseheader()\fR
+return
+\fBLWRES_R_SUCCESS\fR. If there is insufficient space to copy data between the buffer
+\fI*b\fR
+and lightweight resolver packet
+\fI*pkt\fR
+both functions return
+\fBLWRES_R_UNEXPECTEDEND\fR.
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_packet.docbook b/lib/lwres/man/lwres_packet.docbook
new file mode 100644
index 0000000..d588f21
--- /dev/null
+++ b/lib/lwres/man/lwres_packet.docbook
@@ -0,0 +1,291 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_packet.docbook,v 1.7.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_packet</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_lwpacket_renderheader</refname>
+ <refname>lwres_lwpacket_parseheader</refname>
+ <refpurpose>lightweight resolver packet handling functions</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwpacket.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_lwpacket_renderheader</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_lwpacket_parseheader</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+ <refsect1>
+ <title>DESCRIPTION</title>
+ <para>
+ These functions rely on a
+ <type>struct lwres_lwpacket</type>
+ which is defined in
+ <filename>lwres/lwpacket.h</filename>.
+ </para>
+
+ <para><programlisting>
+typedef struct lwres_lwpacket lwres_lwpacket_t;
+ </programlisting>
+ </para>
+ <para><programlisting>
+struct lwres_lwpacket {
+ lwres_uint32_t length;
+ lwres_uint16_t version;
+ lwres_uint16_t pktflags;
+ lwres_uint32_t serial;
+ lwres_uint32_t opcode;
+ lwres_uint32_t result;
+ lwres_uint32_t recvlength;
+ lwres_uint16_t authtype;
+ lwres_uint16_t authlength;
+};
+</programlisting>
+ </para>
+
+ <para>
+ The elements of this structure are:
+ <variablelist>
+ <varlistentry>
+ <term><constant>length</constant></term>
+ <listitem>
+ <para>
+ the overall packet length, including the entire packet header.
+ This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+ calls.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>version</constant></term>
+ <listitem>
+ <para>
+ the header format. There is currently only one format,
+ <type>LWRES_LWPACKETVERSION_0</type>.
+
+ This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+ calls.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>pktflags</constant></term>
+ <listitem>
+ <para>
+ library-defined flags for this packet: for instance whether the
+ packet
+ is a request or a reply. Flag values can be set, but not defined
+ by
+ the caller.
+ This field is filled in by the application wit the exception of
+ the
+ LWRES_LWPACKETFLAG_RESPONSE bit, which is set by the library in
+ the
+ lwres_gabn_*() and lwres_gnba_*() calls.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>serial</constant></term>
+ <listitem>
+ <para>
+ is set by the requestor and is returned in all replies. If two
+ or more
+ packets from the same source have the same serial number and are
+ from
+ the same source, they are assumed to be duplicates and the
+ latter ones
+ may be dropped.
+ This field must be set by the application.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>opcode</constant></term>
+ <listitem>
+ <para>
+ indicates the operation.
+ Opcodes between 0x00000000 and 0x03ffffff are
+ reserved for use by the lightweight resolver library. Opcodes
+ between
+ 0x04000000 and 0xffffffff are application defined.
+ This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+ calls.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>result</constant></term>
+ <listitem>
+ <para>
+ is only valid for replies.
+ Results between 0x04000000 and 0xffffffff are application
+ defined.
+ Results between 0x00000000 and 0x03ffffff are reserved for
+ library use.
+ This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+ calls.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>recvlength</constant></term>
+ <listitem>
+ <para>
+ is the maximum buffer size that the receiver can handle on
+ requests
+ and the size of the buffer needed to satisfy a request when the
+ buffer
+ is too large for replies.
+ This field is supplied by the application.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>authtype</constant></term>
+ <listitem>
+ <para>
+ defines the packet level authentication that is used.
+ Authorisation types between 0x1000 and 0xffff are application
+ defined
+ and types between 0x0000 and 0x0fff are reserved for library
+ use.
+ Currently these are not used and must be zero.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>authlen</constant></term>
+ <listitem>
+ <para>
+ gives the length of the authentication data.
+ Since packet authentication is currently not used, this must be
+ zero.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para>
+ The following opcodes are currently defined:
+ <variablelist>
+ <varlistentry>
+ <term><constant>NOOP</constant></term>
+ <listitem>
+ <para>
+ Success is always returned and the packet contents are echoed.
+ The lwres_noop_*() functions should be used for this type.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>GETADDRSBYNAME</constant></term>
+ <listitem>
+ <para>
+ returns all known addresses for a given name.
+ The lwres_gabn_*() functions should be used for this type.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><constant>GETNAMEBYADDR</constant></term>
+ <listitem>
+ <para>
+ return the hostname for the given address.
+ The lwres_gnba_*() functions should be used for this type.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para><function>lwres_lwpacket_renderheader()</function>
+ transfers the contents of lightweight resolver packet structure
+ <type>lwres_lwpacket_t</type> <parameter>*pkt</parameter> in
+ network byte order to the lightweight resolver buffer,
+ <parameter>*b</parameter>.
+ </para>
+
+ <para><function>lwres_lwpacket_parseheader()</function>
+ performs the converse operation. It transfers data in network
+ byte order from buffer <parameter>*b</parameter> to resolver
+ packet <parameter>*pkt</parameter>. The contents of the buffer
+ <parameter>b</parameter> should correspond to a
+ <type>lwres_lwpacket_t</type>.
+ </para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>RETURN VALUES</title>
+ <para>
+ Successful calls to
+ <function>lwres_lwpacket_renderheader()</function> and
+ <function>lwres_lwpacket_parseheader()</function> return
+ <errorcode>LWRES_R_SUCCESS</errorcode>. If there is insufficient
+ space to copy data between the buffer <parameter>*b</parameter> and
+ lightweight resolver packet <parameter>*pkt</parameter> both
+ functions
+ return <errorcode>LWRES_R_UNEXPECTEDEND</errorcode>.
+ </para>
+
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_packet.html b/lib/lwres/man/lwres_packet.html
new file mode 100644
index 0000000..eeb7ebd
--- /dev/null
+++ b/lib/lwres/man/lwres_packet.html
@@ -0,0 +1,235 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_packet.html,v 1.9.18.17 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_packet</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_lwpacket_renderheader, lwres_lwpacket_parseheader &#8212; lightweight resolver packet handling functions</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/lwpacket.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_lwpacket_renderheader</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_lwpacket_parseheader</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_lwpacket_t * </td>
+<td>
+<var class="pdparam">pkt</var><code>)</code>;</td>
+</tr>
+</table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543389"></a><h2>DESCRIPTION</h2>
+<p>
+ These functions rely on a
+ <span class="type">struct lwres_lwpacket</span>
+ which is defined in
+ <code class="filename">lwres/lwpacket.h</code>.
+ </p>
+<pre class="programlisting">
+typedef struct lwres_lwpacket lwres_lwpacket_t;
+ </pre>
+<p>
+ </p>
+<pre class="programlisting">
+struct lwres_lwpacket {
+ lwres_uint32_t length;
+ lwres_uint16_t version;
+ lwres_uint16_t pktflags;
+ lwres_uint32_t serial;
+ lwres_uint32_t opcode;
+ lwres_uint32_t result;
+ lwres_uint32_t recvlength;
+ lwres_uint16_t authtype;
+ lwres_uint16_t authlength;
+};
+</pre>
+<p>
+ </p>
+<p>
+ The elements of this structure are:
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><code class="constant">length</code></span></dt>
+<dd><p>
+ the overall packet length, including the entire packet header.
+ This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+ calls.
+ </p></dd>
+<dt><span class="term"><code class="constant">version</code></span></dt>
+<dd><p>
+ the header format. There is currently only one format,
+ <span class="type">LWRES_LWPACKETVERSION_0</span>.
+
+ This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+ calls.
+ </p></dd>
+<dt><span class="term"><code class="constant">pktflags</code></span></dt>
+<dd><p>
+ library-defined flags for this packet: for instance whether the
+ packet
+ is a request or a reply. Flag values can be set, but not defined
+ by
+ the caller.
+ This field is filled in by the application wit the exception of
+ the
+ LWRES_LWPACKETFLAG_RESPONSE bit, which is set by the library in
+ the
+ lwres_gabn_*() and lwres_gnba_*() calls.
+ </p></dd>
+<dt><span class="term"><code class="constant">serial</code></span></dt>
+<dd><p>
+ is set by the requestor and is returned in all replies. If two
+ or more
+ packets from the same source have the same serial number and are
+ from
+ the same source, they are assumed to be duplicates and the
+ latter ones
+ may be dropped.
+ This field must be set by the application.
+ </p></dd>
+<dt><span class="term"><code class="constant">opcode</code></span></dt>
+<dd><p>
+ indicates the operation.
+ Opcodes between 0x00000000 and 0x03ffffff are
+ reserved for use by the lightweight resolver library. Opcodes
+ between
+ 0x04000000 and 0xffffffff are application defined.
+ This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+ calls.
+ </p></dd>
+<dt><span class="term"><code class="constant">result</code></span></dt>
+<dd><p>
+ is only valid for replies.
+ Results between 0x04000000 and 0xffffffff are application
+ defined.
+ Results between 0x00000000 and 0x03ffffff are reserved for
+ library use.
+ This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+ calls.
+ </p></dd>
+<dt><span class="term"><code class="constant">recvlength</code></span></dt>
+<dd><p>
+ is the maximum buffer size that the receiver can handle on
+ requests
+ and the size of the buffer needed to satisfy a request when the
+ buffer
+ is too large for replies.
+ This field is supplied by the application.
+ </p></dd>
+<dt><span class="term"><code class="constant">authtype</code></span></dt>
+<dd><p>
+ defines the packet level authentication that is used.
+ Authorisation types between 0x1000 and 0xffff are application
+ defined
+ and types between 0x0000 and 0x0fff are reserved for library
+ use.
+ Currently these are not used and must be zero.
+ </p></dd>
+<dt><span class="term"><code class="constant">authlen</code></span></dt>
+<dd><p>
+ gives the length of the authentication data.
+ Since packet authentication is currently not used, this must be
+ zero.
+ </p></dd>
+</dl></div>
+<p>
+ </p>
+<p>
+ The following opcodes are currently defined:
+ </p>
+<div class="variablelist"><dl>
+<dt><span class="term"><code class="constant">NOOP</code></span></dt>
+<dd><p>
+ Success is always returned and the packet contents are echoed.
+ The lwres_noop_*() functions should be used for this type.
+ </p></dd>
+<dt><span class="term"><code class="constant">GETADDRSBYNAME</code></span></dt>
+<dd><p>
+ returns all known addresses for a given name.
+ The lwres_gabn_*() functions should be used for this type.
+ </p></dd>
+<dt><span class="term"><code class="constant">GETNAMEBYADDR</code></span></dt>
+<dd><p>
+ return the hostname for the given address.
+ The lwres_gnba_*() functions should be used for this type.
+ </p></dd>
+</dl></div>
+<p>
+ </p>
+<p><code class="function">lwres_lwpacket_renderheader()</code>
+ transfers the contents of lightweight resolver packet structure
+ <span class="type">lwres_lwpacket_t</span> <em class="parameter"><code>*pkt</code></em> in
+ network byte order to the lightweight resolver buffer,
+ <em class="parameter"><code>*b</code></em>.
+ </p>
+<p><code class="function">lwres_lwpacket_parseheader()</code>
+ performs the converse operation. It transfers data in network
+ byte order from buffer <em class="parameter"><code>*b</code></em> to resolver
+ packet <em class="parameter"><code>*pkt</code></em>. The contents of the buffer
+ <em class="parameter"><code>b</code></em> should correspond to a
+ <span class="type">lwres_lwpacket_t</span>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543706"></a><h2>RETURN VALUES</h2>
+<p>
+ Successful calls to
+ <code class="function">lwres_lwpacket_renderheader()</code> and
+ <code class="function">lwres_lwpacket_parseheader()</code> return
+ <span class="errorcode">LWRES_R_SUCCESS</span>. If there is insufficient
+ space to copy data between the buffer <em class="parameter"><code>*b</code></em> and
+ lightweight resolver packet <em class="parameter"><code>*pkt</code></em> both
+ functions
+ return <span class="errorcode">LWRES_R_UNEXPECTEDEND</span>.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/man/lwres_resutil.3 b/lib/lwres/man/lwres_resutil.3
new file mode 100644
index 0000000..9aebc9f
--- /dev/null
+++ b/lib/lwres/man/lwres_resutil.3
@@ -0,0 +1,170 @@
+.\" Copyright (C) 2004, 2005, 2007 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: lwres_resutil.3,v 1.17.18.11 2007/01/30 00:23:45 marka Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: lwres_resutil
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "LWRES_RESUTIL" "3" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+lwres_string_parse, lwres_addr_parse, lwres_getaddrsbyname, lwres_getnamebyaddr \- lightweight resolver utility functions
+.SH "SYNOPSIS"
+.nf
+#include <lwres/lwres.h>
+.fi
+.HP 34
+.BI "lwres_result_t lwres_string_parse(lwres_buffer_t\ *" "b" ", char\ **" "c" ", lwres_uint16_t\ *" "len" ");"
+.HP 32
+.BI "lwres_result_t lwres_addr_parse(lwres_buffer_t\ *" "b" ", lwres_addr_t\ *" "addr" ");"
+.HP 36
+.BI "lwres_result_t lwres_getaddrsbyname(lwres_context_t\ *" "ctx" ", const\ char\ *" "name" ", lwres_uint32_t\ " "addrtypes" ", lwres_gabnresponse_t\ **" "structp" ");"
+.HP 35
+.BI "lwres_result_t lwres_getnamebyaddr(lwres_context_t\ *" "ctx" ", lwres_uint32_t\ " "addrtype" ", lwres_uint16_t\ " "addrlen" ", const\ unsigned\ char\ *" "addr" ", lwres_gnbaresponse_t\ **" "structp" ");"
+.SH "DESCRIPTION"
+.PP
+\fBlwres_string_parse()\fR
+retrieves a DNS\-encoded string starting the current pointer of lightweight resolver buffer
+\fIb\fR: i.e.
+\fBb\->current\fR. When the function returns, the address of the first byte of the encoded string is returned via
+\fI*c\fR
+and the length of that string is given by
+\fI*len\fR. The buffer's current pointer is advanced to point at the character following the string length, the encoded string, and the trailing
+\fBNULL\fR
+character.
+.PP
+\fBlwres_addr_parse()\fR
+extracts an address from the buffer
+\fIb\fR. The buffer's current pointer
+\fBb\->current\fR
+is presumed to point at an encoded address: the address preceded by a 32\-bit protocol family identifier and a 16\-bit length field. The encoded address is copied to
+\fBaddr\->address\fR
+and
+\fBaddr\->length\fR
+indicates the size in bytes of the address that was copied.
+\fBb\->current\fR
+is advanced to point at the next byte of available data in the buffer following the encoded address.
+.PP
+\fBlwres_getaddrsbyname()\fR
+and
+\fBlwres_getnamebyaddr()\fR
+use the
+\fBlwres_gnbaresponse_t\fR
+structure defined below:
+.PP
+.RS 4
+.nf
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+.fi
+.RE
+.PP
+The contents of this structure are not manipulated directly but they are controlled through the
+\fBlwres_gabn\fR(3)
+functions.
+.PP
+The lightweight resolver uses
+\fBlwres_getaddrsbyname()\fR
+to perform foward lookups. Hostname
+\fIname\fR
+is looked up using the resolver context
+\fIctx\fR
+for memory allocation.
+\fIaddrtypes\fR
+is a bitmask indicating which type of addresses are to be looked up. Current values for this bitmask are
+\fBLWRES_ADDRTYPE_V4\fR
+for IPv4 addresses and
+\fBLWRES_ADDRTYPE_V6\fR
+for IPv6 addresses. Results of the lookup are returned in
+\fI*structp\fR.
+.PP
+\fBlwres_getnamebyaddr()\fR
+performs reverse lookups. Resolver context
+\fIctx\fR
+is used for memory allocation. The address type is indicated by
+\fIaddrtype\fR:
+\fBLWRES_ADDRTYPE_V4\fR
+or
+\fBLWRES_ADDRTYPE_V6\fR. The address to be looked up is given by
+\fIaddr\fR
+and its length is
+\fIaddrlen\fR
+bytes. The result of the function call is made available through
+\fI*structp\fR.
+.SH "RETURN VALUES"
+.PP
+Successful calls to
+\fBlwres_string_parse()\fR
+and
+\fBlwres_addr_parse()\fR
+return
+\fBLWRES_R_SUCCESS.\fR
+Both functions return
+\fBLWRES_R_FAILURE\fR
+if the buffer is corrupt or
+\fBLWRES_R_UNEXPECTEDEND\fR
+if the buffer has less space than expected for the components of the encoded string or address.
+.PP
+\fBlwres_getaddrsbyname()\fR
+returns
+\fBLWRES_R_SUCCESS\fR
+on success and it returns
+\fBLWRES_R_NOTFOUND\fR
+if the hostname
+\fIname\fR
+could not be found.
+.PP
+\fBLWRES_R_SUCCESS\fR
+is returned by a successful call to
+\fBlwres_getnamebyaddr()\fR.
+.PP
+Both
+\fBlwres_getaddrsbyname()\fR
+and
+\fBlwres_getnamebyaddr()\fR
+return
+\fBLWRES_R_NOMEMORY\fR
+when memory allocation requests fail and
+\fBLWRES_R_UNEXPECTEDEND\fR
+if the buffers used for sending queries and receiving replies are too small.
+.SH "SEE ALSO"
+.PP
+\fBlwres_buffer\fR(3),
+\fBlwres_gabn\fR(3).
+.SH "COPYRIGHT"
+Copyright \(co 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000, 2001 Internet Software Consortium.
+.br
diff --git a/lib/lwres/man/lwres_resutil.docbook b/lib/lwres/man/lwres_resutil.docbook
new file mode 100644
index 0000000..b568629
--- /dev/null
+++ b/lib/lwres/man/lwres_resutil.docbook
@@ -0,0 +1,238 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_resutil.docbook,v 1.6.18.6 2007/08/28 07:20:06 tbox Exp $ -->
+<refentry>
+
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>lwres_resutil</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2007</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refnamediv>
+ <refname>lwres_string_parse</refname>
+ <refname>lwres_addr_parse</refname>
+ <refname>lwres_getaddrsbyname</refname>
+ <refname>lwres_getnamebyaddr</refname>
+ <refpurpose>lightweight resolver utility functions</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_string_parse</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>char **<parameter>c</parameter></paramdef>
+ <paramdef>lwres_uint16_t *<parameter>len</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_addr_parse</function></funcdef>
+ <paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+ <paramdef>lwres_addr_t *<parameter>addr</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_getaddrsbyname</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>const char *<parameter>name</parameter></paramdef>
+ <paramdef>lwres_uint32_t <parameter>addrtypes</parameter></paramdef>
+ <paramdef>lwres_gabnresponse_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+<funcprototype>
+ <funcdef>
+lwres_result_t
+<function>lwres_getnamebyaddr</function></funcdef>
+ <paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+ <paramdef>lwres_uint32_t <parameter>addrtype</parameter></paramdef>
+ <paramdef>lwres_uint16_t <parameter>addrlen</parameter></paramdef>
+ <paramdef>const unsigned char *<parameter>addr</parameter></paramdef>
+ <paramdef>lwres_gnbaresponse_t **<parameter>structp</parameter></paramdef>
+ </funcprototype>
+</funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><function>lwres_string_parse()</function>
+ retrieves a DNS-encoded string starting the current pointer of
+ lightweight resolver buffer <parameter>b</parameter>: i.e.
+ <constant>b-&gt;current</constant>. When the function returns,
+ the address of the first byte of the encoded string is returned
+ via <parameter>*c</parameter> and the length of that string is
+ given by <parameter>*len</parameter>. The buffer's current
+ pointer is advanced to point at the character following the
+ string length, the encoded string, and the trailing
+ <type>NULL</type> character.
+ </para>
+
+ <para><function>lwres_addr_parse()</function>
+ extracts an address from the buffer <parameter>b</parameter>.
+ The buffer's current pointer <constant>b-&gt;current</constant>
+ is presumed to point at an encoded address: the address preceded
+ by a 32-bit protocol family identifier and a 16-bit length
+ field. The encoded address is copied to
+ <constant>addr-&gt;address</constant> and
+ <constant>addr-&gt;length</constant> indicates the size in bytes
+ of the address that was copied.
+ <constant>b-&gt;current</constant> is advanced to point at the
+ next byte of available data in the buffer following the encoded
+ address.
+ </para>
+
+ <para><function>lwres_getaddrsbyname()</function>
+ and <function>lwres_getnamebyaddr()</function> use the
+ <type>lwres_gnbaresponse_t</type> structure defined below:
+ </para>
+
+<para><programlisting>
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+</programlisting></para>
+
+ <para>
+ The contents of this structure are not manipulated directly but
+ they are controlled through the
+ <citerefentry>
+ <refentrytitle>lwres_gabn</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>
+ functions.
+ </para>
+
+ <para>
+ The lightweight resolver uses
+ <function>lwres_getaddrsbyname()</function> to perform
+ foward lookups.
+ Hostname <parameter>name</parameter> is looked up using the
+ resolver
+ context <parameter>ctx</parameter> for memory allocation.
+ <parameter>addrtypes</parameter> is a bitmask indicating
+ which type of
+ addresses are to be looked up. Current values for this bitmask are
+ <type>LWRES_ADDRTYPE_V4</type> for IPv4 addresses and
+ <type>LWRES_ADDRTYPE_V6</type> for IPv6 addresses. Results of the
+ lookup are returned in <parameter>*structp</parameter>.
+ </para>
+
+ <para><function>lwres_getnamebyaddr()</function>
+ performs reverse lookups. Resolver context
+ <parameter>ctx</parameter> is used for memory allocation. The
+ address type is indicated by <parameter>addrtype</parameter>:
+ <type>LWRES_ADDRTYPE_V4</type> or
+ <type>LWRES_ADDRTYPE_V6</type>. The address to be looked up is
+ given by <parameter>addr</parameter> and its length is
+ <parameter>addrlen</parameter> bytes. The result of the
+ function call is made available through
+ <parameter>*structp</parameter>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>RETURN VALUES</title>
+ <para>
+ Successful calls to
+ <function>lwres_string_parse()</function>
+ and
+ <function>lwres_addr_parse()</function>
+ return
+ <errorcode>LWRES_R_SUCCESS.</errorcode>
+ Both functions return
+ <errorcode>LWRES_R_FAILURE</errorcode>
+ if the buffer is corrupt or
+ <errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+ if the buffer has less space than expected for the components of the
+ encoded string or address.
+ </para>
+
+ <para><function>lwres_getaddrsbyname()</function>
+ returns <errorcode>LWRES_R_SUCCESS</errorcode> on success and it
+ returns <errorcode>LWRES_R_NOTFOUND</errorcode> if the hostname
+ <parameter>name</parameter> could not be found.
+ </para>
+ <para><errorcode>LWRES_R_SUCCESS</errorcode>
+ is returned by a successful call to
+ <function>lwres_getnamebyaddr()</function>.
+ </para>
+
+ <para>
+ Both
+ <function>lwres_getaddrsbyname()</function>
+ and
+ <function>lwres_getnamebyaddr()</function>
+ return
+ <errorcode>LWRES_R_NOMEMORY</errorcode>
+ when memory allocation requests fail and
+ <errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+ if the buffers used for sending queries and receiving replies are too
+ small.
+ </para>
+
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>lwres_buffer</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>,
+
+ <citerefentry>
+ <refentrytitle>lwres_gabn</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ </para>
+
+ </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/lib/lwres/man/lwres_resutil.html b/lib/lwres/man/lwres_resutil.html
new file mode 100644
index 0000000..dfa2e1c
--- /dev/null
+++ b/lib/lwres/man/lwres_resutil.html
@@ -0,0 +1,258 @@
+<!--
+ - Copyright (C) 2004, 2005, 2007 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: lwres_resutil.html,v 1.9.18.16 2007/01/30 00:23:45 marka Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>lwres_resutil</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="id2476275"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p>lwres_string_parse, lwres_addr_parse, lwres_getaddrsbyname, lwres_getnamebyaddr &#8212; lightweight resolver utility functions</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="funcsynopsis">
+<pre class="funcsynopsisinfo">#include &lt;lwres/lwres.h&gt;</pre>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_string_parse</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>char ** </td>
+<td>
+<var class="pdparam">c</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_uint16_t * </td>
+<td>
+<var class="pdparam">len</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_addr_parse</b>(</code></td>
+<td>lwres_buffer_t * </td>
+<td>
+<var class="pdparam">b</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_addr_t * </td>
+<td>
+<var class="pdparam">addr</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" style="padding-bottom: 1em">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_getaddrsbyname</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>const char * </td>
+<td>
+<var class="pdparam">name</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_uint32_t  </td>
+<td>
+<var class="pdparam">addrtypes</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gabnresponse_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+<table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0">
+<tr>
+<td><code class="funcdef">
+lwres_result_t
+<b class="fsfunc">lwres_getnamebyaddr</b>(</code></td>
+<td>lwres_context_t * </td>
+<td>
+<var class="pdparam">ctx</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_uint32_t  </td>
+<td>
+<var class="pdparam">addrtype</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_uint16_t  </td>
+<td>
+<var class="pdparam">addrlen</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>const unsigned char * </td>
+<td>
+<var class="pdparam">addr</var>, </td>
+</tr>
+<tr>
+<td> </td>
+<td>lwres_gnbaresponse_t ** </td>
+<td>
+<var class="pdparam">structp</var><code>)</code>;</td>
+</tr>
+</table>
+</div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543466"></a><h2>DESCRIPTION</h2>
+<p><code class="function">lwres_string_parse()</code>
+ retrieves a DNS-encoded string starting the current pointer of
+ lightweight resolver buffer <em class="parameter"><code>b</code></em>: i.e.
+ <code class="constant">b-&gt;current</code>. When the function returns,
+ the address of the first byte of the encoded string is returned
+ via <em class="parameter"><code>*c</code></em> and the length of that string is
+ given by <em class="parameter"><code>*len</code></em>. The buffer's current
+ pointer is advanced to point at the character following the
+ string length, the encoded string, and the trailing
+ <span class="type">NULL</span> character.
+ </p>
+<p><code class="function">lwres_addr_parse()</code>
+ extracts an address from the buffer <em class="parameter"><code>b</code></em>.
+ The buffer's current pointer <code class="constant">b-&gt;current</code>
+ is presumed to point at an encoded address: the address preceded
+ by a 32-bit protocol family identifier and a 16-bit length
+ field. The encoded address is copied to
+ <code class="constant">addr-&gt;address</code> and
+ <code class="constant">addr-&gt;length</code> indicates the size in bytes
+ of the address that was copied.
+ <code class="constant">b-&gt;current</code> is advanced to point at the
+ next byte of available data in the buffer following the encoded
+ address.
+ </p>
+<p><code class="function">lwres_getaddrsbyname()</code>
+ and <code class="function">lwres_getnamebyaddr()</code> use the
+ <span class="type">lwres_gnbaresponse_t</span> structure defined below:
+ </p>
+<pre class="programlisting">
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+</pre>
+<p>
+ The contents of this structure are not manipulated directly but
+ they are controlled through the
+ <span class="citerefentry"><span class="refentrytitle">lwres_gabn</span>(3)</span>
+ functions.
+ </p>
+<p>
+ The lightweight resolver uses
+ <code class="function">lwres_getaddrsbyname()</code> to perform
+ foward lookups.
+ Hostname <em class="parameter"><code>name</code></em> is looked up using the
+ resolver
+ context <em class="parameter"><code>ctx</code></em> for memory allocation.
+ <em class="parameter"><code>addrtypes</code></em> is a bitmask indicating
+ which type of
+ addresses are to be looked up. Current values for this bitmask are
+ <span class="type">LWRES_ADDRTYPE_V4</span> for IPv4 addresses and
+ <span class="type">LWRES_ADDRTYPE_V6</span> for IPv6 addresses. Results of the
+ lookup are returned in <em class="parameter"><code>*structp</code></em>.
+ </p>
+<p><code class="function">lwres_getnamebyaddr()</code>
+ performs reverse lookups. Resolver context
+ <em class="parameter"><code>ctx</code></em> is used for memory allocation. The
+ address type is indicated by <em class="parameter"><code>addrtype</code></em>:
+ <span class="type">LWRES_ADDRTYPE_V4</span> or
+ <span class="type">LWRES_ADDRTYPE_V6</span>. The address to be looked up is
+ given by <em class="parameter"><code>addr</code></em> and its length is
+ <em class="parameter"><code>addrlen</code></em> bytes. The result of the
+ function call is made available through
+ <em class="parameter"><code>*structp</code></em>.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543605"></a><h2>RETURN VALUES</h2>
+<p>
+ Successful calls to
+ <code class="function">lwres_string_parse()</code>
+ and
+ <code class="function">lwres_addr_parse()</code>
+ return
+ <span class="errorcode">LWRES_R_SUCCESS.</span>
+ Both functions return
+ <span class="errorcode">LWRES_R_FAILURE</span>
+ if the buffer is corrupt or
+ <span class="errorcode">LWRES_R_UNEXPECTEDEND</span>
+ if the buffer has less space than expected for the components of the
+ encoded string or address.
+ </p>
+<p><code class="function">lwres_getaddrsbyname()</code>
+ returns <span class="errorcode">LWRES_R_SUCCESS</span> on success and it
+ returns <span class="errorcode">LWRES_R_NOTFOUND</span> if the hostname
+ <em class="parameter"><code>name</code></em> could not be found.
+ </p>
+<p><span class="errorcode">LWRES_R_SUCCESS</span>
+ is returned by a successful call to
+ <code class="function">lwres_getnamebyaddr()</code>.
+ </p>
+<p>
+ Both
+ <code class="function">lwres_getaddrsbyname()</code>
+ and
+ <code class="function">lwres_getnamebyaddr()</code>
+ return
+ <span class="errorcode">LWRES_R_NOMEMORY</span>
+ when memory allocation requests fail and
+ <span class="errorcode">LWRES_R_UNEXPECTEDEND</span>
+ if the buffers used for sending queries and receiving replies are too
+ small.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543676"></a><h2>SEE ALSO</h2>
+<p><span class="citerefentry"><span class="refentrytitle">lwres_buffer</span>(3)</span>,
+
+ <span class="citerefentry"><span class="refentrytitle">lwres_gabn</span>(3)</span>.
+ </p>
+</div>
+</div></body>
+</html>
diff --git a/lib/lwres/print.c b/lib/lwres/print.c
new file mode 100644
index 0000000..49da037
--- /dev/null
+++ b/lib/lwres/print.c
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2004, 2005 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: print.c,v 1.2.2.7 2005/10/14 01:28:30 marka Exp $ */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdio.h> /* for sprintf */
+#include <string.h>
+
+#define LWRES__PRINT_SOURCE /* Used to get the lwres_print_* prototypes. */
+
+#include <lwres/stdlib.h>
+
+#include "assert_p.h"
+#include "print_p.h"
+
+#define LWRES_PRINT_QUADFORMAT LWRES_PLATFORM_QUADFORMAT
+
+int
+lwres__print_sprintf(char *str, const char *format, ...) {
+ va_list ap;
+
+ va_start(ap, format);
+ vsprintf(str, format, ap);
+ va_end(ap);
+ return (strlen(str));
+}
+
+/*
+ * Return length of string that would have been written if not truncated.
+ */
+
+int
+lwres__print_snprintf(char *str, size_t size, const char *format, ...) {
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return (ret);
+
+}
+
+/*
+ * Return length of string that would have been written if not truncated.
+ */
+
+int
+lwres__print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
+ int h;
+ int l;
+ int q;
+ int alt;
+ int zero;
+ int left;
+ int plus;
+ int space;
+ long long tmpi;
+ unsigned long long tmpui;
+ unsigned long width;
+ unsigned long precision;
+ unsigned int length;
+ char buf[1024];
+ char c;
+ void *v;
+ char *save = str;
+ const char *cp;
+ const char *head;
+ int count = 0;
+ int pad;
+ int zeropad;
+ int dot;
+ double dbl;
+#ifdef HAVE_LONG_DOUBLE
+ long double ldbl;
+#endif
+ char fmt[32];
+
+ INSIST(str != NULL);
+ INSIST(format != NULL);
+
+ while (*format != '\0') {
+ if (*format != '%') {
+ if (size > 1U) {
+ *str++ = *format;
+ size--;
+ }
+ count++;
+ format++;
+ continue;
+ }
+ format++;
+
+ /*
+ * Reset flags.
+ */
+ dot = space = plus = left = zero = alt = h = l = q = 0;
+ width = precision = 0;
+ head = "";
+ length = pad = zeropad = 0;
+
+ do {
+ if (*format == '#') {
+ alt = 1;
+ format++;
+ } else if (*format == '-') {
+ left = 1;
+ zero = 0;
+ format++;
+ } else if (*format == ' ') {
+ if (!plus)
+ space = 1;
+ format++;
+ } else if (*format == '+') {
+ plus = 1;
+ space = 0;
+ format++;
+ } else if (*format == '0') {
+ if (!left)
+ zero = 1;
+ format++;
+ } else
+ break;
+ } while (1);
+
+ /*
+ * Width.
+ */
+ if (*format == '*') {
+ width = va_arg(ap, int);
+ format++;
+ } else if (isdigit((unsigned char)*format)) {
+ char *e;
+ width = strtoul(format, &e, 10);
+ format = e;
+ }
+
+ /*
+ * Precision.
+ */
+ if (*format == '.') {
+ format++;
+ dot = 1;
+ if (*format == '*') {
+ precision = va_arg(ap, int);
+ format++;
+ } else if (isdigit((unsigned char)*format)) {
+ char *e;
+ precision = strtoul(format, &e, 10);
+ format = e;
+ }
+ }
+
+ switch (*format) {
+ case '\0':
+ continue;
+ case '%':
+ if (size > 1U) {
+ *str++ = *format;
+ size--;
+ }
+ count++;
+ break;
+ case 'q':
+ q = 1;
+ format++;
+ goto doint;
+ case 'h':
+ h = 1;
+ format++;
+ goto doint;
+ case 'l':
+ l = 1;
+ format++;
+ if (*format == 'l') {
+ q = 1;
+ format++;
+ }
+ goto doint;
+ case 'n':
+ case 'i':
+ case 'd':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ doint:
+ if (precision != 0U)
+ zero = 0;
+ switch (*format) {
+ case 'n':
+ if (h) {
+ short int *p;
+ p = va_arg(ap, short *);
+ REQUIRE(p != NULL);
+ *p = str - save;
+ } else if (l) {
+ long int *p;
+ p = va_arg(ap, long *);
+ REQUIRE(p != NULL);
+ *p = str - save;
+ } else {
+ int *p;
+ p = va_arg(ap, int *);
+ REQUIRE(p != NULL);
+ *p = str - save;
+ }
+ break;
+ case 'i':
+ case 'd':
+ if (q)
+ tmpi = va_arg(ap, long long int);
+ else if (l)
+ tmpi = va_arg(ap, long int);
+ else
+ tmpi = va_arg(ap, int);
+ if (tmpi < 0) {
+ head = "-";
+ tmpui = -tmpi;
+ } else {
+ if (plus)
+ head = "+";
+ else if (space)
+ head = " ";
+ else
+ head = "";
+ tmpui = tmpi;
+ }
+ sprintf(buf, "%" LWRES_PRINT_QUADFORMAT "u",
+ tmpui);
+ goto printint;
+ case 'o':
+ if (q)
+ tmpui = va_arg(ap,
+ unsigned long long int);
+ else if (l)
+ tmpui = va_arg(ap, long int);
+ else
+ tmpui = va_arg(ap, int);
+ sprintf(buf,
+ alt ? "%#" LWRES_PRINT_QUADFORMAT "o"
+ : "%" LWRES_PRINT_QUADFORMAT "o",
+ tmpui);
+ goto printint;
+ case 'u':
+ if (q)
+ tmpui = va_arg(ap,
+ unsigned long long int);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ sprintf(buf, "%" LWRES_PRINT_QUADFORMAT "u",
+ tmpui);
+ goto printint;
+ case 'x':
+ if (q)
+ tmpui = va_arg(ap,
+ unsigned long long int);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ if (alt) {
+ head = "0x";
+ if (precision > 2U)
+ precision -= 2;
+ }
+ sprintf(buf, "%" LWRES_PRINT_QUADFORMAT "x",
+ tmpui);
+ goto printint;
+ case 'X':
+ if (q)
+ tmpui = va_arg(ap,
+ unsigned long long int);
+ else if (l)
+ tmpui = va_arg(ap, unsigned long int);
+ else
+ tmpui = va_arg(ap, unsigned int);
+ if (alt) {
+ head = "0X";
+ if (precision > 2U)
+ precision -= 2;
+ }
+ sprintf(buf, "%" LWRES_PRINT_QUADFORMAT "X",
+ tmpui);
+ goto printint;
+ printint:
+ if (precision != 0U || width != 0U) {
+ length = strlen(buf);
+ if (length < precision)
+ zeropad = precision - length;
+ else if (length < width && zero)
+ zeropad = width - length;
+ if (width != 0U) {
+ pad = width - length -
+ zeropad - strlen(head);
+ if (pad < 0)
+ pad = 0;
+ }
+ }
+ count += strlen(head) + strlen(buf) + pad +
+ zeropad;
+ if (!left) {
+ while (pad > 0 && size > 1U) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ }
+ cp = head;
+ while (*cp != '\0' && size > 1U) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (zeropad > 0 && size > 1U) {
+ *str++ = '0';
+ size--;
+ zeropad--;
+ }
+ cp = buf;
+ while (*cp != '\0' && size > 1U) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1U) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case 's':
+ cp = va_arg(ap, char *);
+ REQUIRE(cp != NULL);
+
+ if (precision != 0U) {
+ /*
+ * cp need not be NULL terminated.
+ */
+ const char *tp;
+ unsigned long n;
+
+ n = precision;
+ tp = cp;
+ while (n != 0U && *tp != '\0')
+ n--, tp++;
+ length = precision - n;
+ } else {
+ length = strlen(cp);
+ }
+ if (width != 0U) {
+ pad = width - length;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += pad + length;
+ if (!left)
+ while (pad > 0 && size > 1U) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ if (precision != 0U)
+ while (precision > 0U && *cp != '\0' &&
+ size > 1U) {
+ *str++ = *cp++;
+ size--;
+ precision--;
+ }
+ else
+ while (*cp != '\0' && size > 1U) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1U) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ case 'c':
+ c = va_arg(ap, int);
+ if (width > 0U) {
+ count += width;
+ width--;
+ if (left) {
+ *str++ = c;
+ size--;
+ }
+ while (width-- > 0U && size > 1U) {
+ *str++ = ' ';
+ size--;
+ }
+ if (!left && size > 1U) {
+ *str++ = c;
+ size--;
+ }
+ } else {
+ count++;
+ if (size > 1U) {
+ *str++ = c;
+ size--;
+ }
+ }
+ break;
+ case 'p':
+ v = va_arg(ap, void *);
+ sprintf(buf, "%p", v);
+ length = strlen(buf);
+ if (precision > length)
+ zeropad = precision - length;
+ if (width > 0U) {
+ pad = width - length - zeropad;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += length + pad + zeropad;
+ if (!left)
+ while (pad > 0 && size > 1U) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ cp = buf;
+ if (zeropad > 0 && buf[0] == '0' &&
+ (buf[1] == 'x' || buf[1] == 'X')) {
+ if (size > 1U) {
+ *str++ = *cp++;
+ size--;
+ }
+ if (size > 1U) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (zeropad > 0 && size > 1U) {
+ *str++ = '0';
+ size--;
+ zeropad--;
+ }
+ }
+ while (*cp != '\0' && size > 1U) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1U) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ case 'D': /*deprecated*/
+ INSIST("use %ld instead of %D" == NULL);
+ case 'O': /*deprecated*/
+ INSIST("use %lo instead of %O" == NULL);
+ case 'U': /*deprecated*/
+ INSIST("use %lu instead of %U" == NULL);
+
+ case 'L':
+#ifdef HAVE_LONG_DOUBLE
+ l = 1;
+#else
+ INSIST("long doubles are not supported" == NULL);
+#endif
+ /*FALLTHROUGH*/
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (!dot)
+ precision = 6;
+ /*
+ * IEEE floating point.
+ * MIN 2.2250738585072014E-308
+ * MAX 1.7976931348623157E+308
+ * VAX floating point has a smaller range than IEEE.
+ *
+ * precisions > 324 don't make much sense.
+ * if we cap the precision at 512 we will not
+ * overflow buf.
+ */
+ if (precision > 512U)
+ precision = 512;
+ sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
+ plus ? "+" : space ? " " : "",
+ precision, l ? "L" : "", *format);
+ switch (*format) {
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+#ifdef HAVE_LONG_DOUBLE
+ if (l) {
+ ldbl = va_arg(ap, long double);
+ sprintf(buf, fmt, ldbl);
+ } else
+#endif
+ {
+ dbl = va_arg(ap, double);
+ sprintf(buf, fmt, dbl);
+ }
+ length = strlen(buf);
+ if (width > 0U) {
+ pad = width - length;
+ if (pad < 0)
+ pad = 0;
+ }
+ count += length + pad;
+ if (!left)
+ while (pad > 0 && size > 1U) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ cp = buf;
+ while (*cp != ' ' && size > 1U) {
+ *str++ = *cp++;
+ size--;
+ }
+ while (pad > 0 && size > 1U) {
+ *str++ = ' ';
+ size--;
+ pad--;
+ }
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ format++;
+ }
+ if (size > 0U)
+ *str = '\0';
+ return (count);
+}
diff --git a/lib/lwres/print_p.h b/lib/lwres/print_p.h
new file mode 100644
index 0000000..4c2d2bf
--- /dev/null
+++ b/lib/lwres/print_p.h
@@ -0,0 +1,86 @@
+/*
+ * 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: print_p.h,v 1.2.2.1 2004/08/28 06:21:13 marka Exp $ */
+
+#ifndef LWRES_PRINT_P_H
+#define LWRES_PRINT_P_H 1
+
+/***
+ *** Imports
+ ***/
+
+#include <lwres/lang.h>
+#include <lwres/platform.h>
+
+/*
+ * This block allows lib/lwres/print.c to be cleanly compiled even if
+ * the platform does not need it. The standard Makefile will still
+ * not compile print.c or archive print.o, so this is just to make test
+ * compilation ("make print.o") easier.
+ */
+#if !defined(LWRES_PLATFORM_NEEDVSNPRINTF) && defined(LWRES__PRINT_SOURCE)
+#define LWRES_PLATFORM_NEEDVSNPRINTF
+#endif
+
+#if !defined(LWRES_PLATFORM_NEEDSPRINTF) && defined(LWRES__PRINT_SOURCE)
+#define LWRES_PLATFORM_NEEDSPRINTF
+#endif
+
+/***
+ *** Macros.
+ ***/
+
+#ifdef __GNUC__
+#define LWRES_FORMAT_PRINTF(fmt, args) \
+ __attribute__((__format__(__printf__, fmt, args)))
+#else
+#define LWRES_FORMAT_PRINTF(fmt, args)
+#endif
+
+/***
+ *** Functions
+ ***/
+
+#ifdef LWRES_PLATFORM_NEEDVSNPRINTF
+#include <stdarg.h>
+#include <stddef.h>
+#endif
+
+LWRES_LANG_BEGINDECLS
+
+#ifdef LWRES_PLATFORM_NEEDVSNPRINTF
+int
+lwres__print_vsnprintf(char *str, size_t size, const char *format, va_list ap)
+ LWRES_FORMAT_PRINTF(3, 0);
+#define vsnprintf lwres__print_vsnprintf
+
+int
+lwres__print_snprintf(char *str, size_t size, const char *format, ...)
+ LWRES_FORMAT_PRINTF(3, 4);
+#define snprintf lwres__print_snprintf
+#endif /* LWRES_PLATFORM_NEEDVSNPRINTF */
+
+#ifdef LWRES_PLATFORM_NEEDSPRINTF
+int
+lwres__print_sprintf(char *str, const char *format, ...) LWRES_FORMAT_PRINTF(2, 3);
+#define sprintf lwres__print_sprintf
+#endif
+
+LWRES_LANG_ENDDECLS
+
+#endif /* LWRES_PRINT_P_H */
diff --git a/lib/lwres/strtoul.c b/lib/lwres/strtoul.c
new file mode 100644
index 0000000..3fc8971
--- /dev/null
+++ b/lib/lwres/strtoul.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 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.
+ */
+
+/*
+ * 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.
+ */
+
+/*! \file */
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+/* $Id: strtoul.c,v 1.2.2.1 2005/06/08 02:07:59 marka Exp $ */
+
+#include <config.h>
+
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <lwres/stdlib.h>
+
+#define DE_CONST(konst, var) \
+ do { \
+ union { const void *k; void *v; } _u; \
+ _u.k = konst; \
+ var = _u.v; \
+ } while (0)
+
+/*!
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+lwres_strtoul(const char *nptr, char **endptr, int base) {
+ const char *s = nptr;
+ unsigned long acc;
+ unsigned char c;
+ unsigned long cutoff;
+ int neg = 0, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ do {
+ c = *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 = (unsigned long)ULONG_MAX / (unsigned long)base;
+ cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (!isascii(c))
+ break;
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ DE_CONST(any ? s - 1 : nptr, *endptr);
+ return (acc);
+}
diff --git a/lib/lwres/unix/Makefile.in b/lib/lwres/unix/Makefile.in
new file mode 100644
index 0000000..577e3d3
--- /dev/null
+++ b/lib/lwres/unix/Makefile.in
@@ -0,0 +1,25 @@
+# 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: Makefile.in,v 1.2 2004/03/05 05:12:59 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = include
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/lwres/unix/include/Makefile.in b/lib/lwres/unix/include/Makefile.in
new file mode 100644
index 0000000..8ca7489
--- /dev/null
+++ b/lib/lwres/unix/include/Makefile.in
@@ -0,0 +1,25 @@
+# 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: Makefile.in,v 1.2 2004/03/05 05:13:03 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = lwres
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/lwres/unix/include/lwres/Makefile.in b/lib/lwres/unix/include/lwres/Makefile.in
new file mode 100644
index 0000000..7e0b594
--- /dev/null
+++ b/lib/lwres/unix/include/lwres/Makefile.in
@@ -0,0 +1,34 @@
+# 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: Makefile.in,v 1.2 2004/03/05 05:13:06 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+HEADERS = net.h
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/lwres
+
+install:: installdirs
+ for i in ${HEADERS}; do \
+ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/lwres ; \
+ done
diff --git a/lib/lwres/unix/include/lwres/net.h b/lib/lwres/unix/include/lwres/net.h
new file mode 100644
index 0000000..8fb14ee
--- /dev/null
+++ b/lib/lwres/unix/include/lwres/net.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2004, 2005 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: net.h,v 1.5.18.2 2005/04/29 00:17:23 marka Exp $ */
+
+#ifndef LWRES_NET_H
+#define LWRES_NET_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file net.h
+ * This module is responsible for defining the following basic networking
+ * types:
+ *
+ *\li struct in_addr
+ *\li struct in6_addr
+ *\li struct sockaddr
+ *\li struct sockaddr_in
+ *\li struct sockaddr_in6
+ *
+ * It ensures that the AF_ and PF_ macros are defined.
+ *
+ * It declares ntoh[sl]() and hton[sl]().
+ *
+ * It declares lwres_net_aton(), lwres_net_ntop(), and lwres_net_pton().
+ *
+ * It ensures that #INADDR_LOOPBACK, #INADDR_ANY and #IN6ADDR_ANY_INIT
+ * are defined.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <lwres/platform.h> /* Required for LWRES_PLATFORM_*. */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h> /* Contractual promise. */
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/un.h>
+
+#include <netinet/in.h> /* Contractual promise. */
+#include <arpa/inet.h> /* Contractual promise. */
+#ifdef LWRES_PLATFORM_NEEDNETINETIN6H
+#include <netinet/in6.h> /* Required on UnixWare. */
+#endif
+#ifdef LWRES_PLATFORM_NEEDNETINET6IN6H
+#include <netinet6/in6.h> /* Required on BSD/OS for in6_pktinfo. */
+#endif
+#include <net/if.h>
+
+#include <lwres/lang.h>
+
+#ifndef LWRES_PLATFORM_HAVEIPV6
+#include <lwres/ipv6.h> /* Contractual promise. */
+#endif
+
+#ifdef LWRES_PLATFORM_HAVEINADDR6
+#define in6_addr in_addr6 /* Required for pre RFC2133 implementations. */
+#endif
+
+/*!
+ * Required for some pre RFC2133 implementations.
+ * IN6ADDR_ANY_INIT and IN6ADDR_LOOPBACK_INIT were added in
+ * draft-ietf-ipngwg-bsd-api-04.txt or draft-ietf-ipngwg-bsd-api-05.txt.
+ * If 's6_addr' is defined then assume that there is a union and three
+ * levels otherwise assume two levels required.
+ */
+#ifndef IN6ADDR_ANY_INIT
+#ifdef s6_addr
+#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
+#else
+#define IN6ADDR_ANY_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }
+#endif
+#endif
+
+/*!
+ * Initialize address loopback. See IN6ADDR_ANY_INIT
+ */
+#ifndef IN6ADDR_LOOPBACK_INIT
+#ifdef s6_addr
+#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
+#else
+#define IN6ADDR_LOOPBACK_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } }
+#endif
+#endif
+
+/*% Used by AI_ALL */
+#ifndef AF_INET6
+#define AF_INET6 99
+#endif
+
+
+/*% Used to return IPV6 address types. */
+#ifndef PF_INET6
+#define PF_INET6 AF_INET6
+#endif
+
+/*% inaddr Loopback */
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001UL
+#endif
+
+LWRES_LANG_BEGINDECLS
+
+const char *
+lwres_net_ntop(int af, const void *src, char *dst, size_t size);
+
+int
+lwres_net_pton(int af, const char *src, void *dst);
+
+int
+lwres_net_aton(const char *cp, struct in_addr *addr);
+
+LWRES_LANG_ENDDECLS
+
+#endif /* LWRES_NET_H */
diff --git a/lib/lwres/version.c b/lib/lwres/version.c
new file mode 100644
index 0000000..33561fd
--- /dev/null
+++ b/lib/lwres/version.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005 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: version.c,v 1.8.18.2 2005/04/29 00:17:21 marka Exp $ */
+
+/*! \file */
+
+#include <lwres/version.h>
+
+const char lwres_version[] = VERSION;
+
+const unsigned int lwres_libinterface = LIBINTERFACE;
+const unsigned int lwres_librevision = LIBREVISION;
+const unsigned int lwres_libage = LIBAGE;
OpenPOWER on IntegriCloud