Compare commits

..

10 Commits

Author SHA1 Message Date
Ondřej Surý
50832edc78 Enforce linking with jemalloc 2021-12-09 20:57:49 +01:00
Ondřej Surý
4f8b1bb37a WIP: Disable internal malloc 2021-12-09 20:57:49 +01:00
Ondřej Surý
0b098b562d WIP: Reduce the memory used by hazard pointers 2021-12-09 20:57:49 +01:00
Ondřej Surý
a1389327aa Merge branch 'matthijs-regen-configure-after-mr-5625' into 'v9_16'
Regenerate configure file

See merge request isc-projects/bind9!5630
2021-12-09 16:51:52 +00:00
Matthijs Mekking
8dd2038f13 Regenerate configure file
Commit 3c77a51f added a configure check for OPENSSL_cleanup. The
regenerated configure file should have been added to that commit.
2021-12-09 17:03:31 +01:00
Matthijs Mekking
5928f2a5e7 Merge branch 'matthijs-fix-openssl-init-ssl-leak-v9_16' into 'v9_16'
Add OPENSSL_cleanup to tls_shutdown function (9.16)

See merge request isc-projects/bind9!5625
2021-12-09 10:07:19 +00:00
Matthijs Mekking
3c77a51f6b Add OPENSSL_cleanup to tls_shutdown function
This prevents a direct leak in OPENSSL_init_crypto (called from
OPENSSL_init_ssl).

Add shim version of OPENSSL_cleanup because it is missing in LibreSSL on
OpenBSD.

(cherry picked from commit 89f4f8f0c8)
2021-12-09 10:47:56 +01:00
Ondřej Surý
95432e0865 Merge branch '3051-missing-destroy-for-pthread-primitives-v9_16' into 'v9_16'
Stop leaking mutex in nmworker and cond in nm socket

