BIND 10 trac871, updated. 364be72653933235d362a57c9342bae1c6e17b3a [trac871] Merge branch 'master' into trac871 Conflicts: src/lib/dns/tsig.cc
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Apr 29 02:42:05 UTC 2011
The branch, trac871 has been updated
via 364be72653933235d362a57c9342bae1c6e17b3a (commit)
via 43f9ce0c56cd14c0349a8f3c3c9a5f4dc092f65a (commit)
via ebe0c4b1e66d359227bdd1bd47395fee7b957f14 (commit)
via d9b00f6ded6d0cfb41a0939cb613c1e7bd703a67 (commit)
via 2c60d79949a79fc8f093f3447c949e7c63f83137 (commit)
via 0ede9e8f8c0e1d89a01cdb1eccb5256363bda0cf (commit)
via 64cee1a7ad8341b83954e022487744060b59d04a (commit)
via 177b356c926307e94a95e6e2de7a3f0ee7124021 (commit)
via 1867180c5e2263baf319514b5b765b8eb4049c08 (commit)
via 6c554c8b4e37daeaa4182d05af69a40a0b78cea2 (commit)
via 6eb7a93e81027bcf67435188c1ff7788965253cb (commit)
via cacab413e886e8c90691428e1e3f78b77814945e (commit)
via ec1ad752576f7f3541b1b57f906256c6a5ae0dc6 (commit)
via 0310b8b77e6adb8671d1f9ebfe826e394e95f53f (commit)
via 78bd2b77782510d02748254a8c79249e493b6024 (commit)
via daf48e860413d4c3229ce309253b29d1ad974c7a (commit)
via 6d03a35ac6dec0508d30cd778fed48257fc6c0e1 (commit)
via 87e4b9874ac16ccc5d236a2fcb8221942713e086 (commit)
via d9433ad4bd9aec1028b9b05aa55e9b083e35a4d4 (commit)
via 9df42279a47eb617f586144dce8cce680598558a (commit)
via 0640f80c7a62cf9c3e289f8290c5a3b44f4385f5 (commit)
via 05c6223cf7f145ec6e96cffed0561a03387b7367 (commit)
via 309bc10ee624106cf75165efd4251312deed3212 (commit)
via abdb0ff5e8cdd781d7c4960bb51d8538f4e3b44e (commit)
via b963854734ff8ba78ccb14f2e5a481c9426881c6 (commit)
via ea46adf9f6bbdd78a06ae748d979986a75b9b8d2 (commit)
via ffbe8a099bece23efb94e3adbe8fdfff8cfb379e (commit)
via 3c194549a61e68ed38bbcd90e69f1f954ff286f4 (commit)
from 28143beb0e57bbd4d62432b81edc8e179b95959f (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 364be72653933235d362a57c9342bae1c6e17b3a
Merge: 28143be 43f9ce0
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Apr 28 18:05:25 2011 -0700
[trac871] Merge branch 'master' into trac871
Conflicts:
src/lib/dns/tsig.cc
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 8 +
configure.ac | 76 ++++++---
doc/Doxyfile | 11 +-
src/bin/auth/tests/Makefile.am | 2 -
src/bin/bind10/run_bind10.sh.in | 4 +-
src/bin/cfgmgr/b10-cfgmgr.py.in | 2 +-
src/bin/stats/run_b10-stats-httpd.sh.in | 2 +-
src/bin/stats/run_b10-stats.sh.in | 2 +-
src/bin/stats/stats.py.in | 3 +-
src/bin/stats/stats_httpd.py.in | 3 +-
src/bin/stats/tests/Makefile.am | 2 +-
src/bin/stats/tests/b10-stats_test.py | 4 +-
src/bin/stats/tests/stats_test.in | 2 +-
src/cppcheck-suppress.lst | 2 +-
src/lib/Makefile.am | 5 +-
src/lib/cryptolink/Makefile.am | 4 +-
src/lib/cryptolink/cryptolink.h | 1 +
src/lib/cryptolink/tests/crypto_unittests.cc | 44 +++--
src/lib/dns/tests/Makefile.am | 1 +
src/lib/dns/tests/tsigkey_unittest.cc | 6 +-
src/lib/dns/tsig.cc | 8 +-
src/lib/dns/tsigkey.cc | 6 +-
src/lib/dns/tsigkey.h | 2 +-
src/lib/nsas/nameserver_address_store.h | 1 -
src/lib/nsas/tests/nameserver_address_unittest.cc | 3 +-
src/lib/nsas/tests/nameserver_entry_unittest.cc | 3 +-
src/lib/nsas/tests/nsas_test.h | 148 +----------------
src/lib/resolve/recursive_query.cc | 66 +++++++-
src/lib/resolve/tests/recursive_query_unittest.cc | 111 +++++++++++-
src/lib/util/unittests/Makefile.am | 2 +-
src/lib/util/unittests/newhook.cc | 2 +-
src/lib/util/unittests/newhook.h | 6 +
src/lib/util/unittests/resolver.h | 193 +++++++++++++++++++++
33 files changed, 504 insertions(+), 231 deletions(-)
mode change 100644 => 100755 src/bin/stats/run_b10-stats-httpd.sh.in
mode change 100644 => 100755 src/bin/stats/run_b10-stats.sh.in
mode change 100644 => 100755 src/bin/stats/tests/stats_test.in
create mode 100644 src/lib/util/unittests/resolver.h
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 87f6b15..99de54f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+226. [func]* jelte
+ Introduced an API for cryptographic operations. Currently it only
+ supports HMAC, intended for use with TSIG. The current
+ implementation uses Botan as the backend library.
+ This introduces a new dependency, on Botan. Currently only Botan
+ 1.8.x works; older or newer versions don't.
+ (Trac#781, git 9df42279a47eb617f586144dce8cce680598558a)
+
225. [func] naokikambe
Added the HTTP/XML interface(b10-stats-httpd) to the statistics feature
in BIND 10. b10-stats-httpd is a standalone HTTP server and it requests
diff --git a/configure.ac b/configure.ac
index 755c630..d3faebf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -375,36 +375,68 @@ fi
AC_SUBST(USE_LCOV)
# Check for Botan
-botan_path=""
+botan_path="yes"
AC_ARG_WITH([botan],
AC_HELP_STRING([--with-botan=PATH],
[specify exact directory of Botan library]),
[botan_path="$withval"])
-# If not specificed, try some common paths
-if test -z "$with_botan"; then
- botandirs="/usr/local /usr/pkg /opt /opt/local /usr"
- for d in $botandirs
- do
- if test -f $d/include/botan/botan.h; then
- botan_path=$d
- break
- fi
- done
+if test "${botan_path}" == "no" ; then
+ AC_MSG_ERROR([Need botan for libcryptolink])
fi
-if test "${botan_path}" ; then
- CPPFLAGS="$CPPFLAGS -I${botan_path}/include"
- LDFLAGS="$LDFLAGS -L${botan_path}/lib -lbotan"
+if test "${botan_path}" != "yes" ; then
+ if test -x "${botan_path}/bin/botan-config" ; then
+ BOTAN_CONFIG="${botan_path}/bin/botan-config"
+ else
+ AC_MSG_ERROR([${botan_path}/bin/botan-config not found])
+ fi
+else
+ AC_PATH_PROG([BOTAN_CONFIG], [botan-config])
+fi
+
+if test -x "${BOTAN_CONFIG}" ; then
+ BOTAN_LDFLAGS=`${BOTAN_CONFIG} --libs`
+ # We expect botan-config --libs to contain -L<path_to_libbotan>, but
+ # this is not always the case. As a heuristics workaround we add
+ # -L`botan-config --prefix/lib` in this case. Same for BOTAN_INCLUDES
+ # (but using include instead of lib) below.
+ echo ${BOTAN_LDFLAGS} | grep -- -L > /dev/null || \
+ BOTAN_LDFLAGS="-L`${BOTAN_CONFIG} --prefix`/lib ${BOTAN_LDFLAGS}"
+ BOTAN_INCLUDES=`${BOTAN_CONFIG} --cflags`
+ echo ${BOTAN_INCLUDES} | grep -- -I > /dev/null || \
+ BOTAN_INCLUDES="-I`${BOTAN_CONFIG} --prefix`/include ${BOTAN_INCLUDES}"
+ # See python_rpath for some info on why we do this
+ if test $rpath_available = yes; then
+ BOTAN_RPATH=
+ for flag in ${BOTAN_LDFLAGS}; do
+ BOTAN_RPATH="${BOTAN_RPATH} `echo $flag | sed -ne 's/^\(\-L\)/-R/p'`"
+ done
+ AC_SUBST(BOTAN_RPATH)
+ fi
+
+ AC_SUBST(BOTAN_LDFLAGS)
+ AC_SUBST(BOTAN_INCLUDES)
fi
+
+CPPFLAGS_SAVED=$CPPFLAGS
+CPPFLAGS="$BOTAN_INCLUDES $CPPFLAGS"
+LDFLAGS_SAVED=$LDFLAGS
+LDFLAGS="$BOTAN_LDFLAGS $LDFLAGS"
+
AC_CHECK_HEADERS([botan/botan.h],,AC_MSG_ERROR([Missing required header files.]))
AC_LINK_IFELSE(
- [AC_LANG_PROGRAM([#include <botan/botan.h>],
+ [AC_LANG_PROGRAM([#include <botan/botan.h>
+ #include <botan/hash.h>
+ ],
[using namespace Botan;
LibraryInitializer::initialize();
+ HashFunction *h = get_hash("MD5");
])],
[AC_MSG_RESULT([checking for Botan library... yes])],
[AC_MSG_RESULT([checking for Botan library... no])
- AC_MSG_ERROR([Missing Botan library])]
+ AC_MSG_ERROR([Needs Botan library 1.8 or higher])]
)
+CPPFLAGS=$CPPFLAGS_SAVED
+LDFLAGS=$LDFLAGS_SAVED
#
# Configure Boost header path
@@ -717,11 +749,6 @@ AC_CONFIG_FILES([Makefile
src/lib/exceptions/tests/Makefile
src/lib/datasrc/Makefile
src/lib/datasrc/tests/Makefile
- src/lib/util/Makefile
- src/lib/util/io/Makefile
- src/lib/util/io/tests/Makefile
- src/lib/util/unittests/Makefile
- src/lib/util/tests/Makefile
src/lib/xfr/Makefile
src/lib/log/Makefile
src/lib/log/compiler/Makefile
@@ -736,6 +763,11 @@ AC_CONFIG_FILES([Makefile
src/lib/cache/tests/Makefile
src/lib/server_common/Makefile
src/lib/server_common/tests/Makefile
+ src/lib/util/Makefile
+ src/lib/util/io/Makefile
+ src/lib/util/io/tests/Makefile
+ src/lib/util/unittests/Makefile
+ src/lib/util/tests/Makefile
tests/Makefile
tests/system/Makefile
tests/tools/Makefile
@@ -858,6 +890,8 @@ dnl includes too
${PYTHON_LDFLAGS}
${PYTHON_LIB}
Boost: ${BOOST_INCLUDES}
+ Botan: ${BOTAN_INCLUDES}
+ ${BOTAN_LDFLAGS}
SQLite: $SQLITE_CFLAGS
$SQLITE_LIBS
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 4677f80..a57d275 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -568,11 +568,12 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/cryptolink \
- ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth \
- ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ \
- ../src/lib/nsas ../src/lib/testutils ../src/lib/cache \
- ../src/lib/server_common/ ../src/bin/sockcreator/ ../src/lib/util/
+INPUT = ../src/lib/cc ../src/lib/config \
+ ../src/lib/cryptolink ../src/lib/dns ../src/lib/datasrc \
+ ../src/bin/auth ../src/bin/resolver ../src/lib/bench \
+ ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas \
+ ../src/lib/testutils ../src/lib/cache ../src/lib/server_common/ \
+ ../src/bin/sockcreator/ ../src/lib/util/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index 026dde3..050373a 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -18,7 +18,6 @@ CLEANFILES = *.gcno *.gcda
TESTS =
if HAVE_GTEST
-BUILT_SOURCES = ../spec_config.h
TESTS += run_unittests
run_unittests_SOURCES = $(top_srcdir)/src/lib/dns/tests/unittest_util.h
run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
@@ -28,7 +27,6 @@ run_unittests_SOURCES += ../change_user.h ../change_user.cc
run_unittests_SOURCES += ../auth_config.h ../auth_config.cc
run_unittests_SOURCES += ../command.h ../command.cc
run_unittests_SOURCES += ../common.h ../common.cc
-run_unittests_SOURCES += ../spec_config.h
run_unittests_SOURCES += ../statistics.h ../statistics.cc
run_unittests_SOURCES += auth_srv_unittest.cc
run_unittests_SOURCES += config_unittest.cc
diff --git a/src/bin/bind10/run_bind10.sh.in b/src/bin/bind10/run_bind10.sh.in
index edc01fe..ba267b4 100644
--- a/src/bin/bind10/run_bind10.sh.in
+++ b/src/bin/bind10/run_bind10.sh.in
@@ -23,14 +23,14 @@ BIND10_PATH=@abs_top_builddir@/src/bin/bind10
PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/resolver:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/stats:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:$PATH
export PATH
-PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/log/.libs
+PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/log/.libs:@abs_top_builddir@/src/lib/util/io/.libs
export PYTHONPATH
# If necessary (rare cases), explicitly specify paths to dynamic libraries
# required by loadable python modules.
SET_ENV_LIBRARY_PATH=@SET_ENV_LIBRARY_PATH@
if test $SET_ENV_LIBRARY_PATH = yes; then
- @ENV_LIBRARY_PATH@=@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/exceptions/.libs:$@ENV_LIBRARY_PATH@
+ @ENV_LIBRARY_PATH@=@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/util/.libs:@abs_top_builddir@/src/lib/util/io/.libs:@abs_top_builddir@/src/lib/exceptions/.libs:$@ENV_LIBRARY_PATH@
export @ENV_LIBRARY_PATH@
fi
diff --git a/src/bin/cfgmgr/b10-cfgmgr.py.in b/src/bin/cfgmgr/b10-cfgmgr.py.in
index 607a6dc..16c8f76 100755
--- a/src/bin/cfgmgr/b10-cfgmgr.py.in
+++ b/src/bin/cfgmgr/b10-cfgmgr.py.in
@@ -41,7 +41,7 @@ if "B10_FROM_SOURCE" in os.environ:
DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
else:
DATA_PATH = os.environ["B10_FROM_SOURCE"]
- PLUGIN_PATH = [DATA_PATH + '/src/bin/cfgmgr/plugins']
+ PLUGIN_PATHS = [DATA_PATH + '/src/bin/cfgmgr/plugins']
else:
PREFIX = "@prefix@"
DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
diff --git a/src/bin/stats/run_b10-stats-httpd.sh.in b/src/bin/stats/run_b10-stats-httpd.sh.in
old mode 100644
new mode 100755
index 6a20412..67c93f0
--- a/src/bin/stats/run_b10-stats-httpd.sh.in
+++ b/src/bin/stats/run_b10-stats-httpd.sh.in
@@ -26,7 +26,7 @@ export BIND10_MSGQ_SOCKET_FILE
STATS_PATH=@abs_top_builddir@/src/bin/stats
-B10_FROM_SOURCE=@abs_top_srcdir@/src/bin/stats
+B10_FROM_SOURCE=@abs_top_srcdir@
export B10_FROM_SOURCE
cd ${STATS_PATH}
diff --git a/src/bin/stats/run_b10-stats.sh.in b/src/bin/stats/run_b10-stats.sh.in
old mode 100644
new mode 100755
index 5623082..b9007c8
--- a/src/bin/stats/run_b10-stats.sh.in
+++ b/src/bin/stats/run_b10-stats.sh.in
@@ -24,7 +24,7 @@ export PYTHONPATH
BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
export BIND10_MSGQ_SOCKET_FILE
-B10_FROM_SOURCE=@abs_top_srcdir@/src/bin/stats
+B10_FROM_SOURCE=@abs_top_srcdir@
export B10_FROM_SOURCE
STATS_PATH=@abs_top_builddir@/src/bin/stats
diff --git a/src/bin/stats/stats.py.in b/src/bin/stats/stats.py.in
index dac8796..dd617f8 100644
--- a/src/bin/stats/stats.py.in
+++ b/src/bin/stats/stats.py.in
@@ -39,7 +39,8 @@ isc.util.process.rename()
# from a directory relative to that, otherwise we use the ones
# installed on the system
if "B10_FROM_SOURCE" in os.environ:
- SPECFILE_LOCATION = os.environ["B10_FROM_SOURCE"] + os.sep + "stats.spec"
+ SPECFILE_LOCATION = os.environ["B10_FROM_SOURCE"] + os.sep + \
+ "src" + os.sep + "bin" + os.sep + "stats" + os.sep + "stats.spec"
else:
PREFIX = "@prefix@"
DATAROOTDIR = "@datarootdir@"
diff --git a/src/bin/stats/stats_httpd.py.in b/src/bin/stats/stats_httpd.py.in
index 20c3442..dd9220e 100644
--- a/src/bin/stats/stats_httpd.py.in
+++ b/src/bin/stats/stats_httpd.py.in
@@ -38,7 +38,8 @@ import isc.util.process
# from a directory relative to that, otherwise we use the ones
# installed on the system
if "B10_FROM_SOURCE" in os.environ:
- BASE_LOCATION = os.environ["B10_FROM_SOURCE"]
+ BASE_LOCATION = os.environ["B10_FROM_SOURCE"] + os.sep + \
+ "src" + os.sep + "bin" + os.sep + "stats"
else:
PREFIX = "@prefix@"
DATAROOTDIR = "@datarootdir@"
diff --git a/src/bin/stats/tests/Makefile.am b/src/bin/stats/tests/Makefile.am
index 1fbb0cc..5a13277 100644
--- a/src/bin/stats/tests/Makefile.am
+++ b/src/bin/stats/tests/Makefile.am
@@ -14,6 +14,6 @@ endif
for pytest in $(PYTESTS) ; do \
echo Running test: $$pytest ; \
env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/stats:$(abs_top_builddir)/src/bin/stats/tests \
- B10_FROM_SOURCE=$(abs_top_srcdir)/src/bin/stats \
+ B10_FROM_SOURCE=$(abs_top_srcdir) \
$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
done
diff --git a/src/bin/stats/tests/b10-stats_test.py b/src/bin/stats/tests/b10-stats_test.py
index 170e464..818b67a 100644
--- a/src/bin/stats/tests/b10-stats_test.py
+++ b/src/bin/stats/tests/b10-stats_test.py
@@ -537,7 +537,9 @@ class TestStats2(unittest.TestCase):
"""
if "B10_FROM_SOURCE" in os.environ:
self.assertEqual(stats.SPECFILE_LOCATION,
- os.environ["B10_FROM_SOURCE"] + os.sep + "stats.spec")
+ os.environ["B10_FROM_SOURCE"] + os.sep + \
+ "src" + os.sep + "bin" + os.sep + "stats" + \
+ os.sep + "stats.spec")
imp.reload(stats)
# change path of SPECFILE_LOCATION
stats.SPECFILE_LOCATION = TEST_SPECFILE_LOCATION
diff --git a/src/bin/stats/tests/stats_test.in b/src/bin/stats/tests/stats_test.in
old mode 100644
new mode 100755
index 39b5a94..9a95c5b
--- a/src/bin/stats/tests/stats_test.in
+++ b/src/bin/stats/tests/stats_test.in
@@ -21,7 +21,7 @@ export PYTHON_EXEC
PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/bin/stats:@abs_top_srcdir@/src/bin/stats/tests
export PYTHONPATH
-B10_FROM_SOURCE=@abs_top_srcdir@/src/bin/stats
+B10_FROM_SOURCE=@abs_top_srcdir@
export B10_FROM_SOURCE
TEST_PATH=@abs_top_srcdir@/src/bin/stats/tests
diff --git a/src/cppcheck-suppress.lst b/src/cppcheck-suppress.lst
index e9c4beb..5e6d81f 100644
--- a/src/cppcheck-suppress.lst
+++ b/src/cppcheck-suppress.lst
@@ -12,4 +12,4 @@ functionConst:src/lib/cache/rrset_cache.h
// Intentional self assignment tests. Suppress warning about them.
selfAssignment:src/lib/dns/tests/name_unittest.cc:293
selfAssignment:src/lib/dns/tests/rdata_unittest.cc:228
-selfAssignment:src/lib/dns/tests/tsigkey_unittest.cc:104
+selfAssignment:src/lib/dns/tests/tsigkey_unittest.cc:120
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 9afc9b3..184b090 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,2 +1,3 @@
-SUBDIRS = exceptions util cryptolink dns cc config python xfr bench log \
- asiolink asiodns nsas cache resolve testutils datasrc server_common
+SUBDIRS = exceptions util cryptolink dns cc config python xfr bench \
+ log asiolink asiodns nsas cache resolve testutils datasrc \
+ server_common
diff --git a/src/lib/cryptolink/Makefile.am b/src/lib/cryptolink/Makefile.am
index 2f5d9c3..93f3443 100644
--- a/src/lib/cryptolink/Makefile.am
+++ b/src/lib/cryptolink/Makefile.am
@@ -1,7 +1,7 @@
SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
-AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += $(BOOST_INCLUDES) $(BOTAN_INCLUDES)
AM_CXXFLAGS = $(B10_CXXFLAGS)
CLEANFILES = *.gcno *.gcda
@@ -10,3 +10,5 @@ lib_LTLIBRARIES = libcryptolink.la
libcryptolink_la_SOURCES = cryptolink.h cryptolink.cc
libcryptolink_la_SOURCES += crypto_hmac.h crypto_hmac.cc
+
+libcryptolink_la_LIBADD = ${BOTAN_LDFLAGS} ${BOTAN_RPATH}
diff --git a/src/lib/cryptolink/cryptolink.h b/src/lib/cryptolink/cryptolink.h
index 34f7cd3..1583136 100644
--- a/src/lib/cryptolink/cryptolink.h
+++ b/src/lib/cryptolink/cryptolink.h
@@ -27,6 +27,7 @@
namespace isc {
namespace cryptolink {
+/// \brief Hash algorithm identifiers
enum HashAlgorithm {
MD5 = 0, ///< MD5
SHA1 = 1, ///< SHA-1
diff --git a/src/lib/cryptolink/tests/crypto_unittests.cc b/src/lib/cryptolink/tests/crypto_unittests.cc
index cdf7857..65018c6 100644
--- a/src/lib/cryptolink/tests/crypto_unittests.cc
+++ b/src/lib/cryptolink/tests/crypto_unittests.cc
@@ -21,7 +21,7 @@
#include <util/buffer.h>
#include <exceptions/exceptions.h>
-#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
using namespace isc::util;
using namespace isc::cryptolink;
@@ -88,9 +88,10 @@ namespace {
CryptoLink& crypto = CryptoLink::getCryptoLink();
// Sign it
- boost::scoped_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+ boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
secret_len,
- hash_algorithm));
+ hash_algorithm),
+ deleteHMAC);
hmac_sign->update(data_buf.getData(), data_buf.getLength());
hmac_sign->sign(hmac_sig, hmac_len);
@@ -98,9 +99,10 @@ namespace {
checkBuffer(hmac_sig, expected_hmac, hmac_len);
// Check whether we can verify it ourselves
- boost::scoped_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+ boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
secret_len,
- hash_algorithm));
+ hash_algorithm),
+ deleteHMAC);
hmac_verify->update(data_buf.getData(), data_buf.getLength());
EXPECT_TRUE(hmac_verify->verify(hmac_sig.getData(),
hmac_sig.getLength()));
@@ -119,17 +121,19 @@ namespace {
const uint8_t* expected_hmac,
size_t hmac_len) {
CryptoLink& crypto = CryptoLink::getCryptoLink();
- boost::scoped_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+ boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
secret_len,
- hash_algorithm));
+ hash_algorithm),
+ deleteHMAC);
hmac_sign->update(data.c_str(), data.size());
std::vector<uint8_t> sig = hmac_sign->sign(hmac_len);
ASSERT_EQ(hmac_len, sig.size());
checkData(&sig[0], expected_hmac, hmac_len);
- boost::scoped_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+ boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
secret_len,
- hash_algorithm));
+ hash_algorithm),
+ deleteHMAC);
hmac_verify->update(data.c_str(), data.size());
EXPECT_TRUE(hmac_verify->verify(&sig[0], sig.size()));
@@ -144,9 +148,10 @@ namespace {
const uint8_t* expected_hmac,
size_t hmac_len) {
CryptoLink& crypto = CryptoLink::getCryptoLink();
- boost::scoped_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+ boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
secret_len,
- hash_algorithm));
+ hash_algorithm),
+ deleteHMAC);
hmac_sign->update(data.c_str(), data.size());
// note: this is not exception-safe, and can leak, but
@@ -157,9 +162,10 @@ namespace {
hmac_sign->sign(sig, hmac_len);
checkData(sig, expected_hmac, hmac_len);
- boost::scoped_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+ boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
secret_len,
- hash_algorithm));
+ hash_algorithm),
+ deleteHMAC);
hmac_verify->update(data.c_str(), data.size());
EXPECT_TRUE(hmac_verify->verify(sig, hmac_len));
@@ -415,10 +421,9 @@ TEST(CryptoLinkTest, HMAC_SHA256_RFC2202_SIGN) {
namespace {
size_t
sigVectorLength(HashAlgorithm alg, size_t len) {
- std::auto_ptr<HMAC> hmac_sign(
- CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg));
- //boost::scoped_ptr<HMAC> hmac_sign(
- // CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg));
+ boost::shared_ptr<HMAC> hmac_sign(
+ CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg),
+ deleteHMAC);
hmac_sign->update("asdf", 4);
const std::vector<uint8_t> sig = hmac_sign->sign(len);
return (sig.size());
@@ -426,8 +431,9 @@ namespace {
size_t
sigBufferLength(HashAlgorithm alg, size_t len) {
- boost::scoped_ptr<HMAC> hmac_sign(
- CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg));
+ boost::shared_ptr<HMAC> hmac_sign(
+ CryptoLink::getCryptoLink().createHMAC("asdf", 4, alg),
+ deleteHMAC);
hmac_sign->update("asdf", 4);
OutputBuffer sig(0);
hmac_sign->sign(sig, len);
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index b0a9672..9783beb 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -58,6 +58,7 @@ run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/io/libutil_io.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
endif
diff --git a/src/lib/dns/tests/tsigkey_unittest.cc b/src/lib/dns/tests/tsigkey_unittest.cc
index 0354cb1..96696d5 100644
--- a/src/lib/dns/tests/tsigkey_unittest.cc
+++ b/src/lib/dns/tests/tsigkey_unittest.cc
@@ -43,12 +43,12 @@ TEST_F(TSIGKeyTest, algorithmNames) {
// Also check conversion to cryptolink definitions
EXPECT_EQ(isc::cryptolink::MD5, TSIGKey(key_name, TSIGKey::HMACMD5_NAME(),
- NULL, 0).getCryptoAlgorithm());
+ NULL, 0).getAlgorithm());
EXPECT_EQ(isc::cryptolink::SHA1, TSIGKey(key_name, TSIGKey::HMACSHA1_NAME(),
- NULL, 0).getCryptoAlgorithm());
+ NULL, 0).getAlgorithm());
EXPECT_EQ(isc::cryptolink::SHA256, TSIGKey(key_name,
TSIGKey::HMACSHA256_NAME(),
- NULL, 0).getCryptoAlgorithm());
+ NULL, 0).getAlgorithm());
}
TEST_F(TSIGKeyTest, construct) {
diff --git a/src/lib/dns/tsig.cc b/src/lib/dns/tsig.cc
index f74dfd2..8e8301d 100644
--- a/src/lib/dns/tsig.cc
+++ b/src/lib/dns/tsig.cc
@@ -85,6 +85,12 @@ TSIGContext::sign(const uint16_t qid, const void* const data,
}
TSIGError error(TSIGError::NOERROR());
+ // TSIG uses 48-bit unsigned integer to represent time signed.
+ // Since gettimeofdayWrapper() returns a 64-bit *signed* integer, we
+ // make sure it's stored in an unsigned 64-bit integer variable and
+ // represents a value in the expected range. (In reality, however,
+ // gettimeofdayWrapper() will return a positive integer that will fit
+ // in 48 bits)
const uint64_t now = (detail::gettimeWrapper() & 0x0000ffffffffffffULL);
// For responses adjust the error code.
@@ -109,7 +115,7 @@ TSIGContext::sign(const uint16_t qid, const void* const data,
HMACPtr hmac(CryptoLink::getCryptoLink().createHMAC(
impl_->key_.getSecret(),
impl_->key_.getSecretLength(),
- impl_->key_.getCryptoAlgorithm()),
+ impl_->key_.getAlgorithm()),
deleteHMAC);
// If the context has previous MAC (either the Request MAC or its own
diff --git a/src/lib/dns/tsigkey.cc b/src/lib/dns/tsigkey.cc
index 615b5b6..c899423 100644
--- a/src/lib/dns/tsigkey.cc
+++ b/src/lib/dns/tsigkey.cc
@@ -109,7 +109,7 @@ TSIGKey::TSIGKey(const std::string& str) : impl_(NULL) {
const HashAlgorithm algorithm = convertAlgorithmName(algo_name);
vector<uint8_t> secret;
- util::encode::decodeBase64(secret_str, secret);
+ isc::util::encode::decodeBase64(secret_str, secret);
impl_ = new TSIGKeyImpl(Name(keyname_str), algo_name, algorithm,
&secret[0], secret.size());
@@ -152,7 +152,7 @@ TSIGKey::getAlgorithmName() const {
}
isc::cryptolink::HashAlgorithm
-TSIGKey::getCryptoAlgorithm() const {
+TSIGKey::getAlgorithm() const {
return (impl_->algorithm_);
}
@@ -171,7 +171,7 @@ TSIGKey::toText() const {
const vector<uint8_t> secret_v(static_cast<const uint8_t*>(getSecret()),
static_cast<const uint8_t*>(getSecret()) +
getSecretLength());
- std::string secret_str = util::encode::encodeBase64(secret_v);
+ std::string secret_str = isc::util::encode::encodeBase64(secret_v);
return (getKeyName().toText() + ":" + secret_str + ":" +
getAlgorithmName().toText());
diff --git a/src/lib/dns/tsigkey.h b/src/lib/dns/tsigkey.h
index 4136278..02dd423 100644
--- a/src/lib/dns/tsigkey.h
+++ b/src/lib/dns/tsigkey.h
@@ -145,7 +145,7 @@ public:
const Name& getAlgorithmName() const;
/// Return the hash algorithm name in the form of cryptolink::HashAlgorithm
- isc::cryptolink::HashAlgorithm getCryptoAlgorithm() const;
+ isc::cryptolink::HashAlgorithm getAlgorithm() const;
/// Return the length of the TSIG secret in bytes.
size_t getSecretLength() const;
diff --git a/src/lib/nsas/nameserver_address_store.h b/src/lib/nsas/nameserver_address_store.h
index 148052d..87845c9 100644
--- a/src/lib/nsas/nameserver_address_store.h
+++ b/src/lib/nsas/nameserver_address_store.h
@@ -38,7 +38,6 @@ template<class T> class LruList;
namespace nsas {
-class ResolverInterface;
template<class T> class HashTable;
class ZoneEntry;
class NameserverEntry;
diff --git a/src/lib/nsas/tests/nameserver_address_unittest.cc b/src/lib/nsas/tests/nameserver_address_unittest.cc
index e3bc5de..1b211e9 100644
--- a/src/lib/nsas/tests/nameserver_address_unittest.cc
+++ b/src/lib/nsas/tests/nameserver_address_unittest.cc
@@ -51,7 +51,8 @@ public:
ns_.reset(new NameserverEntry(name_.toText(), RRClass::IN()));
ns_->askIP(resolver_.get(), boost::shared_ptr<Callback>(new Callback), ANY_OK);
resolver_->asksIPs(name_, 0, 1);
- resolver_->requests[0].second->success(createResponseMessage(rrv4_));
+ resolver_->requests[0].second->success(
+ isc::util::unittests::createResponseMessage(rrv4_));
}
// Return the sample NameserverEntry
diff --git a/src/lib/nsas/tests/nameserver_entry_unittest.cc b/src/lib/nsas/tests/nameserver_entry_unittest.cc
index 7e9f675..3435d26 100644
--- a/src/lib/nsas/tests/nameserver_entry_unittest.cc
+++ b/src/lib/nsas/tests/nameserver_entry_unittest.cc
@@ -72,7 +72,8 @@ private:
RRsetPtr set)
{
if (set) {
- resolver->requests[index].second->success(createResponseMessage(set));
+ resolver->requests[index].second->success(
+ isc::util::unittests::createResponseMessage(set));
} else {
resolver->requests[index].second->failure();
}
diff --git a/src/lib/nsas/tests/nsas_test.h b/src/lib/nsas/tests/nsas_test.h
index 033df81..2dd95ef 100644
--- a/src/lib/nsas/tests/nsas_test.h
+++ b/src/lib/nsas/tests/nsas_test.h
@@ -27,6 +27,7 @@
#include <config.h>
#include <util/buffer.h>
+#include <util/unittests/resolver.h>
#include <dns/message.h>
#include <dns/rdata.h>
#include <dns/rrtype.h>
@@ -35,24 +36,12 @@
#include <dns/rcode.h>
#include <dns/messagerenderer.h>
#include <dns/rdataclass.h>
-#include <resolve/resolver_interface.h>
#include "../nsas_entry.h"
using namespace isc::dns::rdata;
using namespace isc::dns;
using namespace isc::util;
-
-namespace {
- MessagePtr
- createResponseMessage(RRsetPtr answer_rrset)
- {
- MessagePtr response(new Message(Message::RENDER));
- response->setOpcode(Opcode::QUERY());
- response->setRcode(Rcode::NOERROR());
- response->addRRset(Message::SECTION_ANSWER, answer_rrset);
- return response;
- }
-}
+using isc::util::unittests::TestResolver;
namespace isc {
namespace dns {
@@ -223,139 +212,6 @@ private:
static const uint32_t HASHTABLE_DEFAULT_SIZE = 1009; ///< First prime above 1000
-using namespace std;
-
-/*
- * This pretends to be a resolver. It stores the queries and
- * they can be answered.
- */
-class TestResolver : public isc::resolve::ResolverInterface {
- private:
- bool checkIndex(size_t index) {
- return (requests.size() > index);
- }
-
- typedef std::map<isc::dns::Question, RRsetPtr >
- PresetAnswers;
- PresetAnswers answers_;
- public:
- typedef pair<QuestionPtr, CallbackPtr> Request;
- vector<Request> requests;
-
- /// \brief Destructor
- ///
- /// This is important. All callbacks in the requests vector must be
- /// called to remove them from internal loops. Without this, destroying
- /// the NSAS object will leave memory assigned.
- ~TestResolver() {
- for (size_t i = 0; i < requests.size(); ++i) {
- requests[i].second->failure();
- }
- }
-
- virtual void resolve(const QuestionPtr& q, const CallbackPtr& c) {
- PresetAnswers::iterator it(answers_.find(*q));
- if (it == answers_.end()) {
- requests.push_back(Request(q, c));
- } else {
- if (it->second) {
- c->success(createResponseMessage(it->second));
- } else {
- c->failure();
- }
- }
- }
-
- /*
- * Add a preset answer. If shared_ptr() is passed (eg. NULL),
- * it will generate failure. If the question is not preset,
- * it goes to requests and you can answer later.
- */
- void addPresetAnswer(const isc::dns::Question& question,
- RRsetPtr answer)
- {
- answers_[question] = answer;
- }
-
- // Thrown if the query at the given index does not exist.
- class NoSuchRequest : public std::exception { };
-
- // Thrown if the answer does not match the query
- class DifferentRequest : public std::exception { };
-
- QuestionPtr operator[](size_t index) {
- if (index >= requests.size()) {
- throw NoSuchRequest();
- }
- return (requests[index].first);
- }
- /*
- * Looks if the two provided requests in resolver are A and AAAA.
- * Sorts them so index1 is A.
- *
- * Returns false if there aren't enough elements
- */
- bool asksIPs(const Name& name, size_t index1, size_t index2) {
- size_t max = (index1 < index2) ? index2 : index1;
- if (!checkIndex(max)) {
- return false;
- }
- EXPECT_EQ(name, (*this)[index1]->getName());
- EXPECT_EQ(name, (*this)[index2]->getName());
- EXPECT_EQ(RRClass::IN(), (*this)[index1]->getClass());
- EXPECT_EQ(RRClass::IN(), (*this)[index2]->getClass());
- // If they are the other way around, swap
- if ((*this)[index1]->getType() == RRType::AAAA() &&
- (*this)[index2]->getType() == RRType::A())
- {
- TestResolver::Request tmp((*this).requests[index1]);
- (*this).requests[index1] =
- (*this).requests[index2];
- (*this).requests[index2] = tmp;
- }
- // Check the correct addresses
- EXPECT_EQ(RRType::A(), (*this)[index1]->getType());
- EXPECT_EQ(RRType::AAAA(), (*this)[index2]->getType());
- return (true);
- }
-
- /*
- * Sends a simple answer to a query.
- * 1) Provide index of a query and the address(es) to pass.
- * 2) Provide index of query and components of address to pass.
- */
- void answer(size_t index, RRsetPtr& set) {
- if (index >= requests.size()) {
- throw NoSuchRequest();
- }
- requests[index].second->success(createResponseMessage(set));
- }
-
- void answer(size_t index, const Name& name, const RRType& type,
- const rdata::Rdata& rdata, size_t TTL = 100)
- {
- RRsetPtr set(new RRset(name, RRClass::IN(),
- type, RRTTL(TTL)));
- set->addRdata(rdata);
- answer(index, set);
- }
-
-
- void provideNS(size_t index,
- RRsetPtr nameservers)
- {
- if (index >= requests.size()) {
- throw NoSuchRequest();
- }
- if (requests[index].first->getName() != nameservers->getName() ||
- requests[index].first->getType() != RRType::NS())
- {
- throw DifferentRequest();
- }
- requests[index].second->success(createResponseMessage(nameservers));
- }
-};
-
// String constants. These should end in a dot.
static const std::string EXAMPLE_CO_UK("example.co.uk.");
static const std::string EXAMPLE_NET("example.net.");
diff --git a/src/lib/resolve/recursive_query.cc b/src/lib/resolve/recursive_query.cc
index c0d5ee6..34411ee 100644
--- a/src/lib/resolve/recursive_query.cc
+++ b/src/lib/resolve/recursive_query.cc
@@ -28,6 +28,7 @@
#include <dns/message.h>
#include <dns/opcode.h>
#include <dns/exceptions.h>
+#include <dns/rdataclass.h>
#include <resolve/resolve.h>
#include <cache/resolver_cache.h>
@@ -48,6 +49,65 @@ using namespace isc::asiolink;
namespace isc {
namespace asiodns {
+namespace {
+// Function to check if the given name/class has any address in the cache
+bool
+hasAddress(const Name& name, const RRClass& rrClass,
+ const isc::cache::ResolverCache& cache)
+{
+ // FIXME: If we are single-stack and we get only the other type of
+ // address, what should we do? In that case, it will be considered
+ // unreachable, which is most probably true, because A and AAAA will
+ // usually have the same RTT, so we should have both or none from the
+ // glue.
+ return (cache.lookup(name, RRType::A(), rrClass) != RRsetPtr() ||
+ cache.lookup(name, RRType::AAAA(), rrClass) != RRsetPtr());
+}
+
+}
+
+/// \brief Find deepest usable delegation in the cache
+///
+/// This finds the deepest delegation we have in cache and is safe to use.
+/// It is not public function, therefore it's not in header. But it's not
+/// in anonymous namespace, so we can call it from unittests.
+/// \param name The name we want to delegate to.
+/// \param cache The place too look for known delegations.
+std::string
+deepestDelegation(Name name, RRClass rrclass,
+ isc::cache::ResolverCache& cache)
+{
+ RRsetPtr cachedNS;
+ // Look for delegation point from bottom, until we find one with
+ // IP address or get to root.
+ //
+ // We need delegation with IP address so we can ask it right away.
+ // If we don't have the IP address, we would need to ask above it
+ // anyway in the best case, and the NS could be inside the zone,
+ // and we could get all loopy with the NSAS in the worst case.
+ while (name.getLabelCount() > 1 &&
+ (cachedNS = cache.lookupDeepestNS(name, rrclass)) != RRsetPtr()) {
+ // Look if we have an IP address for the NS
+ for (RdataIteratorPtr ns(cachedNS->getRdataIterator());
+ !ns->isLast(); ns->next()) {
+ // Do we have IP for this specific NS?
+ if (hasAddress(dynamic_cast<const rdata::generic::NS&>(
+ ns->getCurrent()).getNSName(), rrclass,
+ cache)) {
+ // Found one, stop checking and use this zone
+ // (there may be more addresses, that's only better)
+ return (cachedNS->getName().toText());
+ }
+ }
+ // We don't have anything for this one, so try something higher
+ if (name.getLabelCount() > 1) {
+ name = name.split(1);
+ }
+ }
+ // Fallback, nothing found, start at root
+ return (".");
+}
+
typedef std::vector<std::pair<std::string, uint16_t> > AddressVector;
// Here we do not use the typedef above, as the SunStudio compiler
@@ -239,7 +299,6 @@ private:
// if we have a response for our query stored already. if
// so, call handlerecursiveresponse(), if not, we call send()
void doLookup() {
- cur_zone_ = ".";
dlog("doLookup: try cache");
Message cached_message(Message::RENDER);
isc::resolve::initResponseMessage(question_, cached_message);
@@ -255,9 +314,12 @@ private:
stop();
}
} else {
+ dlog("doLookup: get lowest usable delegation from cache");
+ cur_zone_ = deepestDelegation(question_.getName(),
+ question_.getClass(), cache_);
send();
}
-
+
}
// Send the current question to the given nameserver address
diff --git a/src/lib/resolve/tests/recursive_query_unittest.cc b/src/lib/resolve/tests/recursive_query_unittest.cc
index 3338893..04a7803 100644
--- a/src/lib/resolve/tests/recursive_query_unittest.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest.cc
@@ -31,7 +31,9 @@
#include <dns/rcode.h>
#include <util/buffer.h>
+#include <util/unittests/resolver.h>
#include <dns/message.h>
+#include <dns/rdataclass.h>
#include <nsas/nameserver_address_store.h>
#include <cache/resolver_cache.h>
@@ -59,6 +61,18 @@ using namespace isc::asiolink;
using namespace isc::dns;
using namespace isc::util;
+namespace isc {
+namespace asiodns {
+
+// This is defined in recursive_query.cc, but not in header (it's not public
+// function). So bring it in to be tested.
+std::string
+deepestDelegation(Name name, RRClass rrclass,
+ isc::cache::ResolverCache& cache);
+
+}
+}
+
namespace {
const char* const TEST_SERVER_PORT = "53535";
const char* const TEST_CLIENT_PORT = "53536";
@@ -110,6 +124,9 @@ class RecursiveQueryTest : public ::testing::Test {
protected:
RecursiveQueryTest();
~RecursiveQueryTest() {
+ // It would delete itself, but after the io_service_, which could
+ // segfailt in case there were unhandled requests
+ resolver_.reset();
if (res_ != NULL) {
freeaddrinfo(res_);
}
@@ -348,12 +365,6 @@ protected:
private:
bool* done_;
};
-
- class MockResolver : public isc::resolve::ResolverInterface {
- void resolve(const QuestionPtr& question,
- const ResolverInterface::CallbackPtr& callback) {
- }
- };
// This version of mock server just stops the io_service when it is resumed
// the second time. (Used in the clientTimeout test, where resume
@@ -423,16 +434,17 @@ protected:
vector<uint8_t> callback_data_;
int sock_;
struct addrinfo* res_;
+ boost::shared_ptr<isc::util::unittests::TestResolver> resolver_;
};
RecursiveQueryTest::RecursiveQueryTest() :
dns_service_(NULL), callback_(NULL), callback_protocol_(0),
- callback_native_(-1), sock_(-1), res_(NULL)
+ callback_native_(-1), sock_(-1), res_(NULL),
+ resolver_(new isc::util::unittests::TestResolver())
{
io_service_ = new IOService();
setDNSService(true, true);
- boost::shared_ptr<MockResolver>mock_resolver(new MockResolver());
- nsas_ = new isc::nsas::NameserverAddressStore(mock_resolver);
+ nsas_ = new isc::nsas::NameserverAddressStore(resolver_);
}
TEST_F(RecursiveQueryTest, v6UDPSend) {
@@ -857,7 +869,88 @@ TEST_F(RecursiveQueryTest, DISABLED_recursiveSendNXDOMAIN) {
EXPECT_EQ(0, answer->getRRCount(Message::SECTION_ANSWER));
}
+// Test that we don't start at root when we have a lower NS cached.
+TEST_F(RecursiveQueryTest, CachedNS) {
+ setDNSService(true, true);
+
+ // Check we have a reasonable fallback - if there's nothing of interest
+ // in the cache, start at root.
+ EXPECT_EQ(".", deepestDelegation(Name("www.somewhere.deep.example.org"),
+ RRClass::IN(), cache_));
+
+ // Prefill the cache. There's a zone with a NS and IP address for one
+ // of them (to see that one is enough) and another deeper one, with NS,
+ // but without IP.
+ RRsetPtr nsUpper(new RRset(Name("example.org"), RRClass::IN(),
+ RRType::NS(), RRTTL(300)));
+ nsUpper->addRdata(rdata::generic::NS(Name("ns.example.org")));
+ nsUpper->addRdata(rdata::generic::NS(Name("ns2.example.org")));
+
+ RRsetPtr nsLower(new RRset(Name("somewhere.deep.example.org"),
+ RRClass::IN(), RRType::NS(), RRTTL(300)));
+ nsLower->addRdata(rdata::generic::NS(Name("ns.somewhere.deep.example.org"))
+ );
+
+ RRsetPtr nsIp(new RRset(Name("ns2.example.org"), RRClass::IN(),
+ RRType::A(), RRTTL(300)));
+ nsIp->addRdata(rdata::in::A("192.0.2.1"));
+
+ // Make sure the test runs in the correct environment (we don't test
+ // the cache, but we need it to unswer this way for the test, so we
+ // just make sure)
+ ASSERT_TRUE(cache_.update(nsUpper));
+ ASSERT_TRUE(cache_.update(nsLower));
+ ASSERT_TRUE(cache_.update(nsIp));
+ RRsetPtr deepest(cache_.lookupDeepestNS(Name(
+ "www.somewhere.deep.example.org"), RRClass::IN()));
+ ASSERT_NE(RRsetPtr(), deepest);
+ ASSERT_EQ(nsLower->getName(), deepest->getName());
+
+ // Direct check of the function that chooses the delegation point
+ // It should not use nsLower, because we don't have IP address for
+ // that one. But it can choose nsUpper.
+ EXPECT_EQ("example.org.",
+ deepestDelegation(Name("www.somewhere.deep.example.org"),
+ RRClass::IN(), cache_));
+
+ // Now more complex and indirect test:
+ // We ask it to resolve the name for us. It will pick up a delegation
+ // point and ask NSAS for it. NSAS will in turn ask resolver for NS record
+ // of the delegation point. We then pick it up from the fake resolver
+ // and check it is the correct one. This checks the delegation point
+ // travels safely trough the whole path there (it would be enough to check
+ // it up to NSAS, but replacing NSAS is more complicated, so we just
+ // include in the test as well for simplicity).
+
+ // Prepare the recursive query
+ vector<pair<string, uint16_t> > roots;
+ roots.push_back(pair<string, uint16_t>("192.0.2.2", 53));
+
+ RecursiveQuery rq(*dns_service_, *nsas_, cache_,
+ vector<pair<string, uint16_t> >(), roots);
+ // Ask a question at the bottom. It should not use the lower NS, because
+ // it would lead to a loop in NS. But it can use the nsUpper one, it has
+ // an IP address and we can avoid asking root.
+ Question q(Name("www.somewhere.deep.example.org"), RRClass::IN(),
+ RRType::A());
+ OutputBufferPtr buffer(new OutputBuffer(0));
+ MessagePtr answer(new Message(Message::RENDER));
+ // The server is here so we have something to pass there
+ MockServer server(*io_service_);
+ rq.resolve(q, answer, buffer, &server);
+ // We don't need to run the service in this test. We are interested only
+ // in the place it starts resolving at
+
+ // Look what is asked by NSAS - it should be our delegation point.
+ EXPECT_NO_THROW(EXPECT_EQ(nsUpper->getName(),
+ (*resolver_)[0]->getName()) <<
+ "It starts resolving at the wrong place") <<
+ "It does not ask NSAS anything, how does it know where to send?";
+}
+
// TODO: add tests that check whether the cache is updated on succesfull
// responses, and not updated on failures.
+
+
}
diff --git a/src/lib/util/unittests/Makefile.am b/src/lib/util/unittests/Makefile.am
index e7cb447..84d7d21 100644
--- a/src/lib/util/unittests/Makefile.am
+++ b/src/lib/util/unittests/Makefile.am
@@ -2,7 +2,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CXXFLAGS = $(B10_CXXFLAGS)
lib_LTLIBRARIES = libutil_unittests.la
-libutil_unittests_la_SOURCES = fork.h fork.cc
+libutil_unittests_la_SOURCES = fork.h fork.cc resolver.h
libutil_unittests_la_SOURCES += newhook.h newhook.cc
CLEANFILES = *.gcno *.gcda
diff --git a/src/lib/util/unittests/newhook.cc b/src/lib/util/unittests/newhook.cc
index b9d9fb6..9e545a5 100644
--- a/src/lib/util/unittests/newhook.cc
+++ b/src/lib/util/unittests/newhook.cc
@@ -36,7 +36,7 @@ operator new(size_t size) throw(std::bad_alloc) {
void
operator delete(void* p) throw() {
if (p != NULL) {
- free (p);
+ free(p);
}
}
#endif
diff --git a/src/lib/util/unittests/newhook.h b/src/lib/util/unittests/newhook.h
index b0dbb64..7eb8ade 100644
--- a/src/lib/util/unittests/newhook.h
+++ b/src/lib/util/unittests/newhook.h
@@ -61,6 +61,12 @@ extern bool force_throw_on_new;
/// The allocation size that triggers an exception in the special operator new
///
+/// This is the exact size that causes an exception to be thrown;
+/// for example, if it is set to 100, an attempt of allocating 100 bytes
+/// will result in an exception, but allocation attempt for 101 bytes won't
+/// (unless, of course, memory is really exhausted and allocation really
+/// fails).
+///
/// The default value is 0. The value of this variable has no meaning
/// unless the use of the special operator is enabled at build time and
/// via \c force_throw_on_new.
diff --git a/src/lib/util/unittests/resolver.h b/src/lib/util/unittests/resolver.h
new file mode 100644
index 0000000..560a892
--- /dev/null
+++ b/src/lib/util/unittests/resolver.h
@@ -0,0 +1,193 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef UTIL_UNITTEST_RESOLVER_H
+#define UTIL_UNITTEST_RESOLVER_H
+
+/// \file resolver.h
+/// \brief Fake resolver
+
+#include <map>
+#include <dns/rrset.h>
+#include <dns/question.h>
+#include <dns/message.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <dns/rrttl.h>
+#include <resolve/resolver_interface.h>
+#include <gtest/gtest.h>
+
+namespace isc {
+namespace util {
+namespace unittests {
+
+/// \brief Put rrset into a message as an answer
+inline static isc::dns::MessagePtr
+createResponseMessage(isc::dns::RRsetPtr answer_rrset)
+{
+ isc::dns::MessagePtr response(new isc::dns::Message(
+ isc::dns::Message::RENDER));
+ response->setOpcode(isc::dns::Opcode::QUERY());
+ response->setRcode(isc::dns::Rcode::NOERROR());
+ response->addRRset(isc::dns::Message::SECTION_ANSWER, answer_rrset);
+ return response;
+}
+
+/// \brief Mock resolver
+///
+/// This class pretends to be a resolver. However, it only stores the
+/// requests and can answer them right away by prepared answers. It doesn't
+/// do any real work and is intended for testing purposes.
+class TestResolver : public isc::resolve::ResolverInterface {
+ private:
+ bool checkIndex(size_t index) {
+ return (requests.size() > index);
+ }
+
+ typedef std::map<isc::dns::Question, isc::dns::RRsetPtr>
+ PresetAnswers;
+ PresetAnswers answers_;
+ public:
+ typedef std::pair<isc::dns::QuestionPtr, CallbackPtr> Request;
+ /// \brief List of requests the tested class sent trough resolve
+ std::vector<Request> requests;
+
+ /// \brief Destructor
+ ///
+ /// This is important. All callbacks in the requests vector must be
+ /// called to remove them from internal loops. Without this, destroying
+ /// the NSAS object will leave memory assigned.
+ ~TestResolver() {
+ for (size_t i = 0; i < requests.size(); ++i) {
+ requests[i].second->failure();
+ }
+ }
+
+ /// \brief Testing version of resolve
+ ///
+ /// If there's a prepared answer (provided by addPresetAnswer), it
+ /// answers it right away. Otherwise it just stores the request in
+ /// the requests member so it can be examined later.
+ virtual void resolve(const isc::dns::QuestionPtr& q,
+ const CallbackPtr& c)
+ {
+ PresetAnswers::iterator it(answers_.find(*q));
+ if (it == answers_.end()) {
+ requests.push_back(Request(q, c));
+ } else {
+ if (it->second) {
+ c->success(createResponseMessage(it->second));
+ } else {
+ c->failure();
+ }
+ }
+ }
+
+ /// \brief Add a preset answer.
+ ///
+ /// Add a preset answer. If shared_ptr() is passed (eg. NULL),
+ /// it will generate failure. If the question is not preset,
+ /// it goes to requests and you can answer later.
+ void addPresetAnswer(const isc::dns::Question& question,
+ isc::dns::RRsetPtr answer)
+ {
+ answers_[question] = answer;
+ }
+
+ /// \brief Thrown if the query at the given index does not exist.
+ class NoSuchRequest : public std::exception { };
+
+ /// \brief Thrown if the answer does not match the query
+ class DifferentRequest : public std::exception { };
+
+ /// \brief Provides the question of request on given answer
+ isc::dns::QuestionPtr operator[](size_t index) {
+ if (index >= requests.size()) {
+ throw NoSuchRequest();
+ }
+ return (requests[index].first);
+ }
+ /// \brief Test it asks for IP addresses
+ /// Looks if the two provided requests in resolver are A and AAAA.
+ /// Sorts them so index1 is A.
+ ///
+ /// Returns false if there aren't enough elements
+ bool asksIPs(const isc::dns::Name& name, size_t index1,
+ size_t index2)
+ {
+ size_t max = (index1 < index2) ? index2 : index1;
+ if (!checkIndex(max)) {
+ return false;
+ }
+ EXPECT_EQ(name, (*this)[index1]->getName());
+ EXPECT_EQ(name, (*this)[index2]->getName());
+ EXPECT_EQ(isc::dns::RRClass::IN(), (*this)[index1]->getClass());
+ EXPECT_EQ(isc::dns::RRClass::IN(), (*this)[index2]->getClass());
+ // If they are the other way around, swap
+ if ((*this)[index1]->getType() == isc::dns::RRType::AAAA() &&
+ (*this)[index2]->getType() == isc::dns::RRType::A())
+ {
+ TestResolver::Request tmp((*this).requests[index1]);
+ (*this).requests[index1] =
+ (*this).requests[index2];
+ (*this).requests[index2] = tmp;
+ }
+ // Check the correct addresses
+ EXPECT_EQ(isc::dns::RRType::A(), (*this)[index1]->getType());
+ EXPECT_EQ(isc::dns::RRType::AAAA(), (*this)[index2]->getType());
+ return (true);
+ }
+
+ /// \brief Answer a request
+ /// Sends a simple answer to a query.
+ /// 1) Provide index of a query and the address(es) to pass.
+ /// 2) Provide index of query and components of address to pass.
+ void answer(size_t index, isc::dns::RRsetPtr& set) {
+ if (index >= requests.size()) {
+ throw NoSuchRequest();
+ }
+ requests[index].second->success(createResponseMessage(set));
+ }
+
+ void answer(size_t index, const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ const isc::dns::rdata::Rdata& rdata, size_t TTL = 100)
+ {
+ isc::dns::RRsetPtr set(new isc::dns::RRset(name,
+ isc::dns::RRClass::IN(),
+ type,
+ isc::dns::RRTTL(TTL)));
+ set->addRdata(rdata);
+ answer(index, set);
+ }
+ /// \Answer the query at index by list of nameservers
+ void provideNS(size_t index, isc::dns::RRsetPtr nameservers)
+ {
+ if (index >= requests.size()) {
+ throw NoSuchRequest();
+ }
+ if (requests[index].first->getName() != nameservers->getName() ||
+ requests[index].first->getType() != isc::dns::RRType::NS())
+ {
+ throw DifferentRequest();
+ }
+ requests[index].second->success(createResponseMessage(nameservers));
+ }
+};
+
+}
+}
+}
+
+#endif
More information about the bind10-changes
mailing list