BIND 10 trac744, updated. 80c0a2c3eec3ac5d3ac862f9b4c5926f0eece6ed [trac744] Logging enhancements
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri May 6 12:33:57 UTC 2011
The branch, trac744 has been updated
via 80c0a2c3eec3ac5d3ac862f9b4c5926f0eece6ed (commit)
via 11439c030741ce402c52ad9d3cd1a407d45a443e (commit)
via e564debcb683454296d3e3cf478748daa0b08cbc (commit)
via fba4ec1d7269284b48042b1a7ea084b531bf8d9c (commit)
via cccc20cac1d91951bd9b707c3dfb532e9ad8686b (commit)
via 68c9545bb7d57933e514ef55779abfd06c38145b (commit)
via 2cf390147f147dfab2c8c63c470177189799ed20 (commit)
via b5646b50e23e6049f233f755d7e143a09d4fb19c (commit)
via d4d910b28b3226d1330b7da1df170c406771b939 (commit)
via 7bb5dc265a830d8993c9cb1da55194631e657587 (commit)
via 1e3c154cd21cede83a8bbd7a559c20752b58ce24 (commit)
via 7c40e60eeaad7f2c1ea79f92e866dee08eafd5ab (commit)
via fcc1b5e13946c5e58e2bd0bf287f551e161f0544 (commit)
via b6d140b6169c130b06896d2b40df58752991a47d (commit)
via eab5008d28b04fdd7c0f4c93051fd3b1c1a416f7 (commit)
via 121d3e844ad6d8ed8aa21dd48c53095e2f770117 (commit)
via c3dad479414b01979693ba71c832aedd681f5044 (commit)
via a23491a635d7f74132fc0b91eac832275f8f1f87 (commit)
via db0ca2fbc64b390f261b5e36938c736321b171f9 (commit)
via 2aca19e705f02400a6b213ef84fa81c86dff0375 (commit)
via cf46f370333b15487f6c02f85749d90c2e0bd710 (commit)
via 50ebc839b1c8389eb1b7b70f02758a9034138552 (commit)
via ac7ff7f2226bdba60809b70caa82659b77c6e2e6 (commit)
via 677cebce1708ba85e46a0712d939176dc7ab7a94 (commit)
via f0fe344b15c3e1be2604201000e6c9fbe6a910bc (commit)
via 9e183cb0529aeb9f0674b5727affa223d8fc9db5 (commit)
via e34dd62b8eca7abfbfd4851140d663efc43041f1 (commit)
via d033a50a7e32664848c360b160e9170cdcd79886 (commit)
via c8b7abc5751b171621be9edd5156dd2691ff60d1 (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 d9433ad4bd9aec1028b9b05aa55e9b083e35a4d4 (commit)
via 9df42279a47eb617f586144dce8cce680598558a (commit)
via 05c6223cf7f145ec6e96cffed0561a03387b7367 (commit)
via fd45c40964a9557c0a6534c6d0cbe5c377d05066 (commit)
via 475e26bae3b3c4c8823c4931638d0a7af0ac66cd (commit)
via f4ad75548592b2f3eeae22de5685cacbf5c82bae (commit)
via dabf205231ff9e720d8693800e311a89ace18488 (commit)
via ed5025a1322aec3c6aa2855ec807bdcb8e013f1d (commit)
via e4034daa010c24286b969cd9ad6d75c30895cd52 (commit)
via 0660b35c79dce9ff27361fee48da8c174bf05cd5 (commit)
via 3e37899f95fe561fee0a73fb5d85071065ef3c7d (commit)
via 088bb8cbca563a17b97166bcbb799fd50bbbca4f (commit)
via f099c11348b7947c64f7467677e9afa58ca7023c (commit)
via ad134794bd3fdbb058fe5d50d8e92c71d03d47cc (commit)
via 5cd716bd9844e154e6ca58a981787614a3a6fe6c (commit)
via adfd1014c34da20e272f058c9cce43130c637071 (commit)
via 65874313065ddb02756d5ef06c8802c7540c17c7 (commit)
via 00e36b253bd643b007f89a8ccb3addac1a723eba (commit)
via 7be4a7e7f859881a3e5a3f4268dbdbc3468b7214 (commit)
via 6c274fd95d3c2bcc99113108f5a68aa0364f924c (commit)
via a1703e5ae5fc9458c066fb4aab7666bf4e5fdb8a (commit)
via 145a6173191e6cd39be3d495a6e5d0511dfe867a (commit)
via fb7877b06ba873d4fb222409dd92b4701ae11ffb (commit)
via 20336851f494ff1d9c8937400a99ed4d0203a340 (commit)
via 246e56b3bb7792789b3aa891e21e580976d9e7be (commit)
via 168bed01625dd25fc2c40bd6b402763849e840ec (commit)
via e831ffa2129fc5e013a0217f004896f6f40f258e (commit)
via 4eda7bbc802b24730eb8ef9e5716fc47f19d5a00 (commit)
via 122d477847f80c7d77bec087a849b9e6743c17d3 (commit)
via e74f6d5e8f9abb081bde606bc46319488c7e546b (commit)
via f137e0fa3a387fcc13898ea6da6b61dcd80dc8ef (commit)
via cf456aa1546145ac403e75535e555d773b39ff20 (commit)
via 006b2ea9dabd869bc05682b73b083ea815d520db (commit)
via c34d8eb763ceb840f65de77a22eb67c8b1ab6392 (commit)
via 2aa47d167c58b6718706f8e037927b824ff0cf00 (commit)
via 604e90d1e0c928cc8d94146beea6e24fe2252eec (commit)
via dcf58b7836e854107438368905576de7d29e0e3b (commit)
via f4f11a9b1c09adb07e2d6b99a0bd342d5a75ea3f (commit)
via 74e6966d7f8f8216dad871f1648cab977fb9fea2 (commit)
via 0334c1798ea43061494a530d8bc274283f1f1fc7 (commit)
via 40f4efbbd9f5685147cd1abf19d12c336bc1b8d9 (commit)
via a57662d6db020dd0b334472b5bb7ea88aefb6a7d (commit)
via 122d9611bd552c3113eca8aa5e91d2b8a3018210 (commit)
via 231b29911894b0f5ddbd0d1444d9dfdf9cb5abb3 (commit)
via 4d55533790df1992aee5c088d4f91593d055c080 (commit)
via c374a5c5a329a307346be02d5b884ab57e1cb8c1 (commit)
via cd3ce64ac0ac3e82ba905f3eea77f1040b7e69b8 (commit)
via 24aa99548a4164d2c57adcf3829cc50f1fd34de5 (commit)
via aa0ddfbb4f0aa61cfee383f5459c2183b353674b (commit)
via 4f1d8d0f2ce99880306f7926a23b28f1aa8e4fd9 (commit)
via a7c4e0bc10a5430008d12081f4cb30d1d0d26723 (commit)
via 3987357f56e0fc2feca75001b963a11f1b7120ff (commit)
via 6cece2fc1d8a086b65421a583cf35b40f6ee1751 (commit)
via 400d3b61a32c0fc47c5f41a93ea649fbde6a5445 (commit)
via fac1bf01a628b3b922af67cdd94f05257b6eef9a (commit)
via 34ba5055b70c9de09d406b3e51ad2e02b98f6439 (commit)
via 238dca82160452df0eb732ce014166777380767e (commit)
via 253d063204f1e0656c89650999c76f942b4840f6 (commit)
via 817462f1ea1f1e9b4e05b2da90b8d311a7b59843 (commit)
via 30ab4cfbd7f0744653248efc5635c68930359eea (commit)
via 97feb3a88bae42f4051cd67384a4dc7dcd018c9a (commit)
via b78eefc13bc53a301327674a10d88cb917d6f28d (commit)
via 34d2f102aedbdb6b818f8eb8deb1e00fe431dae4 (commit)
via 6eab8b3fc5922c7b9c6403f4510b929544eafe30 (commit)
via e29c4f167f9d466eb9310989e836a0be428e5ace (commit)
via 992f3702aad9c83836af20d32e96313ff22cde3b (commit)
via 150914707089969bde30fbc6276abc00f3211ba3 (commit)
from 287ee379ad62f9043699c936dc1204b6a906f52c (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 80c0a2c3eec3ac5d3ac862f9b4c5926f0eece6ed
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri May 6 13:34:47 2011 +0200
[trac744] Logging enhancements
Some texts of messages and parameters.
commit 11439c030741ce402c52ad9d3cd1a407d45a443e
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri May 6 13:15:45 2011 +0200
[trac744] Typos
commit e564debcb683454296d3e3cf478748daa0b08cbc
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri May 6 13:11:18 2011 +0200
[trac744] Decapitalise beginnings of messages
(Or should it be 'decapitate'?)
commit fba4ec1d7269284b48042b1a7ea084b531bf8d9c
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri May 6 13:05:31 2011 +0200
[trac744] Update the message deffinitions to %1
commit cccc20cac1d91951bd9b707c3dfb532e9ad8686b
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri May 6 12:57:58 2011 +0200
[trac744] Update to new logging interface
commit 68c9545bb7d57933e514ef55779abfd06c38145b
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri May 6 11:26:37 2011 +0200
[trac744] Avoid lexical cast if possible
commit 2cf390147f147dfab2c8c63c470177189799ed20
Merge: 287ee379ad62f9043699c936dc1204b6a906f52c b5646b50e23e6049f233f755d7e143a09d4fb19c
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri May 6 11:01:21 2011 +0200
Merge branch 'work/logpos' into work/log/datasrc
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 14 +
configure.ac | 88 ++++-
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/bin/xfrin/tests/Makefile.am | 2 +-
src/bin/xfrout/tests/Makefile.am | 2 +-
src/cppcheck-suppress.lst | 2 +-
src/lib/Makefile.am | 5 +-
src/lib/asiodns/Makefile.am | 11 +-
src/lib/asiodns/asiodef.cc | 39 --
src/lib/asiodns/asiodef.h | 23 -
src/lib/asiodns/asiodef.msg | 16 +-
src/lib/asiodns/io_fetch.cc | 40 +-
src/lib/asiolink/Makefile.am | 1 -
src/lib/asiolink/tests/Makefile.am | 4 -
src/lib/asiolink/tests/run_unittests.cc | 1 -
src/lib/cc/tests/Makefile.am | 1 -
src/lib/cryptolink/Makefile.am | 14 +
src/lib/cryptolink/crypto_hmac.cc | 237 +++++++++
src/lib/cryptolink/crypto_hmac.h | 209 ++++++++
src/lib/cryptolink/cryptolink.cc | 69 +++
src/lib/cryptolink/cryptolink.h | 204 ++++++++
.../{exceptions => cryptolink}/tests/Makefile.am | 11 +-
src/lib/cryptolink/tests/crypto_unittests.cc | 511 ++++++++++++++++++++
.../{util => cryptolink}/tests/run_unittests.cc | 1 +
src/lib/datasrc/cache.cc | 26 +-
src/lib/datasrc/data_source.cc | 145 ++----
src/lib/datasrc/memory_datasrc.cc | 110 ++---
src/lib/datasrc/messagedef.mes | 261 +++++-----
src/lib/datasrc/sqlite3_datasrc.cc | 73 +--
src/lib/datasrc/static_datasrc.cc | 6 +-
src/lib/dns/Makefile.am | 63 ++--
src/lib/dns/edns.h | 2 +-
src/lib/dns/python/tests/Makefile.am | 2 +-
src/lib/dns/python/tests/tsigkey_python_test.py | 22 +
src/lib/dns/python/tsigkey_python.cc | 40 +-
src/lib/dns/tests/Makefile.am | 4 +
src/lib/dns/tests/tsig_unittest.cc | 505 +++++++++++++++++++
src/lib/dns/tests/tsigerror_unittest.cc | 102 ++++
src/lib/dns/tests/tsigkey_unittest.cc | 43 ++
src/lib/dns/tsig.cc | 232 +++++++++
src/lib/dns/tsig.h | 302 ++++++++++++
src/lib/{asiolink/io_error.h => dns/tsigerror.cc} | 52 ++-
src/lib/dns/tsigerror.h | 328 +++++++++++++
src/lib/dns/tsigkey.cc | 96 ++++-
src/lib/dns/tsigkey.h | 36 ++
src/lib/log/Makefile.am | 2 +
src/lib/log/README | 10 +-
src/lib/log/compiler/message.cc | 7 +-
.../log/{root_logger_name.cc => log_formatter.cc} | 39 +-
src/lib/log/log_formatter.h | 171 +++++++
src/lib/log/logger.cc | 63 ++--
src/lib/log/logger.h | 25 +-
src/lib/log/logger_impl.cc | 19 +-
src/lib/log/logger_impl.h | 62 +---
src/lib/log/logger_support.cc | 10 +-
src/lib/log/macros.h | 48 ++
src/lib/log/messagedef.cc | 24 +-
src/lib/log/messagedef.h | 2 +-
src/lib/log/messagedef.mes | 22 +-
src/lib/log/tests/Makefile.am | 1 +
src/lib/log/tests/log_formatter_unittest.cc | 112 +++++
src/lib/log/tests/logger_support_test.cc | 17 +-
src/lib/log/tests/run_time_init_test.sh.in | 4 +-
src/lib/python/isc/notify/tests/Makefile.am | 2 +-
src/lib/util/unittests/Makefile.am | 1 +
.../unittests/newhook.cc} | 55 ++-
src/lib/util/unittests/newhook.h | 82 ++++
77 files changed, 4002 insertions(+), 768 deletions(-)
mode change 100644 => 100755 src/bin/bind10/run_bind10.sh.in
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
delete mode 100644 src/lib/asiodns/asiodef.cc
delete mode 100644 src/lib/asiodns/asiodef.h
create mode 100644 src/lib/cryptolink/Makefile.am
create mode 100644 src/lib/cryptolink/crypto_hmac.cc
create mode 100644 src/lib/cryptolink/crypto_hmac.h
create mode 100644 src/lib/cryptolink/cryptolink.cc
create mode 100644 src/lib/cryptolink/cryptolink.h
copy src/lib/{exceptions => cryptolink}/tests/Makefile.am (61%)
create mode 100644 src/lib/cryptolink/tests/crypto_unittests.cc
copy src/lib/{util => cryptolink}/tests/run_unittests.cc (99%)
create mode 100644 src/lib/dns/tests/tsig_unittest.cc
create mode 100644 src/lib/dns/tests/tsigerror_unittest.cc
create mode 100644 src/lib/dns/tsig.cc
create mode 100644 src/lib/dns/tsig.h
copy src/lib/{asiolink/io_error.h => dns/tsigerror.cc} (50%)
create mode 100644 src/lib/dns/tsigerror.h
copy src/lib/log/{root_logger_name.cc => log_formatter.cc} (60%)
create mode 100644 src/lib/log/log_formatter.h
create mode 100644 src/lib/log/macros.h
create mode 100644 src/lib/log/tests/log_formatter_unittest.cc
copy src/lib/{log/root_logger_name.cc => util/unittests/newhook.cc} (57%)
create mode 100644 src/lib/util/unittests/newhook.h
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 87f6b15..ae1b5e8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+227. [build] jreed
+ Add missing libdns++ rdata files for the distribution (this
+ fixes distcheck error). Change three generated libdns++
+ headers to "nodist" so they aren't included in the distribution
+ (they were mistakenly included in last tarball).
+
+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 82bd3d7..acd8c93 100644
--- a/configure.ac
+++ b/configure.ac
@@ -374,6 +374,79 @@ if test "$lcov" != "no"; then
fi
AC_SUBST(USE_LCOV)
+# Check for Botan
+botan_path="yes"
+AC_ARG_WITH([botan],
+ AC_HELP_STRING([--with-botan=PATH],
+ [specify exact directory of Botan library]),
+ [botan_path="$withval"])
+if test "${botan_path}" == "no" ; then
+ AC_MSG_ERROR([Need botan for libcryptolink])
+fi
+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)
+
+ # According to the libtool manual, it should be sufficient if we
+ # specify the "-R libdir" in our wrapper library of botan (no other
+ # programs will need libbotan directly); "libdir" should be added to
+ # the program's binary image. But we've seen in our build environments
+ # that (some versions of?) libtool doesn't propagate -R as documented,
+ # and it caused a linker error at run time. To work around this, we
+ # also add the rpath to the global LDFLAGS.
+ LDFLAGS="$BOTAN_RPATH $LDFLAGS"
+ 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>
+ #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([Needs Botan library 1.8 or higher])]
+)
+CPPFLAGS=$CPPFLAGS_SAVED
+LDFLAGS=$LDFLAGS_SAVED
+
#
# Configure Boost header path
#
@@ -673,11 +746,8 @@ AC_CONFIG_FILES([Makefile
src/lib/config/Makefile
src/lib/config/tests/Makefile
src/lib/config/tests/testdata/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/cryptolink/Makefile
+ src/lib/cryptolink/tests/Makefile
src/lib/dns/Makefile
src/lib/dns/tests/Makefile
src/lib/dns/tests/testdata/Makefile
@@ -702,6 +772,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
@@ -818,12 +893,15 @@ Flags:
DEFS: $DEFS
CPPFLAGS: $CPPFLAGS
CXXFLAGS: $CXXFLAGS
+ LDFLAGS: $LDFLAGS
B10_CXXFLAGS: $B10_CXXFLAGS
dnl includes too
Python: ${PYTHON_INCLUDES}
${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 83e85b8..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/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
old mode 100644
new mode 100755
index edc01fe..89301bd
--- 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/cryptolink/.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/bin/xfrin/tests/Makefile.am b/src/bin/xfrin/tests/Makefile.am
index dfa7714..d4efbc7 100644
--- a/src/bin/xfrin/tests/Makefile.am
+++ b/src/bin/xfrin/tests/Makefile.am
@@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS)
# required by loadable python modules.
LIBRARY_PATH_PLACEHOLDER =
if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH)
endif
# test using command-line arguments, so use check-local target instead of TESTS
diff --git a/src/bin/xfrout/tests/Makefile.am b/src/bin/xfrout/tests/Makefile.am
index 1ec3c06..11916af 100644
--- a/src/bin/xfrout/tests/Makefile.am
+++ b/src/bin/xfrout/tests/Makefile.am
@@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS)
# required by loadable python modules.
LIBRARY_PATH_PLACEHOLDER =
if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.libs:$$$(ENV_LIBRARY_PATH)
endif
# test using command-line arguments, so use check-local target instead of 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 81455c4..184b090 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,2 +1,3 @@
-SUBDIRS = exceptions util 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/asiodns/Makefile.am b/src/lib/asiodns/Makefile.am
index 4bcdde6..7beaaa3 100644
--- a/src/lib/asiodns/Makefile.am
+++ b/src/lib/asiodns/Makefile.am
@@ -8,12 +8,17 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
AM_CXXFLAGS = $(B10_CXXFLAGS)
-CLEANFILES = *.gcno *.gcda
+CLEANFILES = *.gcno *.gcda asiodef.h asiodef.cc
+
+# Define rule to build logging source files from message file
+asiodef.h asiodef.cc: asiodef.msg
+ $(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/asiodns/asiodef.msg
+
+BUILT_SOURCES = asiodef.h asiodef.cc
lib_LTLIBRARIES = libasiodns.la
libasiodns_la_SOURCES = dns_answer.h
libasiodns_la_SOURCES += asiodns.h
-libasiodns_la_SOURCES += asiodef.cc asiodef.h
libasiodns_la_SOURCES += dns_lookup.h
libasiodns_la_SOURCES += dns_server.h
libasiodns_la_SOURCES += dns_service.cc dns_service.h
@@ -21,6 +26,8 @@ libasiodns_la_SOURCES += tcp_server.cc tcp_server.h
libasiodns_la_SOURCES += udp_server.cc udp_server.h
libasiodns_la_SOURCES += io_fetch.cc io_fetch.h
+nodist_libasiodns_la_SOURCES = asiodef.cc asiodef.h
+
EXTRA_DIST = asiodef.msg
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
diff --git a/src/lib/asiodns/asiodef.cc b/src/lib/asiodns/asiodef.cc
deleted file mode 100644
index 127e848..0000000
--- a/src/lib/asiodns/asiodef.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// File created from asiodef.msg on Mon Feb 28 17:15:30 2011
-
-#include <cstddef>
-#include <log/message_types.h>
-#include <log/message_initializer.h>
-
-namespace isc {
-namespace asiodns {
-
-extern const isc::log::MessageID ASIODNS_FETCHCOMP = "FETCHCOMP";
-extern const isc::log::MessageID ASIODNS_FETCHSTOP = "FETCHSTOP";
-extern const isc::log::MessageID ASIODNS_OPENSOCK = "OPENSOCK";
-extern const isc::log::MessageID ASIODNS_RECVSOCK = "RECVSOCK";
-extern const isc::log::MessageID ASIODNS_RECVTMO = "RECVTMO";
-extern const isc::log::MessageID ASIODNS_SENDSOCK = "SENDSOCK";
-extern const isc::log::MessageID ASIODNS_UNKORIGIN = "UNKORIGIN";
-extern const isc::log::MessageID ASIODNS_UNKRESULT = "UNKRESULT";
-
-} // namespace asiodns
-} // namespace isc
-
-namespace {
-
-const char* values[] = {
- "FETCHCOMP", "upstream fetch to %s(%d) has now completed",
- "FETCHSTOP", "upstream fetch to %s(%d) has been stopped",
- "OPENSOCK", "error %d opening %s socket to %s(%d)",
- "RECVSOCK", "error %d reading %s data from %s(%d)",
- "RECVTMO", "receive timeout while waiting for data from %s(%d)",
- "SENDSOCK", "error %d sending data using %s to %s(%d)",
- "UNKORIGIN", "unknown origin for ASIO error code %d (protocol: %s, address %s)",
- "UNKRESULT", "unknown result (%d) when IOFetch::stop() was executed for I/O to %s(%d)",
- NULL
-};
-
-const isc::log::MessageInitializer initializer(values);
-
-} // Anonymous namespace
-
diff --git a/src/lib/asiodns/asiodef.h b/src/lib/asiodns/asiodef.h
deleted file mode 100644
index 50aa8a9..0000000
--- a/src/lib/asiodns/asiodef.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// File created from asiodef.msg on Mon Feb 28 17:15:30 2011
-
-#ifndef __ASIODEF_H
-#define __ASIODEF_H
-
-#include <log/message_types.h>
-
-namespace isc {
-namespace asiodns {
-
-extern const isc::log::MessageID ASIODNS_FETCHCOMP;
-extern const isc::log::MessageID ASIODNS_FETCHSTOP;
-extern const isc::log::MessageID ASIODNS_OPENSOCK;
-extern const isc::log::MessageID ASIODNS_RECVSOCK;
-extern const isc::log::MessageID ASIODNS_RECVTMO;
-extern const isc::log::MessageID ASIODNS_SENDSOCK;
-extern const isc::log::MessageID ASIODNS_UNKORIGIN;
-extern const isc::log::MessageID ASIODNS_UNKRESULT;
-
-} // namespace asiodns
-} // namespace isc
-
-#endif // __ASIODEF_H
diff --git a/src/lib/asiodns/asiodef.msg b/src/lib/asiodns/asiodef.msg
index 7f86acb..ea3ec2f 100644
--- a/src/lib/asiodns/asiodef.msg
+++ b/src/lib/asiodns/asiodef.msg
@@ -15,42 +15,42 @@
$PREFIX ASIODNS_
$NAMESPACE isc::asiodns
-FETCHCOMP upstream fetch to %s(%d) has now completed
+FETCHCOMP upstream fetch to %1(%2) has now completed
+ A debug message, this records the the upstream fetch (a query made by the
+ resolver on behalf of its client) to the specified address has completed.
-FETCHSTOP upstream fetch to %s(%d) has been stopped
+FETCHSTOP upstream fetch to %1(%2) has been stopped
+ An external component has requested the halting of an upstream fetch. This
+ is an allowed operation, and the message should only appear if debug is
+ enabled.
-OPENSOCK error %d opening %s socket to %s(%d)
+OPENSOCK error %1 opening %2 socket to %3(%4)
+ The asynchronous I/O code encountered an error when trying to open a socket
+ of the specified protocol in order to send a message to the target address.
+ The the number of the system error that cause the problem is given in the
+ message.
-RECVSOCK error %d reading %s data from %s(%d)
+RECVSOCK error %1 reading %2 data from %3(%4)
+ The asynchronous I/O code encountered an error when trying read data from
+ the specified address on the given protocol. The the number of the system
+ error that cause the problem is given in the message.
-SENDSOCK error %d sending data using %s to %s(%d)
+SENDSOCK error %1 sending data using %2 to %3(%4)
+ The asynchronous I/O code encountered an error when trying send data to
+ the specified address on the given protocol. The the number of the system
+ error that cause the problem is given in the message.
-RECVTMO receive timeout while waiting for data from %s(%d)
+RECVTMO receive timeout while waiting for data from %1(%2)
+ An upstream fetch from the specified address timed out. This may happen for
+ any number of reasons and is most probably a problem at the remote server
+ or a problem on the network. The message will only appear if debug is
+ enabled.
-UNKORIGIN unknown origin for ASIO error code %d (protocol: %s, address %s)
+UNKORIGIN unknown origin for ASIO error code %1 (protocol: %2, address %3)
+ This message should not appear and indicates an internal error if it does.
+ Please enter a bug report.
-UNKRESULT unknown result (%d) when IOFetch::stop() was executed for I/O to %s(%d)
+UNKRESULT unknown result (%1) when IOFetch::stop() was executed for I/O to %2(%3)
+ The termination method of the resolver's upstream fetch class was called with
+ an unknown result code (which is given in the message). This message should
+ not appear and may indicate an internal error. Please enter a bug report.
diff --git a/src/lib/asiodns/io_fetch.cc b/src/lib/asiodns/io_fetch.cc
index 8f57d8e..dd1af75 100644
--- a/src/lib/asiodns/io_fetch.cc
+++ b/src/lib/asiodns/io_fetch.cc
@@ -40,6 +40,7 @@
#include <dns/opcode.h>
#include <dns/rcode.h>
#include <log/logger.h>
+#include <log/macros.h>
#include <asiodns/asiodef.h>
#include <asiodns/io_fetch.h>
@@ -339,34 +340,30 @@ IOFetch::stop(Result result) {
data_->stopped = true;
switch (result) {
case TIME_OUT:
- if (logger.isDebugEnabled(1)) {
- logger.debug(20, ASIODNS_RECVTMO,
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
- }
+ LOG_DEBUG(logger, 20, ASIODNS_RECVTMO).
+ arg(data_->remote_snd->getAddress().toText()).
+ arg(data_->remote_snd->getPort());
break;
case SUCCESS:
- if (logger.isDebugEnabled(50)) {
- logger.debug(30, ASIODNS_FETCHCOMP,
- data_->remote_rcv->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_rcv->getPort()));
- }
+ LOG_DEBUG(logger, 50, ASIODNS_FETCHCOMP).
+ arg(data_->remote_rcv->getAddress().toText()).
+ arg(data_->remote_rcv->getPort());
break;
case STOPPED:
// Fetch has been stopped for some other reason. This is
// allowed but as it is unusual it is logged, but with a lower
// debug level than a timeout (which is totally normal).
- logger.debug(1, ASIODNS_FETCHSTOP,
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
+ LOG_DEBUG(logger, 1, ASIODNS_FETCHSTOP).
+ arg(data_->remote_snd->getAddress().toText()).
+ arg(data_->remote_snd->getPort());
break;
default:
- logger.error(ASIODNS_UNKRESULT, static_cast<int>(result),
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
+ LOG_ERROR(logger, ASIODNS_UNKRESULT).
+ arg(data_->remote_snd->getAddress().toText()).
+ arg(data_->remote_snd->getPort());
}
// Stop requested, cancel and I/O's on the socket and shut it down,
@@ -394,12 +391,11 @@ void IOFetch::logIOFailure(asio::error_code ec) {
(data_->origin == ASIODNS_UNKORIGIN));
static const char* PROTOCOL[2] = {"TCP", "UDP"};
- logger.error(data_->origin,
- ec.value(),
- ((data_->remote_snd->getProtocol() == IPPROTO_TCP) ?
- PROTOCOL[0] : PROTOCOL[1]),
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
+ LOG_ERROR(logger, data_->origin).arg(ec.value()).
+ arg((data_->remote_snd->getProtocol() == IPPROTO_TCP) ?
+ PROTOCOL[0] : PROTOCOL[1]).
+ arg(data_->remote_snd->getAddress().toText()).
+ arg(data_->remote_snd->getPort());
}
} // namespace asiodns
diff --git a/src/lib/asiolink/Makefile.am b/src/lib/asiolink/Makefile.am
index 66d5eda..22b3a8e 100644
--- a/src/lib/asiolink/Makefile.am
+++ b/src/lib/asiolink/Makefile.am
@@ -2,7 +2,6 @@ SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
AM_CXXFLAGS = $(B10_CXXFLAGS)
diff --git a/src/lib/asiolink/tests/Makefile.am b/src/lib/asiolink/tests/Makefile.am
index 37d9ef3..bfdf7c1 100644
--- a/src/lib/asiolink/tests/Makefile.am
+++ b/src/lib/asiolink/tests/Makefile.am
@@ -1,6 +1,5 @@
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin
AM_CPPFLAGS += -I$(top_builddir)/src/lib/util -I$(top_srcdir)/src/util
AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
@@ -17,8 +16,6 @@ TESTS =
if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = run_unittests.cc
-run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.h
-run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
run_unittests_SOURCES += io_address_unittest.cc
run_unittests_SOURCES += io_endpoint_unittest.cc
run_unittests_SOURCES += io_socket_unittest.cc
@@ -32,7 +29,6 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(SQLITE_LIBS)
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
diff --git a/src/lib/asiolink/tests/run_unittests.cc b/src/lib/asiolink/tests/run_unittests.cc
index c285f9e..97bcb65 100644
--- a/src/lib/asiolink/tests/run_unittests.cc
+++ b/src/lib/asiolink/tests/run_unittests.cc
@@ -22,7 +22,6 @@ main(int argc, char* argv[])
{
::testing::InitGoogleTest(&argc, argv); // Initialize Google test
isc::log::setRootLoggerName("unittest"); // Set a root logger name
- isc::UnitTestUtil::addDataPath(TEST_DATA_DIR); // Add location of test data
return (RUN_ALL_TESTS());
}
diff --git a/src/lib/cc/tests/Makefile.am b/src/lib/cc/tests/Makefile.am
index 535c464..71e6988 100644
--- a/src/lib/cc/tests/Makefile.am
+++ b/src/lib/cc/tests/Makefile.am
@@ -26,7 +26,6 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
endif
diff --git a/src/lib/cryptolink/Makefile.am b/src/lib/cryptolink/Makefile.am
new file mode 100644
index 0000000..93f3443
--- /dev/null
+++ b/src/lib/cryptolink/Makefile.am
@@ -0,0 +1,14 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES) $(BOTAN_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+CLEANFILES = *.gcno *.gcda
+
+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/crypto_hmac.cc b/src/lib/cryptolink/crypto_hmac.cc
new file mode 100644
index 0000000..9c35f60
--- /dev/null
+++ b/src/lib/cryptolink/crypto_hmac.cc
@@ -0,0 +1,237 @@
+// 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.
+
+#include <cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <botan/botan.h>
+#include <botan/hmac.h>
+#include <botan/hash.h>
+#include <botan/types.h>
+
+namespace {
+const char*
+getBotanHashAlgorithmName(isc::cryptolink::HashAlgorithm algorithm) {
+ switch (algorithm) {
+ case isc::cryptolink::MD5:
+ return ("MD5");
+ break;
+ case isc::cryptolink::SHA1:
+ return ("SHA-1");
+ break;
+ case isc::cryptolink::SHA256:
+ return ("SHA-256");
+ break;
+ case isc::cryptolink::UNKNOWN_HASH:
+ return ("Unknown");
+ break;
+ }
+ // compiler should have prevented us to reach this, since we have
+ // no default. But we need a return value anyway
+ return ("Unknown");
+}
+
+} // local namespace
+
+
+namespace isc {
+namespace cryptolink {
+
+class HMACImpl {
+public:
+ explicit HMACImpl(const void* secret, size_t secret_len,
+ const HashAlgorithm hash_algorithm) {
+ Botan::HashFunction* hash;
+ try {
+ hash = Botan::get_hash(
+ getBotanHashAlgorithmName(hash_algorithm));
+ } catch (const Botan::Algorithm_Not_Found&) {
+ isc_throw(isc::cryptolink::UnsupportedAlgorithm,
+ "Unknown hash algorithm: " + hash_algorithm);
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+
+ hmac_.reset(new Botan::HMAC(hash));
+
+ // If the key length is larger than the block size, we hash the
+ // key itself first.
+ try {
+ if (secret_len > hash->HASH_BLOCK_SIZE) {
+ Botan::SecureVector<Botan::byte> hashed_key =
+ hash->process(static_cast<const Botan::byte*>(secret),
+ secret_len);
+ hmac_->set_key(hashed_key.begin(), hashed_key.size());
+ } else {
+ hmac_->set_key(static_cast<const Botan::byte*>(secret),
+ secret_len);
+ }
+ } catch (const Botan::Invalid_Key_Length& ikl) {
+ isc_throw(BadKey, ikl.what());
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+ ~HMACImpl() { }
+
+ size_t getOutputLength() const {
+ return (hmac_->OUTPUT_LENGTH);
+ }
+
+ void update(const void* data, const size_t len) {
+ try {
+ hmac_->update(static_cast<const Botan::byte*>(data), len);
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+ void sign(isc::util::OutputBuffer& result, size_t len) {
+ try {
+ Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+
+ if (len == 0 || len > b_result.size()) {
+ len = b_result.size();
+ }
+ result.writeData(b_result.begin(), len);
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+ void sign(void* result, size_t len) {
+ try {
+ Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+ size_t output_size = getOutputLength();
+ if (output_size > len) {
+ output_size = len;
+ }
+ memcpy(result, b_result.begin(), output_size);
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+ std::vector<uint8_t> sign(size_t len) {
+ try {
+ Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+ if (len == 0 || len > b_result.size()) {
+ return (std::vector<uint8_t>(b_result.begin(), b_result.end()));
+ } else {
+ return (std::vector<uint8_t>(b_result.begin(), &b_result[len]));
+ }
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+
+ bool verify(const void* sig, size_t len) {
+ // Botan's verify_mac checks if len matches the output_length,
+ // which causes it to fail for truncated signatures, so we do
+ // the check ourselves
+ try {
+ Botan::SecureVector<Botan::byte> our_mac = hmac_->final();
+ if (len == 0 || len > getOutputLength()) {
+ len = getOutputLength();
+ }
+ return (Botan::same_mem(&our_mac[0],
+ static_cast<const unsigned char*>(sig),
+ len));
+ } catch (const Botan::Exception& exc) {
+ isc_throw(isc::cryptolink::LibraryError, exc.what());
+ }
+ }
+
+private:
+ boost::scoped_ptr<Botan::HMAC> hmac_;
+};
+
+HMAC::HMAC(const void* secret, size_t secret_length,
+ const HashAlgorithm hash_algorithm)
+{
+ impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
+}
+
+HMAC::~HMAC() {
+ delete impl_;
+}
+
+size_t
+HMAC::getOutputLength() const {
+ return (impl_->getOutputLength());
+}
+
+void
+HMAC::update(const void* data, const size_t len) {
+ impl_->update(data, len);
+}
+
+void
+HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
+ impl_->sign(result, len);
+}
+
+void
+HMAC::sign(void* result, size_t len) {
+ impl_->sign(result, len);
+}
+
+std::vector<uint8_t>
+HMAC::sign(size_t len) {
+ return impl_->sign(len);
+}
+
+bool
+HMAC::verify(const void* sig, const size_t len) {
+ return (impl_->verify(sig, len));
+}
+
+void
+signHMAC(const void* data, size_t data_len, const void* secret,
+ size_t secret_len, const HashAlgorithm hash_algorithm,
+ isc::util::OutputBuffer& result, size_t len)
+{
+ boost::scoped_ptr<HMAC> hmac(
+ CryptoLink::getCryptoLink().createHMAC(secret,
+ secret_len,
+ hash_algorithm));
+ hmac->update(data, data_len);
+ hmac->sign(result, len);
+}
+
+
+bool
+verifyHMAC(const void* data, const size_t data_len, const void* secret,
+ size_t secret_len, const HashAlgorithm hash_algorithm,
+ const void* sig, const size_t sig_len)
+{
+ boost::scoped_ptr<HMAC> hmac(
+ CryptoLink::getCryptoLink().createHMAC(secret,
+ secret_len,
+ hash_algorithm));
+ hmac->update(data, data_len);
+ return (hmac->verify(sig, sig_len));
+}
+
+void
+deleteHMAC(HMAC* hmac) {
+ delete hmac;
+}
+
+} // namespace cryptolink
+} // namespace isc
diff --git a/src/lib/cryptolink/crypto_hmac.h b/src/lib/cryptolink/crypto_hmac.h
new file mode 100644
index 0000000..2eb0d0e
--- /dev/null
+++ b/src/lib/cryptolink/crypto_hmac.h
@@ -0,0 +1,209 @@
+// 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.
+
+#include <util/buffer.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <cryptolink/cryptolink.h>
+
+#ifndef _ISC_CRYPTO_HMAC_H
+#define _ISC_CRYPTO_HMAC_H
+
+namespace isc {
+namespace cryptolink {
+
+/// Forward declaration, pimpl style
+class HMACImpl;
+
+/// \brief HMAC support
+///
+/// This class is used to create and verify HMAC signatures. Instances
+/// can be created with CryptoLink::createHMAC()
+///
+class HMAC : private boost::noncopyable {
+private:
+ /// \brief Constructor from a secret and a hash algorithm
+ ///
+ /// \exception UnsupportedAlgorithmException if the given algorithm
+ /// is unknown or not supported by the underlying library
+ /// \exception InvalidKeyLength if the given key secret_len is bad
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// Notes: if the secret is longer than the block size of its
+ /// algorithm, the constructor will run it through the hash
+ /// algorithm, and use the digest as the secret for this HMAC
+ /// operation
+ ///
+ /// \param secret The secret to sign with
+ /// \param len The length of the secret
+ /// \param hash_algorithm The hash algorithm
+ HMAC(const void* secret, size_t secret_len,
+ const HashAlgorithm hash_algorithm);
+
+ friend HMAC* CryptoLink::createHMAC(const void*, size_t,
+ const HashAlgorithm);
+
+public:
+ /// \brief Destructor
+ ~HMAC();
+
+ /// \brief Returns the output size of the digest
+ ///
+ /// \return output size of the digest
+ size_t getOutputLength() const;
+
+ /// \brief Add data to digest
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// \param data The data to add
+ /// \param len The size of the data
+ void update(const void* data, const size_t len);
+
+ /// \brief Calculate the final signature
+ ///
+ /// The result will be appended to the given outputbuffer
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// \param result The OutputBuffer to append the result to
+ /// \param len The number of bytes from the result to copy. If this
+ /// value is smaller than the algorithms output size, the
+ /// result will be truncated. If this value is larger, or 0
+ /// (the default), it will be ignored
+ void sign(isc::util::OutputBuffer& result, size_t len = 0);
+
+ /// \brief Calculate the final signature
+ ///
+ /// len bytes of data from the result will be copied to *result
+ /// If len is larger than the output size, only output_size bytes
+ /// will be copied. If it is smaller, the output will be truncated
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// At least len bytes of data must be available for writing at
+ /// result
+ void sign(void* result, size_t len);
+
+ /// \brief Calculate the final signatre
+ ///
+ /// The result will be returned as a std::vector<uint8_t>
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// \param len The number of bytes from the result to copy. If this
+ /// value is smaller than the algorithms output size, the
+ /// result will be truncated. If this value is larger, or 0
+ /// (the default), it will be ignored
+ /// \return a vector containing the signature
+ std::vector<uint8_t> sign(size_t len = 0);
+
+ /// \brief Verify an existing signature
+ ///
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// \param sig The signature to verify
+ /// \param len The length of the signature. If this is non-zero,
+ /// and smaller than the output length of the algorithm,
+ /// only len bytes will be checked
+ /// \return true if the signature is correct, false otherwise
+ bool verify(const void* sig, size_t len);
+
+private:
+ HMACImpl* impl_;
+};
+
+/// \brief Create an HMAC signature for the given data
+///
+/// This is a convenience function that calculates the hmac signature,
+/// given a fixed amount of data. Internally it does the same as
+/// creating an HMAC object, feeding it the data, and calculating the
+/// resulting signature.
+///
+/// \exception UnsupportedAlgorithm if the given algorithm is unknown
+/// or not supported by the underlying library
+/// \exception BadKey if the given key secret_len is bad
+/// \exception LibraryError if there was any unexpected exception
+/// in the underlying library
+///
+/// Notes: if the secret is longer than the block size of its
+/// algorithm, the constructor will run it through the hash
+/// algorithm, and use the digest as the secret for this HMAC
+/// operation
+///
+/// \param data The data to sign
+/// \param data_len The length of the data
+/// \param secret The secret to sign with
+/// \param secret_len The length of the secret
+/// \param hash_algorithm The hash algorithm
+/// \param result The signature will be appended to this buffer
+/// \param len If this is non-zero and less than the output size,
+/// the result will be truncated to len bytes
+void signHMAC(const void* data,
+ const size_t data_len,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ isc::util::OutputBuffer& result,
+ size_t len = 0);
+
+/// \brief Verify an HMAC signature for the given data
+///
+/// This is a convenience function that verifies an hmac signature,
+/// given a fixed amount of data. Internally it does the same as
+/// creating an HMAC object, feeding it the data, and checking the
+/// resulting signature.
+///
+/// \exception UnsupportedAlgorithm if the given algorithm is unknown
+/// or not supported by the underlying library
+/// \exception BadKey if the given key secret_len is bad
+/// \exception LibraryError if there was any unexpected exception
+/// in the underlying library
+///
+/// Notes: if the secret is longer than the block size of its
+/// algorithm, the constructor will run it through the hash
+/// algorithm, and use the digest as the secret for this HMAC
+/// operation
+///
+/// \param data The data to verify
+/// \param data_len The length of the data
+/// \param secret The secret to sign with
+/// \param secret_len The length of the secret
+/// \param hash_algorithm The hash algorithm
+/// \param sig The signature to verify
+/// \param sig_len The length of the signature
+/// \return True if the signature verifies, false if not
+bool verifyHMAC(const void* data,
+ const size_t data_len,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const void* sig,
+ const size_t sig_len);
+
+/// \brief Delete an HMAC object
+void deleteHMAC(HMAC* hmac);
+
+} // namespace cryptolink
+} // namespace isc
+
+#endif // __ISC_CRYPTO_HMAC
+
diff --git a/src/lib/cryptolink/cryptolink.cc b/src/lib/cryptolink/cryptolink.cc
new file mode 100644
index 0000000..d1c375d
--- /dev/null
+++ b/src/lib/cryptolink/cryptolink.cc
@@ -0,0 +1,69 @@
+// 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.
+
+#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+#include <botan/botan.h>
+
+namespace isc {
+namespace cryptolink {
+
+// For Botan, we use the CryptoLink class object in RAII style
+class CryptoLinkImpl {
+private:
+ Botan::LibraryInitializer botan_init_;
+};
+
+CryptoLink::~CryptoLink() {
+ delete impl_;
+}
+
+CryptoLink&
+CryptoLink::getCryptoLink() {
+ CryptoLink& c = getCryptoLinkInternal();
+ if (c.impl_ == NULL) {
+ c.initialize();
+ }
+ return (c);
+}
+
+CryptoLink&
+CryptoLink::getCryptoLinkInternal() {
+ static CryptoLink instance;
+ return (instance);
+}
+
+void
+CryptoLink::initialize() {
+ CryptoLink& c = getCryptoLinkInternal();
+ if (c.impl_ == NULL) {
+ try {
+ c.impl_ = new CryptoLinkImpl();
+ } catch (const Botan::Exception& ex) {
+ isc_throw(InitializationError, ex.what());
+ }
+ }
+}
+
+HMAC*
+CryptoLink::createHMAC(const void* secret, size_t secret_len,
+ const HashAlgorithm hash_algorithm)
+{
+ return (new HMAC(secret, secret_len, hash_algorithm));
+}
+
+} // namespace cryptolink
+} // namespace isc
+
diff --git a/src/lib/cryptolink/cryptolink.h b/src/lib/cryptolink/cryptolink.h
new file mode 100644
index 0000000..1583136
--- /dev/null
+++ b/src/lib/cryptolink/cryptolink.h
@@ -0,0 +1,204 @@
+// 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 _ISC_CRYPTO_H
+#define _ISC_CRYPTO_H
+
+#include <string>
+#include <util/buffer.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <memory>
+
+namespace isc {
+namespace cryptolink {
+
+/// \brief Hash algorithm identifiers
+enum HashAlgorithm {
+ MD5 = 0, ///< MD5
+ SHA1 = 1, ///< SHA-1
+ SHA256 = 2, ///< SHA-256
+ UNKNOWN_HASH = 3 ///< This value can be used in conversion
+ /// functions, to be returned when the
+ /// input is unknown (but a value MUST be
+ /// returned), for instance when the input
+ /// is a Name or a string, and the return
+ /// value is a HashAlgorithm.
+};
+
+// Forward declaration for createHMAC()
+class HMAC;
+
+/// General exception class that is the base for all crypto-related
+/// exceptions
+class CryptoLinkError : public Exception {
+public:
+ CryptoLinkError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// This exception is thrown if there was a problem initializing the
+/// crypto library
+class InitializationError : public CryptoLinkError {
+public:
+ InitializationError(const char* file, size_t line, const char* what) :
+ CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is thrown when a cryptographic action is requested
+/// for an algorithm that is not supported by the underlying library.
+class UnsupportedAlgorithm : public CryptoLinkError {
+public:
+ UnsupportedAlgorithm(const char* file, size_t line, const char* what) :
+ CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is thrown when the underlying library could not
+/// handle the key data.
+class BadKey : public CryptoLinkError {
+public:
+ BadKey(const char* file, size_t line, const char* what) :
+ CryptoLinkError(file, line, what) {}
+};
+
+/// This exception is raised when a general error that was not
+/// specifically caught is thrown by the underlying library. It
+/// is replaced by this one so as not have 'external' exceptions
+/// bubbling up
+class LibraryError : public CryptoLinkError {
+public:
+ LibraryError(const char* file, size_t line, const char* what) :
+ CryptoLinkError(file, line, what) {}
+};
+
+/// Forward declaration for pimpl
+class CryptoLinkImpl;
+
+/// \brief Singleton entry point and factory class
+///
+/// This is a singleton class that serves as the entry point to
+/// the underlying cryptography library, and as a factory for objects
+/// within the cryptolink library.
+///
+/// There is only one way to access it, through getCryptoLink(), which
+/// returns a reference to the initialized library. On the first call,
+/// it will be initialized automatically. You can however initialize it
+/// manually through a call to the initalize(), before your first call
+/// to getCryptoLink. Any subsequent call to initialize() will be a
+/// noop.
+///
+/// In order for the CryptoLink library to be sure that the underlying
+/// library has been initialized, and because we do not want to add
+/// such a check to every class and function within it, we have made
+/// the constructors of all classes within cryptolink private. This way
+/// a caller cannot instantiate an object before the library is
+/// initialized, but must use CryptoLink's create method (e.g.
+/// createHMAC()), which enforces (automatic) initialization.
+///
+/// In order for the CryptoLink class to be able to create objects that
+/// have private constructors, it is declared a friend class of these
+/// classes.
+///
+/// Since these factory functions return bare pointers, we also provide
+/// deleter functions for them (e.g. deleteHMAC()), so that a caller
+/// can use that to make sure it uses the correct delete operator (the
+/// one defined at compilation time of this library). A way to make
+/// sure you do not forget this, is to place the result of the create
+/// functions in a shared_ptr with the corresponding deleter function.
+///
+/// \note All other classes within cryptolink should have private
+/// constructors as well, and should have a factory function from
+/// CryptoLink, and a deleter function.
+///
+// Internal note: we can use this class later to initialize and manage
+// dynamic (PKCS#11) libs
+class CryptoLink : private boost::noncopyable {
+public:
+ /// \brief Returns a reference to the singleton instance
+ ///
+ /// If the library has not been initialized yet, it will be
+ /// initialized with some default values.
+ ///
+ /// Since this class is noncopyable, you must use the return
+ /// value directly, or store it in a reference variable.
+ ///
+ /// \exception InitializationError if initialization fails
+ ///
+ /// \return Reference to the singleton instance
+ static CryptoLink& getCryptoLink();
+
+ /// \brief Initialize the library manually
+ ///
+ /// If the library has already been initialized (either by a call
+ /// to initialize() or automatically in getCryptoLink()), this
+ /// function does nothing.
+ ///
+ /// \note A call to initialize() is not strictly necessary with
+ /// the current implementation.
+ ///
+ /// \exception InitializationError if initialization fails
+ ///
+ static void initialize();
+
+ /// \brief Factory function for HMAC objects
+ ///
+ /// CryptoLink objects cannot be constructed directly. This
+ /// function creates a new HMAC object usable for signing or
+ /// verification.
+ ///
+ /// The caller is responsible for deleting the object, and it is
+ /// therefore highly recommended to place the return value of this
+ /// function in a scoped_ptr or shared_ptr.
+ ///
+ /// Notes: if the secret is longer than the block size of its
+ /// algorithm, the constructor will run it through the hash
+ /// algorithm, and use the digest as the secret for this HMAC
+ /// operation
+ ///
+ /// If you want to safely delete objects created with this method,
+ /// you can use the function deleteHMAC() as defined in
+ /// crypto_hmac.h
+ ///
+ /// \exception UnsupportedAlgorithmException if the given algorithm
+ /// is unknown or not supported by the underlying library
+ /// \exception InvalidKeyLength if the given key secret_len is bad
+ /// \exception LibraryError if there was any unexpected exception
+ /// in the underlying library
+ ///
+ /// \param secret The secret to sign with
+ /// \param secret_len The length of the secret
+ /// \param hash_algorithm The hash algorithm
+ HMAC* createHMAC(const void* secret, size_t secret_len,
+ const HashAlgorithm hash_algorithm);
+
+private:
+ // To enable us to use an optional explicit initialization call,
+ // the 'real' instance getter is private
+ static CryptoLink& getCryptoLinkInternal();
+
+ // To prevent people constructing their own, we make the constructor
+ // private too.
+ CryptoLink() : impl_(NULL) {}
+ ~CryptoLink();
+
+ CryptoLinkImpl* impl_;
+};
+
+} // namespace cryptolink
+} // namespace isc
+
+#endif // _ISC_CRYPTO_H
diff --git a/src/lib/cryptolink/tests/Makefile.am b/src/lib/cryptolink/tests/Makefile.am
new file mode 100644
index 0000000..c8b5e26
--- /dev/null
+++ b/src/lib/cryptolink/tests/Makefile.am
@@ -0,0 +1,26 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += crypto_unittests.cc
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libcryptolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/cryptolink/tests/crypto_unittests.cc b/src/lib/cryptolink/tests/crypto_unittests.cc
new file mode 100644
index 0000000..65018c6
--- /dev/null
+++ b/src/lib/cryptolink/tests/crypto_unittests.cc
@@ -0,0 +1,511 @@
+// 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.
+
+#include <config.h>
+#include <gtest/gtest.h>
+
+#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+#include <util/buffer.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/shared_ptr.hpp>
+
+using namespace isc::util;
+using namespace isc::cryptolink;
+
+namespace {
+ void checkData(const uint8_t* data, const uint8_t* expected,
+ size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ ASSERT_EQ(expected[i], data[i]);
+ }
+ }
+
+ void checkBuffer(const OutputBuffer& buf, const uint8_t* expected,
+ size_t len)
+ {
+ ASSERT_EQ(len, buf.getLength());
+ checkData(static_cast<const uint8_t*>(buf.getData()), expected,
+ len);
+ }
+
+ // Sign and verify with the convenience functions
+ void doHMACTestConv(const std::string& data,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const uint8_t* expected_hmac,
+ size_t hmac_len) {
+ OutputBuffer data_buf(data.size());
+ data_buf.writeData(data.c_str(), data.size());
+ OutputBuffer hmac_sig(0);
+
+ // Sign it
+ signHMAC(data_buf.getData(), data_buf.getLength(),
+ secret, secret_len, hash_algorithm, hmac_sig, hmac_len);
+
+ // Check if the signature is what we expect
+ checkBuffer(hmac_sig, expected_hmac, hmac_len);
+
+ // Check whether we can verify it ourselves
+ EXPECT_TRUE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+ secret, secret_len, hash_algorithm,
+ hmac_sig.getData(),
+ hmac_sig.getLength()));
+
+ // Change the sig by flipping the first octet, and check
+ // whether verification fails then
+ hmac_sig.writeUint8At(~hmac_sig[0], 0);
+ EXPECT_FALSE(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+ secret, secret_len, hash_algorithm,
+ hmac_sig.getData(),
+ hmac_sig.getLength()));
+ }
+
+ // Sign and verify with an instantiation of an HMAC object
+ void doHMACTestDirect(const std::string& data,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const uint8_t* expected_hmac,
+ size_t hmac_len) {
+ OutputBuffer data_buf(data.size());
+ data_buf.writeData(data.c_str(), data.size());
+ OutputBuffer hmac_sig(1);
+ CryptoLink& crypto = CryptoLink::getCryptoLink();
+
+ // Sign it
+ boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+ secret_len,
+ hash_algorithm),
+ deleteHMAC);
+ hmac_sign->update(data_buf.getData(), data_buf.getLength());
+ hmac_sign->sign(hmac_sig, hmac_len);
+
+ // Check if the signature is what we expect
+ checkBuffer(hmac_sig, expected_hmac, hmac_len);
+
+ // Check whether we can verify it ourselves
+ boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+ secret_len,
+ hash_algorithm),
+ deleteHMAC);
+ hmac_verify->update(data_buf.getData(), data_buf.getLength());
+ EXPECT_TRUE(hmac_verify->verify(hmac_sig.getData(),
+ hmac_sig.getLength()));
+
+ // Change the sig by flipping the first octet, and check
+ // whether verification fails then
+ hmac_sig.writeUint8At(~hmac_sig[0], 0);
+ EXPECT_FALSE(hmac_verify->verify(hmac_sig.getData(),
+ hmac_sig.getLength()));
+ }
+
+ void doHMACTestVector(const std::string& data,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const uint8_t* expected_hmac,
+ size_t hmac_len) {
+ CryptoLink& crypto = CryptoLink::getCryptoLink();
+ boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+ secret_len,
+ 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::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+ secret_len,
+ hash_algorithm),
+ deleteHMAC);
+ hmac_verify->update(data.c_str(), data.size());
+ EXPECT_TRUE(hmac_verify->verify(&sig[0], sig.size()));
+
+ sig[0] = ~sig[0];
+ EXPECT_FALSE(hmac_verify->verify(&sig[0], sig.size()));
+ }
+
+ void doHMACTestArray(const std::string& data,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const uint8_t* expected_hmac,
+ size_t hmac_len) {
+ CryptoLink& crypto = CryptoLink::getCryptoLink();
+ boost::shared_ptr<HMAC> hmac_sign(crypto.createHMAC(secret,
+ secret_len,
+ hash_algorithm),
+ deleteHMAC);
+ hmac_sign->update(data.c_str(), data.size());
+
+ // note: this is not exception-safe, and can leak, but
+ // if there is an unexpected exception in the code below we
+ // have more important things to fix.
+ uint8_t* sig = new uint8_t[hmac_len];
+
+ hmac_sign->sign(sig, hmac_len);
+ checkData(sig, expected_hmac, hmac_len);
+
+ boost::shared_ptr<HMAC> hmac_verify(crypto.createHMAC(secret,
+ secret_len,
+ hash_algorithm),
+ deleteHMAC);
+ hmac_verify->update(data.c_str(), data.size());
+ EXPECT_TRUE(hmac_verify->verify(sig, hmac_len));
+
+ sig[0] = ~sig[0];
+ EXPECT_FALSE(hmac_verify->verify(sig, hmac_len));
+
+ delete[] sig;
+ }
+
+ void doHMACTest(const std::string& data,
+ const void* secret,
+ size_t secret_len,
+ const HashAlgorithm hash_algorithm,
+ const uint8_t* expected_hmac,
+ size_t hmac_len) {
+ doHMACTestConv(data, secret, secret_len, hash_algorithm,
+ expected_hmac, hmac_len);
+ doHMACTestDirect(data, secret, secret_len, hash_algorithm,
+ expected_hmac, hmac_len);
+ doHMACTestVector(data, secret, secret_len, hash_algorithm,
+ expected_hmac, hmac_len);
+ doHMACTestArray(data, secret, secret_len, hash_algorithm,
+ expected_hmac, hmac_len);
+ }
+}
+
+//
+// Test values taken from RFC 2202
+//
+TEST(CryptoLinkTest, HMAC_MD5_RFC2202_SIGN) {
+ const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b };
+ const uint8_t hmac_expected[] = { 0x92, 0x94, 0x72, 0x7a, 0x36,
+ 0x38, 0xbb, 0x1c, 0x13, 0xf4,
+ 0x8e, 0xf8, 0x15, 0x8b, 0xfc,
+ 0x9d };
+ doHMACTest("Hi There", secret, 16, MD5, hmac_expected, 16);
+
+ const uint8_t hmac_expected2[] = { 0x75, 0x0c, 0x78, 0x3e, 0x6a,
+ 0xb0, 0xb5, 0x03, 0xea, 0xa8,
+ 0x6e, 0x31, 0x0a, 0x5d, 0xb7,
+ 0x38 };
+ doHMACTest("what do ya want for nothing?", "Jefe", 4, MD5,
+ hmac_expected2, 16);
+
+ const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa };
+ const uint8_t hmac_expected3[] = { 0x56, 0xbe, 0x34, 0x52, 0x1d,
+ 0x14, 0x4c, 0x88, 0xdb, 0xb8,
+ 0xc7, 0x33, 0xf0, 0xe8, 0xb3,
+ 0xf6};
+ doHMACTest(std::string(50, 0xdd), secret3, 16, MD5, hmac_expected3, 16);
+
+ const std::string data4(50, 0xcd);
+ const uint8_t secret4[] = { 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 };
+ const uint8_t hmac_expected4[] = { 0x69, 0x7e, 0xaf, 0x0a, 0xca,
+ 0x3a, 0x3a, 0xea, 0x3a, 0x75,
+ 0x16, 0x47, 0x46, 0xff, 0xaa,
+ 0x79 };
+ doHMACTest(data4, secret4, 25, MD5, hmac_expected4, 16);
+
+ const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c };
+ const uint8_t hmac_expected5[] = { 0x56, 0x46, 0x1e, 0xf2, 0x34,
+ 0x2e, 0xdc, 0x00, 0xf9, 0xba,
+ 0xb9, 0x95, 0x69, 0x0e, 0xfd,
+ 0x4c };
+ doHMACTest("Test With Truncation", secret5, 16, MD5,
+ hmac_expected5, 16);
+ doHMACTest("Test With Truncation", secret5, 16, MD5,
+ hmac_expected5, 12);
+
+ const uint8_t hmac_expected6[] = { 0x6b, 0x1a, 0xb7, 0xfe, 0x4b,
+ 0xd7, 0xbf, 0x8f, 0x0b, 0x62,
+ 0xe6, 0xce, 0x61, 0xb9, 0xd0,
+ 0xcd };
+ doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
+ std::string(80, 0xaa).c_str(), 80, MD5, hmac_expected6, 16);
+
+ const uint8_t hmac_expected7[] = { 0x6f, 0x63, 0x0f, 0xad, 0x67,
+ 0xcd, 0xa0, 0xee, 0x1f, 0xb1,
+ 0xf5, 0x62, 0xdb, 0x3a, 0xa5,
+ 0x3e };
+ doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
+ "One Block-Size Data",
+ std::string(80, 0xaa).c_str(), 80, MD5, hmac_expected7, 16);
+}
+
+//
+// Test values taken from RFC 2202
+//
+TEST(CryptoLinkTest, HMAC_SHA1_RFC2202_SIGN) {
+ const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+ const uint8_t hmac_expected[] = { 0xb6, 0x17, 0x31, 0x86, 0x55,
+ 0x05, 0x72, 0x64, 0xe2, 0x8b,
+ 0xc0, 0xb6, 0xfb, 0x37, 0x8c,
+ 0x8e, 0xf1, 0x46, 0xbe, 0x00 };
+ doHMACTest("Hi There", secret, 20, SHA1, hmac_expected, 20);
+
+ const uint8_t hmac_expected2[] = { 0xef, 0xfc, 0xdf, 0x6a, 0xe5,
+ 0xeb, 0x2f, 0xa2, 0xd2, 0x74,
+ 0x16, 0xd5, 0xf1, 0x84, 0xdf,
+ 0x9c, 0x25, 0x9a, 0x7c, 0x79 };
+ doHMACTest("what do ya want for nothing?", "Jefe", 4, SHA1,
+ hmac_expected2, 20);
+
+ const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa };
+ const uint8_t hmac_expected3[] = { 0x12, 0x5d, 0x73, 0x42, 0xb9,
+ 0xac, 0x11, 0xcd, 0x91, 0xa3,
+ 0x9a, 0xf4, 0x8a, 0xa1, 0x7b,
+ 0x4f, 0x63, 0xf1, 0x75, 0xd3 };
+ doHMACTest(std::string(50, 0xdd), secret3, 20, SHA1, hmac_expected3, 20);
+
+ const uint8_t secret4[] = { 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 };
+ const uint8_t hmac_expected4[] = { 0x4c, 0x90, 0x07, 0xf4, 0x02,
+ 0x62, 0x50, 0xc6, 0xbc, 0x84,
+ 0x14, 0xf9, 0xbf, 0x50, 0xc8,
+ 0x6c, 0x2d, 0x72, 0x35, 0xda };
+ doHMACTest(std::string(50, 0xcd), secret4, 25, SHA1, hmac_expected4, 20);
+
+ const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c };
+ const uint8_t hmac_expected5[] = { 0x4c, 0x1a, 0x03, 0x42, 0x4b,
+ 0x55, 0xe0, 0x7f, 0xe7, 0xf2,
+ 0x7b, 0xe1, 0xd5, 0x8b, 0xb9,
+ 0x32, 0x4a, 0x9a, 0x5a, 0x04 };
+ doHMACTest("Test With Truncation", secret5, 20, SHA1,
+ hmac_expected5, 20);
+ doHMACTest("Test With Truncation", secret5, 20, SHA1,
+ hmac_expected5, 12);
+
+ const uint8_t hmac_expected6[] = { 0xaa, 0x4a, 0xe5, 0xe1, 0x52,
+ 0x72, 0xd0, 0x0e, 0x95, 0x70,
+ 0x56, 0x37, 0xce, 0x8a, 0x3b,
+ 0x55, 0xed, 0x40, 0x21, 0x12 };
+ doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
+ std::string(80, 0xaa).c_str(), 80, SHA1, hmac_expected6, 20);
+
+ const uint8_t hmac_expected7[] = { 0xe8, 0xe9, 0x9d, 0x0f, 0x45,
+ 0x23, 0x7d, 0x78, 0x6d, 0x6b,
+ 0xba, 0xa7, 0x96, 0x5c, 0x78,
+ 0x08, 0xbb, 0xff, 0x1a, 0x91 };
+ doHMACTest("Test Using Larger Than Block-Size Key and Larger Than "
+ "One Block-Size Data",
+ std::string(80, 0xaa).c_str(), 80, SHA1, hmac_expected7, 20);
+}
+
+//
+// Test values taken from RFC 4231
+//
+TEST(CryptoLinkTest, HMAC_SHA256_RFC2202_SIGN) {
+ const uint8_t secret[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+ const uint8_t hmac_expected[] = { 0xb0, 0x34, 0x4c, 0x61, 0xd8,
+ 0xdb, 0x38, 0x53, 0x5c, 0xa8,
+ 0xaf, 0xce, 0xaf, 0x0b, 0xf1,
+ 0x2b, 0x88, 0x1d, 0xc2, 0x00,
+ 0xc9, 0x83, 0x3d, 0xa7, 0x26,
+ 0xe9, 0x37, 0x6c, 0x2e, 0x32,
+ 0xcf, 0xf7 };
+ doHMACTest("Hi There", secret, 20, SHA256, hmac_expected, 32);
+
+ const uint8_t hmac_expected2[] = { 0x5b, 0xdc, 0xc1, 0x46, 0xbf,
+ 0x60, 0x75, 0x4e, 0x6a, 0x04,
+ 0x24, 0x26, 0x08, 0x95, 0x75,
+ 0xc7, 0x5a, 0x00, 0x3f, 0x08,
+ 0x9d, 0x27, 0x39, 0x83, 0x9d,
+ 0xec, 0x58, 0xb9, 0x64, 0xec,
+ 0x38, 0x43 };
+ doHMACTest("what do ya want for nothing?", "Jefe", 4, SHA256,
+ hmac_expected2, 32);
+
+ const uint8_t secret3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa };
+ const uint8_t hmac_expected3[] = { 0x77, 0x3e, 0xa9, 0x1e, 0x36,
+ 0x80, 0x0e, 0x46, 0x85, 0x4d,
+ 0xb8, 0xeb, 0xd0, 0x91, 0x81,
+ 0xa7, 0x29, 0x59, 0x09, 0x8b,
+ 0x3e, 0xf8, 0xc1, 0x22, 0xd9,
+ 0x63, 0x55, 0x14, 0xce, 0xd5,
+ 0x65, 0xfe };
+ doHMACTest(std::string(50, 0xdd), secret3, 20, SHA256, hmac_expected3, 32);
+
+ const uint8_t secret4[] = { 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 };
+ const uint8_t hmac_expected4[] = { 0x82, 0x55, 0x8a, 0x38, 0x9a,
+ 0x44, 0x3c, 0x0e, 0xa4, 0xcc,
+ 0x81, 0x98, 0x99, 0xf2, 0x08,
+ 0x3a, 0x85, 0xf0, 0xfa, 0xa3,
+ 0xe5, 0x78, 0xf8, 0x07, 0x7a,
+ 0x2e, 0x3f, 0xf4, 0x67, 0x29,
+ 0x66, 0x5b };
+ doHMACTest(std::string(50, 0xcd), secret4, 25, SHA256, hmac_expected4, 32);
+
+ const uint8_t secret5[] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c };
+ const uint8_t hmac_expected5[] = { 0xa3, 0xb6, 0x16, 0x74, 0x73,
+ 0x10, 0x0e, 0xe0, 0x6e, 0x0c,
+ 0x79, 0x6c, 0x29, 0x55, 0x55,
+ 0x2b };
+ doHMACTest("Test With Truncation", secret5, 20, SHA256,
+ hmac_expected5, 16);
+
+ const uint8_t hmac_expected6[] = { 0x60, 0xe4, 0x31, 0x59, 0x1e,
+ 0xe0, 0xb6, 0x7f, 0x0d, 0x8a,
+ 0x26, 0xaa, 0xcb, 0xf5, 0xb7,
+ 0x7f, 0x8e, 0x0b, 0xc6, 0x21,
+ 0x37, 0x28, 0xc5, 0x14, 0x05,
+ 0x46, 0x04, 0x0f, 0x0e, 0xe3,
+ 0x7f, 0x54 };
+ doHMACTest("Test Using Larger Than Block-Size Key - Hash Key First",
+ std::string(131, 0xaa).c_str(), 131, SHA256, hmac_expected6, 32);
+
+ const uint8_t hmac_expected7[] = { 0x9b, 0x09, 0xff, 0xa7, 0x1b,
+ 0x94, 0x2f, 0xcb, 0x27, 0x63,
+ 0x5f, 0xbc, 0xd5, 0xb0, 0xe9,
+ 0x44, 0xbf, 0xdc, 0x63, 0x64,
+ 0x4f, 0x07, 0x13, 0x93, 0x8a,
+ 0x7f, 0x51, 0x53, 0x5c, 0x3a,
+ 0x35, 0xe2 };
+ doHMACTest("This is a test using a larger than block-size key and a"
+ " larger than block-size data. The key needs to be hashe"
+ "d before being used by the HMAC algorithm.",
+ std::string(131, 0xaa).c_str(), 131, SHA256, hmac_expected7, 32);
+}
+
+namespace {
+ size_t
+ sigVectorLength(HashAlgorithm alg, size_t len) {
+ 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());
+ }
+
+ size_t
+ sigBufferLength(HashAlgorithm alg, size_t len) {
+ 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);
+ return (sig.getLength());
+ }
+}
+
+TEST(CryptoLinkTest, HMACSigLengthArgument) {
+ std::vector<uint8_t> sig;
+
+ EXPECT_EQ(16, sigVectorLength(MD5, 0));
+ EXPECT_EQ(8, sigVectorLength(MD5, 8));
+ EXPECT_EQ(16, sigVectorLength(MD5, 16));
+ EXPECT_EQ(16, sigVectorLength(MD5, 40));
+ EXPECT_EQ(16, sigVectorLength(MD5, 2000));
+
+ EXPECT_EQ(20, sigBufferLength(SHA1, 0));
+ EXPECT_EQ(8, sigBufferLength(SHA1, 8));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 20));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 40));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 2000));
+
+ EXPECT_EQ(32, sigBufferLength(SHA256, 0));
+ EXPECT_EQ(8, sigBufferLength(SHA256, 8));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 32));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 40));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 3200));
+
+ EXPECT_EQ(16, sigBufferLength(MD5, 0));
+ EXPECT_EQ(8, sigBufferLength(MD5, 8));
+ EXPECT_EQ(16, sigBufferLength(MD5, 16));
+ EXPECT_EQ(16, sigBufferLength(MD5, 40));
+ EXPECT_EQ(16, sigBufferLength(MD5, 2000));
+
+ EXPECT_EQ(20, sigBufferLength(SHA1, 0));
+ EXPECT_EQ(8, sigBufferLength(SHA1, 8));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 20));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 40));
+ EXPECT_EQ(20, sigBufferLength(SHA1, 2000));
+
+ EXPECT_EQ(32, sigBufferLength(SHA256, 0));
+ EXPECT_EQ(8, sigBufferLength(SHA256, 8));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 32));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 40));
+ EXPECT_EQ(32, sigBufferLength(SHA256, 3200));
+}
+
+TEST(CryptoLinkTest, BadKey) {
+ OutputBuffer data_buf(0);
+ OutputBuffer hmac_sig(0);
+ CryptoLink& crypto = CryptoLink::getCryptoLink();
+
+ EXPECT_THROW(crypto.createHMAC(NULL, 0, MD5), BadKey);
+ EXPECT_THROW(crypto.createHMAC(NULL, 0, UNKNOWN_HASH), UnsupportedAlgorithm);
+
+ EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
+ NULL, 0, MD5, hmac_sig), BadKey);
+ EXPECT_THROW(signHMAC(data_buf.getData(), data_buf.getLength(),
+ NULL, 0, UNKNOWN_HASH, hmac_sig),
+ UnsupportedAlgorithm);
+
+ EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+ NULL, 0, MD5, hmac_sig.getData(),
+ hmac_sig.getLength()), BadKey);
+ EXPECT_THROW(verifyHMAC(data_buf.getData(), data_buf.getLength(),
+ NULL, 0, UNKNOWN_HASH, hmac_sig.getData(),
+ hmac_sig.getLength()),
+ UnsupportedAlgorithm);
+}
+
+TEST(CryptoLinkTest, Singleton) {
+ const CryptoLink& c1 = CryptoLink::getCryptoLink();
+ const CryptoLink& c2 = CryptoLink::getCryptoLink();
+ ASSERT_EQ(&c1, &c2);
+}
diff --git a/src/lib/cryptolink/tests/run_unittests.cc b/src/lib/cryptolink/tests/run_unittests.cc
new file mode 100644
index 0000000..d16327e
--- /dev/null
+++ b/src/lib/cryptolink/tests/run_unittests.cc
@@ -0,0 +1,22 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return (RUN_ALL_TESTS());
+}
diff --git a/src/lib/datasrc/cache.cc b/src/lib/datasrc/cache.cc
index ec53164..28831f6 100644
--- a/src/lib/datasrc/cache.cc
+++ b/src/lib/datasrc/cache.cc
@@ -25,6 +25,7 @@
#include <datasrc/cache.h>
#include <datasrc/logger.h>
+#include <log/macros.h>
using namespace std;
using namespace isc::dns;
@@ -206,16 +207,14 @@ public:
HotCacheImpl::HotCacheImpl(int slots, bool enabled) :
enabled_(enabled), slots_(slots), count_(0)
{
- logger.debug(DBG_TRACE_BASIC, DATASRC_CACHE_CREAT);
+ logger.debug(DBG_TRACE_BASIC, DATASRC_CACHE_CREATE);
}
// Insert a cache node into the cache
inline void
HotCacheImpl::insert(const CacheNodePtr node) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_CACHE_INSERT,
- node->getRRset()->getName().toText().c_str());
- }
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_INSERT).
+ arg(node->getRRset()->getName());
std::map<Question, CacheNodePtr>::const_iterator iter;
iter = map_.find(node->question);
if (iter != map_.end()) {
@@ -254,10 +253,8 @@ HotCacheImpl::promote(CacheNodePtr node) {
// Remove a node from the LRU list and the map
void
HotCacheImpl::remove(ConstCacheNodePtr node) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_CACHE_REMOVE,
- node->getRRset()->getName().toText().c_str());
- }
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_REMOVE).
+ arg(node->getRRset()->getName());
lru_.erase(node->lru_entry_);
map_.erase(node->question);
--count_;
@@ -314,26 +311,24 @@ HotCache::retrieve(const Name& n, const RRClass& c, const RRType& t,
return (false);
}
- logger.debug(DBG_TRACE_DATA, DATASRC_CACHE_LOOKUP, n.toText().c_str());
-
std::map<Question, CacheNodePtr>::const_iterator iter;
iter = impl_->map_.find(Question(n, c, t));
if (iter == impl_->map_.end()) {
- logger.debug(DBG_TRACE_DATA, DATASRC_CACHE_NOT_FOUND);
+ logger.debug(DBG_TRACE_DATA, DATASRC_CACHE_NOT_FOUND).arg(n);
return (false);
}
CacheNodePtr node = iter->second;
if (node->isValid()) {
- logger.debug(DBG_TRACE_DATA, DATASRC_CACHE_FOUND);
+ logger.debug(DBG_TRACE_DATA, DATASRC_CACHE_FOUND).arg(n);
impl_->promote(node);
rrset = node->getRRset();
flags = node->getFlags();
return (true);
}
- logger.debug(DBG_TRACE_DATA, DATASRC_CACHE_EXPIRED);
+ logger.debug(DBG_TRACE_DATA, DATASRC_CACHE_EXPIRED).arg(n);
impl_->remove(node);
return (false);
}
@@ -347,7 +342,8 @@ HotCache::setSlots(const int slots) {
return;
}
- logger.info(DATASRC_CACHE_SLOTS, slots);
+ logger.info(DATASRC_CACHE_SLOTS).arg(slots).arg(max(0, impl_->count_ -
+ slots));
while (impl_->slots_ != 0 && impl_->count_ > impl_->slots_) {
impl_->remove(impl_->lru_.back());
diff --git a/src/lib/datasrc/data_source.cc b/src/lib/datasrc/data_source.cc
index 6189d97..6b2de30 100644
--- a/src/lib/datasrc/data_source.cc
+++ b/src/lib/datasrc/data_source.cc
@@ -38,6 +38,8 @@
#include <dns/rrset.h>
#include <dns/rrsetlist.h>
+#include <log/macros.h>
+
#include <cc/data.h>
#define RETERR(x) do { \
@@ -124,11 +126,8 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
const Rdata& rd(it->getCurrent());
if (rrset->getType() == RRType::NS()) {
const generic::NS& ns = dynamic_cast<const generic::NS&>(rd);
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_GET_NS_ADDITIONAL,
- ns.getNSName().toText().c_str(),
- rrset->getName().toText().c_str());
- }
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_GET_NS_ADDITIONAL).
+ arg(ns.getNSName()).arg(rrset->getName());
q.tasks().push(QueryTaskPtr(
new QueryTask(q, ns.getNSName(),
Message::SECTION_ADDITIONAL,
@@ -136,11 +135,8 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
QueryTask::GETADDITIONAL)));
} else if (rrset->getType() == RRType::MX()) {
const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_GET_MX_ADDITIONAL,
- mx.getMXName().toText().c_str(),
- rrset->getName().toText().c_str());
- }
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_GET_MX_ADDITIONAL).
+ arg(mx.getMXName()).arg(rrset->getName());
q.tasks().push(QueryTaskPtr(
new QueryTask(q, mx.getMXName(),
Message::SECTION_ADDITIONAL,
@@ -154,17 +150,14 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
// understand DNAME
void
synthesizeCname(QueryTaskPtr task, RRsetPtr rrset, RRsetList& target) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_SYNTH_CNAME,
- rrset->getName().toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_SYNTH_CNAME).
+ arg(rrset->getName());
RdataIteratorPtr it = rrset->getRdataIterator();
// More than one DNAME RR in the RRset is illegal, so we only have
// to process the first one.
if (it->isLast()) {
- logger.error(DATASRC_QUERY_EMPTY_DNAME,
- rrset->getName().toText().c_str());
+ logger.error(DATASRC_QUERY_EMPTY_DNAME).arg(rrset->getName());
return;
}
@@ -188,24 +181,20 @@ synthesizeCname(QueryTaskPtr task, RRsetPtr rrset, RRsetList& target) {
// to by a CNAME record
void
chaseCname(Query& q, QueryTaskPtr task, RRsetPtr rrset) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_FOLLOW_CNAME,
- rrset->getName().toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_FOLLOW_CNAME).
+ arg(rrset->getName());
RdataIteratorPtr it = rrset->getRdataIterator();
// More than one CNAME RR in the RRset is illegal, so we only have
// to process the first one.
if (it->isLast()) {
- logger.error(DATASRC_QUERY_EMPTY_CNAME,
- rrset->getName().toText().c_str());
+ logger.error(DATASRC_QUERY_EMPTY_CNAME).arg(rrset->getName());
return;
}
// Stop chasing CNAMES after 16 lookups, to prevent loops
if (q.tooMany()) {
- logger.error(DATASRC_QUERY_TOO_MANY_CNAMES,
- rrset->getName().toText().c_str());
+ logger.error(DATASRC_QUERY_TOO_MANY_CNAMES).arg(rrset->getName());
return;
}
@@ -219,10 +208,8 @@ chaseCname(Query& q, QueryTaskPtr task, RRsetPtr rrset) {
// Check the cache for data which can answer the current query task.
bool
checkCache(QueryTask& task, RRsetList& target) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_CHECK_CACHE,
- task.qname.toText().c_str(), task.qtype.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_CHECK_CACHE).arg(task.qname).
+ arg(task.qtype);
HotCache& cache = task.q.getCache();
RRsetList rrsets;
RRsetPtr rrset;
@@ -384,10 +371,8 @@ DataSrc::Result
doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
HotCache& cache = task.q.getCache();
RRsetPtr rrset;
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_DO_QUERY,
- task.qname.toText().c_str(), task.qtype.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_DO_QUERY).arg(task.qname).
+ arg(task.qtype);
// First off, make sure at least we have a matching zone in some data
// source. We must do this before checking the cache, because it can
@@ -398,10 +383,7 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
const Name* const zonename = zoneinfo.getEnclosingZone();
if (ds == NULL) {
task.flags |= DataSrc::NO_SUCH_ZONE;
- if (logger.isInfoEnabled()) {
- logger.info(DATASRC_QUERY_NO_ZONE, task.qname.toText().c_str(),
- task.qclass.toText().c_str());
- }
+ logger.info(DATASRC_QUERY_NO_ZONE).arg(task.qname).arg(task.qclass);
return (DataSrc::SUCCESS);
}
@@ -423,7 +405,7 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
target, task.flags, zonename);
if (result != DataSrc::SUCCESS) {
- logger.error(DATASRC_QUERY_SIMPLE_FAIL, unsigned(result));
+ logger.error(DATASRC_QUERY_SIMPLE_FAIL).arg(result);
return (result);
}
@@ -450,7 +432,7 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
target, task.flags, zonename);
if (result != DataSrc::SUCCESS) {
- logger.error(DATASRC_QUERY_AUTH_FAIL, unsigned(result));
+ logger.error(DATASRC_QUERY_AUTH_FAIL).arg(result);
return (result);
}
@@ -490,8 +472,8 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
if (result != DataSrc::SUCCESS) {
logger.error(task.op == QueryTask::GLUE_QUERY ?
- DATASRC_QUERY_GLUE_FAIL : DATASRC_QUERY_NOGLUE_FAIL,
- unsigned(result));
+ DATASRC_QUERY_GLUE_FAIL : DATASRC_QUERY_NOGLUE_FAIL).
+ arg(result);
return (result);
}
@@ -522,7 +504,7 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
task.flags, zonename);
if (result != DataSrc::SUCCESS) {
- logger.error(DATASRC_QUERY_REF_FAIL, unsigned(result));
+ logger.error(DATASRC_QUERY_REF_FAIL).arg(result);
return (result);
}
@@ -568,11 +550,8 @@ inline void
addToMessage(Query& q, const Message::Section sect, RRsetPtr rrset,
bool no_dnssec = false)
{
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_ADD_RRSET,
- rrset->getName().toText().c_str(),
- rrset->getType().toText().c_str());
- }
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_RRSET).
+ arg(rrset->getName()).arg(rrset->getType());
Message& m = q.message();
if (no_dnssec) {
if (rrset->getType() == RRType::RRSIG() ||
@@ -629,10 +608,8 @@ refQuery(const Query& q, const Name& name, ZoneInfo& zoneinfo,
// they'll be handled in a normal lookup in the zone.
inline bool
hasDelegation(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_DELEGATION,
- task->qname.toText().c_str());
- }
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_DELEGATION).
+ arg(task->qname);
const Name* const zonename = zoneinfo.getEnclosingZone();
if (zonename == NULL) {
@@ -699,10 +676,7 @@ addSOA(Query& q, ZoneInfo& zoneinfo) {
RRsetList soa;
const Name* const zonename = zoneinfo.getEnclosingZone();
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_ADD_SOA,
- zonename->toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_ADD_SOA).arg(*zonename);
QueryTask newtask(q, *zonename, RRType::SOA(), QueryTask::SIMPLE_QUERY);
RETERR(doQueryTask(newtask, zoneinfo, soa));
if (newtask.flags != 0) {
@@ -716,10 +690,7 @@ addSOA(Query& q, ZoneInfo& zoneinfo) {
inline DataSrc::Result
addNSEC(Query& q, const Name& name, ZoneInfo& zoneinfo) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC,
- name.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC).arg(name);
RRsetList nsec;
QueryTask newtask(q, name, RRType::NSEC(), QueryTask::SIMPLE_QUERY);
@@ -736,14 +707,11 @@ inline DataSrc::Result
getNsec3(Query& q, ZoneInfo& zoneinfo, string& hash, RRsetPtr& target) {
const DataSrc* ds = zoneinfo.getDataSource();
const Name* const zonename = zoneinfo.getEnclosingZone();
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC3,
- zonename->toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC3).arg(*zonename);
if (ds == NULL) {
q.message().setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_NO_DS_NSEC3, zonename->toText().c_str());
+ logger.error(DATASRC_QUERY_NO_DS_NSEC3).arg(*zonename);
return (DataSrc::ERROR);
}
@@ -846,8 +814,7 @@ proveNX(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, const bool wildcard) {
const DataSrc* ds = zoneinfo.getDataSource();
if (ds == NULL) {
m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_NO_DS_NSEC,
- zonename->toText().c_str());
+ logger.error(DATASRC_QUERY_NO_DS_NSEC).arg(*zonename);
return (DataSrc::ERROR);
}
ds->findPreviousName(task->qname, nsecname, zonename);
@@ -876,10 +843,7 @@ proveNX(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, const bool wildcard) {
// Attempt a wildcard lookup
inline DataSrc::Result
tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_WILDCARD,
- task->qname.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_QUERY_WILDCARD).arg(task->qname);
Message& m = q.message();
DataSrc::Result result;
found = false;
@@ -933,9 +897,8 @@ tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
result = proveNX(q, task, zoneinfo, true);
if (result != DataSrc::SUCCESS) {
m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_WILDCARD_PROVENX_FAIL,
- task->qname.toText().c_str(),
- unsigned(result));
+ logger.error(DATASRC_QUERY_WILDCARD_PROVENX_FAIL).
+ arg(task->qname).arg(result);
return (DataSrc::ERROR);
}
}
@@ -958,9 +921,8 @@ tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
RRsetList auth;
if (!refQuery(q, *zonename, zoneinfo, auth)) {
- logger.error(DATASRC_QUERY_WILDCARD_REFERRAL,
- task->qname.toText().c_str(),
- unsigned(result));
+ logger.error(DATASRC_QUERY_WILDCARD_REFERRAL).arg(task->qname).
+ arg(result);
return (DataSrc::ERROR);
}
@@ -976,11 +938,8 @@ tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
//
void
DataSrc::doQuery(Query& q) {
- if (logger.isDebugEnabled(DBG_TRACE_BASIC)) {
- logger.debug(DBG_TRACE_BASIC, DATASRC_QUERY_PROCESS,
- q.qname().toText().c_str(), q.qtype().toText().c_str(),
- q.qclass().toText().c_str());
- }
+ logger.debug(DBG_TRACE_BASIC, DATASRC_QUERY_PROCESS).arg(q.qname()).
+ arg(q.qclass());
Message& m = q.message();
vector<RRsetPtr> additional;
@@ -998,9 +957,7 @@ DataSrc::doQuery(Query& q) {
// Can't query directly for RRSIG.
if (task->qtype == RRType::RRSIG()) {
m.setRcode(Rcode::REFUSED());
- if (logger.isWarnEnabled()) {
- logger.warn(DATASRC_QUERY_RRSIG, task->qname.toText().c_str());
- }
+ logger.warn(DATASRC_QUERY_RRSIG).arg(task->qname);
return;
}
@@ -1028,7 +985,7 @@ DataSrc::doQuery(Query& q) {
result = doQueryTask(*task, zoneinfo, data);
if (result != SUCCESS) {
m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_TASK_FAIL, unsigned(result));
+ logger.error(DATASRC_QUERY_TASK_FAIL).arg(result);
return;
}
@@ -1080,8 +1037,7 @@ DataSrc::doQuery(Query& q) {
RRsetList auth;
if (!refQuery(q, Name(*zonename), zoneinfo, auth) ||
!findRRsetFromList(auth, RRType::NS())) {
- logger.error(DATASRC_QUERY_MISSING_NS,
- zonename->toText().c_str());
+ logger.error(DATASRC_QUERY_MISSING_NS).arg(*zonename);
isc_throw(DataSourceError,
"NS RR not found in " << *zonename << "/" <<
q.qclass());
@@ -1129,8 +1085,7 @@ DataSrc::doQuery(Query& q) {
m.setHeaderFlag(Message::HEADERFLAG_AA, false);
if (!refQuery(q, task->qname, zoneinfo, auth)) {
m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_BAD_REFERRAL,
- task->qname.toText().c_str());
+ logger.error(DATASRC_QUERY_BAD_REFERRAL).arg(task->qname);
return;
}
BOOST_FOREACH (RRsetPtr rrset, auth) {
@@ -1162,8 +1117,7 @@ DataSrc::doQuery(Query& q) {
result = tryWildcard(q, task, zoneinfo, wildcard_found);
if (result != SUCCESS) {
m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_WILDCARD_FAIL,
- task->qname.toText().c_str());
+ logger.error(DATASRC_QUERY_WILDCARD_FAIL).arg(task->qname);
return;
}
@@ -1185,8 +1139,7 @@ DataSrc::doQuery(Query& q) {
result = addSOA(q, zoneinfo);
if (result != SUCCESS) {
- logger.error(DATASRC_QUERY_MISSING_SOA,
- zonename->toText().c_str());
+ logger.error(DATASRC_QUERY_MISSING_SOA).arg(*zonename);
isc_throw(DataSourceError,
"SOA RR not found in " << *zonename <<
"/" << q.qclass());
@@ -1203,8 +1156,7 @@ DataSrc::doQuery(Query& q) {
result = proveNX(q, task, zoneinfo, false);
if (result != DataSrc::SUCCESS) {
m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_PROVENX_FAIL,
- task->qname.toText().c_str());
+ logger.error(DATASRC_QUERY_PROVENX_FAIL).arg(task->qname);
return;
}
}
@@ -1311,9 +1263,8 @@ void
MetaDataSrc::addDataSrc(ConstDataSrcPtr data_src) {
logger.debug(DBG_TRACE_BASIC, DATASRC_META_ADD);
if (getClass() != RRClass::ANY() && data_src->getClass() != getClass()) {
- logger.error(DATASRC_META_ADD_CLASS_MISMATCH,
- data_src->getClass().toText().c_str(),
- getClass().toText().c_str());
+ logger.error(DATASRC_META_ADD_CLASS_MISMATCH).
+ arg(data_src->getClass()).arg(getClass());
isc_throw(Unexpected, "class mismatch");
}
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index bef1aaa..8f710ff 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -21,6 +21,7 @@
#include <dns/rrclass.h>
#include <dns/rrsetlist.h>
#include <dns/masterload.h>
+#include <log/macros.h>
#include <datasrc/memory_datasrc.h>
#include <datasrc/rbtree.h>
@@ -95,10 +96,8 @@ struct MemoryZone::MemoryZoneImpl {
l > origin_labels;
--l, wname = wname.split(1)) {
if (wname.isWildcard()) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_MEM_ADD_WILDCARD,
- name.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_MEM_ADD_WILDCARD).
+ arg(name);
// Ensure a separate level exists for the "wildcarding" name,
// and mark the node as "wild".
DomainNode* node;
@@ -135,14 +134,13 @@ struct MemoryZone::MemoryZoneImpl {
// (depending on how we support DNSSEC). We should revisit it
// at that point.
if (!domain->empty()) {
- logger.error(DATASRC_MEM_CNAME_TO_NONEMPTY,
- rrset->getName().toText().c_str());
+ logger.error(DATASRC_MEM_CNAME_TO_NONEMPTY).
+ arg(rrset->getName());
isc_throw(AddError, "CNAME can't be added with other data for "
<< rrset->getName());
}
} else if (domain->find(RRType::CNAME()) != domain->end()) {
- logger.error(DATASRC_MEM_CNAME_COEXIST,
- rrset->getName().toText().c_str());
+ logger.error(DATASRC_MEM_CNAME_COEXIST).arg(rrset->getName());
isc_throw(AddError, "CNAME and " << rrset->getType() <<
" can't coexist for " << rrset->getName());
}
@@ -160,8 +158,7 @@ struct MemoryZone::MemoryZoneImpl {
(rrset->getType() == RRType::NS() &&
domain->find(RRType::DNAME()) != domain->end())))
{
- logger.error(DATASRC_MEM_DNAME_NS,
- rrset->getName().toText().c_str());
+ logger.error(DATASRC_MEM_DNAME_NS).arg(rrset->getName());
isc_throw(AddError, "DNAME can't coexist with NS in non-apex "
"domain " << rrset->getName());
}
@@ -183,9 +180,8 @@ struct MemoryZone::MemoryZoneImpl {
// XXX: this is not only for CNAME or DNAME. We should generalize
// this code for all other "singleton RR types" (such as SOA) in a
// separate task.
- logger.error(DATASRC_MEM_SINGLETON,
- rrset->getName().toText().c_str(),
- rrset->getType().toText().c_str());
+ logger.error(DATASRC_MEM_SINGLETON).arg(rrset->getName()).
+ arg(rrset->getType());
isc_throw(AddError, "multiple RRs of singleton type for "
<< rrset->getName());
}
@@ -194,9 +190,8 @@ struct MemoryZone::MemoryZoneImpl {
if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
compare.getRelation() != NameComparisonResult::EQUAL)
{
- logger.error(DATASRC_MEM_OUT_OF_ZONE,
- rrset->getName().toText().c_str(),
- origin_.toText().c_str());
+ logger.error(DATASRC_MEM_OUT_OF_ZONE).arg(rrset->getName()).
+ arg(origin_);
isc_throw(OutOfZone, "The name " << rrset->getName() <<
" is not contained in zone " << origin_);
}
@@ -211,14 +206,12 @@ struct MemoryZone::MemoryZoneImpl {
// behavior.
if (rrset->getName().isWildcard()) {
if (rrset->getType() == RRType::NS()) {
- logger.error(DATASRC_MEM_WILDCARD_NS,
- rrset->getName().toText().c_str());
+ logger.error(DATASRC_MEM_WILDCARD_NS).arg(rrset->getName());
isc_throw(AddError, "Invalid NS owner name (wildcard): " <<
rrset->getName());
}
if (rrset->getType() == RRType::DNAME()) {
- logger.error(DATASRC_MEM_WILDCARD_DNAME,
- rrset->getName().toText().c_str());
+ logger.error(DATASRC_MEM_WILDCARD_DNAME).arg(rrset->getName());
isc_throw(AddError, "Invalid DNAME owner name (wildcard): " <<
rrset->getName());
}
@@ -231,12 +224,8 @@ struct MemoryZone::MemoryZoneImpl {
*/
// Implementation of MemoryZone::add
result::Result add(const ConstRRsetPtr& rrset, DomainTree* domains) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_MEM_ADD_RRSET,
- rrset->getName().toText().c_str(),
- rrset->getType().toText().c_str(),
- origin_.toText().c_str());
- }
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ADD_RRSET).
+ arg(rrset->getName()).arg(rrset->getType()).arg(origin_);
// Sanitize input
addValidation(rrset);
@@ -298,9 +287,8 @@ struct MemoryZone::MemoryZoneImpl {
void addFromLoad(const ConstRRsetPtr& set, DomainTree* domains) {
switch (add(set, domains)) {
case result::EXIST:
- logger.error(DATASRC_MEM_DUP_RRSET,
- set->getName().toText().c_str(),
- set->getType().toText().c_str());
+ logger.error(DATASRC_MEM_DUP_RRSET).arg(set->getName()).
+ arg(set->getType());
isc_throw(dns::MasterLoadError, "Duplicate rrset: " <<
set->toText());
case result::SUCCESS:
@@ -396,11 +384,8 @@ struct MemoryZone::MemoryZoneImpl {
rrset, bool rename)
{
if (rename) {
- if (logger.isDebugEnabled(DBG_TRACE_DETAILED)) {
- logger.debug(DBG_TRACE_DETAILED, DATASRC_MEM_RENAME,
- rrset->getName().toText().c_str(),
- name.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DETAILED, DATASRC_MEM_RENAME).
+ arg(rrset->getName()).arg(name);
/*
* We lose a signature here. But it would be wrong anyway, because
* the name changed. This might turn out to be unimportant in
@@ -423,10 +408,7 @@ struct MemoryZone::MemoryZoneImpl {
FindResult find(const Name& name, RRType type,
RRsetList* target, const FindOptions options) const
{
- if (logger.isDebugEnabled(DBG_TRACE_BASIC)) {
- logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_FIND,
- name.toText().c_str(), type.toText().c_str());
- }
+ logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_FIND).arg(name).arg(type);
// Get the node
DomainNode* node(NULL);
FindState state(options);
@@ -453,20 +435,16 @@ struct MemoryZone::MemoryZoneImpl {
* is NULL.
*/
if (state.dname_node_ != NULL) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND,
- state.rrset_->getName().toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND).
+ arg(state.rrset_->getName());
// We were traversing a DNAME node (and wanted to go
// lower below it), so return the DNAME
return (FindResult(DNAME, prepareRRset(name, state.rrset_,
rename)));
}
if (state.zonecut_node_ != NULL) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND,
- state.rrset_->getName().toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
+ arg(state.rrset_->getName());
return (FindResult(DELEGATION, prepareRRset(name,
state.rrset_, rename)));
}
@@ -605,19 +583,13 @@ struct MemoryZone::MemoryZoneImpl {
MemoryZone::MemoryZone(const RRClass& zone_class, const Name& origin) :
impl_(new MemoryZoneImpl(zone_class, origin))
{
- if (logger.isDebugEnabled(DBG_TRACE_BASIC)) {
- logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_CREATE,
- origin.toText().c_str(),
- zone_class.toText().c_str());
- }
+ logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_CREATE).arg(origin).
+ arg(zone_class);
}
MemoryZone::~MemoryZone() {
- if (logger.isDebugEnabled(DBG_TRACE_BASIC)) {
- logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_DESTROY,
- getOrigin().toText().c_str(),
- getClass().toText().c_str());
- }
+ logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_DESTROY).arg(getOrigin()).
+ arg(getClass());
delete impl_;
}
@@ -646,11 +618,8 @@ MemoryZone::add(const ConstRRsetPtr& rrset) {
void
MemoryZone::load(const string& filename) {
- if (logger.isDebugEnabled(DBG_TRACE_BASIC)) {
- logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_LOAD,
- getOrigin().toText().c_str(),
- filename.c_str());
- }
+ logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(getOrigin()).
+ arg(filename);
// Load it into a temporary tree
MemoryZoneImpl::DomainTree tmp;
masterLoad(filename.c_str(), getOrigin(), getClass(),
@@ -663,11 +632,8 @@ MemoryZone::load(const string& filename) {
void
MemoryZone::swap(MemoryZone& zone) {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_SWAP,
- getOrigin().toText().c_str(),
- zone.getOrigin().toText().c_str());
- }
+ logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_SWAP).arg(getOrigin()).
+ arg(zone.getOrigin());
std::swap(impl_, zone.impl_);
}
@@ -708,11 +674,8 @@ MemoryDataSrc::addZone(ZonePtr zone) {
"Null pointer is passed to MemoryDataSrc::addZone()");
}
- if (logger.isDebugEnabled(DBG_TRACE_BASIC)) {
- logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_ADD_ZONE,
- zone->getOrigin().toText().c_str(),
- zone->getClass().toText().c_str());
- }
+ logger.debug(DBG_TRACE_BASIC, DATASRC_MEM_ADD_ZONE).arg(zone->getOrigin()).
+ arg(zone->getClass().toText());
const result::Result result = impl_->zone_table.addZone(zone);
if (result == result::SUCCESS) {
@@ -723,10 +686,7 @@ MemoryDataSrc::addZone(ZonePtr zone) {
MemoryDataSrc::FindResult
MemoryDataSrc::findZone(const isc::dns::Name& name) const {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_MEM_FIND_ZONE,
- name.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_MEM_FIND_ZONE).arg(name);
return (FindResult(impl_->zone_table.findZone(name).code,
impl_->zone_table.findZone(name).zone));
}
diff --git a/src/lib/datasrc/messagedef.mes b/src/lib/datasrc/messagedef.mes
index 5a7aa21..e4add48 100644
--- a/src/lib/datasrc/messagedef.mes
+++ b/src/lib/datasrc/messagedef.mes
@@ -17,485 +17,484 @@ $NAMESPACE isc::datasrc
# \brief Messages for the data source library
-CACHE_CREAT Creating the hotspot cache
+CACHE_CREATE creating the hotspot cache
+ Debug information that the hotspot cache was created at startup.
-CACHE_DESTROY Destroying the hotspot cache
+CACHE_DESTROY destroying the hotspot cache
+ Debug information. The hotspot cache is being destroyed.
-CACHE_INSERT Inserting item '%s' into the cache
+CACHE_INSERT inserting item '%1' into the cache
+ Debug information. It means a new item is being inserted into the hotspot
+ cache.
-CACHE_OLD_FOUND Older instance of cache item found, replacing
+CACHE_OLD_FOUND older instance of cache item found, replacing
+ Debug information. While inserting an item into the hotspot cache, an older
+ instance of an item with the same name was found. The old instance will be
+ removed. This should be directly followed by CACHE_REMOVE.
-CACHE_FULL Cache is full, dropping oldest
+CACHE_FULL cache is full, dropping oldest
+ Debug information. After inserting an item into the hotspot cache, the
+ maximum number of items was exceeded, so the least recently used item will
+ be dropped. This should be directly followed by CACHE_REMOVE.
-CACHE_REMOVE Removing '%s' from the cache
+CACHE_REMOVE removing '%1' from the cache
+ Debug information. An item is being removed from the hotspot cache.
-CACHE_LOOKUP Looking up '%s' in the cache
+CACHE_LOOKUP looking up '%1' in the cache
+ Debug information. We are trying to look up an item in the hotspot cache.
+ Further progress and result will follow.
-CACHE_NOT_FOUND The item was not found
-+ Debug information. The item we tried to look in the last CACHE_LOOKUP was
-+ not found in the hotspot cache.
+CACHE_NOT_FOUND the item '%1' was not found
++ Debug information. We tried to look up an item in the hotspot cache, but
++ it is not there.
-CACHE_FOUND The item was found
-+ Debug information. The last CACHE_LOOKUP was successful, eg. we have found
-+ the requested item in the hotspot cache.
+CACHE_FOUND the item '%1' was found
++ Debug information. We successfully looked up an item in the hotspot cache.
-CACHE_EXPIRED The item is expired
-+ Debug information. The item requested in the last CACHE_LOOKUP was in the
-+ hotspot cache, but it was old. We're going to remove it and report we don't
-+ have it (the external result will be the same as with CACHE_NOT_FOUND).
+CACHE_EXPIRED the item '%1' is expired
++ Debug information. We tried to find an item in the hotspot cache and in fact
++ we did, but it was too old. So we pretend we didn't find it at all (the
++ external effect is the same as CACHE_NOT_FOUND).
-CACHE_SLOTS Setting the cache size to '%d'
+CACHE_SLOTS setting the cache size to '%1', dropping '%2' items
+ The maximum allowed number of items of the hotspot cache is set to the given
+ number. If there are too many, we're going to drop them right now. The size
+ of 0 means no limit.
-CACHE_ENABLE Enabling the cache
+CACHE_ENABLE enabling the cache
+ The hotspot cache is enabled from now on.
-CACHE_DISABLE Disabling the cache
+CACHE_DISABLE disabling the cache
+ The hotspot cache is disabled from now on. It is not going to store
+ information or return anything.
-QUERY_SYNTH_CNAME Synthesizing CNAME from DNAME on '%s'
-+ Debug info. While answering a query, we met a DNAME. We'll return the DNAME,
-+ but we're creating a CNAME for clients that don't understand DNAMEs.
+QUERY_SYNTH_CNAME synthesizing CNAME from DNAME on '%1'
++ Debug information. While answering a query, we met a DNAME. We'll return the
++ DNAME, but we're creating a CNAME for clients that don't understand DNAMEs.
-QUERY_EMPTY_DNAME The DNAME on '%s' is empty
+QUERY_EMPTY_DNAME the DNAME on '%1' is empty
+ We tried to synthesize a CNAME from this DNAME, but it contains no records.
+ This indicates problem with supplied data.
-QUERY_GET_NS_ADDITIONAL Addition of A/AAAA for '%s' requested by NS '%s'
+QUERY_GET_NS_ADDITIONAL addition of A/AAAA for '%1' requested by NS '%2'
+ Debug information. While processing a query, we met a NS record. It
+ references the mentioned address, so we want to look up A/AAAA records for it
+ and put it into the additional section.
-QUERY_GET_MX_ADDITIONAL Addition of A/AAAA for '%s' requested by MX '%s'
+QUERY_GET_MX_ADDITIONAL addition of A/AAAA for '%1' requested by MX '%2'
+ Debug information. While processing a query, we met a MX record. It
+ references the mentioned address, so we want to look up A/AAAA records for it
+ and put it into the additional section.
-QUERY_FOLLOW_CNAME Following CNAME at '%s'
+QUERY_FOLLOW_CNAME following CNAME at '%1'
+ Debug information. The domain is a CNAME (or a DNAME and we created a CNAME
+ for it already), so we're following it.
-QUERY_EMPTY_CNAME CNAME at '%s' is empty
+QUERY_EMPTY_CNAME cNAME at '%1' is empty
+ We tried to follow a CNAME, but contains no records. We have nothing to
+ follow, so we will have nothing in the answer. This indicates a problem with
+ supplied data.
-QUERY_TOO_MANY_CNAMES CNAME chain limit exceeded at '%s'
+QUERY_TOO_MANY_CNAMES cNAME chain limit exceeded at '%1'
+ While answering a query, we followed a CNAME. Then another one. And after 16
+ CNAMEs we decided it's enough and we won't follow more. Long CNAME chains
+ are discouraged, and this might be a loop as well. Note that some of the
+ CNAMEs might have been synthesised from DNAMEs internally. This indicates
+ a problem with supplied data.
-QUERY_CHECK_CACHE Checking cache for '%s/%s'
+QUERY_CHECK_CACHE checking cache for '%1/%2'
+ Debug information. While processing a query we're looking into the hotspot
+ cache.
-QUERY_NO_CACHE_ANY_SIMPLE Ignoring cache for ANY query
+QUERY_NO_CACHE_ANY_SIMPLE ignoring cache for ANY query
+ Debug information. We don't really want to use cache for simple ANY query
+ (ANY as the type or class).
-QUERY_NO_CACHE_ANY_AUTH Ignoring cache for ANY query
+QUERY_NO_CACHE_ANY_AUTH ignoring cache for ANY query
+ Debug information. We don't really want to use cache for authoritative ANY
+ query (ANY as the type or class).
-DO_QUERY Handling query for '%s/%s'
+DO_QUERY handling query for '%1/%2'
+ Debug information. We're processing some internal query for given name and
+ type.
-QUERY_NO_ZONE No zone containing '%s' in class '%s'
+QUERY_NO_ZONE no zone containing '%1' in class '%2'
+ We tried to get the domain but there's no zone in our data that encloses
+ the name. Maybe someone sent a query to wrong server for some reason.
-QUERY_CACHED Data found in cache
+QUERY_CACHED data found in cache
+ Debug information. We found the requested data in cache, so we're not
+ querying the real data source.
-QUERY_IS_SIMPLE Simple query
+QUERY_IS_SIMPLE simple query
+ Debug information. The last DO_QUERY is a simple query.
-QUERY_IS_AUTH Auth query
+QUERY_IS_AUTH auth query
+ Debug information. The last DO_QUERY is an auth query.
-QUERY_IS_GLUE Glue query
+QUERY_IS_GLUE glue query
+ Debug information. The last DO_QUERY is query for glue addresses.
-QUERY_IS_NOGLUE Query for non-glue addresses
+QUERY_IS_NOGLUE query for non-glue addresses
+ Debug information. The last DO_QUERY is query for addresses that are not
+ glue.
-QUERY_IS_REF Query for referral
+QUERY_IS_REF query for referral
+ Debug information. The last DO_QUERY is query for referral information.
-QUERY_SIMPLE_FAIL The underlying data source failed with %u
+QUERY_SIMPLE_FAIL the underlying data source failed with %1
+ We queried the data source to answer a simple query and it returned error
-+ (1 is some error, 2 is not implemented). The data source should have log
++ (1 is some error, 2 is not implemented). The data source should have logged
+ the specific error already.
-QUERY_AUTH_FAIL The underlying data source failed with %u
+QUERY_AUTH_FAIL the underlying data source failed with %1
+ We queried the data source to answer authoritative query and it returned
+ error (1 is some error, 2 is not implemented). The data source should have
+ log the specific error already.
-QUERY_GLUE_FAIL The underlying data source failed with %u
+QUERY_GLUE_FAIL the underlying data source failed with %1
+ We queried the data source to answer query for glue addresses and it returned
+ error (1 is some error, 2 is not implemented). The data source should have
+ log the specific error already.
-QUERY_NOGLUE_FAIL The underlying data source failed with %u
+QUERY_NOGLUE_FAIL the underlying data source failed with %1
+ We queried the data source to answer query for non-glue addresses and it
+ returned error (1 is some error, 2 is not implemented). The data source
+ should have log the specific error already.
-QUERY_REF_FAIL The underlying data source failed with %u
+QUERY_REF_FAIL the underlying data source failed with %1
+ We queried the data source to answer query for referral and it
+ returned error (1 is some error, 2 is not implemented). The data source
+ should have log the specific error already.
-QUERY_INVALID_OP Invalid query operation requested
+QUERY_INVALID_OP invalid query operation requested
+ This indicates a programmer error. The DO_QUERY was called with unknown
+ operation code.
-QUERY_ADD_RRSET Adding RRset '%s/%s' to message
-+ Debug information. We're adding the rrset to answer message.
+QUERY_ADD_RRSET adding RRset '%1/%2' to message
++ Debug information. We're adding the RRset to answer message.
-QUERY_COPY_AUTH Copying authoritative section into message
+QUERY_COPY_AUTH copying authoritative section into message
+ Debug information. We're copying referral information into authoritative
+ section of the response message.
-QUERY_DELEGATION Looking for delegation on the path to '%s'
+QUERY_DELEGATION looking for delegation on the path to '%1'
+ Debug information. We're looking if there's a delegation point on the way
+ down to the given domain.
-QUERY_ADD_SOA Adding SOA of '%s'
+QUERY_ADD_SOA adding SOA of '%1'
+ Debug information. We're adding a SOA record for the given zone into the
+ authority section.
-QUERY_ADD_NSEC Adding NSEC record for '%s'
+QUERY_ADD_NSEC adding NSEC record for '%1'
+ Debug information. We're adding NSEC record for this domain.
-QUERY_ADD_NSEC3 Adding NSEC3 record of zone '%s'
+QUERY_ADD_NSEC3 adding NSEC3 record of zone '%1'
+ Debug information. We're adding an NSEC3 record for this zone.
-QUERY_NO_DS_NSEC3 There's no DS record in the '%s' zone
+QUERY_NO_DS_NSEC3 there's no DS record in the '%1' zone
+ We tried to insert a NSEC3 record into the message. But we didn't find a DS
+ record for this zone.
-QUERY_NO_DS_NSEC There's no DS record in the '%s' zone
+QUERY_NO_DS_NSEC there's no DS record in the '%1' zone
+ We tried to insert a NSEC record into the message. But we didn't find a DS
+ record for this zone.
-QUERY_WILDCARD Looking for a wildcard covering '%s'
+QUERY_WILDCARD looking for a wildcard covering '%1'
+ Debug information. We didn't find a direct match, so we're trying to find if
+ there's a wildcard we could use to answer the query.
-QUERY_WILDCARD_PROVENX_FAIL Unable to prove nonexistence of '%s' (%u)
+QUERY_WILDCARD_PROVENX_FAIL unable to prove nonexistence of '%1' (%2)
+ While processing a wildcard, we tried to prove nonexistence of the given
+ domain or record. The code is 1 for error and 2 for not implemented.
-QUERY_WILDCARD_REFERRAL Unable to find referral info for '%s' (%u)
+QUERY_WILDCARD_REFERRAL unable to find referral info for '%1' (%2)
+ While processing a wildcard we met a referral. But we were not able to get
+ information for it. The code is 1 for error, 2 for not implemented.
-QUERY_PROCESS Processing query '%s/%s' in the '%s' class
+QUERY_PROCESS processing query '%1/%2' in the '%3' class
+ Debug information. We're starting to process a user query.
-QUERY_RRSIG Unable to answer RRSIG query
+QUERY_RRSIG unable to answer RRSIG query
+ The server is unable to answer a direct query for RRSIG type, but was asked
+ to do so.
-QUERY_MISPLACED_TASK Task of this type should not be here
+QUERY_MISPLACED_TASK task of this type should not be here
+ This indicates a programming error. We found a task in the internal task
+ queue which wasn't supposed to ever be put into the queue, but handled
+ directly.
-QUERY_TASK_FAIL Task failed with %u
+QUERY_TASK_FAIL task failed with %1
+ The query subtask failed. The reason should have been reported by the subtask
+ already. The code is 1 for error, 2 for not implemented.
-QUERY_MISSING_NS Missing NS records for '%s'
+QUERY_MISSING_NS missing NS records for '%1'
+ We wanted to put the nameserver records into the authority section, but we
+ discovered the zone doesn't have them. This indicates problem with provided
+ data.
-UNEXPECTED_QUERY_STATE Unexpected query state
+UNEXPECTED_QUERY_STATE unexpected query state
+ This indicates a programming error. We generated an internal task of type
+ unknown to us.
-QUERY_FAIL Query failed
+QUERY_FAIL query failed
+ Some subtask of query processing failed. The reason should have been reported
+ already. We are returning SERVFAIL.
-QUERY_BAD_REFERRAL Bad referral to '%s'
+QUERY_BAD_REFERRAL bad referral to '%1'
+ We discovered that the domain lives in another zone. But we are not able to
+ generate referral information to it.
-QUERY_WILDCARD_FAIL Error processing wildcard for '%s'
+QUERY_WILDCARD_FAIL error processing wildcard for '%1'
+ We tried to find a wildcard to cover the domain, but there happened to be
+ some (hopefully already reported) error for it.
-QUERY_MISSING_SOA The zone '%s' has no SOA
+QUERY_MISSING_SOA the zone '%1' has no SOA
+ We tried to answer negatively, but there's no SOA record in the zone.
-QUERY_PROVENX_FAIL Unable to prove nonexistence of '%s'
+QUERY_PROVENX_FAIL unable to prove nonexistence of '%1'
+ The user wants DNSSEC and we discovered the entity doesn't exist (either
+ domain or the record). But there was an error getting NSEC/NSEC3 record
+ to prove the nonexistence.
-QUERY_UNKNOWN_RESULT Unknown result of subtask
+QUERY_UNKNOWN_RESULT unknown result of subtask
+ This indicates a programmer error. The answer of subtask doesn't look like
+ anything we would know.
-META_ADD Adding a data source into meta data source
+META_ADD adding a data source into meta data source
+ Debug information. We add yet another data source into the meta data source
+ (probably at startup or reconfiguration).
-META_ADD_CLASS_MISMATCH Mismatch between classes '%s' and '%s'
+META_ADD_CLASS_MISMATCH mismatch between classes '%1' and '%2'
+ We tried to add a data source of one class into a meta data source of a
+ different type. The types must be the same.
-META_REMOVE Removing data source from meta data source
+META_REMOVE removing data source from meta data source
+ Debug information. We take a data source out of meta data source (probably
+ at shutdown or reconfiguration).
-MEM_ADD_WILDCARD Adding wildcards for '%s'
+MEM_ADD_WILDCARD adding wildcards for '%1'
+ Debug information. We need some special marks above each * in wildcard name
+ in the in-memory data source. We are adding the marks for this name now.
-MEM_CNAME_TO_NONEMPTY Can't add CNAME to domain with other data in '%s'
+MEM_CNAME_TO_NONEMPTY can't add CNAME to domain with other data in '%1'
+ Someone or something tried to add a CNAME into a domain that already contains
+ some other data. But the protocol forbids coexistence of CNAME with anything
+ (RFC 1034, section 3.6.2). This indicates a problem with provided data.
-MEM_CNAME_COEXIST Can't add data to CNAME in domain '%s'
+MEM_CNAME_COEXIST can't add data to CNAME in domain '%1'
+ This is the same problem as in MEM_CNAME_TO_NONEMPTY, but it happened the
+ other way around -- adding some outher data to CNAME.
-MEM_DNAME_NS DNAME and NS can't coexist in non-apex domain '%s'
+MEM_DNAME_NS dNAME and NS can't coexist in non-apex domain '%1'
+ It was requested for DNAME and NS records to be put into the same domain
+ which is not the apex (the top of the zone). This is forbidden by RFC
+ 2672, section 3. This indicates a problem with provided data.
-MEM_SINGLETON Trying to add multiple RRs for domain '%s' and type '%s'
+MEM_SINGLETON trying to add multiple RRs for domain '%1' and type '%2'
+ Some resource types are singletons -- only one is allowed in a domain
+ (for example CNAME or SOA). This indicates a problem with provided data.
-MEM_OUT_OF_ZONE Domain '%s' doesn't belong to zone '%s'
+MEM_OUT_OF_ZONE domain '%1' doesn't belong to zone '%2'
+ It was attempted to add the domain into a zone that shouldn't have it
+ (eg. the domain is not subdomain of the zone origin). This indicates a
+ problem with provided data.
-MEM_WILDCARD_NS NS record in wildcard domain '%s'
+MEM_WILDCARD_NS nS record in wildcard domain '%1'
+ We refuse to load NS record into a wildcard domain. It is'n explicitly
+ forbidden, but the protocol is ambiguous about how this should behave and
-+ bind 9 refuses that as well. We don't like your zone, please describe it
++ BIND 9 refuses that as well. We don't like your zone, please describe it
+ using different tools.
-MEM_WILDCARD_DNAME DNAME record in wildcard domain '%s'
+MEM_WILDCARD_DNAME dNAME record in wildcard domain '%1'
+ We refuse to load DNAME record into a wildcard domain. It is'n explicitly
+ forbidden, but the protocol is ambiguous about how this should behave and
-+ bind 9 refuses that as well. We don't like your zone, please describe it
++ BIND 9 refuses that as well. We don't like your zone, please describe it
+ using different tools.
-MEM_ADD_RRSET Adding RRset '%s/%s' into zone '%s'
+MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'
+ Debug information. We're adding an RRset to the zone of in-memory data
+ source.
-MEM_DUP_RRSET Duplicate rrset '%s/%s'
+MEM_DUP_RRSET duplicate RRset '%1/%2'
+ An RRset is being inserted into in-memory data source for a second time.
+ The original version must be removed first. Note that we don't support
+ loading master files where an RRset is split into multiple locations yet.
-MEM_DNAME_ENCOUNTERED Encountered a DNAME
+MEM_DNAME_ENCOUNTERED encountered a DNAME
+ Debug information. While searching for the requested domain, we encountered
+ a DNAME on the way. This may lead to redirection to a different domain and
+ stop the search.
-MEM_NS_ENCOUNTERED Encountered a NS
+MEM_NS_ENCOUNTERED encountered a NS
+ Debug information. While searching for the requested domain, we encountered
+ a NS on the way (a delegation). This may lead to stop of the search.
-MEM_RENAME Renaming rrset from '%s' to '%s'
+MEM_RENAME renaming RRset from '%1' to '%2'
+ Debug information. We generate an RRset from a different RRset (most probably
+ a wildcard). So we need to rename it to whatever the user asked for. In fact,
+ we can't rename RRset (it's not possible with our libraries), so we create
+ a new one and copy everything.
-MEM_FIND Find '%s/%s'
+MEM_FIND find '%1/%2'
+ Debug information. We're going to search the in-memory data source to find
+ requestet RRset.
-MEM_DNAME_FOUND DNAME found at '%s'
+MEM_DNAME_FOUND dNAME found at '%1'
+ Debug information. We found a DNAME instead of the requested record.
-MEM_DELEG_FOUND Delegation found at '%s'
+MEM_DELEG_FOUND delegation found at '%1'
+ Debug information. We found a delegation point above the requested record.
-MEM_SUPER_STOP Stopped at superdomain, domain is empty
+MEM_SUPER_STOP stopped at superdomain, domain is empty
+ Debug information. The search stopped at a superdomain of the requested
+ domain. The domain is a empty nonterminal, therefore we treat it as NXRRSET
+ case (eg. the domain exists, but it doesn't have the requested record type).
-MEM_WILDCARD_CANCEL Wildcard match canceled
+MEM_WILDCARD_CANCEL wildcard match canceled
+ Debug information. We reached a domain above wildcard, but there's something
+ below the requested domain. Therefore the wildcard doesn't apply here.
+ This behaviour is specified by RFC 1034, section 4.3.3
-MEM_NOTFOUND Requested domain not found
+MEM_NOTFOUND requested domain not found
+ Debug information. The requested domain does not exist.
-MEM_DOMAIN_EMPTY Requested domain is empty
+MEM_DOMAIN_EMPTY requested domain is empty
+ Debug information. The requested domain exists in the tree of domains, but
+ it is empty. Therefore it doesn't contain the requested resource type.
-MEM_EXACT_DELEGATION Delegation at the exact domain
+MEM_EXACT_DELEGATION delegation at the exact domain
+ Debug information. There's a NS record at the requested domain. This means
+ this zone is not authoritative for the requested domain, but a delegation
+ should be followed. The requested domain is an apex of some zone.
-MEM_ANY_SUCCESS ANY query successful
+MEM_ANY_SUCCESS aNY query successful
+ Debug information. The domain was found and we answer an ANY type query by
+ providing everything we found inside the domain.
-MEM_SUCCESS Query successful
+MEM_SUCCESS query successful
+ Debug information. We found the record we searched for.
-MEM_CNAME CNAME at the domain
+MEM_CNAME cNAME at the domain
+ Debug information. The requested domain is an alias to a different domain,
+ returning the CNAME instead.
-MEM_NXRRSET No such type
+MEM_NXRRSET no such type
+ Debug information. The domain exists, but it doesn't hold any record of the
+ requested type.
-MEM_CREATE Creating zone '%s' in '%s' class
+MEM_CREATE creating zone '%1' in '%2' class
+ Debug information. We're creating representation of a zone for the in-memory
+ data source.
-MEM_DESTROY Destroying zone '%s' in '%s' class
+MEM_DESTROY destroying zone '%1' in '%2' class
+ Debug information. We're destroying the representation of zone in the
+ in-memory data source.
-MEM_LOAD Loading zone '%s' from file '%s'
+MEM_LOAD loading zone '%1' from file '%2'
+ Debug information. We're loading the content of zone from a master file.
-MEM_SWAP Swapping contents of two zone representations ('%s' and '%s')
+MEM_SWAP swapping contents of two zone representations ('%1' and '%2')
+ Debug information. We exchange contents of the zones. This is usual practice
+ to do some manipulation in exception-safe manner -- we prepare the new data
+ in a different zone object and when it works, we swap it with the old, then
+ we can safely destroy the old one.
-MEM_ADD_ZONE Adding zone '%s/%s'
+MEM_ADD_ZONE adding zone '%1/%2'
+ Debug information. We're adding this zone into the in-memory data source.
-MEM_FIND_ZONE Looking for zone '%s'
+MEM_FIND_ZONE looking for zone '%1'
+ Debug information. We're looking for a zone in the in-memory data source.
-STATIC_CREATE Creating the static datasource
+STATIC_CREATE creating the static datasource
+ Debug information. We're creating the static data source (the one holding
+ stuff like version.bind).
-STATIC_BAD_CLASS Static data source can handle CH only
+STATIC_BAD_CLASS static data source can handle CH only
+ For some reason, someone asked the static data source a query that is not in
+ the CH class.
-STATIC_FIND Looking for '%s/%s'
+STATIC_FIND looking for '%1/%2'
+ Debug information. We're looking for this resource record set in the static
+ data source.
-SQLITE_FINDREC Looking for record '%s/%s'
+SQLITE_FINDREC looking for record '%1/%2'
+ Debug information. The SQLite data source is looking up records of given name
+ and type in the database.
-SQLITE_ENCLOSURE Looking for zone containing '%s'
+SQLITE_ENCLOSURE looking for zone containing '%1'
+ Debug information. The SQLite data source is trying to identify, which zone
+ should hold this domain.
-SQLITE_ENCLOSURE_BAD_CLASS Class mismatch looking for a zone ('%s' and '%s')
+SQLITE_ENCLOSURE_BAD_CLASS class mismatch looking for a zone ('%1' and '%2')
+ The SQLite data source can handle only one class at a time and it was asked
+ to identify which zone is holding data of a different class.
-SQLITE_ENCLOSURE_NOTFOUND No zone contains it
+SQLITE_ENCLOSURE_NOTFOUND no zone contains it
+ Debug information. The last SQLITE_ENCLOSURE query was unsuccessful, there's
+ no such zone in our data.
-SQLITE_PREVIOUS Looking for name previous to '%s'
+SQLITE_PREVIOUS looking for name previous to '%1'
+ Debug information. We're trying to look up name preceding the supplied one.
-SQLITE_PREVIOUS_NO_ZONE No zone containing '%s'
+SQLITE_PREVIOUS_NO_ZONE no zone containing '%1'
+ The SQLite data source tried to identify name preceding this one. But this
+ one is not contained in any zone in the data source.
-SQLITE_FIND_NSEC3 Looking for NSEC3 in zone '%s' for hash '%s'
+SQLITE_FIND_NSEC3 looking for NSEC3 in zone '%1' for hash '%2'
+ Debug information. We're trying to look up a NSEC3 record in the SQLite data
+ source.
-SQLITE_FIND_NSEC3_NO_ZONE No such zone '%s'
+SQLITE_FIND_NSEC3_NO_ZONE no such zone '%1'
+ The SQLite data source was asked to provide a NSEC3 record for given zone.
+ But it doesn't contain that zone.
-SQLITE_FIND Looking for RRset '%s/%s'
+SQLITE_FIND looking for RRset '%1/%2'
+ Debug information. The SQLite data source is looking up a resource record
+ set.
-SQLITE_FIND_BAD_CLASS Class mismatch looking for an rrset ('%s' and '%s')
+SQLITE_FIND_BAD_CLASS class mismatch looking for an RRset ('%1' and '%2')
+ The SQLite data source was looking up an RRset, but the data source contains
+ different class than the query was for.
-SQLITE_FINDEXACT Looking for exact RRset '%s/%s'
+SQLITE_FINDEXACT looking for exact RRset '%1/%2'
+ Debug information. The SQLite data source is looking up an exact resource
+ record.
-SQLITE_FINDEXACT_BAD_CLASS Class mismatch looking for an rrset ('%s' and '%s')
+SQLITE_FINDEXACT_BAD_CLASS class mismatch looking for an RRset ('%1' and '%2')
+ The SQLite data source was looking up an exact RRset, but the data source
+ contains different class than the query was for.
-SQLITE_FINDADDRS Looking for A/AAAA addresses for '%s'
+SQLITE_FINDADDRS looking for A/AAAA addresses for '%1'
+ Debug information. The data source is looking up the addresses for given
+ domain name.
-SQLITE_FINDADDRS_BAD_CLASS Class mismatch looking for addresses ('%s' and '%s')
+SQLITE_FINDADDRS_BAD_CLASS class mismatch looking for addresses ('%1' and '%2')
+ The SQLite data source was looking up A/AAAA addresses, but the data source
+ contains different class than the query was for.
-SQLITE_FINDREF Looking for referral at '%s'
+SQLITE_FINDREF looking for referral at '%1'
+ Debug information. The SQLite data source is identifying if this domain is
+ a referral and where it goes.
-SQLITE_FINDREF_BAD_CLASS Class mismatch looking for referral ('%s' and '%s')
+SQLITE_FINDREF_BAD_CLASS class mismatch looking for referral ('%1' and '%2')
+ The SQLite data source was trying to identify, if there's a referral. But the
+ but it contains different class than the query was for.
-SQLITE_CREATE SQLite data source created
+SQLITE_CREATE sQLite data source created
+ Debug information. We're creating an instance of the SQLite data source.
-SQLITE_DESTROY SQLite data source destroyed
+SQLITE_DESTROY sQLite data source destroyed
+ Debug information. We're destroying an instance of SQLite data source.
-SQLITE_SETUP Setting up SQLite database
+SQLITE_SETUP setting up SQLite database
+ The database for SQLite data source was found empty. So we're assuming this
+ is the first run and we initialize it with current schema. It'll still
+ contain no data, but it will be ready for use.
-SQLITE_OPEN Opening SQLite database '%s'
+SQLITE_OPEN opening SQLite database '%1'
+ Debug information. The SQLite data source is loading an SQLite database in
+ the provide file.
-SQLITE_CLOSE Closing SQLite database
+SQLITE_CLOSE closing SQLite database
+ Debug information. The SQLite data source is closing the database file.
diff --git a/src/lib/datasrc/sqlite3_datasrc.cc b/src/lib/datasrc/sqlite3_datasrc.cc
index 2bc6d2e..e28804a 100644
--- a/src/lib/datasrc/sqlite3_datasrc.cc
+++ b/src/lib/datasrc/sqlite3_datasrc.cc
@@ -228,10 +228,8 @@ Sqlite3DataSrc::findRecords(const Name& name, const RRType& rdtype,
RRsetList& target, const Name* zonename,
const Mode mode, uint32_t& flags) const
{
- if (logger.isDebugEnabled(DBG_TRACE_DETAILED)) {
- logger.debug(DBG_TRACE_DETAILED, DATASRC_SQLITE_FINDREC,
- name.toText().c_str(), rdtype.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DETAILED, DATASRC_SQLITE_FINDREC).arg(name).
+ arg(rdtype);
flags = 0;
int zone_id = (zonename == NULL) ? findClosest(name, NULL) :
findClosest(*zonename, NULL);
@@ -350,14 +348,11 @@ Sqlite3DataSrc::findClosest(const Name& name, unsigned int* position) const {
void
Sqlite3DataSrc::findClosestEnclosure(DataSrcMatch& match) const {
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE,
- match.getName().toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE).
+ arg(match.getName());
if (match.getClass() != getClass() && match.getClass() != RRClass::ANY()) {
- logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE_BAD_CLASS,
- getClass().toText().c_str(),
- match.getClass().toText().c_str());
+ logger.error(DATASRC_SQLITE_ENCLOSURE_BAD_CLASS).arg(getClass()).
+ arg(match.getClass());
return;
}
@@ -375,14 +370,11 @@ Sqlite3DataSrc::findPreviousName(const Name& qname,
Name& target,
const Name* zonename) const
{
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_PREVIOUS,
- qname.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_PREVIOUS).arg(qname);
const int zone_id = (zonename == NULL) ?
findClosest(qname, NULL) : findClosest(*zonename, NULL);
if (zone_id < 0) {
- logger.error(DATASRC_SQLITE_PREVIOUS_NO_ZONE, qname.toText().c_str());
+ logger.error(DATASRC_SQLITE_PREVIOUS_NO_ZONE).arg(qname.toText());
return (ERROR);
}
@@ -420,14 +412,11 @@ Sqlite3DataSrc::findCoveringNSEC3(const Name& zonename,
string& hashstr,
RRsetList& target) const
{
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_FIND_NSEC3,
- zonename.toText().c_str(), hashstr.c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_FIND_NSEC3).
+ arg(zonename).arg(hashstr);
const int zone_id = findClosest(zonename, NULL);
if (zone_id < 0) {
- logger.error(DATASRC_SQLITE_FIND_NSEC3_NO_ZONE,
- zonename.toText().c_str());
+ logger.error(DATASRC_SQLITE_FIND_NSEC3_NO_ZONE).arg(zonename);
return (ERROR);
}
@@ -508,13 +497,11 @@ Sqlite3DataSrc::findRRset(const Name& qname,
uint32_t& flags,
const Name* zonename) const
{
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_FIND,
- qname.toText().c_str(), qtype.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_FIND).arg(qname).
+ arg(qtype);
if (qclass != getClass() && qclass != RRClass::ANY()) {
- logger.error(DATASRC_SQLITE_FIND_BAD_CLASS,
- getClass().toText().c_str(), qclass.toText().c_str());
+ logger.error(DATASRC_SQLITE_FIND_BAD_CLASS).arg(getClass()).
+ arg(qclass);
return (ERROR);
}
findRecords(qname, qtype, target, zonename, NORMAL, flags);
@@ -529,13 +516,11 @@ Sqlite3DataSrc::findExactRRset(const Name& qname,
uint32_t& flags,
const Name* zonename) const
{
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_FINDEXACT,
- qname.toText().c_str(), qtype.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_FINDEXACT).arg(qname).
+ arg(qtype);
if (qclass != getClass() && qclass != RRClass::ANY()) {
- logger.error(DATASRC_SQLITE_FINDEXACT_BAD_CLASS,
- getClass().toText().c_str(), qclass.toText().c_str());
+ logger.error(DATASRC_SQLITE_FINDEXACT_BAD_CLASS).arg(getClass()).
+ arg(qclass);
return (ERROR);
}
findRecords(qname, qtype, target, zonename, NORMAL, flags);
@@ -559,13 +544,10 @@ Sqlite3DataSrc::findAddrs(const Name& qname,
uint32_t& flags,
const Name* zonename) const
{
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_FINDADDRS,
- qname.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_FINDADDRS).arg(qname);
if (qclass != getClass() && qclass != RRClass::ANY()) {
- logger.error(DATASRC_SQLITE_FINDADDRS_BAD_CLASS,
- getClass().toText().c_str(), qclass.toText().c_str());
+ logger.error(DATASRC_SQLITE_FINDADDRS_BAD_CLASS).arg(getClass()).
+ arg(qclass);
return (ERROR);
}
findRecords(qname, RRType::ANY(), target, zonename, ADDRESS, flags);
@@ -579,13 +561,10 @@ Sqlite3DataSrc::findReferral(const Name& qname,
uint32_t& flags,
const Name* zonename) const
{
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_FINDREF,
- qname.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_SQLITE_FINDREF).arg(qname);
if (qclass != getClass() && qclass != RRClass::ANY()) {
- logger.error(DATASRC_SQLITE_FINDREF_BAD_CLASS,
- getClass().toText().c_str(), qclass.toText().c_str());
+ logger.error(DATASRC_SQLITE_FINDREF_BAD_CLASS).arg(getClass()).
+ arg(qclass);
return (ERROR);
}
findRecords(qname, RRType::ANY(), target, zonename, DELEGATION, flags);
@@ -716,7 +695,7 @@ checkAndSetupSchema(Sqlite3Initializer* initializer) {
//
void
Sqlite3DataSrc::open(const string& name) {
- logger.debug(DBG_TRACE_BASIC, DATASRC_SQLITE_OPEN, name.c_str());
+ logger.debug(DBG_TRACE_BASIC, DATASRC_SQLITE_OPEN).arg(name);
if (dbparameters->db_ != NULL) {
isc_throw(DataSourceError, "Duplicate SQLite open with " << name);
}
diff --git a/src/lib/datasrc/static_datasrc.cc b/src/lib/datasrc/static_datasrc.cc
index 6d7f750..5d9b676 100644
--- a/src/lib/datasrc/static_datasrc.cc
+++ b/src/lib/datasrc/static_datasrc.cc
@@ -157,10 +157,8 @@ StaticDataSrc::findRRset(const Name& qname,
RRsetList& target, uint32_t& flags,
const Name* const zonename) const
{
- if (logger.isDebugEnabled(DBG_TRACE_DATA)) {
- logger.debug(DBG_TRACE_DATA, DATASRC_STATIC_FIND,
- qname.toText().c_str(), qtype.toText().c_str());
- }
+ logger.debug(DBG_TRACE_DATA, DATASRC_STATIC_FIND).arg(qname).
+ arg(qtype);
flags = 0;
if (qclass != getClass() && qclass != RRClass::ANY()) {
logger.error(DATASRC_STATIC_BAD_CLASS);
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 5a7151e..300cd92 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -17,48 +17,52 @@ EXTRA_DIST += rrtype-placeholder.h
# NOTE: when an rdata file is added, please also add to this list:
EXTRA_DIST += rdata/any_255/tsig_250.cc
EXTRA_DIST += rdata/any_255/tsig_250.h
-EXTRA_DIST += rdata/in_1/aaaa_28.cc
-EXTRA_DIST += rdata/in_1/aaaa_28.h
-EXTRA_DIST += rdata/in_1/a_1.cc
-EXTRA_DIST += rdata/in_1/a_1.h
EXTRA_DIST += rdata/ch_3/a_1.cc
EXTRA_DIST += rdata/ch_3/a_1.h
-EXTRA_DIST += rdata/generic/mx_15.h
-EXTRA_DIST += rdata/generic/rrsig_46.cc
+EXTRA_DIST += rdata/generic/cname_5.cc
+EXTRA_DIST += rdata/generic/cname_5.h
+EXTRA_DIST += rdata/generic/detail/nsec_bitmap.cc
+EXTRA_DIST += rdata/generic/detail/nsec_bitmap.h
EXTRA_DIST += rdata/generic/dname_39.cc
-EXTRA_DIST += rdata/generic/rrsig_46.h
EXTRA_DIST += rdata/generic/dname_39.h
-EXTRA_DIST += rdata/generic/ns_2.cc
-EXTRA_DIST += rdata/generic/nsec_47.cc
-EXTRA_DIST += rdata/generic/ns_2.h
-EXTRA_DIST += rdata/generic/nsec_47.h
-EXTRA_DIST += rdata/generic/opt_41.cc
-EXTRA_DIST += rdata/generic/soa_6.cc
-EXTRA_DIST += rdata/generic/cname_5.cc
EXTRA_DIST += rdata/generic/dnskey_48.cc
-EXTRA_DIST += rdata/generic/opt_41.h
-EXTRA_DIST += rdata/generic/soa_6.h
-EXTRA_DIST += rdata/generic/cname_5.h
EXTRA_DIST += rdata/generic/dnskey_48.h
EXTRA_DIST += rdata/generic/ds_43.cc
EXTRA_DIST += rdata/generic/ds_43.h
-EXTRA_DIST += rdata/generic/txt_16.cc
-EXTRA_DIST += rdata/generic/txt_16.h
EXTRA_DIST += rdata/generic/mx_15.cc
-EXTRA_DIST += rdata/generic/nsec3param_51.h
-EXTRA_DIST += rdata/generic/nsec3param_51.cc
+EXTRA_DIST += rdata/generic/mx_15.h
+EXTRA_DIST += rdata/generic/ns_2.cc
+EXTRA_DIST += rdata/generic/ns_2.h
EXTRA_DIST += rdata/generic/nsec3_50.cc
EXTRA_DIST += rdata/generic/nsec3_50.h
+EXTRA_DIST += rdata/generic/nsec3param_51.cc
+EXTRA_DIST += rdata/generic/nsec3param_51.h
+EXTRA_DIST += rdata/generic/nsec_47.cc
+EXTRA_DIST += rdata/generic/nsec_47.h
+EXTRA_DIST += rdata/generic/opt_41.cc
+EXTRA_DIST += rdata/generic/opt_41.h
EXTRA_DIST += rdata/generic/ptr_12.cc
EXTRA_DIST += rdata/generic/ptr_12.h
+EXTRA_DIST += rdata/generic/rp_17.cc
+EXTRA_DIST += rdata/generic/rp_17.h
+EXTRA_DIST += rdata/generic/rrsig_46.cc
+EXTRA_DIST += rdata/generic/rrsig_46.h
+EXTRA_DIST += rdata/generic/soa_6.cc
+EXTRA_DIST += rdata/generic/soa_6.h
+EXTRA_DIST += rdata/generic/txt_16.cc
+EXTRA_DIST += rdata/generic/txt_16.h
EXTRA_DIST += rdata/hs_4/a_1.cc
EXTRA_DIST += rdata/hs_4/a_1.h
+EXTRA_DIST += rdata/in_1/a_1.cc
+EXTRA_DIST += rdata/in_1/a_1.h
+EXTRA_DIST += rdata/in_1/aaaa_28.cc
+EXTRA_DIST += rdata/in_1/aaaa_28.h
#EXTRA_DIST += rdata/template.cc
#EXTRA_DIST += rdata/template.h
# auto-generate by gen-rdatacode.py:
BUILT_SOURCES = rrclass.h rrtype.h rrparamregistry.cc
-#TODO: check this###BUILT_SOURCES = rdataclass.h rdataclass.cc
+BUILT_SOURCES += rdataclass.h rdataclass.cc
lib_LTLIBRARIES = libdns++.la
@@ -80,15 +84,21 @@ libdns___la_SOURCES += rrsetlist.h rrsetlist.cc
libdns___la_SOURCES += rrttl.h rrttl.cc
libdns___la_SOURCES += rrtype.cc
libdns___la_SOURCES += question.h question.cc
+libdns___la_SOURCES += tsig.h tsig.cc
+libdns___la_SOURCES += tsigerror.h tsigerror.cc
libdns___la_SOURCES += tsigkey.h tsigkey.cc
libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.h
libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.cc
libdns___la_CPPFLAGS = $(AM_CPPFLAGS)
-libdns___la_LIBADD = $(top_builddir)/src/lib/util/libutil.la
+# Most applications of libdns++ will only implicitly rely on libcryptolink,
+# so we add the dependency here so that the applications don't have to link
+# libcryptolink explicitly.
+libdns___la_LIBADD = $(top_builddir)/src/lib/cryptolink/libcryptolink.la
+libdns___la_LIBADD += $(top_builddir)/src/lib/util/libutil.la
-nodist_libdns___la_SOURCES = rdataclass.cc rrclass.h rrtype.h
-nodist_libdns___la_SOURCES += rrparamregistry.cc
+nodist_libdns___include_HEADERS = rdataclass.h rrclass.h rrtype.h
+nodist_libdns___la_SOURCES = rdataclass.cc rrparamregistry.cc
rrclass.h: rrclass-placeholder.h
rrtype.h: rrtype-placeholder.h
@@ -106,13 +116,10 @@ libdns___include_HEADERS = \
question.h \
rcode.h \
rdata.h \
- rdataclass.h \
- rrclass.h \
rrparamregistry.h \
rrset.h \
rrsetlist.h \
rrttl.h \
- rrtype.h \
tsigkey.h
# Purposely not installing these headers:
# util/*.h: used only internally, and not actually DNS specific
diff --git a/src/lib/dns/edns.h b/src/lib/dns/edns.h
index b794183..5731b95 100644
--- a/src/lib/dns/edns.h
+++ b/src/lib/dns/edns.h
@@ -386,7 +386,7 @@ private:
///
/// The intended usage of this function is to parse an OPT RR of an incoming
/// DNS message, while updating the RCODE of the message.
-/// One common usage patter is as follows:
+/// One common usage pattern is as follows:
///
/// \code Message msg;
/// ...
diff --git a/src/lib/dns/python/tests/Makefile.am b/src/lib/dns/python/tests/Makefile.am
index 272f1c1..184f06d 100644
--- a/src/lib/dns/python/tests/Makefile.am
+++ b/src/lib/dns/python/tests/Makefile.am
@@ -20,7 +20,7 @@ EXTRA_DIST += testutil.py
# required by loadable python modules.
LIBRARY_PATH_PLACEHOLDER =
if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
endif
# test using command-line arguments, so use check-local target instead of TESTS
diff --git a/src/lib/dns/python/tests/tsigkey_python_test.py b/src/lib/dns/python/tests/tsigkey_python_test.py
index 06e6868..97be501 100644
--- a/src/lib/dns/python/tests/tsigkey_python_test.py
+++ b/src/lib/dns/python/tests/tsigkey_python_test.py
@@ -44,6 +44,28 @@ class TSIGKeyTest(unittest.TestCase):
TSIGKey.HMACMD5_NAME,
'should be binary') # signature mismatch
+ def test_str(self):
+ k1 = TSIGKey('test.example:CwsLCwsLCwsLCwsLCwsLCw==:hmac-md5.sig-alg.reg.int')
+ self.assertEqual(Name('test.example.'), k1.get_key_name())
+ self.assertEqual(Name('hmac-md5.sig-alg.reg.int.'), k1.get_algorithm_name())
+ self.assertEqual(b'\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b',
+ k1.get_secret())
+ self.assertEqual('test.example.:CwsLCwsLCwsLCwsLCwsLCw==:hmac-md5.sig-alg.reg.int.',
+ k1.to_text())
+
+ self.assertRaises(InvalidParameter, TSIGKey,
+ 'test.example:CwsLCwsLCwsLCwsLCwsLCw==:unsupported')
+ self.assertRaises(InvalidParameter, TSIGKey,
+ '::')
+ self.assertRaises(InvalidParameter, TSIGKey,
+ 'test.example:')
+ self.assertRaises(InvalidParameter, TSIGKey,
+ 'test.example:%bad_base_64%')
+ self.assertRaises(InvalidParameter, TSIGKey,
+ 'test.example:CwsLCwsLCwsLCwsLCwsLCw==:')
+ self.assertRaises(InvalidParameter, TSIGKey,
+ 'test.:example:CwsLCwsLCwsLCwsLCwsLCw==')
+
class TSIGKeyRingTest(unittest.TestCase):
key_name = Name('example.com')
secret = b'someRandomData'
diff --git a/src/lib/dns/python/tsigkey_python.cc b/src/lib/dns/python/tsigkey_python.cc
index aa87909..906dfc0 100644
--- a/src/lib/dns/python/tsigkey_python.cc
+++ b/src/lib/dns/python/tsigkey_python.cc
@@ -55,6 +55,7 @@ void TSIGKey_destroy(s_TSIGKey* self);
PyObject* TSIGKey_getKeyName(const s_TSIGKey* self);
PyObject* TSIGKey_getAlgorithmName(const s_TSIGKey* self);
PyObject* TSIGKey_getSecret(const s_TSIGKey* self);
+PyObject* TSIGKey_toText(const s_TSIGKey* self);
// This list contains the actual set of functions we have in
// python. Each entry has
@@ -72,6 +73,8 @@ PyMethodDef TSIGKey_methods[] = {
{ "get_secret",
reinterpret_cast<PyCFunction>(TSIGKey_getSecret), METH_NOARGS,
"Return the value of the TSIG secret." },
+ { "to_text", reinterpret_cast<PyCFunction>(TSIGKey_toText), METH_NOARGS,
+ "Returns the string representation (name:secret:algorithm)" },
{ NULL, NULL, 0, NULL }
};
@@ -148,27 +151,33 @@ createNameObject(const Name& source) {
int
TSIGKey_init(s_TSIGKey* self, PyObject* args) {
+ const char* str;
+
const s_Name* key_name;
const s_Name* algorithm_name;
PyObject* bytes_obj;
const char* secret;
Py_ssize_t secret_len;
- if (PyArg_ParseTuple(args, "O!O!O", &name_type, &key_name,
+
+ try {
+ if (PyArg_ParseTuple(args, "s", &str)) {
+ self->tsigkey = new TSIGKey(str);
+ return (0);
+ } else if (PyArg_ParseTuple(args, "O!O!O", &name_type, &key_name,
&name_type, &algorithm_name, &bytes_obj) &&
- PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) != -1) {
- try {
- self->tsigkey = new TSIGKey(*key_name->name,
- *algorithm_name->name,
- secret, secret_len);
- } catch (const isc::InvalidParameter& ex) {
- PyErr_SetString(po_InvalidParameter, ex.what());
- return (-1);
- } catch (...) {
- PyErr_SetString(po_IscException, "Unexpected exception");
- return (-1);
+ PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) != -1) {
+ self->tsigkey = new TSIGKey(*key_name->name,
+ *algorithm_name->name,
+ secret, secret_len);
+ return (0);
}
- return (0);
+ } catch (const isc::InvalidParameter& ex) {
+ PyErr_SetString(po_InvalidParameter, ex.what());
+ return (-1);
+ } catch (...) {
+ PyErr_SetString(po_IscException, "Unexpected exception");
+ return (-1);
}
PyErr_Clear();
@@ -201,6 +210,11 @@ TSIGKey_getSecret(const s_TSIGKey* const self) {
self->tsigkey->getSecretLength()));
}
+PyObject*
+TSIGKey_toText(const s_TSIGKey* self) {
+ return (Py_BuildValue("s", self->tsigkey->toText().c_str()));
+}
+
// Module Initialization, all statics are initialized here
bool
initModulePart_TSIGKey(PyObject* mod) {
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index f5dd512..7a94653 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -47,6 +47,8 @@ run_unittests_SOURCES += question_unittest.cc
run_unittests_SOURCES += rrparamregistry_unittest.cc
run_unittests_SOURCES += masterload_unittest.cc
run_unittests_SOURCES += message_unittest.cc
+run_unittests_SOURCES += tsig_unittest.cc
+run_unittests_SOURCES += tsigerror_unittest.cc
run_unittests_SOURCES += tsigkey_unittest.cc
run_unittests_SOURCES += run_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
@@ -54,6 +56,8 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
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/tsig_unittest.cc b/src/lib/dns/tests/tsig_unittest.cc
new file mode 100644
index 0000000..28189cc
--- /dev/null
+++ b/src/lib/dns/tests/tsig_unittest.cc
@@ -0,0 +1,505 @@
+// 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.
+
+#include <time.h>
+#include <string>
+#include <stdexcept>
+#include <vector>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/encode/base64.h>
+#include <util/unittests/newhook.h>
+
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/question.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
+
+#include <dns/tests/unittest_util.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::util;
+using namespace isc::util::encode;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+
+// See dnssectime.cc
+namespace isc {
+namespace dns {
+namespace tsig {
+namespace detail {
+extern int64_t (*gettimeFunction)();
+}
+}
+}
+}
+
+namespace {
+// See dnssectime_unittest.cc
+template <int64_t NOW>
+int64_t
+testGetTime() {
+ return (NOW);
+}
+
+class TSIGTest : public ::testing::Test {
+protected:
+ TSIGTest() :
+ tsig_ctx(NULL), qid(0x2d65), test_name("www.example.com"),
+ test_class(RRClass::IN()), test_ttl(86400), message(Message::RENDER),
+ buffer(0), renderer(buffer)
+ {
+ // Make sure we use the system time by default so that we won't be
+ // confused due to other tests that tweak the time.
+ tsig::detail::gettimeFunction = NULL;
+
+ decodeBase64("SFuWd/q99SzF8Yzd1QbB9g==", secret);
+ tsig_ctx.reset(new TSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACMD5_NAME(),
+ &secret[0], secret.size())));
+ tsig_verify_ctx.reset(new TSIGContext(TSIGKey(test_name,
+ TSIGKey::HMACMD5_NAME(),
+ &secret[0],
+ secret.size())));
+ }
+ ~TSIGTest() {
+ tsig::detail::gettimeFunction = NULL;
+ }
+
+ // Many of the tests below create some DNS message and sign it under
+ // some specific TSIG context. This helper method unifies the common
+ // logic with slightly different parameters.
+ ConstTSIGRecordPtr createMessageAndSign(uint16_t qid, const Name& qname,
+ TSIGContext* ctx,
+ unsigned int message_flags =
+ RD_FLAG,
+ RRType qtype = RRType::A(),
+ const char* answer_data = NULL,
+ const RRType* answer_type = NULL,
+ bool add_question = true,
+ Rcode rcode = Rcode::NOERROR());
+
+ // bit-wise constant flags to configure DNS header flags for test
+ // messages.
+ static const unsigned int QR_FLAG = 0x1;
+ static const unsigned int AA_FLAG = 0x2;
+ static const unsigned int RD_FLAG = 0x4;
+
+ boost::scoped_ptr<TSIGContext> tsig_ctx;
+ boost::scoped_ptr<TSIGContext> tsig_verify_ctx;
+ const uint16_t qid;
+ const Name test_name;
+ const RRClass test_class;
+ const RRTTL test_ttl;
+ Message message;
+ OutputBuffer buffer;
+ MessageRenderer renderer;
+ vector<uint8_t> secret;
+};
+
+ConstTSIGRecordPtr
+TSIGTest::createMessageAndSign(uint16_t id, const Name& qname,
+ TSIGContext* ctx, unsigned int message_flags,
+ RRType qtype, const char* answer_data,
+ const RRType* answer_type, bool add_question,
+ Rcode rcode)
+{
+ message.clear(Message::RENDER);
+ message.setQid(id);
+ message.setOpcode(Opcode::QUERY());
+ message.setRcode(rcode);
+ if ((message_flags & QR_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_QR);
+ }
+ if ((message_flags & AA_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_AA);
+ }
+ if ((message_flags & RD_FLAG) != 0) {
+ message.setHeaderFlag(Message::HEADERFLAG_RD);
+ }
+ if (add_question) {
+ message.addQuestion(Question(qname, test_class, qtype));
+ }
+ if (answer_data != NULL) {
+ if (answer_type == NULL) {
+ answer_type = &qtype;
+ }
+ RRsetPtr answer_rrset(new RRset(qname, test_class, *answer_type,
+ test_ttl));
+ answer_rrset->addRdata(createRdata(*answer_type, test_class,
+ answer_data));
+ message.addRRset(Message::SECTION_ANSWER, answer_rrset);
+ }
+ renderer.clear();
+ message.toWire(renderer);
+
+ ConstTSIGRecordPtr tsig = ctx->sign(id, renderer.getData(),
+ renderer.getLength());
+ EXPECT_EQ(TSIGContext::SIGNED, ctx->getState());
+
+ return (tsig);
+}
+
+void
+commonTSIGChecks(ConstTSIGRecordPtr tsig, uint16_t expected_qid,
+ uint64_t expected_timesigned,
+ const uint8_t* expected_mac, size_t expected_maclen,
+ uint16_t expected_error = 0,
+ uint16_t expected_otherlen = 0,
+ const uint8_t* expected_otherdata = NULL,
+ const Name& expected_algorithm = TSIGKey::HMACMD5_NAME())
+{
+ ASSERT_TRUE(tsig != NULL);
+ const any::TSIG& tsig_rdata = tsig->getRdata();
+
+ EXPECT_EQ(expected_algorithm, tsig_rdata.getAlgorithm());
+ EXPECT_EQ(expected_timesigned, tsig_rdata.getTimeSigned());
+ EXPECT_EQ(300, tsig_rdata.getFudge());
+ EXPECT_EQ(expected_maclen, tsig_rdata.getMACSize());
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+ tsig_rdata.getMAC(), tsig_rdata.getMACSize(),
+ expected_mac, expected_maclen);
+ EXPECT_EQ(expected_qid, tsig_rdata.getOriginalID());
+ EXPECT_EQ(expected_error, tsig_rdata.getError());
+ EXPECT_EQ(expected_otherlen, tsig_rdata.getOtherLen());
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+ tsig_rdata.getOtherData(), tsig_rdata.getOtherLen(),
+ expected_otherdata, expected_otherlen);
+}
+
+TEST_F(TSIGTest, initialState) {
+ // Until signing or verifying, the state should be INIT
+ EXPECT_EQ(TSIGContext::INIT, tsig_ctx->getState());
+
+ // And there should be no error code.
+ EXPECT_EQ(TSIGError(Rcode::NOERROR()), tsig_ctx->getError());
+}
+
+// Example output generated by
+// "dig -y www.example.com:SFuWd/q99SzF8Yzd1QbB9g== www.example.com
+// QID: 0x2d65
+// Time Signed: 0x00004da8877a
+// MAC: 227026ad297beee721ce6c6fff1e9ef3
+const uint8_t common_expected_mac[] = {
+ 0x22, 0x70, 0x26, 0xad, 0x29, 0x7b, 0xee, 0xe7,
+ 0x21, 0xce, 0x6c, 0x6f, 0xff, 0x1e, 0x9e, 0xf3
+};
+TEST_F(TSIGTest, sign) {
+ tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ {
+ SCOPED_TRACE("Sign test for query");
+ commonTSIGChecks(createMessageAndSign(qid, test_name, tsig_ctx.get()),
+ qid, 0x4da8877a, common_expected_mac,
+ sizeof(common_expected_mac));
+ }
+}
+
+// Same test as sign, but specifying the key name with upper-case (i.e.
+// non canonical) characters. The digest must be the same. It should actually
+// be ensured at the level of TSIGKey, but we confirm that at this level, too.
+TEST_F(TSIGTest, signUsingUpperCasedKeyName) {
+ tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ TSIGContext cap_ctx(TSIGKey(Name("WWW.EXAMPLE.COM"),
+ TSIGKey::HMACMD5_NAME(),
+ &secret[0], secret.size()));
+
+ {
+ SCOPED_TRACE("Sign test for query using non canonical key name");
+ commonTSIGChecks(createMessageAndSign(qid, test_name, &cap_ctx), qid,
+ 0x4da8877a, common_expected_mac,
+ sizeof(common_expected_mac));
+ }
+}
+
+// Same as the previous test, but for the algorithm name.
+TEST_F(TSIGTest, signUsingUpperCasedAlgorithmName) {
+ tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ TSIGContext cap_ctx(TSIGKey(test_name,
+ Name("HMAC-md5.SIG-alg.REG.int"),
+ &secret[0], secret.size()));
+
+ {
+ SCOPED_TRACE("Sign test for query using non canonical algorithm name");
+ commonTSIGChecks(createMessageAndSign(qid, test_name, &cap_ctx), qid,
+ 0x4da8877a, common_expected_mac,
+ sizeof(common_expected_mac));
+ }
+}
+
+TEST_F(TSIGTest, signAtActualTime) {
+ // Sign the message using the actual time, and check the accuracy of it.
+ // We cannot reasonably predict the expected MAC, so don't bother to
+ // check it.
+ const uint64_t now = static_cast<uint64_t>(time(NULL));
+
+ {
+ SCOPED_TRACE("Sign test for query at actual time");
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get());
+ const any::TSIG& tsig_rdata = tsig->getRdata();
+
+ // Check the resulted time signed is in the range of [now, now + 5]
+ // (5 is an arbitrary choice). Note that due to the order of the call
+ // to time() and sign(), time signed must not be smaller than the
+ // current time.
+ EXPECT_LE(now, tsig_rdata.getTimeSigned());
+ EXPECT_GE(now + 5, tsig_rdata.getTimeSigned());
+ }
+}
+
+TEST_F(TSIGTest, signBadData) {
+ // some specific bad data should be rejected proactively.
+ const unsigned char dummy_data = 0;
+ EXPECT_THROW(tsig_ctx->sign(0, NULL, 10), InvalidParameter);
+ EXPECT_THROW(tsig_ctx->sign(0, &dummy_data, 0), InvalidParameter);
+}
+
+#ifdef ENABLE_CUSTOM_OPERATOR_NEW
+// We enable this test only when we enable custom new/delete at build time
+// We could enable/disable the test runtime using the gtest filter, but
+// we'd basically like to minimize the number of disabled tests (they
+// should generally be considered tests that temporarily fail and should
+// be fixed).
+TEST_F(TSIGTest, signExceptionSafety) {
+ // Check sign() provides the strong exception guarantee for the simpler
+ // case (with a key error and empty MAC). The general case is more
+ // complicated and involves more memory allocation, so the test result
+ // won't be reliable.
+
+ tsig_verify_ctx->verifyTentative(createMessageAndSign(qid, test_name,
+ tsig_ctx.get()),
+ TSIGError::BAD_KEY());
+ // At this point the state should be changed to "CHECKED"
+ ASSERT_EQ(TSIGContext::CHECKED, tsig_verify_ctx->getState());
+ try {
+ int dummydata;
+ isc::util::unittests::force_throw_on_new = true;
+ isc::util::unittests::throw_size_on_new = sizeof(TSIGRecord);
+ tsig_verify_ctx->sign(0, &dummydata, sizeof(dummydata));
+ isc::util::unittests::force_throw_on_new = false;
+ ASSERT_FALSE(true) << "Expected throw on new, but it didn't happen";
+ } catch (const std::bad_alloc&) {
+ isc::util::unittests::force_throw_on_new = false;
+
+ // sign() threw, so the state should still be "CHECKED".
+ EXPECT_EQ(TSIGContext::CHECKED, tsig_verify_ctx->getState());
+ }
+ isc::util::unittests::force_throw_on_new = false;
+}
+#endif // ENABLE_CUSTOM_OPERATOR_NEW
+
+// Same test as "sign" but use a different algorithm just to confirm we don't
+// naively hardcode constants specific to a particular algorithm.
+// Test data generated by
+// "dig -y hmac-sha1:www.example.com:MA+QDhXbyqUak+qnMFyTyEirzng= www.example.com"
+// QID: 0x0967, RDflag
+// Current Time: 00004da8be86
+// Time Signed: 00004dae7d5f
+// HMAC Size: 20
+// HMAC: 415340c7daf824ed684ee586f7b5a67a2febc0d3
+TEST_F(TSIGTest, signUsingHMACSHA1) {
+ tsig::detail::gettimeFunction = testGetTime<0x4dae7d5f>;
+
+ secret.clear();
+ decodeBase64("MA+QDhXbyqUak+qnMFyTyEirzng=", secret);
+ TSIGContext sha1_ctx(TSIGKey(test_name, TSIGKey::HMACSHA1_NAME(),
+ &secret[0], secret.size()));
+
+ const uint16_t sha1_qid = 0x0967;
+ const uint8_t expected_mac[] = {
+ 0x41, 0x53, 0x40, 0xc7, 0xda, 0xf8, 0x24, 0xed, 0x68, 0x4e,
+ 0xe5, 0x86, 0xf7, 0xb5, 0xa6, 0x7a, 0x2f, 0xeb, 0xc0, 0xd3
+ };
+ {
+ SCOPED_TRACE("Sign test using HMAC-SHA1");
+ commonTSIGChecks(createMessageAndSign(sha1_qid, test_name, &sha1_ctx),
+ sha1_qid, 0x4dae7d5f, expected_mac,
+ sizeof(expected_mac), 0, 0, NULL,
+ TSIGKey::HMACSHA1_NAME());
+ }
+}
+
+// An example response to the signed query used for the "sign" test.
+// Answer: www.example.com. 86400 IN A 192.0.2.1
+// MAC: 8fcda66a7cd1a3b9948eb1869d384a9f
+TEST_F(TSIGTest, signResponse) {
+ tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
+ tsig_ctx.get());
+ tsig_verify_ctx->verifyTentative(tsig);
+ EXPECT_EQ(TSIGContext::CHECKED, tsig_verify_ctx->getState());
+
+ // Transform the original message to a response, then sign the response
+ // with the context of "verified state".
+ tsig = createMessageAndSign(qid, test_name, tsig_verify_ctx.get(),
+ QR_FLAG|AA_FLAG|RD_FLAG,
+ RRType::A(), "192.0.2.1");
+ const uint8_t expected_mac[] = {
+ 0x8f, 0xcd, 0xa6, 0x6a, 0x7c, 0xd1, 0xa3, 0xb9,
+ 0x94, 0x8e, 0xb1, 0x86, 0x9d, 0x38, 0x4a, 0x9f
+ };
+ {
+ SCOPED_TRACE("Sign test for response");
+ commonTSIGChecks(tsig, qid, 0x4da8877a,
+ expected_mac, sizeof(expected_mac));
+ }
+}
+
+// Example of signing multiple messages in a single TCP stream,
+// taken from data using BIND 9's "one-answer" transfer-format.
+// First message:
+// QID: 0x3410, flags QR, AA
+// Question: example.com/IN/AXFR
+// Answer: example.com. 86400 IN SOA ns.example.com. root.example.com. (
+// 2011041503 7200 3600 2592000 1200)
+// Time Signed: 0x4da8e951
+// Second message:
+// Answer: example.com. 86400 IN NS ns.example.com.
+// MAC: 102458f7f62ddd7d638d746034130968
+TEST_F(TSIGTest, signContinuation) {
+ tsig::detail::gettimeFunction = testGetTime<0x4da8e951>;
+
+ const uint16_t axfr_qid = 0x3410;
+ const Name zone_name("example.com");
+
+ // Create and sign the AXFR request, then verify it.
+ tsig_verify_ctx->verifyTentative(createMessageAndSign(axfr_qid, zone_name,
+ tsig_ctx.get(), 0,
+ RRType::AXFR()));
+ EXPECT_EQ(TSIGContext::CHECKED, tsig_verify_ctx->getState());
+
+ // Create and sign the first response message (we don't need the result
+ // for the purpose of this test)
+ createMessageAndSign(axfr_qid, zone_name, tsig_verify_ctx.get(),
+ AA_FLAG|QR_FLAG, RRType::AXFR(),
+ "ns.example.com. root.example.com. "
+ "2011041503 7200 3600 2592000 1200",
+ &RRType::SOA());
+
+ // Create and sign the second response message
+ const uint8_t expected_mac[] = {
+ 0x10, 0x24, 0x58, 0xf7, 0xf6, 0x2d, 0xdd, 0x7d,
+ 0x63, 0x8d, 0x74, 0x60, 0x34, 0x13, 0x09, 0x68
+ };
+ {
+ SCOPED_TRACE("Sign test for continued response in TCP stream");
+ commonTSIGChecks(createMessageAndSign(axfr_qid, zone_name,
+ tsig_verify_ctx.get(),
+ AA_FLAG|QR_FLAG, RRType::AXFR(),
+ "ns.example.com.", &RRType::NS(),
+ false),
+ axfr_qid, 0x4da8e951,
+ expected_mac, sizeof(expected_mac));
+ }
+}
+
+// BADTIME example, taken from data using specially hacked BIND 9's nsupdate
+// Query:
+// QID: 0x1830, RD flag
+// Current Time: 00004da8be86
+// Time Signed: 00004da8b9d6
+// Question: www.example.com/IN/SOA
+//(mac) 8406 7d50 b8e7 d054 3d50 5bd9 de2a bb68
+// Response:
+// QRbit, RCODE=9(NOTAUTH)
+// Time Signed: 00004da8b9d6 (the one in the query)
+// MAC: d4b043f6f44495ec8a01260e39159d76
+// Error: 0x12 (BADTIME), Other Len: 6
+// Other data: 00004da8be86
+TEST_F(TSIGTest, badtimeResponse) {
+ tsig::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
+
+ const uint16_t test_qid = 0x7fc4;
+ ConstTSIGRecordPtr tsig = createMessageAndSign(test_qid, test_name,
+ tsig_ctx.get(), 0,
+ RRType::SOA());
+
+ // "advance the clock" and try validating, which should fail due to BADTIME
+ // (verifyTentative actually doesn't check the time, though)
+ tsig::detail::gettimeFunction = testGetTime<0x4da8be86>;
+ tsig_verify_ctx->verifyTentative(tsig, TSIGError::BAD_TIME());
+ EXPECT_EQ(TSIGError::BAD_TIME(), tsig_verify_ctx->getError());
+
+ // make and sign a response in the context of TSIG error.
+ tsig = createMessageAndSign(test_qid, test_name, tsig_verify_ctx.get(),
+ QR_FLAG, RRType::SOA(), NULL, NULL,
+ true, Rcode::NOTAUTH());
+ const uint8_t expected_otherdata[] = { 0, 0, 0x4d, 0xa8, 0xbe, 0x86 };
+ const uint8_t expected_mac[] = {
+ 0xd4, 0xb0, 0x43, 0xf6, 0xf4, 0x44, 0x95, 0xec,
+ 0x8a, 0x01, 0x26, 0x0e, 0x39, 0x15, 0x9d, 0x76
+ };
+ {
+ SCOPED_TRACE("Sign test for response with BADTIME");
+ commonTSIGChecks(tsig, message.getQid(), 0x4da8b9d6,
+ expected_mac, sizeof(expected_mac),
+ 18, // error: BADTIME
+ sizeof(expected_otherdata),
+ expected_otherdata);
+ }
+}
+
+TEST_F(TSIGTest, badsigResponse) {
+ tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ // Sign a simple message, and force the verification to fail with
+ // BADSIG.
+ tsig_verify_ctx->verifyTentative(createMessageAndSign(qid, test_name,
+ tsig_ctx.get()),
+ TSIGError::BAD_SIG());
+
+ // Sign the same message (which doesn't matter for this test) with the
+ // context of "checked state".
+ {
+ SCOPED_TRACE("Sign test for response with BADSIG error");
+ commonTSIGChecks(createMessageAndSign(qid, test_name,
+ tsig_verify_ctx.get()),
+ message.getQid(), 0x4da8877a, NULL, 0,
+ 16); // 16: BADSIG
+ }
+}
+
+TEST_F(TSIGTest, badkeyResponse) {
+ // A similar test as badsigResponse but for BADKEY
+ tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ tsig_verify_ctx->verifyTentative(createMessageAndSign(qid, test_name,
+ tsig_ctx.get()),
+ TSIGError::BAD_KEY());
+ {
+ SCOPED_TRACE("Sign test for response with BADKEY error");
+ commonTSIGChecks(createMessageAndSign(qid, test_name,
+ tsig_verify_ctx.get()),
+ message.getQid(), 0x4da8877a, NULL, 0,
+ 17); // 17: BADKEYSIG
+ }
+}
+
+} // end namespace
diff --git a/src/lib/dns/tests/tsigerror_unittest.cc b/src/lib/dns/tests/tsigerror_unittest.cc
new file mode 100644
index 0000000..5866587
--- /dev/null
+++ b/src/lib/dns/tests/tsigerror_unittest.cc
@@ -0,0 +1,102 @@
+// 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.
+
+#include <string>
+#include <ostream>
+
+#include <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/rcode.h>
+#include <dns/tsigerror.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+
+namespace {
+TEST(TSIGErrorTest, constructFromErrorCode) {
+ // These are pretty trivial, and also test getCode();
+ EXPECT_EQ(0, TSIGError(0).getCode());
+ EXPECT_EQ(18, TSIGError(18).getCode());
+ EXPECT_EQ(65535, TSIGError(65535).getCode());
+}
+
+TEST(TSIGErrorTest, constructFromRcode) {
+ // We use RCODE for code values from 0-15.
+ EXPECT_EQ(0, TSIGError(Rcode::NOERROR()).getCode());
+ EXPECT_EQ(15, TSIGError(Rcode(15)).getCode());
+
+ // From error code 16 TSIG errors define a separate space, so passing
+ // corresponding RCODE for such code values should be prohibited.
+ EXPECT_THROW(TSIGError(Rcode(16)).getCode(), OutOfRange);
+}
+
+TEST(TSIGErrorTest, constants) {
+ // We'll only test arbitrarily chosen subsets of the codes.
+ // This class is quite simple, so it should be suffice.
+
+ EXPECT_EQ(TSIGError::BAD_SIG_CODE, TSIGError(16).getCode());
+ EXPECT_EQ(TSIGError::BAD_KEY_CODE, TSIGError(17).getCode());
+ EXPECT_EQ(TSIGError::BAD_TIME_CODE, TSIGError(18).getCode());
+
+ EXPECT_EQ(0, TSIGError::NOERROR().getCode());
+ EXPECT_EQ(9, TSIGError::NOTAUTH().getCode());
+ EXPECT_EQ(14, TSIGError::RESERVED14().getCode());
+ EXPECT_EQ(TSIGError::BAD_SIG_CODE, TSIGError::BAD_SIG().getCode());
+ EXPECT_EQ(TSIGError::BAD_KEY_CODE, TSIGError::BAD_KEY().getCode());
+ EXPECT_EQ(TSIGError::BAD_TIME_CODE, TSIGError::BAD_TIME().getCode());
+}
+
+TEST(TSIGErrorTest, equal) {
+ EXPECT_TRUE(TSIGError::NOERROR() == TSIGError(Rcode::NOERROR()));
+ EXPECT_TRUE(TSIGError(Rcode::NOERROR()) == TSIGError::NOERROR());
+ EXPECT_TRUE(TSIGError::NOERROR().equals(TSIGError(Rcode::NOERROR())));
+ EXPECT_TRUE(TSIGError::NOERROR().equals(TSIGError(Rcode::NOERROR())));
+
+ EXPECT_TRUE(TSIGError::BAD_SIG() == TSIGError(16));
+ EXPECT_TRUE(TSIGError(16) == TSIGError::BAD_SIG());
+ EXPECT_TRUE(TSIGError::BAD_SIG().equals(TSIGError(16)));
+ EXPECT_TRUE(TSIGError(16).equals(TSIGError::BAD_SIG()));
+}
+
+TEST(TSIGErrorTest, nequal) {
+ EXPECT_TRUE(TSIGError::BAD_KEY() != TSIGError(Rcode::NOERROR()));
+ EXPECT_TRUE(TSIGError(Rcode::NOERROR()) != TSIGError::BAD_KEY());
+ EXPECT_TRUE(TSIGError::BAD_KEY().nequals(TSIGError(Rcode::NOERROR())));
+ EXPECT_TRUE(TSIGError(Rcode::NOERROR()).nequals(TSIGError::BAD_KEY()));
+}
+
+TEST(TSIGErrorTest, toText) {
+ // TSIGError derived from the standard Rcode
+ EXPECT_EQ("NOERROR", TSIGError(Rcode::NOERROR()).toText());
+
+ // Well known TSIG errors
+ EXPECT_EQ("BADSIG", TSIGError::BAD_SIG().toText());
+ EXPECT_EQ("BADKEY", TSIGError::BAD_KEY().toText());
+ EXPECT_EQ("BADTIME", TSIGError::BAD_TIME().toText());
+
+ // Unknown (or not yet supported) codes. Simply converted as numeric.
+ EXPECT_EQ("19", TSIGError(19).toText());
+ EXPECT_EQ("65535", TSIGError(65535).toText());
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST(TSIGErrorTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << TSIGError::BAD_KEY();
+ EXPECT_EQ(TSIGError::BAD_KEY().toText(), oss.str());
+}
+} // end namespace
diff --git a/src/lib/dns/tests/tsigkey_unittest.cc b/src/lib/dns/tests/tsigkey_unittest.cc
index 6b2b8c5..96696d5 100644
--- a/src/lib/dns/tests/tsigkey_unittest.cc
+++ b/src/lib/dns/tests/tsigkey_unittest.cc
@@ -18,6 +18,8 @@
#include <exceptions/exceptions.h>
+#include <cryptolink/cryptolink.h>
+
#include <dns/tsigkey.h>
#include <dns/tests/unittest_util.h>
@@ -38,6 +40,15 @@ TEST_F(TSIGKeyTest, algorithmNames) {
EXPECT_EQ(Name("hmac-md5.sig-alg.reg.int"), TSIGKey::HMACMD5_NAME());
EXPECT_EQ(Name("hmac-sha1"), TSIGKey::HMACSHA1_NAME());
EXPECT_EQ(Name("hmac-sha256"), TSIGKey::HMACSHA256_NAME());
+
+ // Also check conversion to cryptolink definitions
+ EXPECT_EQ(isc::cryptolink::MD5, TSIGKey(key_name, TSIGKey::HMACMD5_NAME(),
+ NULL, 0).getAlgorithm());
+ EXPECT_EQ(isc::cryptolink::SHA1, TSIGKey(key_name, TSIGKey::HMACSHA1_NAME(),
+ NULL, 0).getAlgorithm());
+ EXPECT_EQ(isc::cryptolink::SHA256, TSIGKey(key_name,
+ TSIGKey::HMACSHA256_NAME(),
+ NULL, 0).getAlgorithm());
}
TEST_F(TSIGKeyTest, construct) {
@@ -58,6 +69,11 @@ TEST_F(TSIGKeyTest, construct) {
secret.c_str(),
secret.size()).getAlgorithmName().toText());
+ EXPECT_EQ("example.com.",
+ TSIGKey(Name("EXAMPLE.CoM."), TSIGKey::HMACSHA256_NAME(),
+ secret.c_str(),
+ secret.size()).getKeyName().toText());
+
// Invalid combinations of secret and secret_len:
EXPECT_THROW(TSIGKey(key_name, TSIGKey::HMACSHA1_NAME(), secret.c_str(), 0),
isc::InvalidParameter);
@@ -227,4 +243,31 @@ TEST_F(TSIGKeyRingTest, findFromSome) {
keyring.find(Name("noexist.example")).key);
}
+TEST(TSIGStringTest, TSIGKeyFromToString) {
+ TSIGKey k1 = TSIGKey("test.example:MSG6Ng==:hmac-md5.sig-alg.reg.int");
+ TSIGKey k2 = TSIGKey("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.");
+ TSIGKey k3 = TSIGKey("test.example:MSG6Ng==");
+ TSIGKey k4 = TSIGKey(Name("test.example."), Name("hmac-sha1."), NULL, 0);
+
+ EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+ k1.toText());
+ EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+ k2.toText());
+ EXPECT_EQ("test.example.:MSG6Ng==:hmac-md5.sig-alg.reg.int.",
+ k3.toText());
+ EXPECT_EQ("test.example.::hmac-sha1.", k4.toText());
+
+ EXPECT_THROW(TSIGKey(""), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey(":"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("::"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("..:aa:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example:xxxx:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.::"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:"), isc::InvalidParameter);
+ EXPECT_THROW(TSIGKey("test.example.:MSG6Ng==:unknown"), isc::InvalidParameter);
+
+}
+
+
} // end namespace
diff --git a/src/lib/dns/tsig.cc b/src/lib/dns/tsig.cc
new file mode 100644
index 0000000..48ac5e0
--- /dev/null
+++ b/src/lib/dns/tsig.cc
@@ -0,0 +1,232 @@
+// 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.
+
+#include <sys/time.h>
+
+#include <stdint.h>
+
+#include <cassert> // for the tentative verifyTentative()
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/tsig.h>
+#include <dns/tsigerror.h>
+#include <dns/tsigkey.h>
+
+#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::cryptolink;
+using namespace isc::dns::rdata;
+
+namespace isc {
+namespace dns {
+
+// Borrowed from dnssectime.cc. This trick should be unified somewhere.
+namespace tsig {
+namespace detail {
+int64_t (*gettimeFunction)() = NULL;
+}
+}
+
+namespace {
+int64_t
+gettimeofdayWrapper() {
+ using namespace tsig::detail;
+ if (gettimeFunction != NULL) {
+ return (gettimeFunction());
+ }
+
+ struct timeval now;
+ gettimeofday(&now, NULL);
+
+ return (static_cast<int64_t>(now.tv_sec));
+}
+}
+
+namespace {
+typedef boost::shared_ptr<HMAC> HMACPtr;
+}
+
+const RRClass&
+TSIGRecord::getClass() {
+ return (RRClass::ANY());
+}
+
+struct TSIGContext::TSIGContextImpl {
+ TSIGContextImpl(const TSIGKey& key) :
+ state_(INIT), key_(key), error_(Rcode::NOERROR()),
+ previous_timesigned_(0)
+ {}
+ State state_;
+ TSIGKey key_;
+ vector<uint8_t> previous_digest_;
+ TSIGError error_;
+ uint64_t previous_timesigned_; // only meaningful for response with BADTIME
+};
+
+TSIGContext::TSIGContext(const TSIGKey& key) : impl_(new TSIGContextImpl(key))
+{
+}
+
+TSIGContext::~TSIGContext() {
+ delete impl_;
+}
+
+TSIGContext::State
+TSIGContext::getState() const {
+ return (impl_->state_);
+}
+
+TSIGError
+TSIGContext::getError() const {
+ return (impl_->error_);
+}
+
+ConstTSIGRecordPtr
+TSIGContext::sign(const uint16_t qid, const void* const data,
+ const size_t data_len)
+{
+ if (data == NULL || data_len == 0) {
+ isc_throw(InvalidParameter, "TSIG sign error: empty data is given");
+ }
+
+ 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 = (gettimeofdayWrapper() & 0x0000ffffffffffffULL);
+
+ // For responses adjust the error code.
+ if (impl_->state_ == CHECKED) {
+ error = impl_->error_;
+ }
+
+ // For errors related to key or MAC, return an unsigned response as
+ // specified in Section 4.3 of RFC2845.
+ if (error == TSIGError::BAD_SIG() || error == TSIGError::BAD_KEY()) {
+ ConstTSIGRecordPtr tsig(new TSIGRecord(
+ any::TSIG(impl_->key_.getAlgorithmName(),
+ now, DEFAULT_FUDGE, 0, NULL,
+ qid, error.getCode(), 0, NULL)));
+ impl_->previous_digest_.clear();
+ impl_->state_ = SIGNED;
+ return (tsig);
+ }
+
+ OutputBuffer variables(0);
+ HMACPtr hmac(CryptoLink::getCryptoLink().createHMAC(
+ impl_->key_.getSecret(),
+ impl_->key_.getSecretLength(),
+ impl_->key_.getAlgorithm()),
+ deleteHMAC);
+
+ // If the context has previous MAC (either the Request MAC or its own
+ // previous MAC), digest it.
+ if (impl_->state_ != INIT) {
+ const uint16_t previous_digest_len(impl_->previous_digest_.size());
+ variables.writeUint16(previous_digest_len);
+ if (previous_digest_len != 0) {
+ variables.writeData(&impl_->previous_digest_[0],
+ previous_digest_len);
+ }
+ hmac->update(variables.getData(), variables.getLength());
+ }
+
+ // Digest the message (without TSIG)
+ hmac->update(data, data_len);
+
+ //
+ // Digest TSIG variables. If state_ is SIGNED we skip digesting them
+ // except for time related variables (RFC2845 4.4).
+ //
+ variables.clear();
+ if (impl_->state_ != SIGNED) {
+ impl_->key_.getKeyName().toWire(variables);
+ TSIGRecord::getClass().toWire(variables);
+ variables.writeUint32(TSIGRecord::TSIG_TTL);
+ impl_->key_.getAlgorithmName().toWire(variables);
+ }
+ const uint64_t time_signed = (error == TSIGError::BAD_TIME()) ?
+ impl_->previous_timesigned_ : now;
+ variables.writeUint16(time_signed >> 32);
+ variables.writeUint32(time_signed & 0xffffffff);
+ variables.writeUint16(DEFAULT_FUDGE);
+ hmac->update(variables.getData(), variables.getLength());
+ variables.clear();
+
+ if (impl_->state_ != SIGNED) {
+ variables.writeUint16(error.getCode());
+
+ // For BADTIME error, digest 6 bytes of other data.
+ // (6 bytes = size of time signed value)
+ variables.writeUint16((error == TSIGError::BAD_TIME()) ? 6 : 0);
+ hmac->update(variables.getData(), variables.getLength());
+
+ variables.clear();
+ if (error == TSIGError::BAD_TIME()) {
+ variables.writeUint16(now >> 32);
+ variables.writeUint32(now & 0xffffffff);
+ hmac->update(variables.getData(), variables.getLength());
+ }
+ }
+ const uint16_t otherlen = variables.getLength();
+
+ // Get the final digest, update internal state, then finish.
+ vector<uint8_t> digest = hmac->sign();
+ ConstTSIGRecordPtr tsig(new TSIGRecord(
+ any::TSIG(impl_->key_.getAlgorithmName(),
+ time_signed, DEFAULT_FUDGE,
+ digest.size(), &digest[0],
+ qid, error.getCode(), otherlen,
+ otherlen == 0 ?
+ NULL : variables.getData())));
+ // Exception free from now on.
+ impl_->previous_digest_.swap(digest);
+ impl_->state_ = SIGNED;
+ return (tsig);
+}
+
+void
+TSIGContext::verifyTentative(ConstTSIGRecordPtr tsig, TSIGError error) {
+ const any::TSIG tsig_rdata = tsig->getRdata();
+
+ impl_->error_ = error;
+ if (error == TSIGError::BAD_TIME()) {
+ impl_->previous_timesigned_ = tsig_rdata.getTimeSigned();
+ }
+
+ // For simplicity we assume non empty digests.
+ assert(tsig_rdata.getMACSize() != 0);
+ impl_->previous_digest_.assign(
+ static_cast<const uint8_t*>(tsig_rdata.getMAC()),
+ static_cast<const uint8_t*>(tsig_rdata.getMAC()) +
+ tsig_rdata.getMACSize());
+
+ impl_->state_ = CHECKED;
+}
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/tsig.h b/src/lib/dns/tsig.h
new file mode 100644
index 0000000..55ab41e
--- /dev/null
+++ b/src/lib/dns/tsig.h
@@ -0,0 +1,302 @@
+// 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 __TSIG_H
+#define __TSIG_H 1
+
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <dns/rdataclass.h>
+#include <dns/tsigerror.h>
+#include <dns/tsigkey.h>
+
+namespace isc {
+namespace dns {
+/// TSIG resource record.
+///
+/// A \c TSIGRecord class object represents a TSIG resource record and is
+/// responsible for conversion to and from wire format TSIG record based on
+/// the protocol specification (RFC2845).
+/// This class is provided so that other classes and applications can handle
+/// TSIG without knowing protocol details of TSIG, such as that it uses a
+/// fixed constant of TTL.
+///
+/// \note So the plan is to eventually provide a \c toWire() method and
+/// the "from wire" constructor. They are not yet provided in this initial
+/// step.
+///
+/// \note
+/// This class could be a derived class of \c AbstractRRset. That way
+/// it would be able to be used in a polymorphic way; for example,
+/// an application can construct a TSIG RR by itself and insert it to a
+/// \c Message object as a generic RRset. On the other hand, it would mean
+/// this class would have to implement an \c RdataIterator (even though it
+/// can be done via straightforward forwarding) while the iterator is mostly
+/// redundant since there should be one and only one RDATA for a valid TSIG
+/// RR. Likewise, some methods such as \c setTTL() method wouldn't be well
+/// defined due to such special rules for TSIG as using a fixed TTL.
+/// Overall, TSIG is a very special RR type that simply uses the compatible
+/// resource record format, and it will be unlikely that a user wants to
+/// handle it through a generic interface in a polymorphic way.
+/// We therefore chose to define it as a separate class. This is also
+/// similar to why \c EDNS is a separate class.
+class TSIGRecord {
+public:
+ /// Constructor from TSIG RDATA
+ ///
+ /// \exception std::bad_alloc Resource allocation for copying the RDATA
+ /// fails
+ explicit TSIGRecord(const rdata::any::TSIG& tsig_rdata) :
+ rdata_(tsig_rdata)
+ {}
+
+ /// Return the RDATA of the TSIG RR
+ ///
+ /// \exception None
+ const rdata::any::TSIG& getRdata() const { return (rdata_); }
+
+ /// \name Protocol constants and defaults
+ ///
+ //@{
+ /// Return the RR class of TSIG
+ ///
+ /// TSIG always uses the ANY RR class. This static method returns it,
+ /// when, though unlikely, an application wants to know which class TSIG
+ /// is supposed to use.
+ ///
+ /// \exception None
+ static const RRClass& getClass();
+
+ /// The TTL value to be used in TSIG RRs.
+ static const uint32_t TSIG_TTL = 0;
+ //@}
+
+private:
+ const rdata::any::TSIG rdata_;
+};
+
+/// A pointer-like type pointing to a \c TSIGRecord object.
+typedef boost::shared_ptr<TSIGRecord> TSIGRecordPtr;
+
+/// A pointer-like type pointing to an immutable \c TSIGRecord object.
+typedef boost::shared_ptr<const TSIGRecord> ConstTSIGRecordPtr;
+
+/// TSIG session context.
+///
+/// The \c TSIGContext class maintains a context of a signed session of
+/// DNS transactions by TSIG. In many cases a TSIG signed session consists
+/// of a single set of request (e.g. normal query) and reply (e.g. normal
+/// response), where the request is initially signed by the client, and the
+/// reply is signed by the server using the initial signature. As mentioned
+/// in RFC2845, a session can consist of multiple exchanges in a TCP
+/// connection. As also mentioned in the RFC, an AXFR response often contains
+/// multiple DNS messages, which can belong to the same TSIG session.
+/// This class supports all these cases.
+///
+/// A \c TSIGContext object is generally constructed with a TSIG key to be
+/// used for the session, and keeps track of various kinds of session specific
+/// information, such as the original digest while waiting for a response or
+/// verification error information that is to be used for a subsequent
+/// response.
+///
+/// This class has two main methods, \c sign() and \c verify().
+/// The \c sign() method signs given data (which is supposed to be a complete
+/// DNS message without the TSIG itself) using the TSIG key and other
+/// related information associated with the \c TSIGContext object.
+/// The \c verify() method verifies a given DNS message that contains a TSIG
+/// RR using the key and other internal information.
+///
+/// In general, a DNS client that wants to send a signed query will construct
+/// a \c TSIGContext object with the TSIG key that the client is intending to
+/// use, and sign the query with the context. The client will keeps the
+/// context, and verify the response with it.
+///
+/// On the other hand, a DNS server will construct a \c TSIGContext object
+/// with the information of the TSIG RR included in a query with a set of
+/// possible keys (in the form of a \c TSIGKeyRing object). The constructor
+/// in this mode will identify the appropriate TSIG key (or internally record
+/// an error if it doesn't find a key). The server will then verify the
+/// query with the context, and generate a signed response using the same
+/// same context. (Note: this mode is not yet implemented and may change,
+/// see below).
+///
+/// When multiple messages belong to the same TSIG session, either side
+/// (signer or verifier) will keep using the same context. It records
+/// the latest session state (such as the previous digest) so that repeated
+/// calls to \c sign() or \c verify() work correctly in terms of the TSIG
+/// protocol.
+///
+/// \note The \c verify() method is not yet implemented. The implementation
+/// and documentation should be updated in the corresponding task.
+///
+/// <b>TCP Consideration</b>
+///
+/// RFC2845 describes the case where a single TSIG session is used for
+/// multiple DNS messages (Section 4.4). This class supports signing and
+/// verifying the messages in this scenario, but does not care if the messages
+/// were delivered over a TCP connection or not. If, for example, the
+/// same \c TSIGContext object is used to sign two independent DNS queries
+/// sent over UDP, they will be considered to belong to the same TSIG
+/// session, and, as a result, verification will be likely to fail.
+///
+/// \b Copyability
+///
+/// This class is currently non copyable based on the observation of the
+/// typical usage as described above. But there is no strong technical
+/// reason why this class cannot be copyable. If we see the need for it
+/// in future we may change the implementation on this point.
+///
+/// <b>Note to developers:</b>
+/// One basic design choice is to make the \c TSIGContext class is as
+/// independent from the \c Message class. This is because the latter is
+/// much more complicated, depending on many other classes, while TSIG is
+/// a very specific part of the entire DNS protocol set. If the \c TSIGContext
+/// class depends on \c \c Message, it will be more vulnerable to changes
+/// to other classes, and will be more difficult to test due to the
+/// direct or indirect dependencies. The interface of \c sign() that takes
+/// opaque data (instead of, e.g., a \c Message or \c MessageRenderer object)
+/// is therefore a deliberate design decision.
+class TSIGContext : boost::noncopyable {
+public:
+ /// Internal state of context
+ ///
+ /// The constants of this enum type define a specific state of
+ /// \c TSIGContext to adjust the behavior. The definition is public
+ /// and the state can be seen via the \c getState() method, but this is
+ /// mostly private information. It's publicly visible mainly for testing
+ /// purposes; there is no API for the application to change the state
+ /// directly.
+ enum State {
+ INIT, ///< Initial state
+ SIGNED, ///< Sign completed
+ CHECKED ///< Verification completed (may or may not successfully)
+ };
+
+ /// \name Constructors and destructor
+ ///
+ //@{
+ /// Constructor from a TSIG key.
+ ///
+ /// \exception std::bad_alloc Resource allocation for internal data fails
+ ///
+ /// \param key The TSIG key to be used for TSIG sessions with this context.
+ explicit TSIGContext(const TSIGKey& key);
+
+ /// The destructor.
+ ~TSIGContext();
+ //@}
+
+ /// Sign a DNS message.
+ ///
+ /// This method computes the TSIG MAC for the given data, which is
+ /// generally expected to be a complete, wire-format DNS message
+ /// that doesn't contain a TSIG RR, based on the TSIG key and
+ /// other context information of \c TSIGContext, and returns a
+ /// result in the form of a (pointer object pointing to)
+ /// \c TSIGRecord object.
+ ///
+ /// The caller of this method will use the returned value to render a
+ /// complete TSIG RR into the message that has been signed so that it
+ /// will become a complete TSIG-signed message.
+ ///
+ /// \note Normal applications are not expected to call this method
+ /// directly; they will usually use the \c Message::toWire() method
+ /// with a \c TSIGContext object being a parameter and have the
+ /// \c Message class create a complete signed message.
+ ///
+ /// This method treats the given data as opaque, even though it's generally
+ /// expected to represent a wire-format DNS message (see also the class
+ /// description), and doesn't inspect it in any way. For example, it
+ /// doesn't check whether the data length is sane for a valid DNS message.
+ /// This is also the reason why this method takes the \c qid parameter,
+ /// which will be used as the original ID of the resulting
+ /// \c TSIGRecordx object, even though this value should be stored in the
+ /// first two octets (in wire format) of the given data.
+ ///
+ /// \note This method still checks and rejects empty data (\c NULL pointer
+ /// data or the specified data length is 0) in order to avoid catastrophic
+ /// effect such as program crash. Empty data is not necessarily invalid
+ /// for HMAC computation, but obviously it doesn't make sense for a DNS
+ /// message.
+ ///
+ /// This method provides the strong exception guarantee; unless the method
+ /// returns (without an exception being thrown), the internal state of
+ /// the \c TSIGContext won't be modified.
+ ///
+ /// \exception InvalidParameter \c data is NULL or \c data_len is 0
+ /// \exception cryptolink::LibraryError Some unexpected error in the
+ /// underlying crypto operation
+ /// \exception std::bad_alloc Temporary resource allocation failure
+ ///
+ /// \param qid The QID to be as the value of the original ID field of
+ /// the resulting TSIG record
+ /// \param data Points to the wire-format data to be signed
+ /// \param data_len The length of \c data in bytes
+ ///
+ /// \return A TSIG record for the given data along with the context.
+ ConstTSIGRecordPtr sign(const uint16_t qid, const void* const data,
+ const size_t data_len);
+
+ /// Return the current state of the context
+ ///
+ /// \note
+ /// The states are visible in public mainly for testing purposes.
+ /// Normal applications won't have to deal with them.
+ ///
+ /// \exception None
+ State getState() const;
+
+ /// Return the TSIG error as a result of the latest verification
+ ///
+ /// This method can be called even before verifying anything, but the
+ /// returned value is meaningless in that case.
+ ///
+ /// \exception None
+ TSIGError getError() const;
+
+ // This method is tentatively added for testing until a complete
+ // verify() method is implemented. Once it's done this should be
+ // removed, and corresponding tests should be updated.
+ //
+ // This tentative "verify" method changes the internal state of
+ // the TSIGContext to the CHECKED as if it were verified (though possibly
+ // unsuccessfully) with given tsig_rdata. If the error parameter is
+ // given and not NOERROR, it's recorded inside the context so that the
+ // subsequent sign() will behave accordingly.
+ void verifyTentative(ConstTSIGRecordPtr tsig,
+ TSIGError error = TSIGError::NOERROR());
+
+ /// \name Protocol constants and defaults
+ ///
+ //@{
+ /// The recommended fudge value (in seconds) by RFC2845.
+ ///
+ /// Right now fudge is not tunable, and all TSIGs generated by this API
+ /// will have this value of fudge.
+ static const uint16_t DEFAULT_FUDGE = 300;
+ //@}
+
+private:
+ struct TSIGContextImpl;
+ TSIGContextImpl* impl_;
+};
+}
+}
+
+#endif // __TSIG_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/tsigerror.cc b/src/lib/dns/tsigerror.cc
new file mode 100644
index 0000000..e63c9ab
--- /dev/null
+++ b/src/lib/dns/tsigerror.cc
@@ -0,0 +1,57 @@
+// 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.
+
+#include <ostream>
+#include <string>
+
+#include <boost/lexical_cast.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/rcode.h>
+#include <dns/tsigerror.h>
+
+namespace isc {
+namespace dns {
+namespace {
+const char* const tsigerror_text[] = {
+ "BADSIG",
+ "BADKEY",
+ "BADTIME"
+};
+}
+
+TSIGError::TSIGError(Rcode rcode) : code_(rcode.getCode()) {
+ if (code_ > MAX_RCODE_FOR_TSIGERROR) {
+ isc_throw(OutOfRange, "Invalid RCODE for TSIG Error: " << rcode);
+ }
+}
+
+std::string
+TSIGError::toText() const {
+ if (code_ <= MAX_RCODE_FOR_TSIGERROR) {
+ return (Rcode(code_).toText());
+ } else if (code_ <= BAD_TIME_CODE) {
+ return (tsigerror_text[code_ - (MAX_RCODE_FOR_TSIGERROR + 1)]);
+ } else {
+ return (boost::lexical_cast<std::string>(code_));
+ }
+}
+
+std::ostream&
+operator<<(std::ostream& os, const TSIGError& error) {
+ return (os << error.toText());
+}
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/tsigerror.h b/src/lib/dns/tsigerror.h
new file mode 100644
index 0000000..4463daf
--- /dev/null
+++ b/src/lib/dns/tsigerror.h
@@ -0,0 +1,328 @@
+// 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 __TSIGERROR_H
+#define __TSIGERROR_H 1
+
+#include <ostream>
+#include <string>
+
+#include <dns/rcode.h>
+
+namespace isc {
+namespace dns {
+
+class RRClass;
+
+/// TSIG errors
+///
+/// The \c TSIGError class objects represent standard errors related to
+/// TSIG protocol operations as defined in related specifications, mainly
+/// in RFC2845.
+///
+/// (RCODEs) of the header section of DNS messages, and extended response
+/// codes as defined in the EDNS specification.
+class TSIGError {
+public:
+ /// Constants for pre-defined TSIG error values.
+ ///
+ /// Code values from 0 through 15 (inclusive) are derived from those of
+ /// RCODE and are not defined here. See the \c Rcode class.
+ ///
+ /// \note Unfortunately some systems define "BADSIG" as a macro in a public
+ /// header file. To avoid conflict with it we add an underscore to our
+ /// definitions.
+ enum CodeValue {
+ BAD_SIG_CODE = 16, ///< 16: TSIG verification failure
+ BAD_KEY_CODE = 17, ///< 17: TSIG key is not recognized
+ BAD_TIME_CODE = 18 ///< 18: Current time and time signed are too different
+ };
+
+ /// \name Constructors
+ ///
+ /// We use the default versions of destructor, copy constructor,
+ /// and assignment operator.
+ //@{
+ /// Constructor from the code value.
+ ///
+ /// \exception None
+ ///
+ /// \param code The underlying 16-bit error code value of the \c TSIGError.
+ explicit TSIGError(uint16_t error_code) : code_(error_code) {}
+
+ /// Constructor from \c Rcode.
+ ///
+ /// As defined in RFC2845, error code values from 0 to 15 (inclusive) are
+ /// derived from the DNS RCODEs, which are represented via the \c Rcode
+ /// class in this library. This constructor works as a converter from
+ /// these RCODEs to corresponding TSIGError objects.
+ ///
+ /// \exception isc::OutOfRange Given rcode is not convertible to
+ /// TSIGErrors.
+ ///
+ /// \param rcode the \c Rcode from which the TSIGError should be derived.
+ explicit TSIGError(Rcode rcode);
+ //@}
+
+ /// \brief Returns the \c TSIGCode error code value.
+ ///
+ /// \exception None
+ ///
+ /// \return The underlying code value corresponding to the \c TSIGError.
+ uint16_t getCode() const { return (code_); }
+
+ /// \brief Return true iff two \c TSIGError objects are equal.
+ ///
+ /// Two TSIGError objects are equal iff their error codes are equal.
+ ///
+ /// \exception None
+ ///
+ /// \param other the \c TSIGError object to compare against.
+ /// \return true if the two TSIGError are equal; otherwise false.
+ bool equals(const TSIGError& other) const
+ { return (code_ == other.code_); }
+
+ /// \brief Same as \c equals().
+ bool operator==(const TSIGError& other) const { return (equals(other)); }
+
+ /// \brief Return true iff two \c TSIGError objects are not equal.
+ ///
+ /// \exception None
+ ///
+ /// \param other the \c TSIGError object to compare against.
+ /// \return true if the two TSIGError objects are not equal;
+ /// otherwise false.
+ bool nequals(const TSIGError& other) const
+ { return (code_ != other.code_); }
+
+ /// \brief Same as \c nequals().
+ bool operator!=(const TSIGError& other) const { return (nequals(other)); }
+
+ /// \brief Convert the \c TSIGError to a string.
+ ///
+ /// For codes derived from RCODEs up to 15, this method returns the
+ /// same string as \c Rcode::toText() for the corresponding code.
+ /// For other pre-defined code values (see TSIGError::CodeValue),
+ /// this method returns a string representation of the "mnemonic' used
+ /// for the enum and constant objects as defined in RFC2845.
+ /// For example, the string for code value 16 is "BADSIG", etc.
+ /// For other code values it returns a string representation of the decimal
+ /// number of the value, e.g. "32", "100", etc.
+ ///
+ /// \exception std::bad_alloc Resource allocation for the string fails
+ ///
+ /// \return A string representation of the \c TSIGError.
+ std::string toText() const;
+
+ /// A constant TSIG error object derived from \c Rcode::NOERROR()
+ static const TSIGError& NOERROR();
+
+ /// A constant TSIG error object derived from \c Rcode::FORMERR()
+ static const TSIGError& FORMERR();
+
+ /// A constant TSIG error object derived from \c Rcode::SERVFAIL()
+ static const TSIGError& SERVFAIL();
+
+ /// A constant TSIG error object derived from \c Rcode::NXDOMAIN()
+ static const TSIGError& NXDOMAIN();
+
+ /// A constant TSIG error object derived from \c Rcode::NOTIMP()
+ static const TSIGError& NOTIMP();
+
+ /// A constant TSIG error object derived from \c Rcode::REFUSED()
+ static const TSIGError& REFUSED();
+
+ /// A constant TSIG error object derived from \c Rcode::YXDOMAIN()
+ static const TSIGError& YXDOMAIN();
+
+ /// A constant TSIG error object derived from \c Rcode::YXRRSET()
+ static const TSIGError& YXRRSET();
+
+ /// A constant TSIG error object derived from \c Rcode::NXRRSET()
+ static const TSIGError& NXRRSET();
+
+ /// A constant TSIG error object derived from \c Rcode::NOTAUTH()
+ static const TSIGError& NOTAUTH();
+
+ /// A constant TSIG error object derived from \c Rcode::NOTZONE()
+ static const TSIGError& NOTZONE();
+
+ /// A constant TSIG error object derived from \c Rcode::RESERVED11()
+ static const TSIGError& RESERVED11();
+
+ /// A constant TSIG error object derived from \c Rcode::RESERVED12()
+ static const TSIGError& RESERVED12();
+
+ /// A constant TSIG error object derived from \c Rcode::RESERVED13()
+ static const TSIGError& RESERVED13();
+
+ /// A constant TSIG error object derived from \c Rcode::RESERVED14()
+ static const TSIGError& RESERVED14();
+
+ /// A constant TSIG error object derived from \c Rcode::RESERVED15()
+ static const TSIGError& RESERVED15();
+
+ /// A constant TSIG error object for the BADSIG code
+ /// (see \c TSIGError::BAD_SIG_CODE).
+ static const TSIGError& BAD_SIG();
+
+ /// A constant TSIG error object for the BADKEY code
+ /// (see \c TSIGError::BAD_KEY_CODE).
+ static const TSIGError& BAD_KEY();
+
+ /// A constant TSIG error object for the BADTIME code
+ /// (see \c TSIGError::BAD_TIME_CODE).
+ static const TSIGError& BAD_TIME();
+
+private:
+ // This is internally used to specify the maximum possible RCODE value
+ // that can be convertible to TSIGErrors.
+ static const int MAX_RCODE_FOR_TSIGERROR = 15;
+
+ uint16_t code_;
+};
+
+inline const TSIGError&
+TSIGError::NOERROR() {
+ static TSIGError e(Rcode::NOERROR());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::FORMERR() {
+ static TSIGError e(Rcode::FORMERR());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::SERVFAIL() {
+ static TSIGError e(Rcode::SERVFAIL());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::NXDOMAIN() {
+ static TSIGError e(Rcode::NXDOMAIN());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::NOTIMP() {
+ static TSIGError e(Rcode::NOTIMP());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::REFUSED() {
+ static TSIGError e(Rcode::REFUSED());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::YXDOMAIN() {
+ static TSIGError e(Rcode::YXDOMAIN());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::YXRRSET() {
+ static TSIGError e(Rcode::YXRRSET());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::NXRRSET() {
+ static TSIGError e(Rcode::NXRRSET());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::NOTAUTH() {
+ static TSIGError e(Rcode::NOTAUTH());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::NOTZONE() {
+ static TSIGError e(Rcode::NOTZONE());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED11() {
+ static TSIGError e(Rcode::RESERVED11());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED12() {
+ static TSIGError e(Rcode::RESERVED12());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED13() {
+ static TSIGError e(Rcode::RESERVED13());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED14() {
+ static TSIGError e(Rcode::RESERVED14());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::RESERVED15() {
+ static TSIGError e(Rcode::RESERVED15());
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::BAD_SIG() {
+ static TSIGError e(BAD_SIG_CODE);
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::BAD_KEY() {
+ static TSIGError e(BAD_KEY_CODE);
+ return (e);
+}
+
+inline const TSIGError&
+TSIGError::BAD_TIME() {
+ static TSIGError e(BAD_TIME_CODE);
+ return (e);
+}
+
+/// Insert the \c TSIGError as a string into stream.
+///
+/// This method convert \c tsig_error into a string and inserts it into the
+/// output stream \c os.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param tsig_error An \c TSIGError object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
+std::ostream& operator<<(std::ostream& os, const TSIGError& tsig_error);
+}
+}
+
+#endif // __TSIGERROR_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/tsigkey.cc b/src/lib/dns/tsigkey.cc
index 057191d..c899423 100644
--- a/src/lib/dns/tsigkey.cc
+++ b/src/lib/dns/tsigkey.cc
@@ -15,50 +15,112 @@
#include <map>
#include <utility>
#include <vector>
+#include <sstream>
#include <exceptions/exceptions.h>
+#include <cryptolink/cryptolink.h>
+
#include <dns/name.h>
+#include <util/encode/base64.h>
#include <dns/tsigkey.h>
using namespace std;
+using namespace isc::cryptolink;
namespace isc {
namespace dns {
+namespace {
+ HashAlgorithm
+ convertAlgorithmName(const isc::dns::Name& name) {
+ if (name == TSIGKey::HMACMD5_NAME()) {
+ return (isc::cryptolink::MD5);
+ }
+ if (name == TSIGKey::HMACSHA1_NAME()) {
+ return (isc::cryptolink::SHA1);
+ }
+ if (name == TSIGKey::HMACSHA256_NAME()) {
+ return (isc::cryptolink::SHA256);
+ }
+ isc_throw(InvalidParameter,
+ "Unknown TSIG algorithm is specified: " << name);
+ }
+}
+
struct
TSIGKey::TSIGKeyImpl {
TSIGKeyImpl(const Name& key_name, const Name& algorithm_name,
+ isc::cryptolink::HashAlgorithm algorithm,
const void* secret, size_t secret_len) :
key_name_(key_name), algorithm_name_(algorithm_name),
+ algorithm_(algorithm),
secret_(static_cast<const uint8_t*>(secret),
static_cast<const uint8_t*>(secret) + secret_len)
{
- // Convert the name to the canonical form.
+ // Convert the key and algorithm names to the canonical form.
+ key_name_.downcase();
algorithm_name_.downcase();
}
- const Name key_name_;
+ Name key_name_;
Name algorithm_name_;
+ const isc::cryptolink::HashAlgorithm algorithm_;
const vector<uint8_t> secret_;
};
TSIGKey::TSIGKey(const Name& key_name, const Name& algorithm_name,
const void* secret, size_t secret_len) : impl_(NULL)
{
- if (algorithm_name != HMACMD5_NAME() &&
- algorithm_name != HMACSHA1_NAME() &&
- algorithm_name != HMACSHA256_NAME()) {
- isc_throw(InvalidParameter, "Unknown TSIG algorithm is specified: " <<
- algorithm_name);
- }
+ const HashAlgorithm algorithm = convertAlgorithmName(algorithm_name);
if ((secret != NULL && secret_len == 0) ||
(secret == NULL && secret_len != 0)) {
isc_throw(InvalidParameter,
"TSIGKey secret and its length are inconsistent");
}
-
- impl_ = new TSIGKeyImpl(key_name, algorithm_name, secret, secret_len);
+ impl_ = new TSIGKeyImpl(key_name, algorithm_name, algorithm, secret,
+ secret_len);
+}
+
+TSIGKey::TSIGKey(const std::string& str) : impl_(NULL) {
+ try {
+ istringstream iss(str);
+
+ string keyname_str;
+ getline(iss, keyname_str, ':');
+ if (iss.fail() || iss.bad() || iss.eof()) {
+ isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
+ }
+
+ string secret_str;
+ getline(iss, secret_str, ':');
+ if (iss.fail() || iss.bad()) {
+ isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
+ }
+
+ string algo_str;
+ if (!iss.eof()) {
+ getline(iss, algo_str);
+ }
+ if (iss.fail() || iss.bad()) {
+ isc_throw(InvalidParameter, "Invalid TSIG key string: " << str);
+ }
+
+ const Name algo_name(algo_str.empty() ? "hmac-md5.sig-alg.reg.int" :
+ algo_str);
+ const HashAlgorithm algorithm = convertAlgorithmName(algo_name);
+
+ vector<uint8_t> secret;
+ isc::util::encode::decodeBase64(secret_str, secret);
+
+ impl_ = new TSIGKeyImpl(Name(keyname_str), algo_name, algorithm,
+ &secret[0], secret.size());
+ } catch (const Exception& e) {
+ // 'reduce' the several types of exceptions name parsing and
+ // Base64 decoding can throw to just the InvalidParameter
+ isc_throw(InvalidParameter, e.what());
+ }
}
+
TSIGKey::TSIGKey(const TSIGKey& source) : impl_(new TSIGKeyImpl(*source.impl_))
{}
@@ -89,6 +151,11 @@ TSIGKey::getAlgorithmName() const {
return (impl_->algorithm_name_);
}
+isc::cryptolink::HashAlgorithm
+TSIGKey::getAlgorithm() const {
+ return (impl_->algorithm_);
+}
+
const void*
TSIGKey::getSecret() const {
return ((impl_->secret_.size() > 0) ? &impl_->secret_[0] : NULL);
@@ -99,6 +166,17 @@ TSIGKey::getSecretLength() const {
return (impl_->secret_.size());
}
+std::string
+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 = isc::util::encode::encodeBase64(secret_v);
+
+ return (getKeyName().toText() + ":" + secret_str + ":" +
+ getAlgorithmName().toText());
+}
+
const
Name& TSIGKey::HMACMD5_NAME() {
static Name alg_name("hmac-md5.sig-alg.reg.int");
diff --git a/src/lib/dns/tsigkey.h b/src/lib/dns/tsigkey.h
index e56fa88..02dd423 100644
--- a/src/lib/dns/tsigkey.h
+++ b/src/lib/dns/tsigkey.h
@@ -15,6 +15,8 @@
#ifndef __TSIGKEY_H
#define __TSIGKEY_H 1
+#include <cryptolink/cryptolink.h>
+
namespace isc {
namespace dns {
@@ -90,6 +92,25 @@ public:
TSIGKey(const Name& key_name, const Name& algorithm_name,
const void* secret, size_t secret_len);
+ /// \brief Constructor from an input string
+ ///
+ /// The string must be of the form:
+ /// <name>:<secret>[:<algorithm>]
+ /// Where <name> is a domain name for the key, <secret> is a
+ /// base64 representation of the key secret, and the optional
+ /// algorithm is an algorithm identifier as specified in RFC4635
+ /// The default algorithm is hmac-md5.sig-alg.reg.int.
+ ///
+ /// Since ':' is used as a separator here, it is not possible to
+ /// use this constructor to create keys with a ':' character in
+ /// their name.
+ ///
+ /// \exception InvalidParameter exception if the input string is
+ /// invalid.
+ ///
+ /// \param str The string to make a TSIGKey from
+ explicit TSIGKey(const std::string& str);
+
/// \brief The copy constructor.
///
/// It internally allocates a resource, and if it fails a corresponding
@@ -123,6 +144,9 @@ public:
/// Return the algorithm name.
const Name& getAlgorithmName() const;
+ /// Return the hash algorithm name in the form of cryptolink::HashAlgorithm
+ isc::cryptolink::HashAlgorithm getAlgorithm() const;
+
/// Return the length of the TSIG secret in bytes.
size_t getSecretLength() const;
@@ -139,6 +163,18 @@ public:
const void* getSecret() const;
//@}
+ /// \brief Converts the TSIGKey to a string value
+ ///
+ /// The resulting string will be of the form
+ /// name:secret:algorithm
+ /// Where <name> is a domain name for the key, <secret> is a
+ /// base64 representation of the key secret, and algorithm is
+ /// an algorithm identifier as specified in RFC4635
+ ///
+ /// \param key the TSIG key to convert
+ /// \return The string representation of the given TSIGKey.
+ std::string toText() const;
+
///
/// \name Well known algorithm names as defined in RFC2845 and RFC4635.
///
diff --git a/src/lib/log/Makefile.am b/src/lib/log/Makefile.am
index 5770564..537d08f 100644
--- a/src/lib/log/Makefile.am
+++ b/src/lib/log/Makefile.am
@@ -21,6 +21,8 @@ liblog_la_SOURCES += message_initializer.cc message_initializer.h
liblog_la_SOURCES += message_reader.cc message_reader.h
liblog_la_SOURCES += message_types.h
liblog_la_SOURCES += root_logger_name.cc root_logger_name.h
+liblog_la_SOURCES += log_formatter.h log_formatter.cc
+liblog_la_SOURCES += macros.h
EXTRA_DIST = README
EXTRA_DIST += messagedef.mes
diff --git a/src/lib/log/README b/src/lib/log/README
index ed11b5b..d01b12f 100644
--- a/src/lib/log/README
+++ b/src/lib/log/README
@@ -96,7 +96,7 @@ An example file could be:
$PREFIX TEST_
$NAMESPACE isc::log
-TEST1 message %s is much too large
+TEST1 message %1 is much too large
+ This message is a test for the general message code
UNKNOWN unknown message
@@ -131,8 +131,8 @@ Points to note:
part of the line.
* Message lines. These comprise a symbol name and a message, which may
- include zero or more printf-style tokens. Symbol names will be upper-cased
- by the compiler.
+ include zero or more %1, %2... placeholder tokens. Symbol names will be
+ upper-cased by the compiler.
Message Compiler
@@ -252,14 +252,14 @@ To use the current version of the logging:
4. Issue logging calls using methods on logger, e.g.
- logger.error(DPS_NSTIMEOUT, "isc.org");
+ logger.error(DPS_NSTIMEOUT).arg("isc.org");
(where, in the example above we might have defined the symbol in the message
file with something along the lines of:
$PREFIX DPS_
:
- NSTIMEOUT queries to all nameservers for %s have timed out
+ NSTIMEOUT queries to all nameservers for %1 have timed out
At present, the only logging is to the console.
diff --git a/src/lib/log/compiler/message.cc b/src/lib/log/compiler/message.cc
index 07b87e0..eb9ddca 100644
--- a/src/lib/log/compiler/message.cc
+++ b/src/lib/log/compiler/message.cc
@@ -535,9 +535,12 @@ main(int argc, char* argv[]) {
string text = e.id();
text += ", ";
text += global.getText(e.id());
-
// Format with arguments
- text = isc::util::str::format(text, e.arguments());
+ vector<string> args(e.arguments());
+ for (size_t i(0); i < args.size(); ++ i) {
+ replacePlaceholder(&text, args[i], i + 1);
+ }
+
cerr << text << "\n";
return 1;
diff --git a/src/lib/log/log_formatter.cc b/src/lib/log/log_formatter.cc
new file mode 100644
index 0000000..920d7dd
--- /dev/null
+++ b/src/lib/log/log_formatter.cc
@@ -0,0 +1,39 @@
+// 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.
+
+#include <log/log_formatter.h>
+
+using namespace std;
+using namespace boost;
+
+namespace isc {
+namespace log {
+
+void
+replacePlaceholder(string* message, const string& arg,
+ const unsigned placeholder)
+{
+ string mark("%" + lexical_cast<string>(placeholder));
+ size_t pos(message->find(mark));
+ if (pos != string::npos) {
+ message->replace(pos, mark.size(), arg);
+ } else {
+ // We're missing the placeholder, so add some complain
+ message->append(" @@Missing placeholder " + mark + " for '" + arg +
+ "'@@");
+ }
+}
+
+}
+}
diff --git a/src/lib/log/log_formatter.h b/src/lib/log/log_formatter.h
new file mode 100644
index 0000000..3977eba
--- /dev/null
+++ b/src/lib/log/log_formatter.h
@@ -0,0 +1,171 @@
+// 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 __LOG_FORMATTER_H
+#define __LOG_FORMMATER_H
+
+#include <string>
+#include <boost/lexical_cast.hpp>
+
+namespace isc {
+namespace log {
+
+/// \brief The internal replacement routine
+///
+/// This is used internally by the Formatter. Replaces a placeholder
+/// in the message by replacement. If the placeholder is not found,
+/// it adds a complain at the end.
+void
+replacePlaceholder(std::string* message, const std::string& replacement,
+ const unsigned placeholder);
+
+///
+/// \brief The log message formatter
+///
+/// This class allows us to format logging messages conveniently. We
+/// call something like logger.warn(WARN_MSG).arg(15).arg(dnsMsg). This
+/// outputs some text with placeholders replaced by the arguments, if
+/// the logging verbosity is at WARN level or more.
+///
+/// To make this work, we use the Formatter. The warn (or whatever logging
+/// function) returns a Formatter object. That one holds the string to be
+/// output with the placeholders. It also remembers if there should be any
+/// output at all (eg. if the logging is enabled for this level). When there's
+/// no .arg call on the object, it is destroyed right away and we use the
+/// destructor to output the text (but only in case we should output anything).
+///
+/// If there's an .arg call, it replaces a placeholder with the argument
+/// converted to string and produces another Formatter. We mark the current
+/// Formatter so it won't output anything in it's destructor and the task
+/// to do the output is moved onto the new object. Again, the last one in
+/// the chain is destroyed without any modification and does the real output.
+///
+/// Of course, if the logging is turned off, we don't bother with any replacing
+/// and just return new empty Formatter. As everything here is in the header
+/// file, compiler should be able to easily optimise most of the work with
+/// creating and destroying objects and simply do the replacing only.
+///
+/// User of logging code should not really care much about this class, only
+/// call the .arg method to generate the correct output.
+///
+/// The class is a template to allow easy testing. Also, we want everything
+/// here in the header anyway and it doesn't depend on the details of what
+/// Logger really is, so it doesn't hurt anything.
+template<class Logger> class Formatter {
+private:
+ /// \brief The logger we will use to output the final message
+ Logger* logger_;
+ /// \brief Prefix (eg. "ERROR", "DEBUG" or like that)
+ const char* prefix_;
+ /// \brief The messages with %1, %2... placeholders
+ std::string* message_;
+ /// \brief Which will be the next placeholder to replace
+ const unsigned nextPlaceholder_;
+ /// \brief Should we do output?
+ mutable bool active_;
+ Formatter& operator =(const Formatter& other);
+public:
+ /// \brief Constructor of "active" formatter
+ ///
+ /// This will create a formatter in active mode -- the one when it
+ /// will generate output.
+ ///
+ /// It is not expected to be called by user of logging system directly.
+ ///
+ /// \param prefix The prefix, like "ERROR" or "DEBUG"
+ /// \param message The message with placeholders. We take ownership of
+ /// it and we will modify the string. Must not be NULL and it's
+ /// not checked.
+ /// \param nextPlaceholder It is the number of next placeholder which
+ /// should be replaced. It should be called with 1, higher numbers
+ /// are used internally in the chain.
+ /// \param logger The logger where the final output will go.
+ Formatter(const char* prefix, std::string* message,
+ const unsigned nextPlaceholder, Logger& logger) :
+ logger_(&logger), prefix_(prefix), message_(message),
+ nextPlaceholder_(nextPlaceholder), active_(true)
+ {
+ }
+ /// \brief Constructor of "inactive" formatter
+ ///
+ /// It is not expected to be called by user of the logging system directly.
+ ///
+ /// This will create a formatter that produces no output.
+ Formatter() :
+ message_(NULL),
+ nextPlaceholder_(0),
+ active_(false)
+ {
+ }
+
+ Formatter(const Formatter& other) :
+ logger_(other.logger_), prefix_(other.prefix_),
+ message_(other.message_), nextPlaceholder_(other.nextPlaceholder_),
+ active_(other.active_)
+ {
+ other.active_ = false;
+ }
+ /// \brief Destructor.
+ //
+ /// This is the place where output happens if the formatter is active.
+ ~ Formatter() {
+ if (active_) {
+ logger_->output(prefix_, *message_);
+ }
+ delete message_;
+ }
+ /// \brief Replaces another placeholder
+ ///
+ /// Replaces another placeholder and returns a new formatter with it.
+ /// Deactivates the current formatter. In case the formatter is not active,
+ /// only produces another inactive formatter.
+ ///
+ /// \param arg The argument to place into the placeholder.
+ template<class Arg> Formatter arg(const Arg& value) {
+ if (active_) {
+ return (arg(boost::lexical_cast<std::string>(value)));
+ } else {
+ return (Formatter<Logger>());
+ }
+ }
+ /// \brief String version of arg.
+ Formatter arg(const std::string& arg) {
+ if (active_) {
+ // FIXME: This logic has a problem. If we had a message like
+ // "%1 %2" and called .arg("%2").arg(42), we would get "42 %2".
+ // But we consider this to be rare enough not to complicate
+ // matters.
+ active_ = false;
+ replacePlaceholder(message_, arg, nextPlaceholder_);
+ std::string *message(message_);
+ message_ = NULL;
+ try {
+ return (Formatter<Logger>(prefix_, message,
+ nextPlaceholder_ + 1, *logger_));
+ }
+ // Make sure the memory is not leaked on stuff like bad_alloc
+ catch (...) {
+ delete message;
+ throw;
+ }
+ } else {
+ return (Formatter<Logger>());
+ }
+ }
+};
+
+}
+}
+
+#endif
diff --git a/src/lib/log/logger.cc b/src/lib/log/logger.cc
index 99dc3a1..3131c0b 100644
--- a/src/lib/log/logger.cc
+++ b/src/lib/log/logger.cc
@@ -112,52 +112,57 @@ Logger::isFatalEnabled() {
// Output methods
void
-Logger::debug(int dbglevel, const isc::log::MessageID& ident, ...) {
+Logger::output(const char* sevText, const string& message) {
+ getLoggerPtr()->outputRaw(sevText, message);
+}
+
+Logger::Formatter
+Logger::debug(int dbglevel, const isc::log::MessageID& ident) {
if (isDebugEnabled(dbglevel)) {
- va_list ap;
- va_start(ap, ident);
- getLoggerPtr()->debug(ident, ap);
- va_end(ap);
+ return (Formatter("DEBUG", getLoggerPtr()->lookupMessage(ident), 1,
+ *this));
+ } else {
+ return (Formatter());
}
}
-void
-Logger::info(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::info(const isc::log::MessageID& ident) {
if (isInfoEnabled()) {
- va_list ap;
- va_start(ap, ident);
- getLoggerPtr()->info(ident, ap);
- va_end(ap);
+ return (Formatter("INFO ", getLoggerPtr()->lookupMessage(ident), 1,
+ *this));
+ } else {
+ return (Formatter());
}
}
-void
-Logger::warn(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::warn(const isc::log::MessageID& ident) {
if (isWarnEnabled()) {
- va_list ap;
- va_start(ap, ident);
- getLoggerPtr()->warn(ident, ap);
- va_end(ap);
+ return (Formatter("WARN ", getLoggerPtr()->lookupMessage(ident), 1,
+ *this));
+ } else {
+ return (Formatter());
}
}
-void
-Logger::error(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::error(const isc::log::MessageID& ident) {
if (isErrorEnabled()) {
- va_list ap;
- va_start(ap, ident);
- getLoggerPtr()->error(ident, ap);
- va_end(ap);
+ return (Formatter("ERROR", getLoggerPtr()->lookupMessage(ident), 1,
+ *this));
+ } else {
+ return (Formatter());
}
}
-void
-Logger::fatal(const isc::log::MessageID& ident, ...) {
+Logger::Formatter
+Logger::fatal(const isc::log::MessageID& ident) {
if (isFatalEnabled()) {
- va_list ap;
- va_start(ap, ident);
- getLoggerPtr()->fatal(ident, ap);
- va_end(ap);
+ return (Formatter("FATAL", getLoggerPtr()->lookupMessage(ident), 1,
+ *this));
+ } else {
+ return (Formatter());
}
}
diff --git a/src/lib/log/logger.h b/src/lib/log/logger.h
index 88e88e2..6bd8924 100644
--- a/src/lib/log/logger.h
+++ b/src/lib/log/logger.h
@@ -21,6 +21,7 @@
#include <log/debug_levels.h>
#include <log/logger_levels.h>
#include <log/message_types.h>
+#include <log/log_formatter.h>
namespace isc {
namespace log {
@@ -83,10 +84,11 @@ public:
loggerptr_(NULL), name_(name), infunc_(infunc)
{}
-
/// \brief Destructor
virtual ~Logger();
+ /// \brief The formatter used to replace placeholders
+ typedef isc::log::Formatter<Logger> Formatter;
/// \brief Get Name of Logger
///
@@ -157,36 +159,31 @@ public:
/// \param dbglevel Debug level, ranging between 0 and 99. Higher numbers
/// are used for more verbose output.
/// \param ident Message identification.
- /// \param ... Optional arguments for the message.
- void debug(int dbglevel, const MessageID& ident, ...);
+ Formatter debug(int dbglevel, const MessageID& ident);
/// \brief Output Informational Message
///
/// \param ident Message identification.
- /// \param ... Optional arguments for the message.
- void info(const MessageID& ident, ...);
+ Formatter info(const MessageID& ident);
/// \brief Output Warning Message
///
/// \param ident Message identification.
- /// \param ... Optional arguments for the message.
- void warn(const MessageID& ident, ...);
+ Formatter warn(const MessageID& ident);
/// \brief Output Error Message
///
/// \param ident Message identification.
- /// \param ... Optional arguments for the message.
- void error(const MessageID& ident, ...);
+ Formatter error(const MessageID& ident);
/// \brief Output Fatal Message
///
/// \param ident Message identification.
- /// \param ... Optional arguments for the message.
- void fatal(const MessageID& ident, ...);
+ Formatter fatal(const MessageID& ident);
/// \brief Equality
///
@@ -205,6 +202,12 @@ protected:
static void reset();
private:
+ friend class isc::log::Formatter<Logger>;
+ /// \brief Raw output function
+ ///
+ /// This is used by the formatter to output formatted output.
+ void output(const char* sevText, const std::string& message);
+
/// \brief Copy Constructor
///
/// Disabled (marked private) as it makes no sense to copy the logger -
diff --git a/src/lib/log/logger_impl.cc b/src/lib/log/logger_impl.cc
index 41153e9..a678735 100644
--- a/src/lib/log/logger_impl.cc
+++ b/src/lib/log/logger_impl.cc
@@ -194,17 +194,14 @@ LoggerImpl::isDebugEnabled(int dbglevel) {
}
// Output a general message
+string*
+LoggerImpl::lookupMessage(const MessageID& ident) {
+ return (new string(string(ident) + ", " +
+ MessageDictionary::globalDictionary().getText(ident)));
+}
void
-LoggerImpl::output(const char* sev_text, const MessageID& ident,
- va_list ap)
-{
- char message[512]; // Should be large enough for any message
-
- // Obtain text of the message and substitute arguments.
- const string format = MessageDictionary::globalDictionary().getText(ident);
- vsnprintf(message, sizeof(message), format.c_str(), ap);
-
+LoggerImpl::outputRaw(const char* sevText, const string& message) {
// Get the time in a struct tm format, and convert to text
time_t t_time;
time(&t_time);
@@ -214,8 +211,8 @@ LoggerImpl::output(const char* sev_text, const MessageID& ident,
(void) strftime(chr_time, sizeof(chr_time), "%Y-%m-%d %H:%M:%S", tm_time);
// Now output.
- std::cout << chr_time << " " << sev_text << " [" << getName() << "] " <<
- ident << ", " << message << "\n";
+ cout << chr_time << " " << sevText << " [" << getName() << "] " <<
+ message << endl;
}
} // namespace log
diff --git a/src/lib/log/logger_impl.h b/src/lib/log/logger_impl.h
index 9fc9cf9..187e478 100644
--- a/src/lib/log/logger_impl.h
+++ b/src/lib/log/logger_impl.h
@@ -167,64 +167,16 @@ public:
}
}
-
- /// \brief Output General Message
- ///
- /// The message is formatted to include the date and time, the severity
- /// and the logger generating the message.
+ /// \brief Raw output
///
- /// \param sev_text Severity level as a text string
- /// \param ident Message identification
- /// \param ap Variable argument list holding message arguments
- void output(const char* sev_text, const MessageID& ident,
- va_list ap);
-
+ /// Writes the message with time into the log. Used by the Formatter
+ /// to produce output.
+ void outputRaw(const char* sev_text, const std::string& message);
- /// \brief Output Debug Message
+ /// \brief Look up message text in dictionary
///
- /// \param ident Message identification.
- /// \param text Text to log
- /// \param ap Variable argument list holding message arguments
- void debug(const MessageID& ident, va_list ap) {
- output("DEBUG", ident, ap);
- }
-
-
- /// \brief Output Informational Message
- ///
- /// \param ident Message identification.
- /// \param text Text to log
- /// \param ap Variable argument list holding message arguments
- void info(const MessageID& ident, va_list ap) {
- output("INFO ", ident, ap);
- }
-
- /// \brief Output Warning Message
- ///
- /// \param ident Message identification.
- /// \param text Text to log
- /// \param ap Variable argument list holding message arguments
- void warn(const MessageID& ident, va_list ap) {
- output("WARN ", ident, ap);
- }
-
- /// \brief Output Error Message
- ///
- /// \param ident Message identification.
- /// \param text Text to log
- /// \param ap Variable argument list holding message arguments
- void error(const MessageID& ident, va_list ap) {
- output("ERROR", ident, ap);
- }
-
- /// \brief Output Fatal Message
- ///
- /// \param ident Message identification.
- /// \param text Text to log
- /// \param ap Variable argument list holding message arguments
- void fatal(const MessageID& ident, va_list ap) {
- output("FATAL", ident, ap);
- }
+ /// This gets you the unformatted text of message for given ID.
+ std::string* lookupMessage(const MessageID& id);
/// \brief Equality
///
diff --git a/src/lib/log/logger_support.cc b/src/lib/log/logger_support.cc
index f8bf075..83147aa 100644
--- a/src/lib/log/logger_support.cc
+++ b/src/lib/log/logger_support.cc
@@ -62,7 +62,7 @@ readLocalMessageFile(const char* file) {
MessageDictionary& dictionary = MessageDictionary::globalDictionary();
MessageReader reader(&dictionary);
try {
- logger.info(MSG_RDLOCMES, file);
+ logger.info(MSG_RDLOCMES).arg(file);
reader.readFile(file, MessageReader::REPLACE);
// File successfully read, list the duplicates
@@ -70,7 +70,7 @@ readLocalMessageFile(const char* file) {
for (MessageReader::MessageIDCollection::const_iterator
i = unknown.begin(); i != unknown.end(); ++i) {
string message_id = boost::lexical_cast<string>(*i);
- logger.warn(MSG_IDNOTFND, message_id.c_str());
+ logger.warn(MSG_IDNOTFND).arg(message_id);
}
}
catch (MessageException& e) {
@@ -82,11 +82,11 @@ readLocalMessageFile(const char* file) {
break;
case 1:
- logger.error(ident, args[0].c_str());
+ logger.error(ident).arg(args[0]);
break;
default: // 2 or more (2 should be the maximum)
- logger.error(ident, args[0].c_str(), args[1].c_str());
+ logger.error(ident).arg(args[0]).arg(args[1]);
}
}
}
@@ -117,7 +117,7 @@ initLogger(const string& root, isc::log::Severity severity, int dbglevel,
vector<string>::iterator new_end =
unique(duplicates.begin(), duplicates.end());
for (vector<string>::iterator i = duplicates.begin(); i != new_end; ++i) {
- logger.warn(MSG_DUPMSGID, i->c_str());
+ logger.warn(MSG_DUPMSGID).arg(*i);
}
}
diff --git a/src/lib/log/macros.h b/src/lib/log/macros.h
new file mode 100644
index 0000000..4a5ac19
--- /dev/null
+++ b/src/lib/log/macros.h
@@ -0,0 +1,48 @@
+// 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 __LOG_MACROS_H
+#define __LOG_MACROS_H
+
+/// \brief Macro to conveniently test debug output and log it
+#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE) \
+ if (!(LOGGER).isDebugEnabled((LEVEL))) { \
+ } else \
+ (LOGGER).debug((LEVEL), (MESSAGE))
+
+/// \brief Macro to conveniently test info output and log it
+#define LOG_INFO(LOGGER, MESSAGE) \
+ if (!(LOGGER).isInfoEnabled()) { \
+ } else \
+ (LOGGER).info((MESSAGE))
+
+/// \brief Macro to conveniently test warn output and log it
+#define LOG_WARN(LOGGER, MESSAGE) \
+ if (!(LOGGER).isWarnEnabled()) { \
+ } else \
+ (LOGGER).warn((MESSAGE))
+
+/// \brief Macro to conveniently test error output and log it
+#define LOG_ERROR(LOGGER, MESSAGE) \
+ if (!(LOGGER).isErrorEnabled()) { \
+ } else \
+ (LOGGER).error((MESSAGE))
+
+/// \brief Macro to conveniently test fatal output and log it
+#define LOG_FATAL(LOGGER, MESSAGE) \
+ if (!(LOGGER).isFatalEnabled()) { \
+ } else \
+ (LOGGER).fatal((MESSAGE))
+
+#endif
diff --git a/src/lib/log/messagedef.cc b/src/lib/log/messagedef.cc
index f680a74..46086d0 100644
--- a/src/lib/log/messagedef.cc
+++ b/src/lib/log/messagedef.cc
@@ -1,4 +1,4 @@
-// File created from messagedef.mes on Mon Feb 14 11:07:45 2011
+// File created from messagedef.mes on Thu May 5 16:57:11 2011
#include <cstddef>
#include <log/message_types.h>
@@ -33,21 +33,21 @@ namespace {
const char* values[] = {
"DUPLNS", "duplicate $NAMESPACE directive found",
"DUPLPRFX", "duplicate $PREFIX directive found",
- "DUPMSGID", "duplicate message ID (%s) in compiled code",
- "IDNOTFND", "could not replace message for '%s': no such message identification",
- "MSGRDERR", "error reading from message file %s: %s",
- "MSGWRTERR", "error writing to %s: %s",
- "NOMSGTXT", "a line containing a message ID ('%s') and nothing else was found",
+ "DUPMSGID", "duplicate message ID (%1) in compiled code",
+ "IDNOTFND", "could not replace message for '%1': no such message identification",
+ "MSGRDERR", "error reading from message file %1: %2",
+ "MSGWRTERR", "error writing to %1: %2",
+ "NOMSGTXT", "a line containing a message ID ('%1') and nothing else was found",
"NSEXTRARG", "$NAMESPACE directive has too many arguments",
- "NSINVARG", "$NAMESPACE directive has an invalid argument ('%s')",
+ "NSINVARG", "$NAMESPACE directive has an invalid argument ('%1')",
"NSNOARG", "no arguments were given to the $NAMESPACE directive",
- "OPNMSGIN", "unable to open message file %s for input: %s",
- "OPNMSGOUT", "unable to open %s for output: %s",
+ "OPNMSGIN", "unable to open message file %1 for input: %2",
+ "OPNMSGOUT", "unable to open %1 for output: %2",
"PRFEXTRARG", "$PREFIX directive has too many arguments",
- "PRFINVARG", "$PREFIX directive has an invalid argument ('%s')",
+ "PRFINVARG", "$PREFIX directive has an invalid argument ('%1')",
"PRFNOARG", "no arguments were given to the $PREFIX directive",
- "RDLOCMES", "reading local message file %s",
- "UNRECDIR", "unrecognised directive '%s'",
+ "RDLOCMES", "reading local message file %1",
+ "UNRECDIR", "unrecognised directive '%1'",
NULL
};
diff --git a/src/lib/log/messagedef.h b/src/lib/log/messagedef.h
index eb8f4ea..47867e6 100644
--- a/src/lib/log/messagedef.h
+++ b/src/lib/log/messagedef.h
@@ -1,4 +1,4 @@
-// File created from messagedef.mes on Mon Feb 14 11:07:45 2011
+// File created from messagedef.mes on Thu May 5 16:57:11 2011
#ifndef __MESSAGEDEF_H
#define __MESSAGEDEF_H
diff --git a/src/lib/log/messagedef.mes b/src/lib/log/messagedef.mes
index 3599388..077830c 100644
--- a/src/lib/log/messagedef.mes
+++ b/src/lib/log/messagedef.mes
@@ -23,7 +23,7 @@ $NAMESPACE isc::log
# chicken-and-egg situation where we need the files to build the message
# compiler, yet we need the compiler to build the files.
-DUPMSGID duplicate message ID (%s) in compiled code
+DUPMSGID duplicate message ID (%1) in compiled code
+ Indicative of a programming error, when it started up, BIND10 detected that
+ the given message ID had been registered by one or more modules. (All message
+ IDs should be unique throughout BIND10.) This has no impact on the operation
@@ -44,7 +44,7 @@ DUPLPRFX duplicate $PREFIX directive found
+ this version of the code, such a condition is regarded as an error and the
+ read will be abandoned.
-IDNOTFND could not replace message for '%s': no such message identification
+IDNOTFND could not replace message for '%1': no such message identification
+ During start-up a local message file was read. A line with the listed
+ message identification was found in the file, but the identification is not
+ one contained in the compiled-in message dictionary. Either the message
@@ -55,10 +55,10 @@ IDNOTFND could not replace message for '%s': no such message identification
+ This message may appear a number of times in the file, once for every such
+ unknown message identification.
-MSGRDERR error reading from message file %s: %s
+MSGRDERR error reading from message file %1: %2
+ The specified error was encountered reading from the named message file.
-MSGWRTERR error writing to %s: %s
+MSGWRTERR error writing to %1: %2
+ The specified error was encountered by the message compiler when writing to
+ the named output file.
@@ -67,13 +67,13 @@ NSEXTRARG $NAMESPACE directive has too many arguments
+ generated symbol names are placed. This error is generated when the
+ compiler finds a $NAMESPACE directive with more than one argument.
-NSINVARG $NAMESPACE directive has an invalid argument ('%s')
+NSINVARG $NAMESPACE directive has an invalid argument ('%1')
+ The $NAMESPACE argument should be a valid C++ namespace. The reader does a
+ cursory check on its validity, checking that the characters in the namespace
+ are correct. The error is generated when the reader finds an invalid
+ character. (Valid are alphanumeric characters, underscores and colons.)
-NOMSGTXT a line containing a message ID ('%s') and nothing else was found
+NOMSGTXT a line containing a message ID ('%1') and nothing else was found
+ Message definitions comprise lines starting with a message identification (a
+ symbolic name for the message) and followed by the text of the message. This
+ error is generated when a line is found in the message file that contains just
@@ -84,11 +84,11 @@ NSNOARG no arguments were given to the $NAMESPACE directive
+ generated symbol names are placed. This error is generated when the
+ compiler finds a $NAMESPACE directive with no arguments.
-OPNMSGIN unable to open message file %s for input: %s
+OPNMSGIN unable to open message file %1 for input: %2
+ The program was not able to open the specified input message file for the
+ reason given.
-OPNMSGOUT unable to open %s for output: %s
+OPNMSGOUT unable to open %1 for output: %2
+ The program was not able to open the specified output file for the reason
+ given.
@@ -97,7 +97,7 @@ PRFEXTRARG $PREFIX directive has too many arguments
+ symbol names when a C++ .h file is created. This error is generated when the
+ compiler finds a $PREFIX directive with more than one argument.
-PRFINVARG $PREFIX directive has an invalid argument ('%s')
+PRFINVARG $PREFIX directive has an invalid argument ('%1')
+ The $PREFIX argument is used in a symbol name in a C++ header file. As such,
+ it must adhere to restrictions on C++ symbol names (e.g. may only contain
+ alphanumeric characters or underscores, and may nor start with a digit). A
@@ -109,11 +109,11 @@ PRFNOARG no arguments were given to the $PREFIX directive
+ symbol names when a C++ .h file is created. This error is generated when the
+ compiler finds a $PREFIX directive with no arguments.
-RDLOCMES reading local message file %s
+RDLOCMES reading local message file %1
+ This is an informational message output by BIND10 when it starts to read a
+ local message file. (A local message file may replace the text of one of more
+ messages; the ID of the message will not be changed though.)
-UNRECDIR unrecognised directive '%s'
+UNRECDIR unrecognised directive '%1'
+ A line starting with a dollar symbol was found, but the first word on the line
+ (shown in the message) was not a recognised message compiler directive.
diff --git a/src/lib/log/tests/Makefile.am b/src/lib/log/tests/Makefile.am
index b9fe150..46065e8 100644
--- a/src/lib/log/tests/Makefile.am
+++ b/src/lib/log/tests/Makefile.am
@@ -22,6 +22,7 @@ run_unittests_SOURCES += message_reader_unittest.cc
run_unittests_SOURCES += message_initializer_unittest.cc
run_unittests_SOURCES += message_initializer_unittest_2.cc
run_unittests_SOURCES += run_unittests.cc
+run_unittests_SOURCES += log_formatter_unittest.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/log/tests/log_formatter_unittest.cc b/src/lib/log/tests/log_formatter_unittest.cc
new file mode 100644
index 0000000..59157db
--- /dev/null
+++ b/src/lib/log/tests/log_formatter_unittest.cc
@@ -0,0 +1,112 @@
+// 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.
+
+#include <gtest/gtest.h>
+#include <log/log_formatter.h>
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+namespace {
+
+class FormatterTest : public ::testing::Test {
+protected:
+ typedef pair<const char*, string> Output;
+ typedef isc::log::Formatter<FormatterTest> Formatter;
+ vector<Output> outputs;
+public:
+ void output(const char* prefix, const string& message) {
+ outputs.push_back(Output(prefix, message));
+ }
+ // Just shortcut for new string
+ string* s(const char* text) {
+ return (new string(text));
+ }
+};
+
+// Create an inactive formatter and check it doesn't produce any output
+TEST_F(FormatterTest, inactive) {
+ Formatter();
+ EXPECT_EQ(0, outputs.size());
+}
+
+// Create an active formatter and check it produces output. Does no arg
+// substitution yet
+TEST_F(FormatterTest, active) {
+ Formatter("TEST", s("Text of message"), 1, *this);
+ ASSERT_LE(1, outputs.size());
+ EXPECT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("Text of message", outputs[0].second);
+}
+
+// No output even when we have an arg on the inactive formatter
+TEST_F(FormatterTest, inactiveArg) {
+ Formatter().arg("Hello");
+ EXPECT_EQ(0, outputs.size());
+}
+
+// Create an active formatter and replace a placeholder with string
+TEST_F(FormatterTest, stringArg) {
+ {
+ SCOPED_TRACE("C++ string");
+ Formatter("TEST", s("Hello %1"), 1, *this).arg(string("World"));
+ ASSERT_LE(1, outputs.size());
+ EXPECT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("Hello World", outputs[0].second);
+ }
+ {
+ SCOPED_TRACE("C++ string");
+ Formatter("TEST", s("Hello %1"), 1, *this).arg(string("Internet"));
+ ASSERT_LE(2, outputs.size());
+ EXPECT_EQ(2, outputs.size());
+ EXPECT_STREQ("TEST", outputs[1].first);
+ EXPECT_EQ("Hello Internet", outputs[1].second);
+ }
+}
+
+// Can convert to string
+TEST_F(FormatterTest, intArg) {
+ Formatter("TEST", s("The answer is %1"), 1, *this).arg(42);
+ ASSERT_LE(1, outputs.size());
+ EXPECT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("The answer is 42", outputs[0].second);
+}
+
+// Can use multiple arguments at different places
+TEST_F(FormatterTest, multiArg) {
+ Formatter("TEST", s("The %2 are %1"), 1, *this).arg("switched").
+ arg("arguments");
+ ASSERT_LE(1, outputs.size());
+ EXPECT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("The arguments are switched", outputs[0].second);
+}
+
+// Can survive and complains if placeholder is missing
+TEST_F(FormatterTest, missingPlace) {
+ EXPECT_NO_THROW(Formatter("TEST", s("Missing the first %2"), 1, *this).
+ arg("missing").arg("argument"));
+ ASSERT_LE(1, outputs.size());
+ EXPECT_EQ(1, outputs.size());
+ EXPECT_STREQ("TEST", outputs[0].first);
+ EXPECT_EQ("Missing the first argument "
+ "@@Missing placeholder %1 for 'missing'@@", outputs[0].second);
+}
+
+}
diff --git a/src/lib/log/tests/logger_support_test.cc b/src/lib/log/tests/logger_support_test.cc
index 4d8863e..d0d5c53 100644
--- a/src/lib/log/tests/logger_support_test.cc
+++ b/src/lib/log/tests/logger_support_test.cc
@@ -23,6 +23,7 @@
#include <iostream>
#include <log/logger.h>
+#include <log/macros.h>
#include <log/logger_support.h>
#include <log/root_logger_name.h>
@@ -92,13 +93,13 @@ int main(int argc, char** argv) {
initLogger("alpha", severity, dbglevel, localfile);
// Log a few messages
- logger_ex.fatal(MSG_MSGWRTERR, "test1", "42");
- logger_ex.error(MSG_UNRECDIR, "false");
- logger_dlm.warn(MSG_MSGRDERR, "a.txt", "dummy test");
- logger_dlm.info(MSG_OPNMSGIN, "example.msg", "dummy test");
- logger_ex.debug(0, MSG_UNRECDIR, "[abc]");
- logger_ex.debug(24, MSG_UNRECDIR, "[24]");
- logger_ex.debug(25, MSG_UNRECDIR, "[25]");
- logger_ex.debug(26, MSG_UNRECDIR, "[26]");
+ LOG_FATAL(logger_ex, MSG_MSGWRTERR).arg("test1").arg("42");
+ LOG_ERROR(logger_ex, MSG_UNRECDIR).arg("false");
+ LOG_WARN(logger_dlm, MSG_MSGRDERR).arg("a.txt").arg("dummy test");
+ LOG_INFO(logger_dlm, MSG_OPNMSGIN).arg("example.msg").arg("dummy test");
+ LOG_DEBUG(logger_ex, 0, MSG_UNRECDIR).arg("[abc]");
+ LOG_DEBUG(logger_ex, 24, MSG_UNRECDIR).arg("[24]");
+ LOG_DEBUG(logger_ex, 25, MSG_UNRECDIR).arg("[25]");
+ LOG_DEBUG(logger_ex, 26, MSG_UNRECDIR).arg("[26]");
return (0);
}
diff --git a/src/lib/log/tests/run_time_init_test.sh.in b/src/lib/log/tests/run_time_init_test.sh.in
index e2bdf6f..1010566 100755
--- a/src/lib/log/tests/run_time_init_test.sh.in
+++ b/src/lib/log/tests/run_time_init_test.sh.in
@@ -30,8 +30,8 @@ passfail() {
cat > $localmes << .
NOTHERE this message is not in the global dictionary
-MSGRDERR replacement read error, parameters: '%s' and '%s'
-UNRECDIR replacement unrecognised directive message, parameter is '%s'
+MSGRDERR replacement read error, parameters: '%1' and '%2'
+UNRECDIR replacement unrecognised directive message, parameter is '%1'
.
echo -n "1. runInitTest default parameters: "
diff --git a/src/lib/python/isc/notify/tests/Makefile.am b/src/lib/python/isc/notify/tests/Makefile.am
index 07129ec..a83ff86 100644
--- a/src/lib/python/isc/notify/tests/Makefile.am
+++ b/src/lib/python/isc/notify/tests/Makefile.am
@@ -6,7 +6,7 @@ EXTRA_DIST = $(PYTESTS)
# required by loadable python modules.
LIBRARY_PATH_PLACEHOLDER =
if SET_ENV_LIBRARY_PATH
-LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
endif
# test using command-line arguments, so use check-local target instead of TESTS
diff --git a/src/lib/util/unittests/Makefile.am b/src/lib/util/unittests/Makefile.am
index 4d5896f..84d7d21 100644
--- a/src/lib/util/unittests/Makefile.am
+++ b/src/lib/util/unittests/Makefile.am
@@ -3,5 +3,6 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
lib_LTLIBRARIES = libutil_unittests.la
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
new file mode 100644
index 0000000..9e545a5
--- /dev/null
+++ b/src/lib/util/unittests/newhook.cc
@@ -0,0 +1,51 @@
+// 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.
+
+#include <stdlib.h>
+
+#include <new>
+#include <stdexcept>
+
+#include "newhook.h"
+
+#ifdef ENABLE_CUSTOM_OPERATOR_NEW
+void*
+operator new(size_t size) throw(std::bad_alloc) {
+ if (isc::util::unittests::force_throw_on_new &&
+ size == isc::util::unittests::throw_size_on_new) {
+ throw std::bad_alloc();
+ }
+ void* p = malloc(size);
+ if (p == NULL) {
+ throw std::bad_alloc();
+ }
+ return (p);
+}
+
+void
+operator delete(void* p) throw() {
+ if (p != NULL) {
+ free(p);
+ }
+}
+#endif
+
+namespace isc {
+namespace util {
+namespace unittests {
+bool force_throw_on_new = false;
+size_t throw_size_on_new = 0;
+}
+}
+}
diff --git a/src/lib/util/unittests/newhook.h b/src/lib/util/unittests/newhook.h
new file mode 100644
index 0000000..7eb8ade
--- /dev/null
+++ b/src/lib/util/unittests/newhook.h
@@ -0,0 +1,82 @@
+// 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_UNITTESTS_NEWHOOK_H
+#define __UTIL_UNITTESTS_NEWHOOK_H 1
+
+/**
+ * @file newhook.h
+ * @short Enable the use of special operator new that throws for testing.
+ *
+ * This small utility allows a test case to force the global operator new
+ * to throw for a given size to test a case where memory allocation fails
+ * (which normally doesn't happen). To enable the feature, everything must
+ * be built with defining ENABLE_CUSTOM_OPERATOR_NEW beforehand, and set
+ * \c force_throw_on_new to \c true and \c throw_size_on_new to the size
+ * of data that should trigger the exception, immediately before starting
+ * the specific test that needs the exception.
+ *
+ * Example:
+ * \code #include <util/unittests/newhook.h>
+ * ...
+ * TEST(SomeTest, newException) {
+ * isc::util::unittests::force_throw_on_new = true;
+ * isc::util::unittests::throw_size_on_new = sizeof(Foo);
+ * try {
+ * // this will do 'new Foo()' internally and should throw
+ * createFoo();
+ * isc::util::unittests::force_throw_on_new = false;
+ * ASSERT_FALSE(true) << "Expected throw on new";
+ * } catch (const std::bad_alloc&) {
+ * isc::util::unittests::force_throw_on_new = false;
+ * // do some integrity check, etc, if necessary
+ * }
+ * } \endcode
+ *
+ * Replacing the global operator new (and delete) is a dangerous technique,
+ * and triggering an exception solely based on the allocation size is not
+ * reliable, so this feature is disabled by default two-fold: The
+ * ENABLE_CUSTOM_OPERATOR_NEW build time variable, and run-time
+ * \c force_throw_on_new.
+ */
+
+namespace isc {
+namespace util {
+namespace unittests {
+/// Switch to enable the use of special operator new
+///
+/// This is set to \c false by default.
+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.
+extern size_t throw_size_on_new;
+}
+}
+}
+
+#endif // __UTIL_UNITTESTS_NEWHOOK_H
+
+// Local Variables:
+// mode: c++
+// End:
More information about the bind10-changes
mailing list