See merge request isc-projects/bind9!5626
2021-12-08 17:39:12 +00:00
Ondřej Surý
1804a0332a Add CHANGES and release not for [GL #3051]
(cherry picked from commit dff5888d9b)
2021-12-08 18:20:16 +01:00
Ondřej Surý
d5cdcf924a Stop leaking mutex in nmworker and cond in nm socket
On FreeBSD, the pthread primitives are not solely allocated on stack,
but part of the object lives on the heap.  Missing pthread_*_destroy
causes the heap memory to grow and in case of fast lived object it's
possible to run out-of-memory.

Properly destroy the leaking mutex (worker->lock) and
the leaking condition (sock->cond).

(cherry picked from commit 57d0fabadd)
2021-12-08 18:19:37 +01:00
14 changed files with 276 additions and 81 deletions

View File

@@ -1,4 +1,6 @@
--- 9.16.24 released ---
5776. [bug] Add a missing isc_condition_destroy() for nmsocket
condition variable and add missing isc_mutex_destroy()
for nmworker lock. [GL #3051]
5773. [func] Change the message when accepting TCP connection has
failed to say "Accepting TCP connection failed" and

View File

@@ -288,6 +288,9 @@
/* Define to 1 if you have the <net/route.h> header file. */
#undef HAVE_NET_ROUTE_H
/* Define to 1 if you have the `OPENSSL_cleanup' function. */
#undef HAVE_OPENSSL_CLEANUP
/* define if OpenSSL supports Ed25519 */
#undef HAVE_OPENSSL_ED25519

108
configure vendored
View File

@@ -780,6 +780,8 @@ PANDOC
W3M
LN
ARFLAGS
JEMALLOC_LIBS
JEMALLOC_CFLAGS
XTARGETS
PKG_CONFIG_LIBDIR
PKG_CONFIG_PATH
@@ -967,6 +969,8 @@ LT_SYS_LIBRARY_PATH
PKG_CONFIG
PKG_CONFIG_PATH
PKG_CONFIG_LIBDIR
JEMALLOC_CFLAGS
JEMALLOC_LIBS
PYTHON
MAXMINDDB_CFLAGS
MAXMINDDB_LIBS
@@ -1725,6 +1729,10 @@ Some influential environment variables:
directories to add to pkg-config's search path
PKG_CONFIG_LIBDIR
path overriding pkg-config's built-in search path
JEMALLOC_CFLAGS
C compiler flags for JEMALLOC, overriding pkg-config
JEMALLOC_LIBS
linker flags for JEMALLOC, overriding pkg-config
PYTHON path to python executable
MAXMINDDB_CFLAGS
C compiler flags for MAXMINDDB, overriding pkg-config
@@ -12321,6 +12329,104 @@ else
fi
# Enforce jemalloc
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for jemalloc" >&5
$as_echo_n "checking for jemalloc... " >&6; }
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for jemalloc" >&5
$as_echo_n "checking for jemalloc... " >&6; }
if test -n "$JEMALLOC_CFLAGS"; then
pkg_cv_JEMALLOC_CFLAGS="$JEMALLOC_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"jemalloc\""; } >&5
($PKG_CONFIG --exists --print-errors "jemalloc") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_JEMALLOC_CFLAGS=`$PKG_CONFIG --cflags "jemalloc" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test -n "$JEMALLOC_LIBS"; then
pkg_cv_JEMALLOC_LIBS="$JEMALLOC_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"jemalloc\""; } >&5
($PKG_CONFIG --exists --print-errors "jemalloc") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_JEMALLOC_LIBS=`$PKG_CONFIG --libs "jemalloc" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
JEMALLOC_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "jemalloc" 2>&1`
else
JEMALLOC_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "jemalloc" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$JEMALLOC_PKG_ERRORS" >&5
as_fn_error $? "Package requirements (jemalloc) were not met:
$JEMALLOC_PKG_ERRORS
Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
Alternatively, you may set the environment variables JEMALLOC_CFLAGS
and JEMALLOC_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
Alternatively, you may set the environment variables JEMALLOC_CFLAGS
and JEMALLOC_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.
To get pkg-config, see <http://pkg-config.freedesktop.org/>.
See \`config.log' for more details" "$LINENO" 5; }
else
JEMALLOC_CFLAGS=$pkg_cv_JEMALLOC_CFLAGS
JEMALLOC_LIBS=$pkg_cv_JEMALLOC_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
fi
CFLAGS="$JEMALLOC_CFLAGS $CFLAGS"
LDFLAGS="$JEMALLOC_LDFLAGS $LDFLAGS"
LIBS="$JEMALLOC_LIBS $LIBS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable fuzzing mode" >&5
$as_echo_n "checking whether to enable fuzzing mode... " >&6; }
case $enable_fuzzing in #(
@@ -16892,7 +16998,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
# Check for functions added in OpenSSL or LibreSSL
#
for ac_func in OPENSSL_init_ssl OPENSSL_init_crypto
for ac_func in OPENSSL_init_ssl OPENSSL_init_crypto OPENSSL_cleanup
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"

View File

@@ -117,6 +117,13 @@ AC_ARG_ENABLE([fuzzing],
[],
[enable_fuzzing=no])
# Enforce jemalloc
AC_MSG_CHECKING([for jemalloc])
PKG_CHECK_MODULES([JEMALLOC], [jemalloc])
CFLAGS="$JEMALLOC_CFLAGS $CFLAGS"
LDFLAGS="$JEMALLOC_LDFLAGS $LDFLAGS"
LIBS="$JEMALLOC_LIBS $LIBS"
AC_MSG_CHECKING([whether to enable fuzzing mode])
AS_CASE([$enable_fuzzing],
[no],[AC_MSG_RESULT([no])],
@@ -832,7 +839,7 @@ AC_COMPILE_IFELSE(
# Check for functions added in OpenSSL or LibreSSL
#
AC_CHECK_FUNCS([OPENSSL_init_ssl OPENSSL_init_crypto])
AC_CHECK_FUNCS([OPENSSL_init_ssl OPENSSL_init_crypto OPENSSL_cleanup])
AC_CHECK_FUNCS([CRYPTO_zalloc])
AC_CHECK_FUNCS([EVP_CIPHER_CTX_new EVP_CIPHER_CTX_free])
AC_CHECK_FUNCS([EVP_MD_CTX_new EVP_MD_CTX_free EVP_MD_CTX_reset])

View File

@@ -59,7 +59,7 @@ https://www.isc.org/download/. There you will find additional
information about each release, source code, and pre-compiled versions
for Microsoft Windows operating systems.
.. include:: ../notes/notes-9.16.24.rst
.. include:: ../notes/notes-current.rst
.. include:: ../notes/notes-9.16.23.rst
.. include:: ../notes/notes-9.16.22.rst
.. include:: ../notes/notes-9.16.21.rst

View File

@@ -1,35 +0,0 @@
..
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, you can obtain one at https://mozilla.org/MPL/2.0/.
See the COPYRIGHT file distributed with this work for additional
information regarding copyright ownership.
Notes for BIND 9.16.24
----------------------
Feature Changes
~~~~~~~~~~~~~~~
- Previously, when an incoming TCP connection could not be accepted
because the client closed the connection early, an error message of
``TCP connection failed: socket is not connected`` was logged. This
message has been changed to ``Accepting TCP connection failed: socket
is not connected``. The severity level at which this type of message
is logged has also been changed from ``error`` to ``info`` for the
following triggering events: ``socket is not connected``, ``quota
reached``, and ``soft quota reached``. :gl:`#2700`
- ``dnssec-dsfromkey`` no longer generates DS records from revoked keys.
:gl:`#853`
Bug Fixes
~~~~~~~~~
- Removing a configured ``catalog-zone`` clause from the configuration,
running ``rndc reconfig``, then bringing back the removed
``catalog-zone`` clause and running ``rndc reconfig`` again caused
``named`` to crash. This has been fixed. :gl:`#1608`

View File

@@ -0,0 +1,57 @@
..
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, you can obtain one at https://mozilla.org/MPL/2.0/.
See the COPYRIGHT file distributed with this work for additional
information regarding copyright ownership.
Notes for BIND 9.16.24
----------------------
Security Fixes
~~~~~~~~~~~~~~
- None.
Known Issues
~~~~~~~~~~~~
- None.
New Features
~~~~~~~~~~~~
- None.
Removed Features
~~~~~~~~~~~~~~~~
- None.
Feature Changes
~~~~~~~~~~~~~~~
- None.
- Previously, when an incoming TCP connection could not be accepted because the client
closed the connection early, an error message of ``TCP connection
failed: socket is not connected`` was logged. This message has been changed
to ``Accepting TCP connection failed: socket is not connected``. The
severity level at which this type of message is logged has also
been changed from ``error`` to ``info`` for the following triggering
events: ``socket is not connected``, ``quota reached``, and ``soft
quota reached``. :gl:`#2700`
Bug Fixes
~~~~~~~~~
- Removing a configured ``catalog-zone`` clause from the configuration, running
``rndc reconfig``, then bringing back the removed ``catalog-zone`` clause and
running ``rndc reconfig`` again caused ``named`` to crash. This has been fixed.
:gl:`#1608`
- On FreeBSD, a TCP connection would leak a small amount of heap memory leading
to out-of-memory problem in a long run. This has been fixed. :gl:`#3051`

View File

@@ -45,6 +45,7 @@
#include <inttypes.h>
#include <isc/align.h>
#include <isc/atomic.h>
#include <isc/hp.h>
#include <isc/mem.h>
@@ -53,14 +54,12 @@
#include <isc/thread.h>
#include <isc/util.h>
#define HP_MAX_THREADS 128
static int isc__hp_max_threads = HP_MAX_THREADS;
#define HP_MAX_HPS 4 /* This is named 'K' in the HP paper */
#define CLPAD (128 / sizeof(uintptr_t))
#define HP_THRESHOLD_R 0 /* This is named 'R' in the HP paper */
#define CACHELINE_SIZE 64
/* Maximum number of retired objects per thread */
static int isc__hp_max_retired = HP_MAX_THREADS * HP_MAX_HPS;
static int isc__hp_max_threads = 1;
#define HP_MAX_HPS 4 /* This is named 'K' in the HP paper */
#define CLPAD (CACHELINE_SIZE / sizeof(uintptr_t))
#define HP_THRESHOLD_R 0 /* This is named 'R' in the HP paper */
typedef struct retirelist {
int size;
@@ -69,10 +68,11 @@ typedef struct retirelist {
struct isc_hp {
int max_hps;
int max_retired;
isc_mem_t *mctx;
atomic_uintptr_t **hp;
retirelist_t **rl;
isc_hp_deletefunc_t *deletefunc;
alignas(CACHELINE_SIZE) atomic_uintptr_t **hp;
alignas(CACHELINE_SIZE) retirelist_t **rl;
};
static inline int
@@ -82,35 +82,72 @@ tid(void) {
void
isc_hp_init(int max_threads) {
REQUIRE(max_threads > 0);
if (isc__hp_max_threads > max_threads) {
return;
}
isc__hp_max_threads = max_threads;
isc__hp_max_retired = max_threads * HP_MAX_HPS;
}
static size_t
hp_clpad(size_t max_hps) {
size_t hp_size = max_hps * sizeof(atomic_uintptr_t);
size_t hp_padding = 0;
while (hp_size > CACHELINE_SIZE) {
hp_size -= CACHELINE_SIZE;
}
if (hp_size > 0) {
hp_padding = CACHELINE_SIZE / hp_size;
}
return (hp_size + hp_padding);
}
isc_hp_t *
isc_hp_new(isc_mem_t *mctx, size_t max_hps, isc_hp_deletefunc_t *deletefunc) {
isc_hp_t *hp = isc_mem_get(mctx, sizeof(*hp));
REQUIRE(isc__hp_max_threads > 0);
REQUIRE(max_hps <= HP_MAX_HPS);
if (max_hps == 0) {
max_hps = HP_MAX_HPS;
}
*hp = (isc_hp_t){ .max_hps = max_hps, .deletefunc = deletefunc };
*hp = (isc_hp_t){
.max_hps = max_hps,
.max_retired = isc__hp_max_threads * max_hps,
.deletefunc = deletefunc,
};
isc_mem_attach(mctx, &hp->mctx);
hp->hp = isc_mem_get(mctx, isc__hp_max_threads * sizeof(hp->hp[0]));
hp->rl = isc_mem_get(mctx, isc__hp_max_threads * sizeof(hp->rl[0]));
for (int i = 0; i < isc__hp_max_threads; i++) {
hp->hp[i] = isc_mem_get(mctx, CLPAD * 2 * sizeof(hp->hp[i][0]));
hp->rl[i] = isc_mem_get(mctx, sizeof(*hp->rl[0]));
*hp->rl[i] = (retirelist_t){ .size = 0 };
hp->hp[i] = isc_mem_get(mctx, hp_clpad(hp->max_hps));
for (int j = 0; j < hp->max_hps; j++) {
atomic_init(&hp->hp[i][j], 0);
}
hp->rl[i]->list = isc_mem_get(
hp->mctx, isc__hp_max_retired * sizeof(uintptr_t));
}
/*
* It's not nice that we have a lot of empty space, but we need padding
* to avoid false sharing.
*/
hp->rl = isc_mem_get(mctx,
(isc__hp_max_threads * CLPAD) * sizeof(hp->rl[0]));
for (int i = 0; i < isc__hp_max_threads; i++) {
retirelist_t *rl;
rl = isc_mem_get(mctx, sizeof(*rl));
rl->size = 0;
rl->list = isc_mem_get(hp->mctx,
hp->max_retired * sizeof(uintptr_t));
hp->rl[i * CLPAD] = rl;
}
return (hp);
@@ -119,19 +156,22 @@ isc_hp_new(isc_mem_t *mctx, size_t max_hps, isc_hp_deletefunc_t *deletefunc) {
void
isc_hp_destroy(isc_hp_t *hp) {
for (int i = 0; i < isc__hp_max_threads; i++) {
isc_mem_put(hp->mctx, hp->hp[i],
CLPAD * 2 * sizeof(hp->hp[i][0]));
retirelist_t *rl = hp->rl[i * CLPAD];
for (int j = 0; j < hp->rl[i]->size; j++) {
void *data = (void *)hp->rl[i]->list[j];
for (int j = 0; j < rl->size; j++) {
void *data = (void *)rl->list[j];
hp->deletefunc(data);
}
isc_mem_put(hp->mctx, hp->rl[i]->list,
isc__hp_max_retired * sizeof(uintptr_t));
isc_mem_put(hp->mctx, hp->rl[i], sizeof(*hp->rl[0]));
isc_mem_put(hp->mctx, rl->list,
hp->max_retired * sizeof(uintptr_t));
isc_mem_put(hp->mctx, rl, sizeof(*rl));
}
for (int i = 0; i < isc__hp_max_threads; i++) {
isc_mem_put(hp->mctx, hp->hp[i], hp_clpad(hp->max_hps));
}
isc_mem_put(hp->mctx, hp->hp, isc__hp_max_threads * sizeof(hp->hp[0]));
isc_mem_put(hp->mctx, hp->rl, isc__hp_max_threads * sizeof(hp->rl[0]));
isc_mem_put(hp->mctx, hp->rl,
(isc__hp_max_threads * CLPAD) * sizeof(hp->rl[0]));
isc_mem_putanddetach(&hp->mctx, hp, sizeof(*hp));
}
@@ -173,15 +213,16 @@ isc_hp_protect_release(isc_hp_t *hp, int ihp, atomic_uintptr_t ptr) {
void
isc_hp_retire(isc_hp_t *hp, uintptr_t ptr) {
hp->rl[tid()]->list[hp->rl[tid()]->size++] = ptr;
INSIST(hp->rl[tid()]->size < isc__hp_max_retired);
retirelist_t *rl = hp->rl[tid() * CLPAD];
rl->list[rl->size++] = ptr;
INSIST(rl->size < hp->max_retired);
if (hp->rl[tid()]->size < HP_THRESHOLD_R) {
if (rl->size < HP_THRESHOLD_R) {
return;
}
for (int iret = 0; iret < hp->rl[tid()]->size; iret++) {
uintptr_t obj = hp->rl[tid()]->list[iret];
for (int iret = 0; iret < rl->size; iret++) {
uintptr_t obj = rl->list[iret];
bool can_delete = true;
for (int itid = 0; itid < isc__hp_max_threads && can_delete;
itid++) {
@@ -194,11 +235,9 @@ isc_hp_retire(isc_hp_t *hp, uintptr_t ptr) {
}
if (can_delete) {
size_t bytes = (hp->rl[tid()]->size - iret) *
sizeof(hp->rl[tid()]->list[0]);
memmove(&hp->rl[tid()]->list[iret],
&hp->rl[tid()]->list[iret + 1], bytes);
hp->rl[tid()]->size--;
size_t bytes = (rl->size - iret) * sizeof(rl->list[0]);
memmove(&rl->list[iret], &rl->list[iret + 1], bytes);
rl->size--;
hp->deletefunc((void *)obj);
}
}

View File

@@ -117,7 +117,7 @@ LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_defaultflags;
*/
#if !defined(ISC_MEM_USE_INTERNAL_MALLOC) && !__SANITIZE_ADDRESS__
#define ISC_MEM_USE_INTERNAL_MALLOC 1
#define ISC_MEM_USE_INTERNAL_MALLOC 0
#endif /* ifndef ISC_MEM_USE_INTERNAL_MALLOC */
/*

View File

@@ -425,6 +425,7 @@ nm_destroy(isc_nm_t **mgr0) {
isc_mempool_put(mgr->evpool, ievent);
}
isc_condition_destroy(&worker->cond_prio);
isc_mutex_destroy(&worker->lock);
r = uv_loop_close(&worker->loop);
INSIST(r == 0);
@@ -1267,8 +1268,9 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree FLARG) {
isc_mem_free(sock->mgr->mctx, sock->ah_frees);
isc_mem_free(sock->mgr->mctx, sock->ah_handles);
isc_mutex_destroy(&sock->lock);
isc_condition_destroy(&sock->scond);
isc_condition_destroy(&sock->cond);
isc_mutex_destroy(&sock->lock);
#ifdef NETMGR_TRACE
LOCK(&sock->mgr->lock);
ISC_LIST_UNLINK(sock->mgr->active_sockets, sock, active_link);

View File

@@ -220,3 +220,10 @@ OPENSSL_init_ssl(uint64_t opts, const void *settings) {
return (1);
}
#endif
#if !HAVE_OPENSSL_CLEANUP
void
OPENSSL_cleanup(void) {
return;
}
#endif

View File

@@ -119,6 +119,11 @@ OPENSSL_init_ssl(uint64_t opts, const void *settings);
#endif
#if !HAVE_OPENSSL_CLEANUP
void
OPENSSL_cleanup(void);
#endif
#if !HAVE_TLS_SERVER_METHOD
#define TLS_server_method SSLv23_server_method
#endif

View File

@@ -13,6 +13,7 @@
#include <openssl/bn.h>
#include <openssl/conf.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/opensslv.h>
#include <openssl/rand.h>
@@ -123,8 +124,9 @@ tls_shutdown(void) {
REQUIRE(atomic_load(&init_done));
REQUIRE(!atomic_load(&shut_done));
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
OPENSSL_cleanup();
#else
CONF_modules_unload(1);
OBJ_cleanup();
EVP_cleanup();

View File

@@ -5,7 +5,7 @@ PRODUCT=BIND
DESCRIPTION="(Extended Support Version)"
MAJORVER=9
MINORVER=16
PATCHVER=24
PATCHVER=23
RELEASETYPE=
RELEASEVER=
EXTENSIONS=