[svn] commit: r2362 - in /branches/trac172: ./ src/bin/auth/ src/bin/auth/tests/ src/bin/bind10/ src/bin/bind10/tests/ src/bin/bindctl/ src/bin/bindctl/tests/ src/bin/cfgmgr/ src/bin/cfgmgr/tests/ src/bin/cmdctl/ src/bin/cmdctl/tests/ src/bin/host/ src/bin/loadzone/ src/bin/loadzone/testdata/ src/bin/loadzone/tests/ src/bin/xfrin/ src/bin/xfrin/tests/ src/bin/xfrout/ src/bin/xfrout/tests/ src/lib/ src/lib/cc/ src/lib/config/tests/ src/lib/datasrc/ src/lib/datasrc/tests/ src/lib/datasrc/tests/testdata/ src/lib/dns/ src/lib/dns/python/ src/lib/dns/rdata/generic/ src/lib/dns/tests/ src/lib/python/isc/ src/lib/python/isc/config/ src/lib/python/isc/config/tests/ src/lib/python/isc/datasrc/ src/lib/python/isc/dns/ src/lib/python/isc/log/ src/lib/xfr/ tools/
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Jun 30 18:48:16 UTC 2010
Author: jelte
Date: Wed Jun 30 18:48:15 2010
New Revision: 2362
Log:
sync with trunk for merge
Added:
branches/trac172/src/bin/bind10/tests/args_test.py
- copied unchanged from r2361, trunk/src/bin/bind10/tests/args_test.py
branches/trac172/src/bin/cfgmgr/tests/
- copied from r2361, trunk/src/bin/cfgmgr/tests/
branches/trac172/src/bin/cmdctl/cmdctl.spec.pre.in
- copied unchanged from r2361, trunk/src/bin/cmdctl/cmdctl.spec.pre.in
branches/trac172/src/bin/loadzone/tests/
- copied from r2361, trunk/src/bin/loadzone/tests/
branches/trac172/src/lib/dns/python/
- copied from r2361, trunk/src/lib/dns/python/
branches/trac172/src/lib/python/isc/dns/
- copied from r2361, trunk/src/lib/python/isc/dns/
branches/trac172/src/lib/python/isc/log/
- copied from r2361, trunk/src/lib/python/isc/log/
branches/trac172/src/lib/xfr/fdshare_python.cc
- copied unchanged from r2361, trunk/src/lib/xfr/fdshare_python.cc
Removed:
branches/trac172/src/bin/bindctl/bindctl.pem
branches/trac172/src/bin/cmdctl/cmdctl.spec
branches/trac172/src/bin/loadzone/testdata/
branches/trac172/src/lib/dns/python_dns.cc
Modified:
branches/trac172/ (props changed)
branches/trac172/ChangeLog
branches/trac172/configure.ac
branches/trac172/src/bin/auth/Makefile.am
branches/trac172/src/bin/auth/asio_link.cc
branches/trac172/src/bin/auth/asio_link.h
branches/trac172/src/bin/auth/auth_srv.cc
branches/trac172/src/bin/auth/main.cc
branches/trac172/src/bin/auth/tests/Makefile.am
branches/trac172/src/bin/bind10/bind10.py.in
branches/trac172/src/bin/bind10/run_bind10.sh.in
branches/trac172/src/bin/bind10/tests/bind10_test.in
branches/trac172/src/bin/bindctl/Makefile.am
branches/trac172/src/bin/bindctl/TODO
branches/trac172/src/bin/bindctl/bindcmd.py
branches/trac172/src/bin/bindctl/bindctl-source.py.in
branches/trac172/src/bin/bindctl/cmdparse.py
branches/trac172/src/bin/bindctl/exception.py
branches/trac172/src/bin/bindctl/tests/bindctl_test.py
branches/trac172/src/bin/cfgmgr/Makefile.am
branches/trac172/src/bin/cfgmgr/b10-cfgmgr.py.in (contents, props changed)
branches/trac172/src/bin/cfgmgr/b10-cfgmgr.xml (props changed)
branches/trac172/src/bin/cmdctl/Makefile.am
branches/trac172/src/bin/cmdctl/TODO
branches/trac172/src/bin/cmdctl/cmdctl.py.in
branches/trac172/src/bin/cmdctl/tests/Makefile.am
branches/trac172/src/bin/cmdctl/tests/cmdctl_test.in
branches/trac172/src/bin/cmdctl/tests/cmdctl_test.py
branches/trac172/src/bin/host/Makefile.am
branches/trac172/src/bin/host/host.cc
branches/trac172/src/bin/loadzone/Makefile.am
branches/trac172/src/bin/loadzone/b10-loadzone.py.in
branches/trac172/src/bin/loadzone/run_loadzone.sh.in
branches/trac172/src/bin/xfrin/ (props changed)
branches/trac172/src/bin/xfrin/tests/Makefile.am
branches/trac172/src/bin/xfrin/tests/xfrin_test.py
branches/trac172/src/bin/xfrin/xfrin.py.in
branches/trac172/src/bin/xfrout/run_b10-xfrout.sh.in
branches/trac172/src/bin/xfrout/tests/Makefile.am
branches/trac172/src/bin/xfrout/tests/xfrout_test.py
branches/trac172/src/bin/xfrout/xfrout.py.in
branches/trac172/src/bin/xfrout/xfrout.spec.pre.in
branches/trac172/src/lib/Makefile.am
branches/trac172/src/lib/cc/ (props changed)
branches/trac172/src/lib/cc/Makefile.am
branches/trac172/src/lib/cc/session.cc
branches/trac172/src/lib/cc/session_unittests.cc
branches/trac172/src/lib/config/tests/Makefile.am
branches/trac172/src/lib/datasrc/ (props changed)
branches/trac172/src/lib/datasrc/data_source.cc
branches/trac172/src/lib/datasrc/sqlite3_datasrc.cc
branches/trac172/src/lib/datasrc/tests/Makefile.am
branches/trac172/src/lib/datasrc/tests/datasrc_unittest.cc
branches/trac172/src/lib/datasrc/tests/test_datasrc.cc
branches/trac172/src/lib/datasrc/tests/test_datasrc.h
branches/trac172/src/lib/datasrc/tests/testdata/example.org
branches/trac172/src/lib/datasrc/tests/testdata/example.org.sqlite3
branches/trac172/src/lib/dns/ (props changed)
branches/trac172/src/lib/dns/Makefile.am
branches/trac172/src/lib/dns/message.cc
branches/trac172/src/lib/dns/message.h
branches/trac172/src/lib/dns/name.cc
branches/trac172/src/lib/dns/rdata/generic/rrsig_46.cc (props changed)
branches/trac172/src/lib/dns/rrsetlist.cc
branches/trac172/src/lib/dns/rrsetlist.h
branches/trac172/src/lib/dns/tests/ (props changed)
branches/trac172/src/lib/dns/tests/Makefile.am
branches/trac172/src/lib/python/isc/Makefile.am
branches/trac172/src/lib/python/isc/__init__.py
branches/trac172/src/lib/python/isc/config/cfgmgr.py
branches/trac172/src/lib/python/isc/config/tests/cfgmgr_test.py
branches/trac172/src/lib/python/isc/datasrc/master.py
branches/trac172/src/lib/xfr/Makefile.am
branches/trac172/tools/import_boost.sh
Modified: branches/trac172/ChangeLog
==============================================================================
--- branches/trac172/ChangeLog (original)
+++ branches/trac172/ChangeLog Wed Jun 30 18:48:15 2010
@@ -1,11 +1,98 @@
- 53. [bug] zhanglikun
+ 68. [func] zhanglikun
+ Add options -c(--certificate-chain) to bindctl. Override class
+ HTTPSConnection to support server certificate validation.
+ Add support to cmdctl.spec file, now there are three configurable
+ items for cmdctl: 'key_file', 'cert_file' and 'accounts_file',
+ all of them can be changed in runtime.
+ (Trac #127, svn r2357)
+
+ 67. [func] zhanglikun
+ Make bindctl's command parser only do minimal check. Parameter
+ value can be a sequence of non-space characters, or a string
+ surrounded by quotation marks(these marks can be a part of the
+ value string in escaped form). Make error message be more
+ friendly.(if there is some error in parameter's value, the
+ parameter name will be provided). Refactor function login_to_cmdctl()
+ in class BindCmdInterpreter: avoid using Exception to catch all
+ exceptions.
+ (Trac #220, svn r2356)
+
+ 66. [bug] each
+ Check for duplicate RRsets before inserting data into a message
+ section; this, among other things, will prevent multiple copies
+ of the same CNAME from showing up when there's a loop. (Trac #69,
+ svn r2350)
+
+ 65. [func] shentingting
+ Added verbose options to exactly what is happening with loadzone.
+ Added loadzone test suite of different file formats to load.
+ (Trac #197, #199, #244, #161, #198, #174, #175, svn r2340)
+
+ 64. [func] jerry
+ Added python logging framework. It is for testing and experimenting
+ with logging ideas. Currently, it supports three channels(file,
+ syslog and stderr) and five levels(debug, info, warning, error and
+ critical).
+ (Trac #176, svn r2338)
+
+ 63. [func] shane
+ Added initial support for setuid(), using the "-u" flag. This will
+ be replaced in the future, but for now provides a reasonable
+ starting point.
+ (Trac #180, svn r2330)
+
+ 62. [func] jelte
+ bin/xfrin: Use the database_file as configured in Auth to transfers
+ bin/xfrout: Use the database_file as configured in Auth to transfers
+
+ 61. [bug] jelte
+ bin/auth: Enable b10-auth to be launched in source tree
+ (i.e. use a zone database file relative to that)
+
+ 60. [build] jinmei
+ Supported SunStudio C++ compiler. Note: gtest still doesn't work.
+ (Trac #251, svn r2310)
+
+ 59. [bug] jinmei
+ lib/datasrc,bin/auth: The authoritative server could return a
+ SERVFAIL with a partial answer if it finds a data source broken
+ while looking for an answer. This can happen, for example, if a
+ zone that doesn't have an NS RR is configured and loaded as a
+ sqlite3 data source. (Trac #249, r2286)
+
+ 58. [bug] jinmei
+ Worked around an interaction issue between ASIO and standard C++
+ library headers. Without this ASIO didn't work: sometimes the
+ application crashes, sometimes it blocked in the ASIO module.
+ (Trac #248, svn r2187, r2190)
+
+ 57. [func] jinmei
+ lib/datasrc: used a simpler version of Name::split (change 31) for
+ better readability. No behavior change. (Trac #200, svn r2159)
+
+ 56. [func]* jinmei
+ lib/dns: renamed the library name to libdns++ to avoid confusion
+ with the same name of library of BIND 9.
+ (Trac #190, svn r2153)
+
+ 55. [bug] shane
+ bin/xfrout: xfrout exception on Ctrl-C now no longer generates
+ exception for 'Interrupted system call'
+ (Track #136, svn r2147)
+
+ 54. [bug] zhanglikun
+ bin/xfrout: Enable b10-xfrout can be launched in source
+ code tree.
+ (Trac #224, svn r2103)
+
+ 53. [bug] zhanglikun
bin/bindctl: Generate a unique session ID by using
socket.gethostname() instead of socket.gethostbyname(),
since the latter one could make bindctl stall if its own
host name can't be resolved.
(Trac #228, svn r2096)
- 52. [func] zhanglikun
+ 52. [func] zhanglikun
bin/xfrout: When xfrout is launched, check whether the
socket file is being used by one running xfrout process,
if it is, exit from python. If the file isn't a socket file
@@ -67,6 +154,10 @@
Renamed libauth to libdatasrc.
38. [bug] zhanglikun
+ Send command 'shutdown' to Xfrin and Xfrout when boss receive SIGINT.
+ Remove unused socket file when Xfrout process exits. Make sure Xfrout
+ exit by itself when it receives SIGINT, instead of being killed by the
+ signal SIGTERM or SIGKILL sent from boss.
(Trac #135, #151, #134, svn r1797)
37. [build] jinmei
@@ -127,7 +218,7 @@
24. [func]
Support case-sensitive name compression in MessageRenderer.
- (svn r1704)
+ (Trac #142, svn r1704)
23. [func]
Support a simple name with possible compression. (svn r1701)
Modified: branches/trac172/configure.ac
==============================================================================
--- branches/trac172/configure.ac (original)
+++ branches/trac172/configure.ac Wed Jun 30 18:48:15 2010
@@ -9,11 +9,23 @@
# Checks for programs.
AC_PROG_CXX
-AC_PROG_CC
AC_PROG_LIBTOOL
# Use C++ language
-AC_LANG_CPLUSPLUS
+AC_LANG([C++])
+
+# Identify the compiler: this check must be after AC_PROG_CXX and AC_LANG.
+AM_CONDITIONAL(USE_GXX, test "X${GXX}" = "Xyes")
+AC_CHECK_DECL([__SUNPRO_CC], [SUNCXX="yes"], [SUNCXX="no"])
+
+# OS dependent compiler flags
+case "$host" in
+*-solaris*)
+ # Solaris requires special definitions to get some standard libraries
+ # (e.g. getopt(3)) available with common used header files.
+ CPPFLAGS="$CPPFLAGS -D_XPG4_2 -D__EXTENSIONS__"
+ ;;
+esac
m4_define([_AM_PYTHON_INTERPRETER_LIST], [python python3 python3.1])
AC_ARG_WITH([pythonpath],
@@ -74,6 +86,12 @@
AC_SUBST(PYTHON_INCLUDES)
AC_SUBST(PYTHON_LDFLAGS)
+CPPFLAGS_SAVED="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS ${PYTHON_INCLUDES}"
+AC_CHECK_HEADERS([Python.h],, AC_MSG_ERROR([Missing Python.h]))
+CPPFLAGS="$CPPFLAGS_SAVED"
+
+
# Check for python library (not absolutely mandatory, but needed for
# Boost.Python when we use it. See below.)
LDFLAGS_SAVED="$LDFLAGS"
@@ -87,8 +105,8 @@
# TODO: check for _sqlite3.py module
-#
-# B10_CXXFLAGS is the default C++ compiler flags. This will (and should) be
+# Compiler dependent settings: define some mandatory CXXFLAGS here.
+# We also use a separate variable B10_CXXFLAGS. This will (and should) be
# used as the default value for each specifc AM_CXXFLAGS:
# AM_CXXFLAGS = $(B10_CXXFLAGS)
# AM_CXXFLAGS += ... # add module specific flags
@@ -97,17 +115,24 @@
# gcc's -Wno-XXX option must be specified after -Wall or -Wextra, we cannot
# specify the default warning flags in CXXFLAGS and let specific modules
# "override" the default.
-#
-B10_CXXFLAGS=
-
-if test "X$GCC" = "Xyes"; then
-B10_CXXFLAGS="-g -Wall -Wextra -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare"
+
+CXXFLAGS=-g
+werror_ok=0
+
+# SunStudio compiler requires special compiler options for boost
+# (http://blogs.sun.com/sga/entry/boost_mini_howto)
+if test "$SUNCXX" = "yes"; then
+CXXFLAGS="$CXXFLAGS -library=stlport4 -features=tmplife -features=tmplrefstatic"
+fi
+
+# gcc specific settings:
+if test "X$GXX" = "Xyes"; then
+B10_CXXFLAGS="-Wall -Wextra -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare"
UNUSED_PARAM_ATTRIBUTE='__attribute__((unused))'
# Certain versions of gcc (g++) have a bug that incorrectly warns about
# the use of anonymous name spaces even if they're closed in a single
# translation unit. For these versions we have to disable -Werror.
-werror_ok=0
CXXFLAGS_SAVED="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $B10_CXXFLAGS -Werror"
AC_MSG_CHECKING(for in-TU anonymous namespace breakage)
@@ -118,13 +143,13 @@
B10_CXXFLAGS="$B10_CXXFLAGS -Werror"],
[AC_MSG_RESULT(yes)])
CXXFLAGS="$CXXFLAGS_SAVED"
-fi dnl GCC = yes
+fi dnl GXX = yes
AM_CONDITIONAL(GCC_WERROR_OK, test $werror_ok = 1)
AC_DEFINE_UNQUOTED(UNUSED_PARAM, $UNUSED_PARAM_ATTRIBUTE, Define to compiler keyword indicating a function argument is intentionally unused)
# produce PIC unless we disable shared libraries. need this for python bindings.
-if test $enable_shared != "no" -a "X$GCC" = "Xyes"; then
+if test $enable_shared != "no" -a "X$GXX" = "Xyes"; then
B10_CXXFLAGS="$B10_CXXFLAGS -fPIC"
fi
@@ -212,52 +237,6 @@
AC_SUBST(BOOST_LDFLAGS)
# Check availability of the Boost Python library
-
-AC_MSG_CHECKING([for boost::python library])
-AC_ARG_WITH([boost-python],
-AC_HELP_STRING([--with-boost-python],
- [specify whether to use the boost python library]),
- [with_boost_python="$withval"], [with_boost_python="auto"])
-if test "$with_boost_python" != "no"; then
- if test "$with_boost_python" != "auto" -a "X$PYTHON_LIB" = X; then
- AC_MSG_ERROR([Boost.Python requested but python library is not available])
- fi
- LDFLAGS_SAVED="$LDFLAGS"
- LIBS_SAVED="$LIBS"
- CPPFLAGS_SAVED="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES"
-
- for BOOST_TRY_LIB in boost_python boost_python-mt; do
- LDFLAGS="$LDFLAGS_SAVED ${BOOST_LDFLAGS} ${PYTHON_LDFLAGS}"
- LIBS="$LIBS_SAVED -l${BOOST_TRY_LIB} ${PYTHON_LIB}"
- AC_TRY_LINK([#include <boost/python/module.hpp>
- using namespace boost::python;
- BOOST_PYTHON_MODULE(test) { throw "Boost::Python test."; }],
- [ return 0; ],
- [ AC_MSG_RESULT(yes)
- BOOST_PYTHON_LIB="-l${BOOST_TRY_LIB}"
- ],[])
- if test "X${BOOST_PYTHON_LIB}" != X; then
- break
- fi
- done
-
- LDFLAGS="$LDFLAGS_SAVED"
- CPPFLAGS="$CPPFLAGS_SAVED"
- LIBS="$LIBS_SAVED"
-fi
-
-if test "X${BOOST_PYTHON_LIB}" = X; then
- AC_MSG_RESULT(no)
- if test "$with_boost_python" = "yes"; then
- AC_MSG_ERROR([boost python library is requested but not found])
- fi
-else
- AC_DEFINE(HAVE_BOOST_PYTHON, 1, Define to 1 if boost python library is available)
-fi
-
-AM_CONDITIONAL(HAVE_BOOST_PYTHON, test "X${BOOST_PYTHON_LIB}" != X)
-AC_SUBST(BOOST_PYTHON_LIB)
#
# Check availability of gtest, which will be used for unit tests.
@@ -310,6 +289,11 @@
AC_SUBST(GTEST_LDFLAGS)
AC_SUBST(GTEST_LDADD)
+dnl check for pkg-config itself so we don't try the m4 macro without pkg-config
+AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes, no)
+if test "x$HAVE_PKG_CONFIG" = "xno" ; then
+ AC_MSG_ERROR(Please install pkg-config)
+fi
PKG_CHECK_MODULES(SQLITE, sqlite3 >= 3.3.9, enable_features="$enable_features SQLite3")
# I can't get some of the #include <asio.hpp> right without this
@@ -359,7 +343,7 @@
# run time performance. Hpefully we can find a better solution or the ASIO
# code will be updated by the time we really need it.
AC_CHECK_HEADERS(sys/devpoll.h, ac_cv_have_devpoll=yes, ac_cv_have_devpoll=no)
-if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GCC" = "Xyes"; then
+if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GXX" = "Xyes"; then
CPPFLAGS="$CPPFLAGS -DASIO_DISABLE_DEV_POLL=1"
fi
@@ -388,8 +372,11 @@
src/bin/bindctl/Makefile
src/bin/bindctl/tests/Makefile
src/bin/cfgmgr/Makefile
+ src/bin/cfgmgr/tests/Makefile
src/bin/host/Makefile
src/bin/loadzone/Makefile
+ src/bin/loadzone/tests/correct/Makefile
+ src/bin/loadzone/tests/error/Makefile
src/bin/msgq/Makefile
src/bin/msgq/tests/Makefile
src/bin/auth/Makefile
@@ -408,19 +395,25 @@
src/lib/python/isc/cc/tests/Makefile
src/lib/python/isc/config/Makefile
src/lib/python/isc/config/tests/Makefile
+ src/lib/python/isc/log/Makefile
+ src/lib/python/isc/log/tests/Makefile
src/lib/config/Makefile
src/lib/config/tests/Makefile
src/lib/dns/Makefile
src/lib/dns/tests/Makefile
+ src/lib/dns/python/Makefile
+ src/lib/dns/python/tests/Makefile
src/lib/exceptions/Makefile
src/lib/datasrc/Makefile
src/lib/datasrc/tests/Makefile
src/lib/xfr/Makefile
])
AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
+ src/bin/cfgmgr/tests/b10-cfgmgr_test.py
src/bin/cmdctl/cmdctl.py
src/bin/cmdctl/run_b10-cmdctl.sh
src/bin/cmdctl/tests/cmdctl_test
+ src/bin/cmdctl/cmdctl.spec.pre
src/bin/xfrin/tests/xfrin_test
src/bin/xfrin/xfrin.py
src/bin/xfrin/xfrin.spec.pre
@@ -436,6 +429,8 @@
src/bin/bindctl/bindctl-source.py
src/bin/bindctl/tests/bindctl_test
src/bin/loadzone/run_loadzone.sh
+ src/bin/loadzone/tests/correct/correct_test.sh
+ src/bin/loadzone/tests/error/error_test.sh
src/bin/loadzone/b10-loadzone.py
src/bin/usermgr/run_b10-cmdctl-usermgr.sh
src/bin/usermgr/b10-cmdctl-usermgr.py
@@ -447,6 +442,7 @@
src/lib/config/tests/data_def_unittests_config.h
src/lib/python/isc/config/tests/config_test
src/lib/python/isc/cc/tests/cc_test
+ src/lib/python/isc/log/tests/log_test
src/lib/dns/gen-rdatacode.py
src/lib/python/bind10_config.py
src/lib/dns/tests/testdata/gen-wiredata.py
@@ -462,11 +458,14 @@
chmod +x src/bin/bindctl/tests/bindctl_test
chmod +x src/bin/bindctl/run_bindctl.sh
chmod +x src/bin/loadzone/run_loadzone.sh
+ chmod +x src/bin/loadzone/tests/correct/correct_test.sh
+ chmod +x src/bin/loadzone/tests/error/error_test.sh
chmod +x src/bin/usermgr/run_b10-cmdctl-usermgr.sh
chmod +x src/bin/msgq/run_msgq.sh
chmod +x src/bin/msgq/tests/msgq_test
chmod +x src/lib/dns/gen-rdatacode.py
chmod +x src/lib/dns/tests/testdata/gen-wiredata.py
+ chmod +x src/lib/dns/python/tests/libdns_python_test
])
AC_OUTPUT
Modified: branches/trac172/src/bin/auth/Makefile.am
==============================================================================
--- branches/trac172/src/bin/auth/Makefile.am (original)
+++ branches/trac172/src/bin/auth/Makefile.am Wed Jun 30 18:48:15 2010
@@ -36,7 +36,10 @@
libasio_link_a_SOURCES = asio_link.cc asio_link.h
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
# B10_CXXFLAGS)
-libasio_link_a_CXXFLAGS = $(AM_CXXFLAGS) -Wno-unused-parameter
+libasio_link_a_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_GXX
+libasio_link_a_CXXFLAGS += -Wno-unused-parameter
+endif
libasio_link_a_CPPFLAGS = $(AM_CPPFLAGS)
BUILT_SOURCES = spec_config.h
@@ -45,15 +48,13 @@
b10_auth_SOURCES += common.h
b10_auth_SOURCES += main.cc
b10_auth_LDADD = $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a
-b10_auth_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a
+b10_auth_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a
b10_auth_LDADD += $(top_builddir)/src/lib/config/.libs/libcfgclient.a
-b10_auth_LDADD += $(top_builddir)/src/lib/cc/libcc.a
+b10_auth_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
b10_auth_LDADD += $(top_builddir)/src/bin/auth/libasio_link.a
b10_auth_LDADD += $(SQLITE_LIBS)
-if HAVE_BOOST_PYTHON
b10_auth_LDADD += $(top_builddir)/src/lib/xfr/.libs/libxfr.a
-endif
# TODO: config.h.in is wrong because doesn't honor pkgdatadir
# and can't use @datadir@ because doesn't expand default ${prefix}
Modified: branches/trac172/src/bin/auth/asio_link.cc
==============================================================================
--- branches/trac172/src/bin/auth/asio_link.cc (original)
+++ branches/trac172/src/bin/auth/asio_link.cc Wed Jun 30 18:48:15 2010
@@ -16,6 +16,7 @@
#include <config.h>
+#include <unistd.h> // for some IPC/network system calls
#include <asio.hpp>
#include <boost/bind.hpp>
@@ -23,10 +24,7 @@
#include <dns/message.h>
#include <dns/messagerenderer.h>
-#if defined(HAVE_BOOST_PYTHON)
-#define USE_XFROUT
#include <xfr/xfrout_client.h>
-#endif
#include <asio_link.h>
@@ -39,15 +37,15 @@
using namespace std;
using namespace isc::dns;
-#ifdef USE_XFROUT
using namespace isc::xfr;
-#endif
namespace {
// As a short term workaround, we have XFROUT specific code. We should soon
// refactor the code with some abstraction so that we can separate this level
// details from the (AS)IO module.
-#ifdef USE_XFROUT
+
+// This was contained in an ifdef USE_XFROUT, but we should really check
+// live if we do xfrout
//TODO. The sample way for checking axfr query, the code should be merged to auth server class
bool
check_axfr_query(char* const msg_data, const uint16_t msg_len) {
@@ -64,11 +62,21 @@
}
//TODO. Send the xfr query to xfrout module, the code should be merged to auth server class
+//BIGGERTODO: stop using hardcoded install-path locations!
void
dispatch_axfr_query(const int tcp_sock, char const axfr_query[],
const uint16_t query_len)
{
- string path(UNIX_SOCKET_FILE);
+ string path;
+ if (getenv("B10_FROM_BUILD")) {
+ path = string(getenv("B10_FROM_BUILD")) + "/auth_xfrout_conn";
+ } else {
+ path = UNIX_SOCKET_FILE;
+ }
+
+ if (getenv("B10_FROM_BUILD")) {
+ path = string(getenv("B10_FROM_BUILD")) + "/auth_xfrout_conn";
+ }
XfroutClient xfr_client(path);
try {
xfr_client.connect();
@@ -78,10 +86,9 @@
}
catch (const exception & err) {
//if (verbose_mode)
- cerr << "error handle xfr query:" << err.what() << endl;
- }
-}
-#endif
+ cerr << "error handle xfr query " << UNIX_SOCKET_FILE << ":" << err.what() << endl;
+ }
+}
}
namespace asio_link {
@@ -134,13 +141,11 @@
{
if (!error) {
InputBuffer dnsbuffer(data_, bytes_transferred);
-#ifdef USE_XFROUT
if (check_axfr_query(data_, bytes_transferred)) {
dispatch_axfr_query(socket_.native(), data_, bytes_transferred);
// start to get new query ?
start();
} else {
-#endif
if (auth_server_->processMessage(dnsbuffer, dns_message_,
response_renderer_, false)) {
responselen_buffer_.writeUint16(
@@ -154,9 +159,7 @@
} else {
delete this;
}
-#ifdef USE_XFROUT
}
-#endif
} else {
delete this;
}
Modified: branches/trac172/src/bin/auth/asio_link.h
==============================================================================
--- branches/trac172/src/bin/auth/asio_link.h (original)
+++ branches/trac172/src/bin/auth/asio_link.h Wed Jun 30 18:48:15 2010
@@ -24,7 +24,7 @@
class IOService {
public:
- IOService(AuthSrv* auth_server, const char* port,
+ IOService(AuthSrv* auth_server, const char* const port,
const bool use_ipv4, const bool use_ipv6);
~IOService();
void run();
Modified: branches/trac172/src/bin/auth/auth_srv.cc
==============================================================================
--- branches/trac172/src/bin/auth/auth_srv.cc (original)
+++ branches/trac172/src/bin/auth/auth_srv.cc Wed Jun 30 18:48:15 2010
@@ -243,7 +243,8 @@
impl_->data_sources_.doQuery(query);
} catch (const Exception& ex) {
if (impl_->verbose_mode_) {
- cerr << "[b10-auth] Internal error, returning SERVFAIL: " << ex.what() << endl;
+ cerr << "[b10-auth] Internal error, returning SERVFAIL: " <<
+ ex.what() << endl;
}
makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
impl_->verbose_mode_);
@@ -273,9 +274,22 @@
bool is_default;
string item("database_file");
ElementPtr value = cs_->getValue(is_default, item);
+ final = Element::createMap();
+
+ // If the value is the default, and we are running from
+ // a specific directory ('from build'), we need to use
+ // a different value than the default (which may not exist)
+ // (btw, this should not be done here in the end, i think
+ // the from-source script should have a check for this,
+ // but for that we need offline access to config, so for
+ // now this is a decent solution)
+ if (is_default && getenv("B10_FROM_BUILD")) {
+ value = Element::create(string(getenv("B10_FROM_BUILD")) +
+ "/bind10_zones.sqlite3");
+ }
+ final->set(item, value);
+
db_file_ = value->stringValue();
- final = Element::createMap();
- final->set(item, value);
} else {
return (answer);
}
Modified: branches/trac172/src/bin/auth/main.cc
==============================================================================
--- branches/trac172/src/bin/auth/main.cc (original)
+++ branches/trac172/src/bin/auth/main.cc Wed Jun 30 18:48:15 2010
@@ -148,12 +148,12 @@
io_service = new asio_link::IOService(auth_server, port, use_ipv4,
use_ipv6);
- ModuleCCSession cs(specfile, io_service->get_io_service(), my_config_handler, my_command_handler);
+ ModuleCCSession cs(specfile, io_service->get_io_service(),
+ my_config_handler, my_command_handler);
auth_server->setConfigSession(&cs);
auth_server->updateConfig(ElementPtr());
-
cout << "[b10-auth] Server started." << endl;
io_service->run();
} catch (const std::exception& ex) {
Modified: branches/trac172/src/bin/auth/tests/Makefile.am
==============================================================================
--- branches/trac172/src/bin/auth/tests/Makefile.am (original)
+++ branches/trac172/src/bin/auth/tests/Makefile.am Wed Jun 30 18:48:15 2010
@@ -20,9 +20,9 @@
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(SQLITE_LIBS)
run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a
run_unittests_LDADD += $(top_builddir)/src/lib/config/.libs/libcfgclient.a
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.a
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
endif
Modified: branches/trac172/src/bin/bind10/bind10.py.in
==============================================================================
--- branches/trac172/src/bin/bind10/bind10.py.in (original)
+++ branches/trac172/src/bin/bind10/bind10.py.in Wed Jun 30 18:48:15 2010
@@ -57,6 +57,9 @@
import select
import random
from optparse import OptionParser, OptionValueError
+import io
+import pwd
+import posix
import isc.cc
@@ -108,21 +111,38 @@
when = time.time()
return max(when, self.restart_time)
+class ProcessInfoError(Exception): pass
+
class ProcessInfo:
"""Information about a process"""
dev_null = open(os.devnull, "w")
def __init__(self, name, args, env={}, dev_null_stdout=False,
- dev_null_stderr=False):
+ dev_null_stderr=False, uid=None, username=None):
self.name = name
self.args = args
self.env = env
self.dev_null_stdout = dev_null_stdout
self.dev_null_stderr = dev_null_stderr
self.restart_schedule = RestartSchedule()
+ self.uid = uid
+ self.username = username
self._spawn()
+ def _setuid(self):
+ """Function used before running a program that needs to run as a
+ different user."""
+ if self.uid is not None:
+ try:
+ posix.setuid(self.uid)
+ except OSError as e:
+ if e.errno == errno.EPERM:
+ # if we failed to change user due to permission report that
+ raise ProcessInfoError("Unable to change to user %s (uid %d)" % (self.username, self.uid))
+ else:
+ # otherwise simply re-raise whatever error we found
+ raise
def _spawn(self):
if self.dev_null_stdout:
@@ -138,14 +158,15 @@
# on construction (self.env).
spawn_env = os.environ
spawn_env.update(self.env)
- if not 'B10_FROM_SOURCE' in os.environ:
+ if 'B10_FROM_SOURCE' not in os.environ:
spawn_env['PATH'] = "@@LIBEXECDIR@@:" + spawn_env['PATH']
self.process = subprocess.Popen(self.args,
stdin=subprocess.PIPE,
stdout=spawn_stdout,
stderr=spawn_stderr,
close_fds=True,
- env=spawn_env,)
+ env=spawn_env,
+ preexec_fn=self._setuid)
self.pid = self.process.pid
self.restart_schedule.set_run_start_time()
@@ -155,7 +176,8 @@
class BoB:
"""Boss of BIND class."""
- def __init__(self, msgq_socket_file=None, auth_port=5300, verbose=False):
+ def __init__(self, msgq_socket_file=None, auth_port=5300, verbose=False,
+ setuid=None, username=None):
"""Initialize the Boss of BIND. This is a singleton (only one
can run).
@@ -171,6 +193,8 @@
self.processes = {}
self.dead_processes = {}
self.runnable = False
+ self.uid = setuid
+ self.username = username
def config_handler(self, new_config):
if self.verbose:
@@ -225,12 +249,14 @@
sys.stdout.write("[bind10] Starting b10-msgq\n")
try:
c_channel = ProcessInfo("b10-msgq", ["b10-msgq"], c_channel_env,
- True, not self.verbose)
+ True, not self.verbose, uid=self.uid,
+ username=self.username)
except Exception as e:
return "Unable to start b10-msgq; " + str(e)
self.processes[c_channel.pid] = c_channel
if self.verbose:
- sys.stdout.write("[bind10] Started b10-msgq (PID %d)\n" % c_channel.pid)
+ sys.stdout.write("[bind10] Started b10-msgq (PID %d)\n" %
+ c_channel.pid)
# now connect to the c-channel
cc_connect_start = time.time()
@@ -250,7 +276,8 @@
sys.stdout.write("[bind10] Starting b10-cfgmgr\n")
try:
bind_cfgd = ProcessInfo("b10-cfgmgr", ["b10-cfgmgr"],
- c_channel_env)
+ c_channel_env, uid=self.uid,
+ username=self.username)
except Exception as e:
c_channel.process.kill()
return "Unable to start b10-cfgmgr; " + str(e)
@@ -271,23 +298,6 @@
self.ccs.start()
if self.verbose:
sys.stdout.write("[bind10] ccsession started\n")
-
- # start the xfrout before auth-server, to make sure every xfr-query can
- # be processed properly.
- xfrout_args = ['b10-xfrout']
- if self.verbose:
- sys.stdout.write("[bind10] Starting b10-xfrout\n")
- xfrout_args += ['-v']
- try:
- xfrout = ProcessInfo("b10-xfrout", xfrout_args,
- c_channel_env )
- except Exception as e:
- c_channel.process.kill()
- bind_cfgd.process.kill()
- return "Unable to start b10-xfrout; " + str(e)
- self.processes[xfrout.pid] = xfrout
- if self.verbose:
- sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % xfrout.pid)
# start b10-auth
# XXX: this must be read from the configuration manager in the future
@@ -307,6 +317,28 @@
self.processes[auth.pid] = auth
if self.verbose:
sys.stdout.write("[bind10] Started b10-auth (PID %d)\n" % auth.pid)
+
+ # everything after the authoritative server can run as non-root
+ if self.uid is not None:
+ posix.setuid(self.uid)
+
+ # start the xfrout before auth-server, to make sure every xfr-query can
+ # be processed properly.
+ xfrout_args = ['b10-xfrout']
+ if self.verbose:
+ sys.stdout.write("[bind10] Starting b10-xfrout\n")
+ xfrout_args += ['-v']
+ try:
+ xfrout = ProcessInfo("b10-xfrout", xfrout_args,
+ c_channel_env )
+ except Exception as e:
+ c_channel.process.kill()
+ bind_cfgd.process.kill()
+ return "Unable to start b10-xfrout; " + str(e)
+ self.processes[xfrout.pid] = xfrout
+ if self.verbose:
+ sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" %
+ xfrout.pid)
# start b10-xfrin
xfrin_args = ['b10-xfrin']
@@ -324,7 +356,8 @@
return "Unable to start b10-xfrin; " + str(e)
self.processes[xfrind.pid] = xfrind
if self.verbose:
- sys.stdout.write("[bind10] Started b10-xfrin (PID %d)\n" % xfrind.pid)
+ sys.stdout.write("[bind10] Started b10-xfrin (PID %d)\n" %
+ xfrind.pid)
# start the b10-cmdctl
# XXX: we hardcode port 8080
@@ -344,7 +377,8 @@
return "Unable to start b10-cmdctl; " + str(e)
self.processes[cmd_ctrld.pid] = cmd_ctrld
if self.verbose:
- sys.stdout.write("[bind10] Started b10-cmdctl (PID %d)\n" % cmd_ctrld.pid)
+ sys.stdout.write("[bind10] Started b10-cmdctl (PID %d)\n" %
+ cmd_ctrld.pid)
self.runnable = True
@@ -353,7 +387,7 @@
def stop_all_processes(self):
"""Stop all processes."""
cmd = { "command": ['shutdown']}
- self.cc_session.group_sendmsg(cmd, 'Boss', 'Cmd-Ctrld')
+ self.cc_session.group_sendmsg(cmd, 'Boss', 'Cmdctl')
self.cc_session.group_sendmsg(cmd, "Boss", "ConfigManager")
self.cc_session.group_sendmsg(cmd, "Boss", "Auth")
self.cc_session.group_sendmsg(cmd, "Boss", "Xfrout")
@@ -435,11 +469,16 @@
sys.stdout.write("[bind10] Unknown child pid %d exited.\n" % pid)
def restart_processes(self):
- """Restart any dead processes."""
+ """Restart any dead processes.
+ Returns the time when the next process is ready to be restarted.
+ If the server is shutting down, returns 0.
+ If there are no processes, returns None.
+ The values returned can be safely passed into select() as the
+ timeout value."""
next_restart = None
# if we're shutting down, then don't restart
if not self.runnable:
- return next_restart
+ return 0
# otherwise look through each dead process and try to restart
still_dead = {}
now = time.time()
@@ -510,6 +549,10 @@
def main():
global options
global boss_of_bind
+ # Enforce line buffering on stdout, even when not a TTY
+ sys.stdout = io.TextIOWrapper(sys.stdout.detach(), line_buffering=True)
+
+
# Parse any command-line options.
parser = OptionParser(version=__version__)
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
@@ -520,7 +563,42 @@
parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
type="string", default=None,
help="UNIX domain socket file the b10-msgq daemon will use")
+ parser.add_option("-u", "--user", dest="user",
+ type="string", default=None,
+ help="Change user after startup (must run as root)")
(options, args) = parser.parse_args()
+ if args:
+ parser.print_help()
+ sys.exit(1)
+
+ # Check user ID.
+ setuid = None
+ username = None
+ if options.user:
+ # Try getting information about the user, assuming UID passed.
+ try:
+ pw_ent = pwd.getpwuid(int(options.user))
+ setuid = pw_ent.pw_uid
+ username = pw_ent.pw_name
+ except ValueError:
+ pass
+ except KeyError:
+ pass
+
+ # Next try getting information about the user, assuming user name
+ # passed.
+ # If the information is both a valid user name and user number, we
+ # prefer the name because we try it second. A minor point, hopefully.
+ try:
+ pw_ent = pwd.getpwnam(options.user)
+ setuid = pw_ent.pw_uid
+ username = pw_ent.pw_name
+ except KeyError:
+ pass
+
+ if setuid is None:
+ sys.stderr.write("bind10: invalid user: '%s'\n" % options.user)
+ sys.exit(1)
# Announce startup.
if options.verbose:
@@ -543,11 +621,12 @@
# Go bob!
boss_of_bind = BoB(options.msgq_socket_file, int(options.auth_port),
- options.verbose)
+ options.verbose, setuid, username)
startup_result = boss_of_bind.startup()
if startup_result:
sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)
sys.exit(1)
+ sys.stdout.write("[bind10] BIND 10 started\n")
# In our main loop, we check for dead processes or messages
# on the c-channel.
@@ -584,6 +663,7 @@
# shutdown
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
boss_of_bind.shutdown()
+ sys.exit(0)
if __name__ == "__main__":
main()
Modified: branches/trac172/src/bin/bind10/run_bind10.sh.in
==============================================================================
--- branches/trac172/src/bin/bind10/run_bind10.sh.in (original)
+++ branches/trac172/src/bin/bind10/run_bind10.sh.in Wed Jun 30 18:48:15 2010
@@ -23,7 +23,8 @@
PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:$PATH
export PATH
-PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/xfr/.libs
+PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs
+#PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/xfr/.libs
export PYTHONPATH
B10_FROM_SOURCE=@abs_top_srcdir@
Modified: branches/trac172/src/bin/bind10/tests/bind10_test.in
==============================================================================
--- branches/trac172/src/bin/bind10/tests/bind10_test.in (original)
+++ branches/trac172/src/bin/bind10/tests/bind10_test.in Wed Jun 30 18:48:15 2010
@@ -27,5 +27,6 @@
export PYTHONPATH
cd ${BIND10_PATH}/tests
-exec ${PYTHON_EXEC} -O bind10_test.py $*
+${PYTHON_EXEC} -O bind10_test.py $*
+exec ${PYTHON_EXEC} -O args_test.py $*
Modified: branches/trac172/src/bin/bindctl/Makefile.am
==============================================================================
--- branches/trac172/src/bin/bindctl/Makefile.am (original)
+++ branches/trac172/src/bin/bindctl/Makefile.am Wed Jun 30 18:48:15 2010
@@ -9,8 +9,6 @@
pythondir = $(pyexecdir)/bindctl
bindctldir = $(DESTDIR)$(pkgdatadir)
-bindctl_DATA = bindctl.pem
-EXTRA_DIST += bindctl.pem
CLEANFILES = bindctl
@@ -26,14 +24,3 @@
-e "s|@@SYSCONFDIR@@|@sysconfdir@|" \
-e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" bindctl-source.py >$@
chmod a+x $@
-
-if INSTALL_CONFIGURATIONS
-
-# TODO: permissions handled later
-install-data-local:
- $(mkinstalldirs) $(DESTDIR)/@sysconfdir@/@PACKAGE@
- if test ! -f $(DESTDIR)$(sysconfdir)/@PACKAGE@/bindctl.pem; then \
- $(INSTALL_DATA) $(srcdir)/bindctl.pem $(DESTDIR)$(sysconfdir)/@PACKAGE@/ ; \
- fi
-
-endif
Modified: branches/trac172/src/bin/bindctl/TODO
==============================================================================
--- branches/trac172/src/bin/bindctl/TODO (original)
+++ branches/trac172/src/bin/bindctl/TODO Wed Jun 30 18:48:15 2010
@@ -18,3 +18,4 @@
If the default user is saved in file, its password shouldn't be saved in plaintext.
7. Need to think of what exactly to do with responses received to commands
(currently it simply print the map)
+8. Remove bindctl-source.py.in(replace with bindctl-source.py) when merging to trunk.
Modified: branches/trac172/src/bin/bindctl/bindcmd.py
==============================================================================
--- branches/trac172/src/bin/bindctl/bindcmd.py (original)
+++ branches/trac172/src/bin/bindctl/bindcmd.py Wed Jun 30 18:48:15 2010
@@ -36,6 +36,9 @@
from hashlib import sha1
import csv
import ast
+import pwd
+import getpass
+import traceback
try:
from collections import OrderedDict
@@ -49,6 +52,8 @@
except ImportError:
my_readline = sys.stdin.readline
+CSV_FILE_NAME = 'default_user.csv'
+FAIL_TO_CONNECT_WITH_CMDCTL = "Fail to connect with b10-cmdctl module, is it running?"
CONFIG_MODULE_NAME = 'config'
CONST_BINDCTL_HELP = """
usage: <module name> <command name> [param1 = value1 [, param2 = value2]]
@@ -58,10 +63,34 @@
Type \"<module_name> <command_name> help\" for help on the specific command.
\nAvailable module names: """
+class ValidatedHTTPSConnection(http.client.HTTPSConnection):
+ '''Overrides HTTPSConnection to support certification
+ validation. '''
+ def __init__(self, host, ca_certs):
+ http.client.HTTPSConnection.__init__(self, host)
+ self.ca_certs = ca_certs
+
+ def connect(self):
+ ''' Overrides the connect() so that we do
+ certificate validation. '''
+ sock = socket.create_connection((self.host, self.port),
+ self.timeout)
+ if self._tunnel_host:
+ self.sock = sock
+ self._tunnel()
+
+ req_cert = ssl.CERT_NONE
+ if self.ca_certs:
+ req_cert = ssl.CERT_REQUIRED
+ self.sock = ssl.wrap_socket(sock, self.key_file,
+ self.cert_file,
+ cert_reqs=req_cert,
+ ca_certs=self.ca_certs)
+
class BindCmdInterpreter(Cmd):
"""simple bindctl example."""
- def __init__(self, server_port = 'localhost:8080', pem_file = "bindctl.pem"):
+ def __init__(self, server_port = 'localhost:8080', pem_file = None):
Cmd.__init__(self)
self.location = ""
self.prompt_end = '> '
@@ -70,40 +99,73 @@
self.modules = OrderedDict()
self.add_module_info(ModuleInfo("help", desc = "Get help for bindctl"))
self.server_port = server_port
- self.pem_file = pem_file
- self._connect_to_cmd_ctrld()
+ self.conn = ValidatedHTTPSConnection(self.server_port,
+ ca_certs=pem_file)
self.session_id = self._get_session_id()
-
- def _connect_to_cmd_ctrld(self):
- '''Connect to cmdctl in SSL context. '''
- try:
- self.conn = http.client.HTTPSConnection(self.server_port,
- cert_file=self.pem_file)
- except Exception as e:
- print(e, "can't connect to %s, please make sure cmd-ctrld is running" %
- self.server_port)
def _get_session_id(self):
'''Generate one session id for the connection. '''
rand = os.urandom(16)
now = time.time()
- session_id = sha1(("%s%s%s" %(rand, now,
+ session_id = sha1(("%s%s%s" %(rand, now,
socket.gethostname())).encode())
digest = session_id.hexdigest()
return digest
def run(self):
- '''Parse commands inputted from user and send them to cmdctl. '''
+ '''Parse commands from user and send them to cmdctl. '''
try:
if not self.login_to_cmdctl():
- return False
-
- # Get all module information from cmd-ctrld
- self.config_data = isc.config.UIModuleCCSession(self)
- self._update_commands()
+ return
+
self.cmdloop()
+ except FailToLogin as err:
+ print(err)
+ print(FAIL_TO_CONNECT_WITH_CMDCTL)
+ traceback.print_exc()
except KeyboardInterrupt:
- return True
+ print('\nExit from bindctl')
+
+ def _get_saved_user_info(self, dir, file_name):
+ ''' Read all the available username and password pairs saved in
+ file(path is "dir + file_name"), Return value is one list of elements
+ ['name', 'password'], If get information failed, empty list will be
+ returned.'''
+ if (not dir) or (not os.path.exists(dir)):
+ return []
+
+ try:
+ csvfile = None
+ users = []
+ csvfile = open(dir + file_name)
+ users_info = csv.reader(csvfile)
+ for row in users_info:
+ users.append([row[0], row[1]])
+ except (IOError, IndexError) as e:
+ pass
+ finally:
+ if csvfile:
+ csvfile.close()
+ return users
+
+ def _save_user_info(self, username, passwd, dir, file_name):
+ ''' Save username and password in file "dir + file_name"
+ If it's saved properly, return True, or else return False. '''
+ try:
+ if not os.path.exists(dir):
+ os.mkdir(dir, 0o700)
+
+ csvfilepath = dir + file_name
+ csvfile = open(csvfilepath, 'w')
+ os.chmod(csvfilepath, 0o600)
+ writer = csv.writer(csvfile)
+ writer.writerow([username, passwd])
+ csvfile.close()
+ except Exception as e:
+ print(e, "\nCannot write %s%s; default user is not stored" % (dir, file_name))
+ return False
+
+ return True
def login_to_cmdctl(self):
'''Login to cmdctl with the username and password inputted
@@ -112,33 +174,21 @@
time, username and password saved in 'default_user.csv' will be
used first.
'''
- csvfile = None
- bsuccess = False
- try:
- cvsfilepath = ""
- if ('HOME' in os.environ):
- cvsfilepath = os.environ['HOME']
- cvsfilepath += os.sep + '.bind10' + os.sep
- cvsfilepath += 'default_user.csv'
- csvfile = open(cvsfilepath)
- users = csv.reader(csvfile)
- for row in users:
- param = {'username': row[0], 'password' : row[1]}
+ csv_file_dir = pwd.getpwnam(getpass.getuser()).pw_dir
+ csv_file_dir += os.sep + '.bind10' + os.sep
+ users = self._get_saved_user_info(csv_file_dir, CSV_FILE_NAME)
+ for row in users:
+ param = {'username': row[0], 'password' : row[1]}
+ try:
response = self.send_POST('/login', param)
data = response.read().decode()
- if response.status == http.client.OK:
- print(data + ' login as ' + row[0] )
- bsuccess = True
- break
- except IOError as e:
- pass
- except Exception as e:
- print(e)
- finally:
- if csvfile:
- csvfile.close()
- if bsuccess:
- return True
+ except socket.error:
+ traceback.print_exc()
+ raise FailToLogin()
+
+ if response.status == http.client.OK:
+ print(data + ' login as ' + row[0] )
+ return True
count = 0
print("[TEMP MESSAGE]: username :root password :bind10")
@@ -151,33 +201,17 @@
username = input("Username:")
passwd = getpass.getpass()
param = {'username': username, 'password' : passwd}
- response = self.send_POST('/login', param)
- data = response.read().decode()
- print(data)
-
+ try:
+ response = self.send_POST('/login', param)
+ data = response.read().decode()
+ print(data)
+ except socket.error as e:
+ traceback.print_exc()
+ raise FailToLogin()
+
if response.status == http.client.OK:
- cvsfilepath = ""
- try:
- if ('HOME' in os.environ):
- cvsfilepath = os.environ['HOME']
- cvsfilepath += os.sep + '.bind10' + os.sep
- if not os.path.exists(cvsfilepath):
- os.mkdir(cvsfilepath, 0o700)
- else:
- print("Cannot determine location of $HOME. Not storing default user")
- return True
- cvsfilepath += 'default_user.csv'
- csvfile = open(cvsfilepath, 'w')
- os.chmod(cvsfilepath, 0o600)
- writer = csv.writer(csvfile)
- writer.writerow([username, passwd])
- csvfile.close()
- except Exception as e:
- # just not store it
- print("Cannot write ~/.bind10/default_user.csv; default user is not stored")
- print(e)
+ self._save_user_info(username, passwd, csv_file_dir, CSV_FILE_NAME)
return True
-
def _update_commands(self):
'''Update the commands of all modules. '''
@@ -211,7 +245,19 @@
headers = {"cookie" : self.session_id}
self.conn.request('POST', url, param, headers)
return self.conn.getresponse()
-
+
+ def _update_all_modules_info(self):
+ ''' Get all modules' information from cmdctl, including
+ specification file and configuration data. This function
+ should be called before interpreting command line or complete-key
+ is entered. This may not be the best way to keep bindctl
+ and cmdctl share same modules information, but it works.'''
+ self.config_data = isc.config.UIModuleCCSession(self)
+ self._update_commands()
+
+ def precmd(self, line):
+ self._update_all_modules_info()
+ return line
def postcmd(self, stop, line):
'''Update the prompt after every command'''
@@ -308,8 +354,11 @@
if cmd.module != CONFIG_MODULE_NAME:
for param_name in cmd.params:
param_spec = command_info.get_param_with_name(param_name).param_spec
- cmd.params[param_name] = isc.config.config_data.convert_type(param_spec, cmd.params[param_name])
-
+ try:
+ cmd.params[param_name] = isc.config.config_data.convert_type(param_spec, cmd.params[param_name])
+ except isc.cc.data.DataTypeError as e:
+ raise isc.cc.data.DataTypeError('Invalid parameter value for \"%s\", the type should be \"%s\" \n'
+ % (param_name, param_spec['item_type']) + str(e))
def _handle_cmd(self, cmd):
'''Handle a command entered by the user'''
@@ -356,6 +405,7 @@
def complete(self, text, state):
if 0 == state:
+ self._update_all_modules_info()
text = text.strip()
hints = []
cur_line = my_readline()
@@ -441,13 +491,14 @@
cmd = BindCmdParse(line)
self._validate_cmd(cmd)
self._handle_cmd(cmd)
- except BindCtlException as e:
- print("Error! ", e)
- self._print_correct_usage(e)
- except isc.cc.data.DataTypeError as e:
- print("Error! ", e)
- self._print_correct_usage(e)
-
+ except (IOError, http.client.HTTPException) as err:
+ print('Error!', err)
+ print(FAIL_TO_CONNECT_WITH_CMDCTL)
+ except BindCtlException as err:
+ print("Error! ", err)
+ self._print_correct_usage(err)
+ except isc.cc.data.DataTypeError as err:
+ print("Error! ", err)
def _print_correct_usage(self, ept):
if isinstance(ept, CmdUnknownModuleSyntaxError):
@@ -556,7 +607,7 @@
if (len(cmd.params) != 0):
cmd_params = json.dumps(cmd.params)
- print("send the message to cmd-ctrld")
+ print("send the command to cmd-ctrld")
reply = self.send_POST(url, cmd.params)
data = reply.read().decode()
print("received reply:", data)
Modified: branches/trac172/src/bin/bindctl/bindctl-source.py.in
==============================================================================
--- branches/trac172/src/bin/bindctl/bindctl-source.py.in (original)
+++ branches/trac172/src/bin/bindctl/bindctl-source.py.in Wed Jun 30 18:48:15 2010
@@ -97,13 +97,16 @@
def set_bindctl_options(parser):
parser.add_option('-p', '--port', dest = 'port', type = 'int',
- action = 'callback', callback=check_port,
- default = '8080', help = 'port for cmdctl of bind10')
+ action = 'callback', callback=check_port,
+ default = '8080', help = 'port for cmdctl of bind10')
parser.add_option('-a', '--address', dest = 'addr', type = 'string',
- action = 'callback', callback=check_addr,
- default = '127.0.0.1', help = 'IP address for cmdctl of bind10')
+ action = 'callback', callback=check_addr,
+ default = '127.0.0.1', help = 'IP address for cmdctl of bind10')
+ parser.add_option('-c', '--certificate-chain', dest = 'cert_chain',
+ type = 'string', action = 'store',
+ help = 'PEM formatted server certificate validation chain file')
if __name__ == '__main__':
try:
@@ -111,14 +114,7 @@
set_bindctl_options(parser)
(options, args) = parser.parse_args()
server_addr = options.addr + ':' + str(options.port)
- # If B10_FROM_SOURCE is set in the environment, we use PEM file
- # from a directory relative to that, otherwise we use the one
- # installed on the system
- if "B10_FROM_SOURCE" in os.environ:
- SYSCONF_PATH = os.environ["B10_FROM_SOURCE"] + "/src/bin/bindctl"
- else:
- SYSCONF_PATH = "@@SYSCONFDIR@@/@PACKAGE@"
- tool = BindCmdInterpreter(server_addr, pem_file = SYSCONF_PATH + "/bindctl.pem")
+ tool = BindCmdInterpreter(server_addr, pem_file=options.cert_chain)
prepare_config_commands(tool)
tool.run()
except Exception as e:
Modified: branches/trac172/src/bin/bindctl/cmdparse.py
==============================================================================
--- branches/trac172/src/bin/bindctl/cmdparse.py (original)
+++ branches/trac172/src/bin/bindctl/cmdparse.py Wed Jun 30 18:48:15 2010
@@ -24,15 +24,19 @@
from bindctl.mycollections import OrderedDict
param_name_str = "^\s*(?P<param_name>[\w]+)\s*=\s*"
-param_value_str = "(?P<param_value>[\w\.:/-]+)"
-param_value_with_quota_str = "[\"\'](?P<param_value>[\w\.:, /-]+)[\"\']"
+
+# The value string can be a sequence without space or comma
+# characters, or a string surroundedby quotation marks(such marks
+# can be part of string in an escaped form)
+#param_value_str = "(?P<param_value>[\"\'].+?(?<!\\\)[\"\']|[^\'\"][^, ]+)"
+param_value_str = "(?P<param_value>[^\'\" ][^, ]+)"
+param_value_with_quota_str = "[\"\'](?P<param_value>.+?)(?<!\\\)[\"\']"
next_params_str = "(?P<blank>\s*)(?P<comma>,?)(?P<next_params>.*)$"
PARAM_WITH_QUOTA_PATTERN = re.compile(param_name_str +
- param_value_with_quota_str +
+ param_value_with_quota_str +
next_params_str)
PARAM_PATTERN = re.compile(param_name_str + param_value_str + next_params_str)
-
# Used for module and command name
NAME_PATTERN = re.compile("^\s*(?P<name>[\w]+)(?P<blank>\s*)(?P<others>.*)$")
@@ -98,7 +102,6 @@
groups = PARAM_PATTERN.match(param_text) or \
PARAM_WITH_QUOTA_PATTERN.match(param_text)
-
if not groups:
# ok, fill in the params in the order entered
params = re.findall("([^\" ]+|\".*\")", param_text)
Modified: branches/trac172/src/bin/bindctl/exception.py
==============================================================================
--- branches/trac172/src/bin/bindctl/exception.py (original)
+++ branches/trac172/src/bin/bindctl/exception.py Wed Jun 30 18:48:15 2010
@@ -115,3 +115,10 @@
def __str__(self):
return str("Parameter '%s' is missed for command '%s' of module '%s'" %
(self.param, self.command, self.module))
+
+
+class FailToLogin(BindCtlException):
+ def __str__(self):
+ return "Fail to login to cmdctl"
+
+
Modified: branches/trac172/src/bin/bindctl/tests/bindctl_test.py
==============================================================================
--- branches/trac172/src/bin/bindctl/tests/bindctl_test.py (original)
+++ branches/trac172/src/bin/bindctl/tests/bindctl_test.py Wed Jun 30 18:48:15 2010
@@ -16,6 +16,7 @@
import unittest
import isc.cc.data
+import os
from bindctl import cmdparse
from bindctl import bindcmd
from bindctl.moduleinfo import *
@@ -50,12 +51,31 @@
assert cmd.params["zone_name"] == "cnnic.cn"
assert cmd.params["file"] == "cnnic.cn.file"
assert cmd.params["master"] == '1.1.1.1'
+
+ def testCommandWithParamters_2(self):
+ '''Test whether the parameters in key=value can be parsed properly.'''
+ cmd = cmdparse.BindCmdParse('zone cmd name = 1:34::2')
+ self.assertEqual(cmd.params['name'], '1:34::2')
+
+ cmd = cmdparse.BindCmdParse('zone cmd name = 1\"\'34**&2 value=44\"\'\"')
+ self.assertEqual(cmd.params['name'], '1\"\'34**&2')
+ self.assertEqual(cmd.params['value'], '44\"\'\"')
+
+ cmd = cmdparse.BindCmdParse('zone cmd name = 1\"\'34**&2 ,value= 44\"\'\"')
+ self.assertEqual(cmd.params['name'], '1\"\'34**&2')
+ self.assertEqual(cmd.params['value'], '44\"\'\"')
+ cmd = cmdparse.BindCmdParse('zone cmd name = 1\'34**&2value=44\"\'\" value = \"==============\'')
+ self.assertEqual(cmd.params['name'], '1\'34**&2value=44\"\'\"')
+ self.assertEqual(cmd.params['value'], '==============')
+
+ cmd = cmdparse.BindCmdParse('zone cmd name = \"1234, 567890 \" value ==&*/')
+ self.assertEqual(cmd.params['name'], '1234, 567890 ')
+ self.assertEqual(cmd.params['value'], '=&*/')
def testCommandWithListParam(self):
- cmd = cmdparse.BindCmdParse("zone set zone_name='cnnic.cn', master='1.1.1.1, 2.2.2.2'")
- assert cmd.params["master"] == '1.1.1.1, 2.2.2.2'
-
+ cmd = cmdparse.BindCmdParse("zone set zone_name='cnnic.cn', master='1.1.1.1, 2.2.2.2'")
+ assert cmd.params["master"] == '1.1.1.1, 2.2.2.2'
def testCommandWithHelpParam(self):
cmd = cmdparse.BindCmdParse("zone add help")
@@ -217,8 +237,32 @@
assert self.random_names[i] == cmd_names[i+1]
assert self.random_names[i] == module_names[i+1]
i = i + 1
-
-
+
+class FakeBindCmdInterpreter(bindcmd.BindCmdInterpreter):
+ def __init__(self):
+ pass
+
+class TestBindCmdInterpreter(unittest.TestCase):
+
+ def _create_invalid_csv_file(self, csvfilename):
+ import csv
+ csvfile = open(csvfilename, 'w')
+ writer = csv.writer(csvfile)
+ writer.writerow(['name1'])
+ writer.writerow(['name2'])
+ csvfile.close()
+
+ def test_get_saved_user_info(self):
+ cmd = FakeBindCmdInterpreter()
+ users = cmd._get_saved_user_info('/notexist', 'cvs_file.cvs')
+ self.assertEqual([], users)
+
+ csvfilename = 'csv_file.csv'
+ self._create_invalid_csv_file(csvfilename)
+ users = cmd._get_saved_user_info('./', csvfilename)
+ self.assertEqual([], users)
+ os.remove(csvfilename)
+
if __name__== "__main__":
unittest.main()
Modified: branches/trac172/src/bin/cfgmgr/Makefile.am
==============================================================================
--- branches/trac172/src/bin/cfgmgr/Makefile.am (original)
+++ branches/trac172/src/bin/cfgmgr/Makefile.am Wed Jun 30 18:48:15 2010
@@ -1,8 +1,10 @@
+SUBDIRS = tests
+
pkglibexecdir = $(libexecdir)/@PACKAGE@
pkglibexec_SCRIPTS = b10-cfgmgr
-CLEANFILES = b10-cfgmgr
+CLEANFILES = b10-cfgmgr b10-cfgmgr.pyc
b10_cfgmgrdir = @localstatedir@/@PACKAGE@
#B10_cfgmgr_DATA =
Modified: branches/trac172/src/bin/cfgmgr/b10-cfgmgr.py.in
==============================================================================
--- branches/trac172/src/bin/cfgmgr/b10-cfgmgr.py.in (original)
+++ branches/trac172/src/bin/cfgmgr/b10-cfgmgr.py.in Wed Jun 30 18:48:15 2010
@@ -14,6 +14,8 @@
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# $Id$
import sys; sys.path.append ('@@PYTHONPATH@@')
@@ -38,7 +40,8 @@
if cm:
cm.running = False
-if __name__ == "__main__":
+def main():
+ global cm
try:
cm = ConfigManager(DATA_PATH)
signal.signal(signal.SIGINT, signal_handler)
@@ -53,3 +56,6 @@
print("[b10-cfgmgr] Interrupted, exiting")
if cm:
cm.write_config()
+
+if __name__ == "__main__":
+ main()
Modified: branches/trac172/src/bin/cmdctl/Makefile.am
==============================================================================
--- branches/trac172/src/bin/cmdctl/Makefile.am (original)
+++ branches/trac172/src/bin/cmdctl/Makefile.am Wed Jun 30 18:48:15 2010
@@ -17,9 +17,8 @@
b10_cmdctl_DATA += cmdctl.spec
EXTRA_DIST = $(CMDCTL_CONFIGURATIONS)
-EXTRA_DIST += cmdctl.spec
-CLEANFILES= b10-cmdctl cmdctl.pyc
+CLEANFILES= b10-cmdctl cmdctl.pyc cmdctl.spec
man_MANS = b10-cmdctl.8
EXTRA_DIST += $(man_MANS) b10-cmdctl.xml
@@ -30,6 +29,9 @@
xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cmdctl.xml
endif
+
+cmdctl.spec: cmdctl.spec.pre
+ $(SED) -e "s|@@SYSCONFDIR@@|$(sysconfdir)|" cmdctl.spec.pre >$@
# TODO: does this need $$(DESTDIR) also?
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
Modified: branches/trac172/src/bin/cmdctl/TODO
==============================================================================
--- branches/trac172/src/bin/cmdctl/TODO (original)
+++ branches/trac172/src/bin/cmdctl/TODO Wed Jun 30 18:48:15 2010
@@ -1,8 +1,6 @@
-. Refine code for b10-cmdctl.
-. Add value type check according module specification.
. Add return code for RESTful API document of b10-cmdctl.
-. Add more unit tests for b10-cmdctl.
. Update man page for b10-cmdctl?
+. Add check for the content of key/certificate file
+ (when cmdctl starts or is configured by bindctl).
+. Use only one msgq/session to communicate with other modules?
-. Add id to each command, so the receiver knows if the response is what it wants.
-. Make cmdctl can be configured through bindctl.(after id is added)
Modified: branches/trac172/src/bin/cmdctl/cmdctl.py.in
==============================================================================
--- branches/trac172/src/bin/cmdctl/cmdctl.py.in (original)
+++ branches/trac172/src/bin/cmdctl/cmdctl.py.in Wed Jun 30 18:48:15 2010
@@ -41,6 +41,7 @@
import random
import time
import signal
+from isc.config import ccsession
from optparse import OptionParser, OptionValueError
from hashlib import sha1
try:
@@ -50,29 +51,27 @@
__version__ = 'BIND10'
URL_PATTERN = re.compile('/([\w]+)(?:/([\w]+))?/?')
-
-# If B10_FROM_SOURCE is set in the environment, we use data files
+CONFIG_DATA_URL = 'config_data'
+MODULE_SPEC_URL = 'module_spec'
+
+
+# If B10_FROM_BUILD is set in the environment, we use data files
# from a directory relative to that, otherwise we use the ones
# installed on the system
-if "B10_FROM_SOURCE" in os.environ:
- SPECFILE_PATH = os.environ["B10_FROM_SOURCE"] + "/src/bin/cmdctl"
- SYSCONF_PATH = os.environ["B10_FROM_SOURCE"] + "/src/bin/cmdctl"
+if "B10_FROM_BUILD" in os.environ:
+ SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/cmdctl"
else:
PREFIX = "@prefix@"
DATAROOTDIR = "@datarootdir@"
SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
- SYSCONF_PATH = "@sysconfdir@/@PACKAGE@".replace("${prefix}", PREFIX)
SPECFILE_LOCATION = SPECFILE_PATH + os.sep + "cmdctl.spec"
-USER_INFO_FILE = SYSCONF_PATH + os.sep + "cmdctl-accounts.csv"
-PRIVATE_KEY_FILE = SYSCONF_PATH + os.sep + "cmdctl-keyfile.pem"
-CERTIFICATE_FILE = SYSCONF_PATH + os.sep + "cmdctl-certfile.pem"
-
+
+class CmdctlException(Exception):
+ pass
+
class SecureHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
'''https connection request handler.
- Currently only GET and POST are supported.
-
- '''
-
+ Currently only GET and POST are supported. '''
def do_GET(self):
'''The client should send its session id in header with
the name 'cookie'
@@ -167,13 +166,13 @@
user_name = user_info.get('username')
if not user_name:
return False, ["need user name"]
- if not self.server.user_infos.get(user_name):
+ if not self.server.get_user_info(user_name):
return False, ["user doesn't exist"]
user_pwd = user_info.get('password')
if not user_pwd:
return False, ["need password"]
- local_info = self.server.user_infos.get(user_name)
+ local_info = self.server.get_user_info(user_name)
pwd_hashval = sha1((user_pwd + local_info[1]).encode())
if pwd_hashval.hexdigest() != local_info[0]:
return False, ["password doesn't match"]
@@ -197,9 +196,6 @@
pass
rcode, reply = self.server.send_command_to_module(mod, cmd, param)
- if self.server._verbose:
- print('[b10-cmdctl] Finish send message \'%s\' to module %s' % (cmd, mod))
-
ret = http.client.OK
if rcode != 0:
ret = http.client.BAD_REQUEST
@@ -214,65 +210,167 @@
'''Get all modules' config data/specification from configmanager.
receive command from client and resend it to proper module.
'''
-
- def __init__(self, verbose = False):
+ def __init__(self, httpserver, verbose = False):
+ ''' httpserver: the http server which use the object of
+ CommandControl to communicate with other modules. '''
self._verbose = verbose
- self.cc = isc.cc.Session()
- self.cc.group_subscribe('Cmd-Ctrld')
- self.module_spec = self.get_module_specification()
- self.config_data = self.get_config_data()
-
+ self._httpserver = httpserver
+ self._lock = threading.Lock()
+ self._setup_session()
+ self.modules_spec = self._get_modules_specification()
+ self._config_data = self._get_config_data_from_config_manager()
+ self._serving = True
+ self._start_msg_handle_thread()
+
+ def _setup_session(self):
+ '''Setup the session for receving the commands
+ sent from other modules. There are two sessions
+ for cmdctl, one(self.module_cc) is used for receiving
+ commands sent from other modules, another one (self._cc)
+ is used to send the command from Bindctl or other tools
+ to proper modules.'''
+ self._cc = isc.cc.Session()
+ self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
+ self.config_handler,
+ self.command_handler)
+ self._module_name = self._module_cc.get_module_spec().get_module_name()
+ self._cmdctl_config_data = self._module_cc.get_full_config()
+ self._module_cc.start()
+
+ def _accounts_file_check(self, filepath):
+ ''' Check whether the accounts file is valid, each row
+ should be a list with 3 items.'''
+ csvfile = None
+ errstr = None
+ try:
+ csvfile = open(filepath)
+ reader = csv.reader(csvfile)
+ for row in reader:
+ a = (row[0], row[1], row[2])
+ except (IOError, IndexError) as e:
+ errstr = 'Invalid accounts file: ' + str(e)
+ finally:
+ if csvfile:
+ csvfile.close()
+
+ return errstr
+
+ def _config_data_check(self, new_config):
+ ''' Check whether the new config data is valid or
+ not. '''
+ errstr = None
+ for key in new_config:
+ if key == 'version':
+ continue
+ elif key in ['key_file', 'cert_file']:
+ #TODO, only check whether the file exist,
+ # further check need to be done: eg. whether
+ # the private/certificate is valid.
+ path = new_config[key]
+ if not os.path.exists(path):
+ errstr = "the file doesn't exist: " + path
+ elif key == 'accounts_file':
+ errstr = self._accounts_file_check(new_config[key])
+ else:
+ errstr = 'unknown config item: ' + key
+
+ if errstr != None:
+ self.log_info('Fail to apply config data, ' + errstr)
+ return ccsession.create_answer(1, errstr)
+
+ return ccsession.create_answer(0)
+
+ def config_handler(self, new_config):
+ answer = self._config_data_check(new_config)
+ rcode, val = ccsession.parse_answer(answer)
+ if rcode != 0:
+ return answer
+
+ with self._lock:
+ for key in new_config:
+ if key in self._cmdctl_config_data:
+ self._cmdctl_config_data[key] = new_config[key]
+ return answer
+
+ def command_handler(self, command, args):
+ answer = ccsession.create_answer(0)
+ if command == ccsession.COMMAND_MODULE_SPECIFICATION_UPDATE:
+ with self._lock:
+ self.modules_spec[args[0]] = args[1]
+
+ elif command == ccsession.COMMAND_SHUTDOWN:
+ #When cmdctl get 'shutdown' command from boss,
+ #shutdown the outer httpserver.
+ self._httpserver.shutdown()
+ self._serving = False
+
+ elif command == 'print_settings':
+ answer = ccsession.create_answer(0, self._cmdctl_config_data)
+ else:
+ answer = ccsession.create_answer(1, 'unknown command: ' + command)
+
+ return answer
+
+ def _start_msg_handle_thread(self):
+ ''' Start one thread to handle received message from msgq.'''
+ td = threading.Thread(target=self._handle_msg_from_msgq)
+ td.daemon = True
+ td.start()
+
+ def _handle_msg_from_msgq(self):
+ '''Process all the received commands with module session. '''
+ while self._serving:
+ self._module_cc.check_command()
+
def _parse_command_result(self, rcode, reply):
'''Ignore the error reason when command rcode isn't 0, '''
if rcode != 0:
return {}
return reply
+ def _get_config_data_from_config_manager(self):
+ '''Get config data for all modules from configmanager '''
+ rcode, reply = self.send_command('ConfigManager', ccsession.COMMAND_GET_CONFIG)
+ return self._parse_command_result(rcode, reply)
+
+ def _update_config_data(self, module_name, command_name):
+ '''Get lastest config data for all modules from configmanager '''
+ if module_name == 'ConfigManager' and command_name == ccsession.COMMAND_SET_CONFIG:
+ data = self._get_config_data_from_config_manager()
+ with self._lock:
+ self._config_data = data
+
def get_config_data(self):
- '''Get config data for all modules from configmanager '''
- rcode, reply = self.send_command('ConfigManager', isc.config.ccsession.COMMAND_GET_CONFIG)
+ with self._lock:
+ data = self._config_data
+ return data
+
+ def get_modules_spec(self):
+ with self._lock:
+ spec = self.modules_spec
+ return spec
+
+ def _get_modules_specification(self):
+ '''Get all the modules' specification files. '''
+ rcode, reply = self.send_command('ConfigManager', ccsession.COMMAND_GET_MODULE_SPEC)
return self._parse_command_result(rcode, reply)
-
- def update_config_data(self, module_name, command_name):
- '''Get lastest config data for all modules from configmanager '''
- if module_name == 'ConfigManager' and command_name == isc.config.ccsession.COMMAND_SET_CONFIG:
- self.config_data = self.get_config_data()
-
- def get_module_specification(self):
- rcode, reply = self.send_command('ConfigManager', isc.config.ccsession.COMMAND_GET_MODULE_SPEC)
- return self._parse_command_result(rcode, reply)
-
- def handle_recv_msg(self):
- '''Handle received message, if 'shutdown' is received, return False'''
- (message, env) = self.cc.group_recvmsg(True)
- command, arg = isc.config.ccsession.parse_command(message)
- while command:
- if command == isc.config.ccsession.COMMAND_MODULE_SPECIFICATION_UPDATE:
- self.module_spec[arg[0]] = arg[1]
- elif command == isc.config.ccsession.COMMAND_SHUTDOWN:
- return False
- (message, env) = self.cc.group_recvmsg(True)
- command, arg = isc.config.ccsession.parse_command(message)
-
- return True
-
def send_command_with_check(self, module_name, command_name, params = None):
'''Before send the command to modules, check if module_name, command_name
parameters are legal according the spec file of the module.
- Return rcode, dict.
+ Return rcode, dict. TODO, the rcode should be defined properly.
rcode = 0: dict is the correct returned value.
rcode > 0: dict is : { 'error' : 'error reason' }
'''
-
# core module ConfigManager does not have a specification file
if module_name == 'ConfigManager':
return self.send_command(module_name, command_name, params)
- if module_name not in self.module_spec.keys():
+ specs = self.get_modules_spec()
+ if module_name not in specs.keys():
return 1, {'error' : 'unknown module'}
- spec_obj = isc.config.module_spec.ModuleSpec(self.module_spec[module_name], False)
+ spec_obj = isc.config.module_spec.ModuleSpec(specs[module_name], False)
errors = []
if not spec_obj.validate_command(command_name, params, errors):
return 1, {'error': errors[0]}
@@ -281,123 +379,157 @@
def send_command(self, module_name, command_name, params = None):
'''Send the command from bindctl to proper module. '''
-
- errstr = 'no error'
+ errstr = 'unknown error'
if self._verbose:
- self.log_info('[b10-cmdctl] send command \'%s\' to %s\n' %(command_name, module_name))
- try:
- msg = isc.config.ccsession.create_command(command_name, params)
- seq = self.cc.group_sendmsg(msg, module_name)
+ self.log_info("Begin send command '%s' to module '%s'" %(command_name, module_name))
+
+ if module_name == self._module_name:
+ # Process the command sent to cmdctl directly.
+ answer = self.command_handler(command_name, params)
+ else:
+ msg = ccsession.create_command(command_name, params)
+ seq = self._cc.group_sendmsg(msg, module_name)
#TODO, it may be blocked, msqg need to add a new interface waiting in timeout.
- answer, env = self.cc.group_recvmsg(False, seq)
- if answer:
- try:
- rcode, arg = isc.config.ccsession.parse_answer(answer)
- if rcode == 0:
- self.update_config_data(module_name, command_name)
- if arg != None:
- return rcode, arg
- else:
- return rcode, {}
+ answer, env = self._cc.group_recvmsg(False, seq)
+
+ if self._verbose:
+ self.log_info("Finish send command '%s' to module '%s'" % (command_name, module_name))
+
+ if answer:
+ try:
+ rcode, arg = ccsession.parse_answer(answer)
+ if rcode == 0:
+ self._update_config_data(module_name, command_name)
+ if arg != None:
+ return rcode, arg
else:
- # todo: exception
- errstr = str(answer['result'][1])
- except isc.config.ccsession.ModuleCCSessionError as mcse:
- errstr = str("Error in ccsession answer:") + str(mcse)
- self.log_info(answer)
- except Exception as e:
- errstr = str(e)
- self.log_info('\'%s\':[b10-cmdctl] fail send command \'%s\' to %s\n' % (e, command_name, module_name))
+ return rcode, {}
+ else:
+ # TODO: exception
+ errstr = str(answer['result'][1])
+ except ccsession.ModuleCCSessionError as mcse:
+ errstr = str("Error in ccsession answer:") + str(mcse)
+ self.log_info(errstr)
return 1, {'error': errstr}
def log_info(self, msg):
sys.stdout.write("[b10-cmdctl] %s\n" % str(msg))
+ def get_cmdctl_config_data(self):
+ ''' If running in source code tree, use keyfile, certificate
+ and user accounts file in source code. '''
+ if "B10_FROM_SOURCE" in os.environ:
+ sysconf_path = os.environ["B10_FROM_SOURCE"] + "/src/bin/cmdctl/"
+ accountsfile = sysconf_path + "cmdctl-accounts.csv"
+ keyfile = sysconf_path + "cmdctl-keyfile.pem"
+ certfile = sysconf_path + "cmdctl-certfile.pem"
+ return (keyfile, certfile, accountsfile)
+
+ with self._lock:
+ keyfile = self._cmdctl_config_data.get('key_file')
+ certfile = self._cmdctl_config_data.get('cert_file')
+ accountsfile = self._cmdctl_config_data.get('accounts_file')
+
+ return (keyfile, certfile, accountsfile)
+
class SecureHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
'''Make the server address can be reused.'''
allow_reuse_address = True
- def __init__(self, server_address, RequestHandlerClass, idle_timeout = 1200, verbose = False):
+ def __init__(self, server_address, RequestHandlerClass,
+ CommandControlClass,
+ idle_timeout = 1200, verbose = False):
'''idle_timeout: the max idle time for login'''
http.server.HTTPServer.__init__(self, server_address, RequestHandlerClass)
self.user_sessions = {}
self.idle_timeout = idle_timeout
- self.cmdctrl = CommandControl()
- self.__is_shut_down = threading.Event()
- self.__serving = False
+ self.cmdctl = CommandControlClass(self, verbose)
self._verbose = verbose
- self.user_infos = {}
- self._read_user_info()
-
- def _read_user_info(self):
- '''Read all user's name and its' password from csv file.'''
- csvfile = None
- try:
- csvfile = open(USER_INFO_FILE)
- reader = csv.reader(csvfile)
- for row in reader:
- self.user_infos[row[0]] = [row[1], row[2]]
- except Exception as e:
- self.log_info('[b10-cmdctl] Fail to read user information :\'%s\'\n' % e)
- finally:
- if csvfile:
- csvfile.close()
-
+ self._lock = threading.Lock()
+ self._user_infos = {}
+ self._accounts_file = None
+
+ def _create_user_info(self, accounts_file):
+ '''Read all user's name and its' salt, hashed password
+ from accounts file.'''
+ if (self._accounts_file == accounts_file) and (len(self._user_infos) > 0):
+ return
+
+ with self._lock:
+ self._user_infos = {}
+ csvfile = None
+ try:
+ csvfile = open(accounts_file)
+ reader = csv.reader(csvfile)
+ for row in reader:
+ self._user_infos[row[0]] = [row[1], row[2]]
+ except (IOError, IndexError) as e:
+ self.log_info("Fail to read user database, %s" % e)
+ finally:
+ if csvfile:
+ csvfile.close()
+
+ self._accounts_file = accounts_file
+ if len(self._user_infos) == 0:
+ self.log_info("Fail to get user information, will deny any user")
+
+ def get_user_info(self, username):
+ '''Get user's salt and hashed string. If the user
+ doesn't exist, return None, or else, the list
+ [salt, hashed password] will be returned.'''
+ with self._lock:
+ info = self._user_infos.get(username)
+ return info
+
def save_user_session_id(self, session_id):
- # Record user's id and login time.
+ ''' Record user's id and login time. '''
self.user_sessions[session_id] = time.time()
+ def _check_key_and_cert(self, key, cert):
+ # TODO, check the content of key/certificate file
+ if not os.path.exists(key):
+ raise CmdctlException("key file '%s' doesn't exist " % key)
+
+ if not os.path.exists(cert):
+ raise CmdctlException("certificate file '%s' doesn't exist " % cert)
+
+ def _wrap_socket_in_ssl_context(self, sock, key, cert):
+ try:
+ self._check_key_and_cert(key, cert)
+ ssl_sock = ssl.wrap_socket(sock,
+ server_side = True,
+ certfile = cert,
+ keyfile = key,
+ ssl_version = ssl.PROTOCOL_SSLv23)
+ return ssl_sock
+ except (ssl.SSLError, CmdctlException) as err :
+ self.log_info("Deny client's connection because %s" % str(err))
+ self.close_request(sock)
+ # raise socket error to finish the request
+ raise socket.error
+
def get_request(self):
'''Get client request socket and wrap it in SSL context. '''
+ key, cert, account_file = self.cmdctl.get_cmdctl_config_data()
+ self._create_user_info(account_file)
newsocket, fromaddr = self.socket.accept()
- try:
- connstream = ssl.wrap_socket(newsocket,
- server_side = True,
- certfile = CERTIFICATE_FILE,
- keyfile = PRIVATE_KEY_FILE,
- ssl_version = ssl.PROTOCOL_SSLv23)
- return (connstream, fromaddr)
- except ssl.SSLError as e :
- self.log_info('[b10-cmdctl] deny client\'s invalid connection:\'%s\'\n' % e)
- self.close_request(newsocket)
- # raise socket error to finish the request
- raise socket.error
-
+ ssl_sock = self._wrap_socket_in_ssl_context(newsocket, key, cert)
+ return (ssl_sock, fromaddr)
def get_reply_data_for_GET(self, id, module):
'''Currently only support the following three url GET request '''
rcode, reply = http.client.NO_CONTENT, []
if not module:
- if id == 'config_data':
- rcode, reply = http.client.OK, self.cmdctrl.config_data
- elif id == 'module_spec':
- rcode, reply = http.client.OK, self.cmdctrl.module_spec
+ if id == CONFIG_DATA_URL:
+ rcode, reply = http.client.OK, self.cmdctl.get_config_data()
+ elif id == MODULE_SPEC_URL:
+ rcode, reply = http.client.OK, self.cmdctl.get_modules_spec()
return rcode, reply
-
- def serve_forever(self, poll_interval = 0.5):
- '''Start cmdctl as one tcp server. '''
- self.__serving = True
- self.__is_shut_down.clear()
- while self.__serving:
- if not self.cmdctrl.handle_recv_msg():
- break
-
- r, w, e = select.select([self], [], [], poll_interval)
- if r:
- self._handle_request_noblock()
-
- self.__is_shut_down.set()
-
- def shutdown(self):
- self.__serving = False
- self.__is_shut_down.wait()
-
-
def send_command_to_module(self, module_name, command_name, params):
- return self.cmdctrl.send_command_with_check(module_name, command_name, params)
+ return self.cmdctl.send_command_with_check(module_name, command_name, params)
def log_info(self, msg):
sys.stdout.write("[b10-cmdctl] %s\n" % str(msg))
@@ -416,8 +548,9 @@
def run(addr = 'localhost', port = 8080, idle_timeout = 1200, verbose = False):
''' Start cmdctl as one https server. '''
if verbose:
- sys.stdout.write("[b10-cmdctl] starting on :%s port:%d\n" %(addr, port))
- httpd = SecureHTTPServer((addr, port), SecureHTTPRequestHandler, idle_timeout, verbose)
+ sys.stdout.write("[b10-cmdctl] starting on %s port:%d\n" %(addr, port))
+ httpd = SecureHTTPServer((addr, port), SecureHTTPRequestHandler,
+ CommandControl, idle_timeout, verbose)
httpd.serve_forever()
def check_port(option, opt_str, value, parser):
@@ -453,13 +586,12 @@
parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False,
help="display more about what is going on")
-
if __name__ == '__main__':
try:
+ set_signal_handler()
parser = OptionParser(version = __version__)
set_cmd_options(parser)
(options, args) = parser.parse_args()
- set_signal_handler()
run(options.addr, options.port, options.idle_timeout, options.verbose)
except isc.cc.SessionError as se:
sys.stderr.write("[b10-cmdctl] Error creating b10-cmdctl, "
Modified: branches/trac172/src/bin/cmdctl/tests/Makefile.am
==============================================================================
--- branches/trac172/src/bin/cmdctl/tests/Makefile.am (original)
+++ branches/trac172/src/bin/cmdctl/tests/Makefile.am Wed Jun 30 18:48:15 2010
@@ -8,5 +8,7 @@
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/cmdctl \
+ CMDCTL_SPEC_PATH=$(abs_top_builddir)/src/bin/cmdctl \
+ CMDCTL_SRC_PATH=$(abs_top_srcdir)/src/bin/cmdctl \
$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
done
Modified: branches/trac172/src/bin/cmdctl/tests/cmdctl_test.in
==============================================================================
--- branches/trac172/src/bin/cmdctl/tests/cmdctl_test.in (original)
+++ branches/trac172/src/bin/cmdctl/tests/cmdctl_test.in Wed Jun 30 18:48:15 2010
@@ -18,10 +18,10 @@
PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
export PYTHON_EXEC
-BINDCTL_TEST_PATH=@abs_top_srcdir@/src/bin/cmdctl/tests
+CMDCTL_TEST_PATH=@abs_top_srcdir@/src/bin/cmdctl/tests
PYTHONPATH=@abs_top_srcdir@/src/bin/cmdctl
export PYTHONPATH
-cd ${BINDCTL_TEST_PATH}
+cd ${CMDCTL_TEST_PATH}
exec ${PYTHON_EXEC} -O cmdctl_test.py $*
Modified: branches/trac172/src/bin/cmdctl/tests/cmdctl_test.py
==============================================================================
--- branches/trac172/src/bin/cmdctl/tests/cmdctl_test.py (original)
+++ branches/trac172/src/bin/cmdctl/tests/cmdctl_test.py Wed Jun 30 18:48:15 2010
@@ -16,7 +16,16 @@
import unittest
import socket
+import tempfile
from cmdctl import *
+
+SPEC_FILE_PATH = '..' + os.sep
+if 'CMDCTL_SPEC_PATH' in os.environ:
+ SPEC_FILE_PATH = os.environ['CMDCTL_SPEC_PATH'] + os.sep
+
+SRC_FILE_PATH = '..' + os.sep
+if 'CMDCTL_SRC_PATH' in os.environ:
+ SRC_FILE_PATH = os.environ['CMDCTL_SRC_PATH'] + os.sep
# Rewrite the class for unittest.
class MySecureHTTPRequestHandler(SecureHTTPRequestHandler):
@@ -42,17 +51,20 @@
os.remove('tmp.file')
-class MySecureHTTPServer(SecureHTTPServer):
+class FakeSecureHTTPServer(SecureHTTPServer):
def __init__(self):
self.user_sessions = {}
+ self.cmdctl = FakeCommandControlForTestRequestHandler()
+ self._verbose = True
+ self._user_infos = {}
self.idle_timeout = 1200
- self.cmdctrl = MyCommandControl()
- self._verbose = False
-
-class MyCommandControl(CommandControl):
+ self._lock = threading.Lock()
+
+class FakeCommandControlForTestRequestHandler(CommandControl):
def __init__(self):
- self.config_data = {}
- self.module_spec = {}
+ self._config_data = {}
+ self.modules_spec = {}
+ self._lock = threading.Lock()
def send_command(self, mod, cmd, param):
return 0, {}
@@ -60,14 +72,17 @@
class TestSecureHTTPRequestHandler(unittest.TestCase):
def setUp(self):
+ self.old_stdout = sys.stdout
+ sys.stdout = open(os.devnull, 'w')
self.handler = MySecureHTTPRequestHandler()
- self.handler.server = MySecureHTTPServer()
+ self.handler.server = FakeSecureHTTPServer()
self.handler.server.user_sessions = {}
- self.handler.server.user_infos = {}
+ self.handler.server._user_infos = {}
self.handler.headers = {}
self.handler.rfile = open("check.tmp", 'w+b')
def tearDown(self):
+ sys.stdout = self.old_stdout
self.handler.rfile.close()
os.remove('check.tmp')
@@ -145,7 +160,7 @@
def test_check_user_name_and_pwd(self):
self.handler.headers = {}
ret, msg = self.handler._check_user_name_and_pwd()
- self.assertTrue(ret == False)
+ self.assertFalse(ret)
self.assertEqual(msg, ['invalid username or password'])
def test_check_user_name_and_pwd_1(self):
@@ -154,9 +169,9 @@
self.handler.headers['Content-Length'] = len
self.handler.rfile.seek(0, 0)
- self.handler.server.user_infos['root'] = ['aa', 'aaa']
- ret, msg = self.handler._check_user_name_and_pwd()
- self.assertTrue(ret == False)
+ self.handler.server._user_infos['root'] = ['aa', 'aaa']
+ ret, msg = self.handler._check_user_name_and_pwd()
+ self.assertFalse(ret)
self.assertEqual(msg, ['password doesn\'t match'])
def test_check_user_name_and_pwd_2(self):
@@ -166,7 +181,7 @@
self.handler.rfile.seek(0, 0)
ret, msg = self.handler._check_user_name_and_pwd()
- self.assertTrue(ret == False)
+ self.assertFalse(ret)
self.assertEqual(msg, ['invalid username or password'])
def test_check_user_name_and_pwd_3(self):
@@ -176,7 +191,7 @@
self.handler.rfile.seek(0, 0)
ret, msg = self.handler._check_user_name_and_pwd()
- self.assertTrue(ret == False)
+ self.assertFalse(ret)
self.assertEqual(msg, ['need user name'])
def test_check_user_name_and_pwd_4(self):
@@ -185,9 +200,9 @@
self.handler.headers['Content-Length'] = len
self.handler.rfile.seek(0, 0)
- self.handler.server.user_infos['root'] = ['aa', 'aaa']
- ret, msg = self.handler._check_user_name_and_pwd()
- self.assertTrue(ret == False)
+ self.handler.server._user_infos['root'] = ['aa', 'aaa']
+ ret, msg = self.handler._check_user_name_and_pwd()
+ self.assertFalse(ret)
self.assertEqual(msg, ['need password'])
def test_check_user_name_and_pwd_5(self):
@@ -197,7 +212,7 @@
self.handler.rfile.seek(0, 0)
ret, msg = self.handler._check_user_name_and_pwd()
- self.assertTrue(ret == False)
+ self.assertFalse(ret)
self.assertEqual(msg, ['user doesn\'t exist'])
def test_do_POST(self):
@@ -247,8 +262,8 @@
self.handler.rfile.seek(0, 0)
self.handler.path = '/module/command'
- self.handler.server.cmdctrl.module_spec = {}
- self.handler.server.cmdctrl.module_spec['module'] = self._gen_module_spec()
+ self.handler.server.cmdctl.modules_spec = {}
+ self.handler.server.cmdctl.modules_spec['module'] = self._gen_module_spec()
rcode, reply = self.handler._handle_post_request()
self.assertEqual(http.client.OK, rcode)
@@ -259,10 +274,160 @@
self.handler.rfile.seek(0, 0)
self.handler.path = '/module/command'
- self.handler.server.cmdctrl.module_spec = {}
- self.handler.server.cmdctrl.module_spec['module'] = self._gen_module_spec()
+ self.handler.server.cmdctl.modules_spec = {}
+ self.handler.server.cmdctl.modules_spec['module'] = self._gen_module_spec()
rcode, reply = self.handler._handle_post_request()
self.assertEqual(http.client.BAD_REQUEST, rcode)
+class MyCommandControl(CommandControl):
+ def _get_modules_specification(self):
+ return {}
+
+ def _get_config_data_from_config_manager(self):
+ return {}
+
+ def _setup_session(self):
+ spec_file = SPEC_FILE_PATH + 'cmdctl.spec'
+ module_spec = isc.config.module_spec_from_file(spec_file)
+ config = isc.config.config_data.ConfigData(module_spec)
+ self._module_name = 'Cmdctl'
+ self._cmdctl_config_data = config.get_full_config()
+
+ def _handle_msg_from_msgq(self):
+ pass
+
+class TestCommandControl(unittest.TestCase):
+
+ def setUp(self):
+ self.old_stdout = sys.stdout
+ sys.stdout = open(os.devnull, 'w')
+ self.cmdctl = MyCommandControl(None, True)
+
+ def tearDown(self):
+ sys.stdout = self.old_stdout
+
+ def _check_config(self, cmdctl):
+ key, cert, account = cmdctl.get_cmdctl_config_data()
+ self.assertIsNotNone(key)
+ self.assertIsNotNone(cert)
+ self.assertIsNotNone(account)
+
+ def test_get_cmdctl_config_data(self):
+ old_env = os.environ
+ if 'B10_FROM_SOURCE' in os.environ:
+ del os.environ['B10_FROM_SOURCE']
+ self.cmdctl.get_cmdctl_config_data()
+ self._check_config(self.cmdctl)
+ os.environ = old_env
+
+ old_env = os.environ
+ os.environ['B10_FROM_SOURCE'] = '../'
+ self._check_config(self.cmdctl)
+ os.environ = old_env
+
+ def test_parse_command_result(self):
+ self.assertEqual({}, self.cmdctl._parse_command_result(1, {'error' : 1}))
+ self.assertEqual({'a': 1}, self.cmdctl._parse_command_result(0, {'a' : 1}))
+
+ def _check_answer(self, answer, rcode_, msg_):
+ rcode, msg = ccsession.parse_answer(answer)
+ self.assertEqual(rcode, rcode_)
+ self.assertEqual(msg, msg_)
+
+ def test_command_handler(self):
+ answer = self.cmdctl.command_handler('unknown-command', None)
+ self._check_answer(answer, 1, 'unknown command: unknown-command')
+
+ answer = self.cmdctl.command_handler('print_settings', None)
+ rcode, msg = ccsession.parse_answer(answer)
+ self.assertEqual(rcode, 0)
+ self.assertTrue(msg != None)
+
+ def test_check_config_handler(self):
+ answer = self.cmdctl.config_handler({'non-exist': 123})
+ self._check_answer(answer, 1, 'unknown config item: non-exist')
+
+ old_env = os.environ
+ os.environ['B10_FROM_SOURCE'] = '../'
+ self._check_config(self.cmdctl)
+ os.environ = old_env
+
+ answer = self.cmdctl.config_handler({'key_file': '/user/non-exist_folder'})
+ self._check_answer(answer, 1, "the file doesn't exist: /user/non-exist_folder")
+
+ answer = self.cmdctl.config_handler({'cert_file': '/user/non-exist_folder'})
+ self._check_answer(answer, 1, "the file doesn't exist: /user/non-exist_folder")
+
+ answer = self.cmdctl.config_handler({'accounts_file': '/user/non-exist_folder'})
+ self._check_answer(answer, 1,
+ "Invalid accounts file: [Errno 2] No such file or directory: '/user/non-exist_folder'")
+
+ # Test with invalid accounts file
+ file_name = 'tmp.account.file'
+ temp_file = open(file_name, 'w')
+ writer = csv.writer(temp_file)
+ writer.writerow(['a', 'b'])
+ temp_file.close()
+ answer = self.cmdctl.config_handler({'accounts_file': file_name})
+ self._check_answer(answer, 1, "Invalid accounts file: list index out of range")
+ os.remove(file_name)
+
+ def test_send_command(self):
+ rcode, value = self.cmdctl.send_command('Cmdctl', 'print_settings', None)
+ self.assertEqual(rcode, 0)
+
+class MySecureHTTPServer(SecureHTTPServer):
+ def server_bind(self):
+ pass
+
+class TestSecureHTTPServer(unittest.TestCase):
+ def setUp(self):
+ self.old_stdout = sys.stdout
+ sys.stdout = open(os.devnull, 'w')
+ self.server = MySecureHTTPServer(('localhost', 8080),
+ MySecureHTTPRequestHandler,
+ MyCommandControl, verbose=True)
+
+ def tearDown(self):
+ sys.stdout = self.old_stdout
+
+ def test_create_user_info(self):
+ self.server._create_user_info('/local/not-exist')
+ self.assertEqual(0, len(self.server._user_infos))
+
+ self.server._create_user_info(SRC_FILE_PATH + 'cmdctl-accounts.csv')
+ self.assertEqual(1, len(self.server._user_infos))
+ self.assertTrue('root' in self.server._user_infos)
+
+ def test_check_key_and_cert(self):
+ self.assertRaises(CmdctlException, self.server._check_key_and_cert,
+ '/local/not-exist', 'cmdctl-keyfile.pem')
+
+ self.server._check_key_and_cert(SRC_FILE_PATH + 'cmdctl-keyfile.pem',
+ SRC_FILE_PATH + 'cmdctl-certfile.pem')
+
+ def test_wrap_sock_in_ssl_context(self):
+ sock = socket.socket()
+ self.assertRaises(socket.error,
+ self.server._wrap_socket_in_ssl_context,
+ sock,
+ '../cmdctl-keyfile',
+ '../cmdctl-certfile')
+
+ sock1 = socket.socket()
+ self.server._wrap_socket_in_ssl_context(sock1,
+ SRC_FILE_PATH + 'cmdctl-keyfile.pem',
+ SRC_FILE_PATH + 'cmdctl-certfile.pem')
+
+class TestFuncNotInClass(unittest.TestCase):
+ def test_check_port(self):
+ self.assertRaises(OptionValueError, check_port, None, 'port', -1, None)
+ self.assertRaises(OptionValueError, check_port, None, 'port', 65536, None)
+ self.assertRaises(OptionValueError, check_addr, None, 'ipstr', 'a.b.d', None)
+ self.assertRaises(OptionValueError, check_addr, None, 'ipstr', '1::0:a.b', None)
+
+
if __name__== "__main__":
unittest.main()
+
+
Modified: branches/trac172/src/bin/host/Makefile.am
==============================================================================
--- branches/trac172/src/bin/host/Makefile.am (original)
+++ branches/trac172/src/bin/host/Makefile.am Wed Jun 30 18:48:15 2010
@@ -7,7 +7,7 @@
bin_PROGRAMS = host
host_SOURCES = host.cc
-host_LDADD = $(top_builddir)/src/lib/dns/.libs/libdns.a
+host_LDADD = $(top_builddir)/src/lib/dns/.libs/libdns++.a
host_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
#man_MANS = host.1
Modified: branches/trac172/src/bin/host/host.cc
==============================================================================
--- branches/trac172/src/bin/host/host.cc (original)
+++ branches/trac172/src/bin/host/host.cc Wed Jun 30 18:48:15 2010
@@ -19,6 +19,8 @@
#include <sys/time.h> // for gettimeofday
#include <sys/socket.h> // networking functions and definitions on FreeBSD
+#include <unistd.h>
+
#include <string>
#include <iostream>
Modified: branches/trac172/src/bin/loadzone/Makefile.am
==============================================================================
--- branches/trac172/src/bin/loadzone/Makefile.am (original)
+++ branches/trac172/src/bin/loadzone/Makefile.am Wed Jun 30 18:48:15 2010
@@ -1,3 +1,5 @@
+SUBDIRS = tests/correct
+SUBDIRS += tests/error
bin_SCRIPTS = b10-loadzone
CLEANFILES = b10-loadzone
@@ -22,23 +24,27 @@
$(mkinstalldirs) $(DESTDIR)/@localstatedir@/@PACKAGE@
# TODO: permissions handled later
-EXTRA_DIST += testdata/README
-EXTRA_DIST += testdata/dsset-subzone.example.com.
-EXTRA_DIST += testdata/example.com
-EXTRA_DIST += testdata/example.com.signed
-EXTRA_DIST += testdata/Kexample.com.+005+04456.key
-EXTRA_DIST += testdata/Kexample.com.+005+04456.private
-EXTRA_DIST += testdata/Kexample.com.+005+33495.key
-EXTRA_DIST += testdata/Kexample.com.+005+33495.private
-EXTRA_DIST += testdata/Ksql1.example.com.+005+12447.key
-EXTRA_DIST += testdata/Ksql1.example.com.+005+12447.private
-EXTRA_DIST += testdata/Ksql1.example.com.+005+33313.key
-EXTRA_DIST += testdata/Ksql1.example.com.+005+33313.private
-EXTRA_DIST += testdata/Ksql2.example.com.+005+38482.key
-EXTRA_DIST += testdata/Ksql2.example.com.+005+38482.private
-EXTRA_DIST += testdata/Ksql2.example.com.+005+63192.key
-EXTRA_DIST += testdata/Ksql2.example.com.+005+63192.private
-EXTRA_DIST += testdata/sql1.example.com
-EXTRA_DIST += testdata/sql1.example.com.signed
-EXTRA_DIST += testdata/sql2.example.com
-EXTRA_DIST += testdata/sql2.example.com.signed
+EXTRA_DIST += tests/normal/README
+EXTRA_DIST += tests/normal/dsset-subzone.example.com
+EXTRA_DIST += tests/normal/example.com
+EXTRA_DIST += tests/normal/example.com.signed
+EXTRA_DIST += tests/normal/Kexample.com.+005+04456.key
+EXTRA_DIST += tests/normal/Kexample.com.+005+04456.private
+EXTRA_DIST += tests/normal/Kexample.com.+005+33495.key
+EXTRA_DIST += tests/normal/Kexample.com.+005+33495.private
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+12447.key
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+12447.private
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+33313.key
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+33313.private
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+38482.key
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+38482.private
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+63192.key
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+63192.private
+EXTRA_DIST += tests/normal/sql1.example.com
+EXTRA_DIST += tests/normal/sql1.example.com.signed
+EXTRA_DIST += tests/normal/sql2.example.com
+EXTRA_DIST += tests/normal/sql2.example.com.signed
+
+pytest:
+ $(SHELL) tests/correct/correct_test.sh
+ $(SHELL) tests/error/error_test.sh
Modified: branches/trac172/src/bin/loadzone/b10-loadzone.py.in
==============================================================================
--- branches/trac172/src/bin/loadzone/b10-loadzone.py.in (original)
+++ branches/trac172/src/bin/loadzone/b10-loadzone.py.in Wed Jun 30 18:48:15 2010
@@ -19,7 +19,8 @@
import re, getopt
import isc.datasrc
from isc.datasrc.master import MasterFile
-
+import time
+import os
#########################################################################
# usage: print usage note and exit
#########################################################################
@@ -57,23 +58,32 @@
if len(args) != 1:
usage()
zonefile = args[0]
-
+ verbose = os.isatty(sys.stdout.fileno())
try:
- master = MasterFile(zonefile, initial_origin)
+ master = MasterFile(zonefile, initial_origin, verbose)
except Exception as e:
- print("Error reading zone file: " + str(e))
+ sys.stderr.write("Error reading zone file: %s\n" % str(e))
exit(1)
try:
zone = master.zonename()
+ if verbose:
+ sys.stdout.write("Using SQLite3 database file %s\n" % dbfile)
+ sys.stdout.write("Zone name is %s\n" % zone)
+ sys.stdout.write("Loading file \"%s\"\n" % zonefile)
except Exception as e:
- print("Error reading zone file: " + str(e))
+ sys.stdout.write("\n")
+ sys.stderr.write("Error reading zone file: %s\n" % str(e))
exit(1)
try:
isc.datasrc.sqlite3_ds.load(dbfile, zone, master.zonedata)
+ if verbose:
+ master.closeverbose()
+ sys.stdout.write("\nDone.\n")
except Exception as e:
- print("Error loading database: " + str(e))
+ sys.stdout.write("\n")
+ sys.stderr.write("Error loading database: %s\n"% str(e))
exit(1)
if __name__ == "__main__":
Modified: branches/trac172/src/bin/loadzone/run_loadzone.sh.in
==============================================================================
--- branches/trac172/src/bin/loadzone/run_loadzone.sh.in (original)
+++ branches/trac172/src/bin/loadzone/run_loadzone.sh.in Wed Jun 30 18:48:15 2010
@@ -21,5 +21,5 @@
PYTHONPATH=@abs_top_builddir@/src/lib/python
export PYTHONPATH
-LOADZONE_PATH=@abs_top_srcdir@/src/bin/loadzone
+LOADZONE_PATH=@abs_top_builddir@/src/bin/loadzone
exec ${LOADZONE_PATH}/b10-loadzone $*
Modified: branches/trac172/src/bin/xfrin/tests/Makefile.am
==============================================================================
--- branches/trac172/src/bin/xfrin/tests/Makefile.am (original)
+++ branches/trac172/src/bin/xfrin/tests/Makefile.am Wed Jun 30 18:48:15 2010
@@ -1,7 +1,5 @@
PYTESTS = xfrin_test.py
EXTRA_DIST = $(PYTESTS)
-
-if HAVE_BOOST_PYTHON
# later will have configure option to choose this, like: coverage run --branch
PYCOVERAGE = $(PYTHON)
@@ -9,8 +7,6 @@
check-local:
for pytest in $(PYTESTS) ; do \
echo Running test: $$pytest ; \
- env PYTHONPATH=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/bin/xfrin:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
+ env PYTHONPATH=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/bin/xfrin:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
done
-
-endif
Modified: branches/trac172/src/bin/xfrin/tests/xfrin_test.py
==============================================================================
--- branches/trac172/src/bin/xfrin/tests/xfrin_test.py (original)
+++ branches/trac172/src/bin/xfrin/tests/xfrin_test.py Wed Jun 30 18:48:15 2010
@@ -23,7 +23,7 @@
# Commonly used (mostly constant) test parameters
#
TEST_ZONE_NAME = "example.com"
-TEST_RRCLASS = rr_class.IN()
+TEST_RRCLASS = RRClass.IN()
TEST_DB_FILE = 'db_file'
TEST_MASTER_IPV4_ADDRESS = '127.0.0.1'
TEST_MASTER_IPV4_ADDRINFO = (socket.AF_INET, socket.SOCK_STREAM,
@@ -37,16 +37,16 @@
# If some other process uses this port test will fail.
TEST_MASTER_PORT = '53535'
-soa_rdata = create_rdata(rr_type.SOA(), TEST_RRCLASS,
- 'master.example.com. admin.example.com ' +
- '1234 3600 1800 2419200 7200')
-soa_rrset = rrset(name(TEST_ZONE_NAME), TEST_RRCLASS, rr_type.SOA(),
- rr_ttl(3600))
+soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
+ 'master.example.com. admin.example.com ' +
+ '1234 3600 1800 2419200 7200')
+soa_rrset = RRset(Name(TEST_ZONE_NAME), TEST_RRCLASS, RRType.SOA(),
+ RRTTL(3600))
soa_rrset.add_rdata(soa_rdata)
-example_axfr_question = question(name(TEST_ZONE_NAME), TEST_RRCLASS,
- rr_type.AXFR())
-example_soa_question = question(name(TEST_ZONE_NAME), TEST_RRCLASS,
- rr_type.SOA())
+example_axfr_question = Question(Name(TEST_ZONE_NAME), TEST_RRCLASS,
+ RRType.AXFR())
+example_soa_question = Question(Name(TEST_ZONE_NAME), TEST_RRCLASS,
+ RRType.SOA())
default_questions = [example_axfr_question]
default_answers = [soa_rrset]
@@ -121,26 +121,25 @@
return len(data)
def create_response_data(self, response = True, bad_qid = False,
- rcode = rcode.NOERROR(),
+ rcode = Rcode.NOERROR(),
questions = default_questions,
answers = default_answers):
- resp = message(message_mode.RENDER)
+ resp = Message(Message.RENDER)
qid = self.qid
if bad_qid:
qid += 1
resp.set_qid(qid)
- resp.set_opcode(op_code.QUERY())
+ resp.set_opcode(Opcode.QUERY())
resp.set_rcode(rcode)
if response:
- resp.set_header_flag(message_flag.QR())
+ resp.set_header_flag(MessageFlag.QR())
[resp.add_question(q) for q in questions]
- [resp.add_rrset(section.ANSWER(), a) for a in answers]
-
- obuf = output_buffer(0)
- renderer = message_render(obuf)
+ [resp.add_rrset(Section.ANSWER(), a) for a in answers]
+
+ renderer = MessageRenderer()
resp.to_wire(renderer)
- reply_data = struct.pack('H', socket.htons(obuf.get_length()))
- reply_data += obuf.get_data()
+ reply_data = struct.pack('H', socket.htons(renderer.get_length()))
+ reply_data += renderer.get_data()
return reply_data
@@ -158,7 +157,7 @@
'questions': [example_soa_question],
'bad_qid': False,
'response': True,
- 'rcode': rcode.NOERROR(),
+ 'rcode': Rcode.NOERROR(),
'axfr_after_soa': self._create_normal_response_data
}
@@ -189,11 +188,11 @@
c.close()
def test_init_chclass(self):
- c = XfrinConnection({}, 'example.com.', rr_class.CH(), TEST_DB_FILE,
+ c = XfrinConnection({}, 'example.com.', RRClass.CH(), TEST_DB_FILE,
threading.Event(), TEST_MASTER_IPV4_ADDRINFO)
- axfrmsg = c._create_query(rr_type.AXFR())
- self.assertEqual(question_iter(axfrmsg).get_question().get_class(),
- rr_class.CH())
+ axfrmsg = c._create_query(RRType.AXFR())
+ self.assertEqual(axfrmsg.get_question()[0].get_class(),
+ RRClass.CH())
c.close()
def test_response_with_invalid_msg(self):
@@ -201,41 +200,41 @@
self.assertRaises(XfrinTestException, self._handle_xfrin_response)
def test_response_without_end_soa(self):
- self.conn._send_query(rr_type.AXFR())
+ self.conn._send_query(RRType.AXFR())
self.conn.reply_data = self.conn.create_response_data()
self.assertRaises(XfrinTestException, self._handle_xfrin_response)
def test_response_bad_qid(self):
- self.conn._send_query(rr_type.AXFR())
+ self.conn._send_query(RRType.AXFR())
self.conn.reply_data = self.conn.create_response_data(bad_qid = True)
self.assertRaises(XfrinException, self._handle_xfrin_response)
def test_response_non_response(self):
- self.conn._send_query(rr_type.AXFR())
+ self.conn._send_query(RRType.AXFR())
self.conn.reply_data = self.conn.create_response_data(response = False)
self.assertRaises(XfrinException, self._handle_xfrin_response)
def test_response_error_code(self):
- self.conn._send_query(rr_type.AXFR())
+ self.conn._send_query(RRType.AXFR())
self.conn.reply_data = self.conn.create_response_data(
- rcode=rcode.SERVFAIL())
+ rcode=Rcode.SERVFAIL())
self.assertRaises(XfrinException, self._handle_xfrin_response)
def test_response_multi_question(self):
- self.conn._send_query(rr_type.AXFR())
+ self.conn._send_query(RRType.AXFR())
self.conn.reply_data = self.conn.create_response_data(
questions=[example_axfr_question, example_axfr_question])
self.assertRaises(XfrinException, self._handle_xfrin_response)
def test_response_empty_answer(self):
- self.conn._send_query(rr_type.AXFR())
+ self.conn._send_query(RRType.AXFR())
self.conn.reply_data = self.conn.create_response_data(answers=[])
# Should an empty answer trigger an exception? Even though it's very
# unusual it's not necessarily invalid. Need to revisit.
self.assertRaises(XfrinException, self._handle_xfrin_response)
def test_response_non_response(self):
- self.conn._send_query(rr_type.AXFR())
+ self.conn._send_query(RRType.AXFR())
self.conn.reply_data = self.conn.create_response_data(response = False)
self.assertRaises(XfrinException, self._handle_xfrin_response)
@@ -247,7 +246,7 @@
def test_soacheck_with_bad_response(self):
self.conn.response_generator = self._create_broken_response_data
- self.assertRaises(UserWarning, self.conn._check_soa_serial)
+ self.assertRaises(MessageTooShort, self.conn._check_soa_serial)
def test_soacheck_badqid(self):
self.soa_response_params['bad_qid'] = True
@@ -260,14 +259,14 @@
self.assertRaises(XfrinException, self.conn._check_soa_serial)
def test_soacheck_error_code(self):
- self.soa_response_params['rcode'] = rcode.SERVFAIL()
+ self.soa_response_params['rcode'] = Rcode.SERVFAIL()
self.conn.response_generator = self._create_soa_response_data
self.assertRaises(XfrinException, self.conn._check_soa_serial)
def test_response_shutdown(self):
self.conn.response_generator = self._create_normal_response_data
self.conn._shutdown_event.set()
- self.conn._send_query(rr_type.AXFR())
+ self.conn._send_query(RRType.AXFR())
self.assertRaises(XfrinException, self._handle_xfrin_response)
def test_response_timeout(self):
@@ -282,13 +281,13 @@
def test_response_bad_message(self):
self.conn.response_generator = self._create_broken_response_data
- self.conn._send_query(rr_type.AXFR())
+ self.conn._send_query(RRType.AXFR())
self.assertRaises(Exception, self._handle_xfrin_response)
def test_response(self):
# normal case.
self.conn.response_generator = self._create_normal_response_data
- self.conn._send_query(rr_type.AXFR())
+ self.conn._send_query(RRType.AXFR())
# two SOAs, and only these have been transfered. the 2nd SOA is just
# a marker, so only 1 RR has been provided in the iteration.
self.assertEqual(self._handle_xfrin_response(), 1)
@@ -317,7 +316,10 @@
def test_do_soacheck_broken_response(self):
self.conn.response_generator = self._create_broken_response_data
- self.assertEqual(self.conn.do_xfrin(True), XFRIN_FAIL)
+ # XXX: TODO: this test failed here, should xfr not raise an
+ # exception but simply drop and return FAIL?
+ #self.assertEqual(self.conn.do_xfrin(True), XFRIN_FAIL)
+ self.assertRaises(MessageTooShort, self.conn.do_xfrin, True)
def test_do_soacheck_badqid(self):
# the QID mismatch would internally trigger a XfrinException exception,
@@ -488,12 +490,12 @@
self.args)['result'][0], 1)
def test_command_handler_retransfer_nomodule(self):
- dns_module = sys.modules['bind10_dns'] # this must exist
- del sys.modules['bind10_dns']
+ dns_module = sys.modules['libdns_python'] # this must exist
+ del sys.modules['libdns_python']
self.assertEqual(self.xfr.command_handler("retransfer",
self.args)['result'][0], 1)
# sys.modules is global, so we must recover it
- sys.modules['bind10_dns'] = dns_module
+ sys.modules['libdns_python'] = dns_module
def test_command_handler_refresh(self):
# at this level, refresh is no different than retransfer.
Modified: branches/trac172/src/bin/xfrin/xfrin.py.in
==============================================================================
--- branches/trac172/src/bin/xfrin/xfrin.py.in (original)
+++ branches/trac172/src/bin/xfrin/xfrin.py.in Wed Jun 30 18:48:15 2010
@@ -29,7 +29,7 @@
from optparse import OptionParser, OptionValueError
from isc.config.ccsession import *
try:
- from bind10_dns import *
+ from libdns_python import *
except ImportError as e:
# C++ loadable module may not be installed; even so the xfrin process
# must keep running, so we warn about it and move forward.
@@ -40,11 +40,14 @@
# installed on the system
if "B10_FROM_BUILD" in os.environ:
SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrin"
+ AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
else:
PREFIX = "@prefix@"
DATAROOTDIR = "@datarootdir@"
SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+ AUTH_SPECFILE_PATH = SPECFILE_PATH
SPECFILE_LOCATION = SPECFILE_PATH + "/xfrin.spec"
+AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + "/auth.spec"
__version__ = 'BIND10'
@@ -98,14 +101,13 @@
def _create_query(self, query_type):
'''Create dns query message. '''
- msg = message(message_mode.RENDER)
+ msg = Message(Message.RENDER)
query_id = random.randint(0, 0xFFFF)
self._query_id = query_id
msg.set_qid(query_id)
- msg.set_opcode(op_code.QUERY())
- msg.set_rcode(rcode.NOERROR())
- query_question = question(name(self._zone_name), self._rrclass,
- query_type)
+ msg.set_opcode(Opcode.QUERY())
+ msg.set_rcode(Rcode.NOERROR())
+ query_question = Question(Name(self._zone_name), self._rrclass, query_type)
msg.add_question(query_question)
return msg
@@ -120,13 +122,12 @@
'''Send query message over TCP. '''
msg = self._create_query(query_type)
- obuf = output_buffer(0)
- render = message_render(obuf)
+ render = MessageRenderer()
msg.to_wire(render)
- header_len = struct.pack('H', socket.htons(obuf.get_length()))
+ header_len = struct.pack('H', socket.htons(render.get_length()))
self._send_data(header_len)
- self._send_data(obuf.get_data())
+ self._send_data(render.get_data())
def _asyncore_loop(self):
'''
@@ -157,12 +158,12 @@
True: soa serial in master is bigger
'''
- self._send_query(rr_type.SOA())
+ self._send_query(RRType("SOA"))
data_len = self._get_request_response(2)
msg_len = socket.htons(struct.unpack('H', data_len)[0])
soa_response = self._get_request_response(msg_len)
- msg = message(message_mode.PARSE)
- msg.from_wire(input_buffer(soa_response))
+ msg = Message(Message.PARSE)
+ msg.from_wire(soa_response)
# perform some minimal level validation. It's an open issue how
# strict we should be (see the comment in _check_response_header())
@@ -181,11 +182,12 @@
if check_soa:
logstr = 'SOA check for \'%s\' ' % self._zone_name
ret = self._check_soa_serial()
-
+
logstr = 'transfer of \'%s\': AXFR ' % self._zone_name
if ret == XFRIN_OK:
self.log_msg(logstr + 'started')
- self._send_query(rr_type.AXFR())
+ # TODO: .AXFR() RRType.AXFR()
+ self._send_query(RRType(252))
isc.datasrc.sqlite3_ds.load(self._db_file, self._zone_name,
self._handle_xfrin_response)
@@ -226,10 +228,10 @@
# cause interoperability trouble with stricter checks.
msg_rcode = msg.get_rcode()
- if msg_rcode != rcode.NOERROR():
+ if msg_rcode != Rcode.NOERROR():
raise XfrinException('error response: %s' % msg_rcode.to_text())
- if not msg.get_header_flag(message_flag.QR()):
+ if not msg.get_header_flag(MessageFlag.QR()):
raise XfrinException('response is not a response ')
if msg.get_qid() != self._query_id:
@@ -240,28 +242,24 @@
self._check_response_header(msg)
- if msg.get_rr_count(section.ANSWER()) == 0:
+ if msg.get_rr_count(Section.ANSWER()) == 0:
raise XfrinException('answer section is empty')
- if msg.get_rr_count(section.QUESTION()) > 1:
+ if msg.get_rr_count(Section.QUESTION()) > 1:
raise XfrinException('query section count greater than 1')
- def _handle_answer_section(self, rrset_iter):
+ def _handle_answer_section(self, answer_section):
'''Return a generator for the reponse in one tcp package to a zone transfer.'''
- while not rrset_iter.is_last():
- rrset = rrset_iter.get_rrset()
- rrset_iter.next()
+ for rrset in answer_section:
rrset_name = rrset.get_name().to_text()
rrset_ttl = int(rrset.get_ttl().to_text())
rrset_class = rrset.get_class().to_text()
rrset_type = rrset.get_type().to_text()
- rdata_iter = rrset.get_rdata_iterator()
- rdata_iter.first()
- while not rdata_iter.is_last():
+ for rdata in rrset.get_rdata():
# Count the soa record count
- if rrset.get_type() == rr_type.SOA():
+ if rrset.get_type() == RRType("SOA"):
self._soa_rr_count += 1
# XXX: the current DNS message parser can't preserve the
@@ -273,24 +271,22 @@
# Avoid inserting soa record twice
break
- rdata_text = rdata_iter.get_current().to_text()
+ rdata_text = rdata.to_text()
yield (rrset_name, rrset_ttl, rrset_class, rrset_type,
rdata_text)
- rdata_iter.next()
def _handle_xfrin_response(self):
'''Return a generator for the response to a zone transfer. '''
-
while True:
data_len = self._get_request_response(2)
msg_len = socket.htons(struct.unpack('H', data_len)[0])
recvdata = self._get_request_response(msg_len)
- msg = message(message_mode.PARSE)
- msg.from_wire(input_buffer(recvdata))
+ msg = Message(Message.PARSE)
+ msg.from_wire(recvdata)
self._check_response_status(msg)
-
- rrset_iter = section_iter(msg, section.ANSWER())
- for rr in self._handle_answer_section(rrset_iter):
+
+ answer_section = msg.get_section(Section.ANSWER())
+ for rr in self._handle_answer_section(answer_section):
yield rr
if self._soa_rr_count == 2:
@@ -411,7 +407,7 @@
# The default RR class is IN. We should fix this so that
# the class is passed in the command arg (where we specify
# the default)
- rrclass = rr_class.IN()
+ rrclass = RRClass.IN()
zone_name, master_addr, db_file = self._parse_cmd_params(args)
ret = self.xfrin_start(zone_name, rrclass, db_file, master_addr,
False if command == 'retransfer' else True)
@@ -441,7 +437,18 @@
db_file = args.get('db_file')
if not db_file:
#TODO, the db file path should be got in auth server's configuration
- db_file = '@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3'
+ # if we need access to this configuration more often, we
+ # should add it on start, and not remove it here
+ # (or, if we have writable ds, we might not need this in
+ # the first place)
+ self._cc.add_remote_config(AUTH_SPECFILE_LOCATION)
+ db_file, is_default = self._cc.get_remote_config_value("Auth", "database_file")
+ if is_default and "B10_FROM_BUILD" in os.environ:
+ # this too should be unnecessary, but currently the
+ # 'from build' override isn't stored in the config
+ # (and we don't have writable datasources yet)
+ db_file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
+ self._cc.remove_remote_config(AUTH_SPECFILE_LOCATION)
return (zone_name, master_addrinfo, db_file)
@@ -451,8 +458,8 @@
def xfrin_start(self, zone_name, rrclass, db_file, master_addrinfo,
check_soa = True):
- if "bind10_dns" not in sys.modules:
- return (1, "xfrin failed, can't load dns message python library: 'bind10_dns'")
+ if "libdns_python" not in sys.modules:
+ return (1, "xfrin failed, can't load dns message python library: 'libdns_python'")
# check max_transfer_in, else return quota error
if self.recorder.count() >= self._max_transfers_in:
Modified: branches/trac172/src/bin/xfrout/run_b10-xfrout.sh.in
==============================================================================
--- branches/trac172/src/bin/xfrout/run_b10-xfrout.sh.in (original)
+++ branches/trac172/src/bin/xfrout/run_b10-xfrout.sh.in Wed Jun 30 18:48:15 2010
@@ -19,7 +19,7 @@
export PYTHON_EXEC
MYPATH_PATH=@abs_top_builddir@/src/bin/xfrout
-PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/xfr/.libs
+PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/dns/python/.libs
export PYTHONPATH
cd ${MYPATH_PATH}
Modified: branches/trac172/src/bin/xfrout/tests/Makefile.am
==============================================================================
--- branches/trac172/src/bin/xfrout/tests/Makefile.am (original)
+++ branches/trac172/src/bin/xfrout/tests/Makefile.am Wed Jun 30 18:48:15 2010
@@ -1,7 +1,5 @@
PYTESTS = xfrout_test.py
EXTRA_DIST = $(PYTESTS)
-
-if HAVE_BOOST_PYTHON
# later will have configure option to choose this, like: coverage run --branch
PYCOVERAGE = $(PYTHON)
@@ -9,8 +7,6 @@
check-local:
for pytest in $(PYTESTS) ; do \
echo Running test: $$pytest ; \
- env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
+ env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
done
-
-endif
Modified: branches/trac172/src/bin/xfrout/tests/xfrout_test.py
==============================================================================
--- branches/trac172/src/bin/xfrout/tests/xfrout_test.py (original)
+++ branches/trac172/src/bin/xfrout/tests/xfrout_test.py Wed Jun 30 18:48:15 2010
@@ -19,7 +19,7 @@
import unittest
import os
from isc.cc.session import *
-from bind10_dns import *
+from libdns_python import *
from xfrout import *
# our fake socket, where we can read and insert messages
@@ -46,8 +46,8 @@
def read_msg(self):
sent_data = self.readsent()
- get_msg = message(message_mode.PARSE)
- get_msg.from_wire(input_buffer(bytes(sent_data[2:])))
+ get_msg = Message(Message.PARSE)
+ get_msg.from_wire(bytes(sent_data[2:]))
return get_msg
def clear_send(self):
@@ -69,15 +69,16 @@
class TestXfroutSession(unittest.TestCase):
def getmsg(self):
- msg = message(message_mode.PARSE)
- msg.from_wire(input_buffer(self.mdata))
+ msg = Message(Message.PARSE)
+ msg.from_wire(self.mdata)
return msg
def setUp(self):
request = MySocket(socket.AF_INET,socket.SOCK_STREAM)
- self.xfrsess = MyXfroutSession(request, None, None)
+ self.log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False )
+ self.xfrsess = MyXfroutSession(request, None, None, self.log)
self.xfrsess.server = Dbserver()
- self.mdata = b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01'
+ self.mdata = bytes(b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)
self.soa_record = (4, 3, 'example.com.', 'com.example.', 3600, 'SOA', None, 'master.example.com. admin.example.com. 1234 3600 1800 2419200 7200')
@@ -96,7 +97,7 @@
def test_reply_xfrout_query_with_error_rcode(self):
msg = self.getmsg()
- self.xfrsess._reply_query_with_error_rcode(msg, self.sock, rcode(3))
+ self.xfrsess._reply_query_with_error_rcode(msg, self.sock, Rcode(3))
get_msg = self.sock.read_msg()
self.assertEqual(get_msg.get_rcode().to_text(), "NXDOMAIN")
@@ -110,7 +111,7 @@
self.assertEqual(msg.get_qid(), qid)
self.assertEqual(msg.get_opcode(), opcode)
self.assertEqual(msg.get_rcode(), rcode)
- self.assertTrue(msg.get_header_flag(message_flag.AA()))
+ self.assertTrue(msg.get_header_flag(MessageFlag.AA()))
def test_reply_query_with_format_error(self):
@@ -122,11 +123,10 @@
def test_create_rrset_from_db_record(self):
rrset = self.xfrsess._create_rrset_from_db_record(self.soa_record)
self.assertEqual(rrset.get_name().to_text(), "example.com.")
- self.assertEqual(rrset.get_class(), rr_class.IN())
+ self.assertEqual(rrset.get_class(), RRClass("IN"))
self.assertEqual(rrset.get_type().to_text(), "SOA")
- rdata_iter = rrset.get_rdata_iterator()
- rdata_iter.first()
- self.assertEqual(rdata_iter.get_current().to_text(), self.soa_record[7])
+ rdata = rrset.get_rdata()
+ self.assertEqual(rdata[0].to_text(), self.soa_record[7])
def test_send_message_with_last_soa(self):
rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
@@ -136,18 +136,17 @@
self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa)
get_msg = self.sock.read_msg()
- self.assertEqual(get_msg.get_rr_count(section.QUESTION()), 1)
- self.assertEqual(get_msg.get_rr_count(section.ANSWER()), 1)
- self.assertEqual(get_msg.get_rr_count(section.AUTHORITY()), 0)
-
- answer_rrset_iter = section_iter(get_msg, section.ANSWER())
- answer = answer_rrset_iter.get_rrset()
+ self.assertEqual(get_msg.get_rr_count(Section.QUESTION()), 1)
+ self.assertEqual(get_msg.get_rr_count(Section.ANSWER()), 1)
+ self.assertEqual(get_msg.get_rr_count(Section.AUTHORITY()), 0)
+
+ #answer_rrset_iter = section_iter(get_msg, section.ANSWER())
+ answer = get_msg.get_section(Section.ANSWER())[0]#answer_rrset_iter.get_rrset()
self.assertEqual(answer.get_name().to_text(), "example.com.")
- self.assertEqual(answer.get_class(), rr_class.IN())
+ self.assertEqual(answer.get_class(), RRClass("IN"))
self.assertEqual(answer.get_type().to_text(), "SOA")
- rdata_iter = answer.get_rdata_iterator()
- rdata_iter.first()
- self.assertEqual(rdata_iter.get_current().to_text(), self.soa_record[7])
+ rdata = answer.get_rdata()
+ self.assertEqual(rdata[0].to_text(), self.soa_record[7])
def test_get_message_len(self):
msg = self.getmsg()
@@ -205,7 +204,7 @@
def test_dns_xfrout_start_notauth(self):
self.xfrsess._get_query_zone_name = self.default
def notauth(formpara):
- return rcode.NOTAUTH()
+ return Rcode.NOTAUTH()
self.xfrsess._check_xfrout_available = notauth
self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
get_msg = self.sock.read_msg()
@@ -214,7 +213,7 @@
def test_dns_xfrout_start_noerror(self):
self.xfrsess._get_query_zone_name = self.default
def noerror(form):
- return rcode.NOERROR()
+ return Rcode.NOERROR()
self.xfrsess._check_xfrout_available = noerror
def myreply(msg, sock, zonename):
@@ -236,28 +235,35 @@
sqlite3_ds.get_zone_datas = get_zone_datas
self.xfrsess._reply_xfrout_query(self.getmsg(), self.sock, "example.com.")
reply_msg = self.sock.read_msg()
- self.assertEqual(reply_msg.get_rr_count(section.ANSWER()), 2)
-
- # set event
- self.xfrsess.server._shutdown_event.set()
- self.assertRaises(XfroutException, self.xfrsess._reply_xfrout_query, self.getmsg(), self.sock, "example.com.")
+ self.assertEqual(reply_msg.get_rr_count(Section.ANSWER()), 2)
+
+class MyCCSession():
+ def __init__(self):
+ pass
+
+ def get_remote_config_value(self, module_name, identifier):
+ if module_name == "Auth" and identifier == "database_file":
+ return "initdb.file", False
+ else:
+ return "unknown", False
+
class MyUnixSockServer(UnixSockServer):
def __init__(self):
self._lock = threading.Lock()
self._transfers_counter = 0
self._shutdown_event = threading.Event()
- self._db_file = "initdb.file"
self._max_transfers_out = 10
+ self._cc = MyCCSession()
+ self._log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False )
class TestUnixSockServer(unittest.TestCase):
def setUp(self):
self.unix = MyUnixSockServer()
def test_updata_config_data(self):
- self.unix.update_config_data({'transfers_out':10, 'db_file':"db.file"})
+ self.unix.update_config_data({'transfers_out':10 })
self.assertEqual(self.unix._max_transfers_out, 10)
- self.assertEqual(self.unix._db_file, "db.file")
def test_get_db_file(self):
self.assertEqual(self.unix.get_db_file(), "initdb.file")
Modified: branches/trac172/src/bin/xfrout/xfrout.py.in
==============================================================================
--- branches/trac172/src/bin/xfrout/xfrout.py.in (original)
+++ branches/trac172/src/bin/xfrout/xfrout.py.in Wed Jun 30 18:48:15 2010
@@ -26,13 +26,15 @@
from socketserver import *
import os
from isc.config.ccsession import *
+from isc.log.log import *
from isc.cc import SessionError
import socket
+import select
import errno
from optparse import OptionParser, OptionValueError
try:
- from bind10_xfr import *
- from bind10_dns import *
+ from libxfr_python import *
+ from libdns_python import *
except ImportError as e:
# C++ loadable module may not be installed; even so the xfrout process
# must keep running, so we warn about it and move forward.
@@ -40,29 +42,35 @@
if "B10_FROM_BUILD" in os.environ:
SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
+ AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
+ UNIX_SOCKET_FILE= os.environ["B10_FROM_BUILD"] + "/auth_xfrout_conn"
else:
PREFIX = "@prefix@"
DATAROOTDIR = "@datarootdir@"
SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+ AUTH_SPECFILE_PATH = SPECFILE_PATH
+ UNIX_SOCKET_FILE = "@@LOCALSTATEDIR@@/auth_xfrout_conn"
+
SPECFILE_LOCATION = SPECFILE_PATH + "/xfrout.spec"
-UNIX_SOCKET_FILE = "@@LOCALSTATEDIR@@/auth_xfrout_conn"
-
+AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + os.sep + "auth.spec"
MAX_TRANSFERS_OUT = 10
-verbose_mode = False
-
-
-class XfroutException(Exception): pass
-
+VERBOSE_MODE = False
class XfroutSession(BaseRequestHandler):
+ def __init__(self, request, client_address, server, log):
+ # The initializer for the superclass may call functions
+ # that need _log to be set, so we set it first
+ self._log = log
+ BaseRequestHandler.__init__(self, request, client_address, server)
+
def handle(self):
fd = recv_fd(self.request.fileno())
+
if fd < 0:
# This may happen when one xfrout process try to connect to
# xfrout unix socket server, to check whether there is another
# xfrout running.
- print("[b10-xfrout] Failed to receive the FD for XFR connection, "
- "maybe because another xfrout process was started.")
+ self._log.log_message("error", "Failed to receive the file descriptor for XFR connection")
return
data_len = self.request.recv(2)
@@ -72,27 +80,27 @@
try:
self.dns_xfrout_start(sock, msgdata)
except Exception as e:
- if verbose_mode:
- self.log_msg(str(e))
-
+ self._log.log_message("error", str(e))
+
+ sock.shutdown(socket.SHUT_RDWR)
sock.close()
+ os.close(fd)
+ pass
def _parse_query_message(self, mdata):
''' parse query message to [socket,message]'''
#TODO, need to add parseHeader() in case the message header is invalid
try:
- msg = message(message_mode.PARSE)
- msg.from_wire(input_buffer(mdata))
+ msg = Message(Message.PARSE)
+ Message.from_wire(msg, mdata)
except Exception as err:
- if verbose_mode:
- self.log_msg(str(err))
- return rcode.FORMERR(), None
-
- return rcode.NOERROR(), msg
+ self._log.log_message("error", str(err))
+ return Rcode.FORMERR(), None
+
+ return Rcode.NOERROR(), msg
def _get_query_zone_name(self, msg):
- q_iter = question_iter(msg)
- question = q_iter.get_question()
+ question = msg.get_question()[0]
return question.get_name().to_text()
@@ -105,12 +113,14 @@
def _send_message(self, sock, msg):
- obuf = output_buffer(0)
- render = message_render(obuf)
+ #obuf = output_buffer(0)
+ #render = message_render(obuf)
+ render = MessageRenderer()
+ render.set_length_limit(65535)
msg.to_wire(render)
- header_len = struct.pack('H', socket.htons(obuf.get_length()))
+ header_len = struct.pack('H', socket.htons(render.get_length()))
self._send_data(sock, header_len)
- self._send_data(sock, obuf.get_data())
+ self._send_data(sock, render.get_data())
def _reply_query_with_error_rcode(self, msg, sock, rcode_):
@@ -125,7 +135,7 @@
return # query message is invalid. send nothing back.
msg.make_response()
- msg.set_rcode(rcode.FORMERR())
+ msg.set_rcode(Rcode.FORMERR())
self._send_message(sock, msg)
@@ -150,40 +160,37 @@
eg. check allow_transfer setting,
'''
if not self._zone_exist(zone_name):
- return rcode.NOTAUTH()
+ return Rcode.NOTAUTH()
if self._zone_is_empty(zone_name):
- return rcode.SERVFAIL()
+ return Rcode.SERVFAIL()
#TODO, check allow_transfer
if not self.server.increase_transfers_counter():
- return rcode.REFUSED()
-
- return rcode.NOERROR()
+ return Rcode.REFUSED()
+
+ return Rcode.NOERROR()
def dns_xfrout_start(self, sock, msg_query):
rcode_, msg = self._parse_query_message(msg_query)
#TODO. create query message and parse header
- if rcode_ != rcode.NOERROR():
+ if rcode_ != Rcode.NOERROR():
return self._reply_query_with_format_error(msg, sock)
zone_name = self._get_query_zone_name(msg)
rcode_ = self._check_xfrout_available(zone_name)
- if rcode_ != rcode.NOERROR():
+ if rcode_ != Rcode.NOERROR():
+ self._log.log_message("info", "transfer of '%s/IN' failed: %s",
+ zone_name, rcode_.to_text())
return self. _reply_query_with_error_rcode(msg, sock, rcode_)
try:
- if verbose_mode:
- self.log_msg("transfer of '%s/IN': AXFR started" % zone_name)
-
+ self._log.log_message("info", "transfer of '%s/IN': AXFR started" % zone_name)
self._reply_xfrout_query(msg, sock, zone_name)
-
- if verbose_mode:
- self.log_msg("transfer of '%s/IN': AXFR end" % zone_name)
+ self._log.log_message("info", "transfer of '%s/IN': AXFR end" % zone_name)
except Exception as err:
- if verbose_mode:
- sys.stderr.write("[b10-xfrout] %s\n" % str(err))
+ self._log.log_message("error", str(err))
self.server.decrease_transfers_counter()
return
@@ -194,21 +201,21 @@
opcode = msg.get_opcode()
rcode = msg.get_rcode()
- msg.clear(message_mode.RENDER)
+ msg.clear(Message.RENDER)
msg.set_qid(qid)
msg.set_opcode(opcode)
msg.set_rcode(rcode)
- msg.set_header_flag(message_flag.AA())
- msg.set_header_flag(message_flag.QR())
+ msg.set_header_flag(MessageFlag.AA())
+ msg.set_header_flag(MessageFlag.QR())
return msg
def _create_rrset_from_db_record(self, record):
'''Create one rrset from one record of datasource, if the schema of record is changed,
This function should be updated first.
'''
- rrtype_ = rr_type(record[5])
- rdata_ = create_rdata(rrtype_, rr_class.IN(), " ".join(record[7:]))
- rrset_ = rrset(name(record[2]), rr_class.IN(), rrtype_, rr_ttl( int(record[4])))
+ rrtype_ = RRType(record[5])
+ rdata_ = Rdata(rrtype_, RRClass("IN"), " ".join(record[7:]))
+ rrset_ = RRset(Name(record[2]), RRClass("IN"), rrtype_, RRTTL( int(record[4])))
rrset_.add_rdata(rdata_)
return rrset_
@@ -217,20 +224,19 @@
added, a new message should be created to send out the last soa .
'''
- obuf = output_buffer(0)
- render = message_render(obuf)
+ render = MessageRenderer()
msg.to_wire(render)
- old_message_len = obuf.get_length()
- msg.add_rrset(section.ANSWER(), rrset_soa)
+ old_message_len = render.get_length()
+ msg.add_rrset(Section.ANSWER(), rrset_soa)
msg.to_wire(render)
- message_len = obuf.get_length()
+ message_len = render.get_length()
if message_len != old_message_len:
self._send_message(sock, msg)
else:
msg = self._clear_message(msg)
- msg.add_rrset(section.ANSWER(), rrset_soa)
+ msg.add_rrset(Section.ANSWER(), rrset_soa)
self._send_message(sock, msg)
def _get_message_len(self, msg):
@@ -238,59 +244,62 @@
a better way, I need check with jinmei later.
'''
- obuf = output_buffer(0)
- render = message_render(obuf)
+ render = MessageRenderer()
msg.to_wire(render)
- return obuf.get_length()
+ return render.get_length()
def _reply_xfrout_query(self, msg, sock, zone_name):
#TODO, there should be a better way to insert rrset.
msg.make_response()
- msg.set_header_flag(message_flag.AA())
+ msg.set_header_flag(MessageFlag.AA())
soa_record = sqlite3_ds.get_zone_soa(zone_name, self.server.get_db_file())
rrset_soa = self._create_rrset_from_db_record(soa_record)
- msg.add_rrset(section.ANSWER(), rrset_soa)
+ msg.add_rrset(Section.ANSWER(), rrset_soa)
old_message_len = 0
# TODO, Since add_rrset() return nothing when rrset can't be added, so I have to compare
# the message length to know if the rrset has been added sucessfully.
for rr_data in sqlite3_ds.get_zone_datas(zone_name, self.server.get_db_file()):
if self.server._shutdown_event.is_set(): # Check if xfrout is shutdown
- raise XfroutException("shutdown!")
-
- if rr_type(rr_data[5]) == rr_type.SOA(): #ignore soa record
+ self._log.log_message("error", "shutdown!")
+
+ # TODO: RRType.SOA() ?
+ if RRType(rr_data[5]) == RRType("SOA"): #ignore soa record
continue
-
+
rrset_ = self._create_rrset_from_db_record(rr_data)
- msg.add_rrset(section.ANSWER(), rrset_)
- message_len = self._get_message_len(msg)
+ msg.add_rrset(Section.ANSWER(), rrset_)
+ message_len = self._get_message_len(msg)
if message_len != old_message_len:
old_message_len = message_len
continue
self._send_message(sock, msg)
msg = self._clear_message(msg)
- msg.add_rrset(section.ANSWER(), rrset_) # Add the rrset to the new message
+ msg.add_rrset(Section.ANSWER(), rrset_) # Add the rrset to the new message
old_message_len = 0
self._send_message_with_last_soa(msg, sock, rrset_soa)
- def log_msg(self, msg):
- print('[b10-xfrout] ', msg)
-
class UnixSockServer(ThreadingUnixStreamServer):
'''The unix domain socket server which accept xfr query sent from auth server.'''
- def __init__(self, sock_file, handle_class, shutdown_event, config_data):
+ def __init__(self, sock_file, handle_class, shutdown_event, config_data, cc, log):
self._remove_unused_sock_file(sock_file)
self._sock_file = sock_file
ThreadingUnixStreamServer.__init__(self, sock_file, handle_class)
self._lock = threading.Lock()
self._transfers_counter = 0
self._shutdown_event = shutdown_event
+ self._log = log
self.update_config_data(config_data)
+ self._cc = cc
+
+ def finish_request(self, request, client_address):
+ '''Finish one request by instantiating RequestHandlerClass.'''
+ self.RequestHandlerClass(request, client_address, self, self._log)
def _remove_unused_sock_file(self, sock_file):
'''Try to remove the socket file. If the file is being used
@@ -327,22 +336,27 @@
ThreadingUnixStreamServer.shutdown(self)
try:
os.unlink(self._sock_file)
- except:
- pass
+ except Exception as e:
+ self._log.log_message("error", str(e))
def update_config_data(self, new_config):
'''Apply the new config setting of xfrout module. '''
-
+ self._log.log_message('info', 'update config data start.')
self._lock.acquire()
self._max_transfers_out = new_config.get('transfers_out')
- self._db_file = new_config.get('db_file')
+ self._log.log_message('info', 'max transfer out : %d', self._max_transfers_out)
self._lock.release()
+ self._log.log_message('info', 'update config data complete.')
def get_db_file(self):
- self._lock.acquire()
- file = self._db_file
- self._lock.release()
+ file, is_default = self._cc.get_remote_config_value("Auth", "database_file")
+ # this too should be unnecessary, but currently the
+ # 'from build' override isn't stored in the config
+ # (and we don't have indirect python access to datasources yet)
+ if is_default and "B10_FROM_BUILD" in os.environ:
+ file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
return file
+
def increase_transfers_counter(self):
'''Return False, if counter + 1 > max_transfers_out, or else
@@ -362,29 +376,45 @@
self._lock.release()
def listen_on_xfr_query(unix_socket_server):
-
'''Listen xfr query in one single thread. Polls for shutdown
every 0.1 seconds, is there a better time?
'''
- unix_socket_server.serve_forever(poll_interval = 0.1)
+
+ while True:
+ try:
+ unix_socket_server.serve_forever(poll_interval = 0.1)
+ except select.error as err:
+ # serve_forever() calls select.select(), which can be
+ # interrupted.
+ # If it is interrupted, it raises select.error with the
+ # errno set to EINTR. We ignore this case, and let the
+ # normal program flow continue by trying serve_forever()
+ # again.
+ if err.args[0] != errno.EINTR: raise
+
class XfroutServer:
def __init__(self):
self._unix_socket_server = None
+ self._log = None
self._listen_sock_file = UNIX_SOCKET_FILE
self._shutdown_event = threading.Event()
self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
+ self._cc.add_remote_config(AUTH_SPECFILE_LOCATION);
self._config_data = self._cc.get_full_config()
self._cc.start()
+ self._log = isc.log.NSLogger(self._config_data.get('log_name'), self._config_data.get('log_file'),
+ self._config_data.get('log_severity'), self._config_data.get('log_versions'),
+ self._config_data.get('log_max_bytes'), True)
self._start_xfr_query_listener()
-
def _start_xfr_query_listener(self):
'''Start a new thread to accept xfr query. '''
self._unix_socket_server = UnixSockServer(self._listen_sock_file, XfroutSession,
- self._shutdown_event, self._config_data);
+ self._shutdown_event, self._config_data,
+ self._cc, self._log);
listener = threading.Thread(target = listen_on_xfr_query, args = (self._unix_socket_server,))
listener.start()
@@ -398,6 +428,9 @@
continue
self._config_data[key] = new_config[key]
+ if self._log:
+ self._log.update_config(new_config)
+
if self._unix_socket_server:
self._unix_socket_server.update_config_data(self._config_data)
@@ -423,8 +456,7 @@
def command_handler(self, cmd, args):
if cmd == "shutdown":
- if verbose_mode:
- print("[b10-xfrout] Received shutdown command")
+ self._log.log_message("info", "Received shutdown command.")
self.shutdown()
answer = create_answer(0)
else:
@@ -459,18 +491,18 @@
parser = OptionParser()
set_cmd_options(parser)
(options, args) = parser.parse_args()
- verbose_mode = options.verbose
+ VERBOSE_MODE = options.verbose
set_signal_handler()
xfrout_server = XfroutServer()
xfrout_server.run()
except KeyboardInterrupt:
- print("[b10-xfrout] exit xfrout process")
+ sys.stderr.write("[b10-xfrout] exit xfrout process")
except SessionError as e:
- print('[b10-xfrout] Error creating xfrout, '
- 'is the command channel daemon running?' )
+ sys.stderr.write("[b10-xfrout] Error creating xfrout,"
+ "is the command channel daemon running?")
except ModuleCCSessionError as e:
- print('[b10-xfrout] exit xfrout process:', e)
+ sys.stderr.write("info", '[b10-xfrout] exit xfrout process:', e)
if xfrout_server:
xfrout_server.shutdown()
Modified: branches/trac172/src/bin/xfrout/xfrout.spec.pre.in
==============================================================================
--- branches/trac172/src/bin/xfrout/xfrout.spec.pre.in (original)
+++ branches/trac172/src/bin/xfrout/xfrout.spec.pre.in Wed Jun 30 18:48:15 2010
@@ -12,7 +12,37 @@
"item_name": "db_file",
"item_type": "string",
"item_optional": False,
- "item_default": '@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3'
+ "item_default": "@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3"
+ },
+ {
+ "item_name": "log_name",
+ "item_type": "string",
+ "item_optional": False,
+ "item_default": "Xfrout"
+ },
+ {
+ "item_name": "log_file",
+ "item_type": "string",
+ "item_optional": False,
+ "item_default": "@@LOCALSTATEDIR@@/@PACKAGE@/log/Xfrout.log"
+ },
+ {
+ "item_name": "log_severity",
+ "item_type": "string",
+ "item_optional": False,
+ "item_default": "debug"
+ },
+ {
+ "item_name": "log_versions",
+ "item_type": "integer",
+ "item_optional": False,
+ "item_default": 5
+ },
+ {
+ "item_name": "log_max_bytes",
+ "item_type": "integer",
+ "item_optional": False,
+ "item_default": 1048576
}
],
"commands": [
Modified: branches/trac172/src/lib/Makefile.am
==============================================================================
--- branches/trac172/src/lib/Makefile.am (original)
+++ branches/trac172/src/lib/Makefile.am Wed Jun 30 18:48:15 2010
@@ -1,4 +1,1 @@
-SUBDIRS = exceptions dns cc config datasrc python
-if HAVE_BOOST_PYTHON
-SUBDIRS += xfr
-endif
+SUBDIRS = exceptions dns cc config datasrc python xfr
Modified: branches/trac172/src/lib/cc/Makefile.am
==============================================================================
--- branches/trac172/src/lib/cc/Makefile.am (original)
+++ branches/trac172/src/lib/cc/Makefile.am Wed Jun 30 18:48:15 2010
@@ -6,10 +6,12 @@
# error. Unfortunately there doesn't seem to be an easy way to selectively
# avoid the error. As a short term workaround we suppress this warning
# for the entire this module. See also src/bin/auth/Makefile.am.
+if USE_GXX
AM_CXXFLAGS += -Wno-unused-parameter
+endif
-lib_LIBRARIES = libcc.a
-libcc_a_SOURCES = data.cc data.h session.cc session.h
+lib_LTLIBRARIES = libcc.la
+libcc_la_SOURCES = data.cc data.h session.cc session.h
CLEANFILES = *.gcno *.gcda session_config.h
@@ -27,8 +29,8 @@
# TODO: remove PTHREAD_LDFLAGS (and from configure too)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) $(PTHREAD_LDFLAGS)
-run_unittests_LDADD = libcc.a $(GTEST_LDADD)
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a
+run_unittests_LDADD = libcc.la $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
endif
Modified: branches/trac172/src/lib/cc/session.cc
==============================================================================
--- branches/trac172/src/lib/cc/session.cc (original)
+++ branches/trac172/src/lib/cc/session.cc Wed Jun 30 18:48:15 2010
@@ -19,6 +19,17 @@
#include <stdint.h>
+// XXX: there seems to be a strange dependency between ASIO and std library
+// definitions. On some platforms if we include std headers before ASIO
+// headers unexpected behaviors will happen.
+// A middle term solution is to generalize our local wrapper interface
+// (currently only available for the auth server), where all such portability
+// issues are hidden, and to have other modules use the wrapper.
+#include <unistd.h> // for some IPC/network system calls
+#include <asio.hpp>
+#include <asio/error_code.hpp>
+#include <asio/system_error.hpp>
+
#include <cstdio>
#include <vector>
#include <iostream>
@@ -28,10 +39,6 @@
#include <boost/bind.hpp>
#include <boost/function.hpp>
-
-#include <asio.hpp>
-#include <asio/error_code.hpp>
-#include <asio/system_error.hpp>
#include <exceptions/exceptions.h>
Modified: branches/trac172/src/lib/cc/session_unittests.cc
==============================================================================
--- branches/trac172/src/lib/cc/session_unittests.cc (original)
+++ branches/trac172/src/lib/cc/session_unittests.cc Wed Jun 30 18:48:15 2010
@@ -15,10 +15,13 @@
// $Id: data_unittests.cc 1899 2010-05-21 12:03:59Z jelte $
#include "config.h"
+
+// XXX: the ASIO header must be included before others. See session.cc.
+#include <asio.hpp>
+
#include <gtest/gtest.h>
#include <session.h>
-#include <asio.hpp>
#include <exceptions/exceptions.h>
using namespace isc::cc;
Modified: branches/trac172/src/lib/config/tests/Makefile.am
==============================================================================
--- branches/trac172/src/lib/config/tests/Makefile.am (original)
+++ branches/trac172/src/lib/config/tests/Makefile.am Wed Jun 30 18:48:15 2010
@@ -2,7 +2,9 @@
AM_CXXFLAGS = $(B10_CXXFLAGS)
# see src/lib/cc/Makefile.am for -Wno-unused-parameter
+if USE_GXX
AM_CXXFLAGS += -Wno-unused-parameter
+endif
CLEANFILES = *.gcno *.gcda
@@ -20,6 +22,9 @@
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
run_unittests_LDADD += libfake_session.la
run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+# link *only* to data.o from lib/cc (more importantly, don't link in
+# the session class provided there, since we use our own fake_session
+# here)
run_unittests_LDADD += $(top_builddir)/src/lib/cc/data.o
endif
Modified: branches/trac172/src/lib/datasrc/data_source.cc
==============================================================================
--- branches/trac172/src/lib/datasrc/data_source.cc (original)
+++ branches/trac172/src/lib/datasrc/data_source.cc Wed Jun 30 18:48:15 2010
@@ -166,6 +166,25 @@
return (DataSrc::ERROR);
}
+// Add an RRset (and its associated RRSIG) to a message section,
+// checking first to ensure that there isn't already an RRset with
+// the same name and type.
+inline void
+addToMessage(Query& q, const Section& sect, RRsetPtr rrset,
+ bool no_dnssec = false)
+{
+ Message& m = q.message();
+ if (no_dnssec) {
+ if (rrset->getType() == RRType::RRSIG() || !m.hasRRset(sect, rrset)) {
+ m.addRRset(sect, rrset, false);
+ }
+ } else {
+ if (!m.hasRRset(sect, rrset)) {
+ m.addRRset(sect, rrset, q.wantDnssec());
+ }
+ }
+}
+
// Copy referral information into the authority section of a message
inline void
copyAuth(Query& q, RRsetList& auth) {
@@ -176,7 +195,7 @@
if (rrset->getType() == RRType::DS() && !q.wantDnssec()) {
continue;
}
- q.message().addRRset(Section::AUTHORITY(), rrset, q.wantDnssec());
+ addToMessage(q, Section::AUTHORITY(), rrset);
getAdditional(q, rrset);
}
}
@@ -192,7 +211,7 @@
// Lookup failed
return (false);
}
-
+
// Referral bit is expected, so clear it when checking flags
if ((newtask.flags & ~DataSrc::REFERRAL) != 0) {
return (false);
@@ -202,18 +221,18 @@
}
// Match downward, from the zone apex to the query name, looking for
-// referrals.
+// referrals. Note that we exclude the apex name and query name themselves;
+// they'll be handled in a normal lookup in the zone.
inline bool
hasDelegation(const DataSrc* ds, const Name* zonename, Query& q,
QueryTaskPtr task)
{
- const int nlen = task->qname.getLabelCount();
- const int diff = nlen - zonename->getLabelCount();
+ const int diff = task->qname.getLabelCount() - zonename->getLabelCount();
if (diff > 1) {
bool found = false;
RRsetList ref;
- for (int i = diff; i > 1; --i) {
- const Name sub(task->qname.split(i - 1, nlen - i));
+ for (int i = diff - 1; i > 0; --i) {
+ const Name sub(task->qname.split(i));
if (refQuery(sub, q.qclass(), ds, zonename, ref)) {
found = true;
break;
@@ -232,14 +251,12 @@
RRsetPtr r = ref.findRRset(RRType::DNAME(), q.qclass());
if (r != NULL) {
RRsetList syn;
- q.message().addRRset(Section::ANSWER(), r, q.wantDnssec());
+ addToMessage(q, Section::ANSWER(), r);
q.message().setHeaderFlag(MessageFlag::AA());
synthesizeCname(task, r, syn);
if (syn.size() == 1) {
- q.message().addRRset(Section::ANSWER(),
- syn.findRRset(RRType::CNAME(),
- q.qclass()),
- q.wantDnssec());
+ addToMessage(q, Section::ANSWER(),
+ syn.findRRset(RRType::CNAME(), q.qclass()));
chaseCname(q, task, syn.findRRset(RRType::CNAME(),
q.qclass()));
return (true);
@@ -264,7 +281,6 @@
inline DataSrc::Result
addSOA(Query& q, const Name* zonename, const DataSrc* ds) {
- Message& m = q.message();
RRsetList soa;
QueryTask newtask(*zonename, q.qclass(), RRType::SOA(),
@@ -274,8 +290,8 @@
return (DataSrc::ERROR);
}
- m.addRRset(Section::AUTHORITY(), soa.findRRset(RRType::SOA(), q.qclass()),
- q.wantDnssec());
+ addToMessage(q, Section::AUTHORITY(),
+ soa.findRRset(RRType::SOA(), q.qclass()));
return (DataSrc::SUCCESS);
}
@@ -284,14 +300,13 @@
const Name& zonename, const DataSrc* ds)
{
RRsetList nsec;
- Message& m = q.message();
QueryTask newtask(name, task->qclass, RRType::NSEC(),
QueryTask::SIMPLE_QUERY);
RETERR(doQueryTask(ds, &zonename, newtask, nsec));
if (newtask.flags == 0) {
- m.addRRset(Section::AUTHORITY(), nsec.findRRset(RRType::NSEC(),
- q.qclass()), true);
+ addToMessage(q, Section::AUTHORITY(),
+ nsec.findRRset(RRType::NSEC(), q.qclass()));
}
return (DataSrc::SUCCESS);
@@ -344,14 +359,13 @@
proveNX(Query& q, QueryTaskPtr task, const DataSrc* ds,
const Name& zonename, const bool wildcard)
{
- Message& m = q.message();
ConstNsec3ParamPtr nsec3 = getNsec3Param(q, ds, zonename);
if (nsec3 != NULL) {
// Attach the NSEC3 record covering the QNAME
RRsetPtr rrset;
string hash1(nsec3->getHash(task->qname));
RETERR(getNsec3(ds, zonename, q.qclass(), hash1, rrset));
- m.addRRset(Section::AUTHORITY(), rrset, true);
+ addToMessage(q, Section::AUTHORITY(), rrset);
// If this is an NXRRSET or NOERROR/NODATA, we're done
if ((task->flags & DataSrc::TYPE_NOT_FOUND) != 0) {
@@ -360,11 +374,11 @@
// Find the closest provable enclosing name for QNAME
Name enclosure(zonename);
- const int nlen = task->qname.getLabelCount();
- const int diff = nlen - enclosure.getLabelCount();
+ const int diff = task->qname.getLabelCount() -
+ enclosure.getLabelCount();
string hash2;
for (int i = 1; i <= diff; ++i) {
- enclosure = task->qname.split(i, nlen - i);
+ enclosure = task->qname.split(i);
string nodehash(nsec3->getHash(enclosure));
if (nodehash == hash1) {
break;
@@ -376,7 +390,7 @@
// we don't want to use one until we find an exact match
RETERR(getNsec3(ds, zonename, q.qclass(), hash2, rrset));
if (hash2 == nodehash) {
- m.addRRset(Section::AUTHORITY(), rrset, true);
+ addToMessage(q, Section::AUTHORITY(), rrset);
break;
}
}
@@ -391,7 +405,7 @@
string hash3(nsec3->getHash(Name("*").concatenate(enclosure)));
RETERR(getNsec3(ds, zonename, q.qclass(), hash3, rrset));
if (hash3 != hash1 && hash3 != hash2) {
- m.addRRset(Section::AUTHORITY(), rrset, true);
+ addToMessage(q, Section::AUTHORITY(), rrset);
}
} else {
Name nsecname(task->qname);
@@ -434,8 +448,7 @@
return (DataSrc::SUCCESS);
}
- const int nlen = task->qname.getLabelCount();
- const int diff = nlen - zonename->getLabelCount();
+ const int diff = task->qname.getLabelCount() - zonename->getLabelCount();
if (diff < 1) {
return (DataSrc::SUCCESS);
}
@@ -445,7 +458,7 @@
bool cname = false;
for (int i = 1; i <= diff; ++i) {
- const Name& wname(star.concatenate(task->qname.split(i, nlen - i)));
+ const Name& wname(star.concatenate(task->qname.split(i)));
QueryTask newtask(wname, task->qclass, task->qtype, Section::ANSWER(),
QueryTask::AUTH_QUERY);
result = doQueryTask(ds, zonename, newtask, wild);
@@ -488,13 +501,13 @@
RRsetPtr rrset = wild.findRRset(RRType::CNAME(), q.qclass());
if (rrset != NULL) {
rrset->setName(task->qname);
- m.addRRset(Section::ANSWER(), rrset, q.wantDnssec());
+ addToMessage(q, Section::ANSWER(), rrset);
chaseCname(q, task, rrset);
}
} else {
BOOST_FOREACH (RRsetPtr rrset, wild) {
rrset->setName(task->qname);
- m.addRRset(Section::ANSWER(), rrset, q.wantDnssec());
+ addToMessage(q, Section::ANSWER(), rrset);
}
RRsetList auth;
@@ -541,8 +554,7 @@
// (Note that RRtype DS queries need to go to the parent.)
const int nlabels = task->qname.getLabelCount() - 1;
NameMatch match(nlabels != 0 && task->qtype == RRType::DS() ?
- task->qname.split(1, task->qname.getLabelCount() - 1) :
- task->qname);
+ task->qname.split(1) : task->qname);
findClosestEnclosure(match, task->qclass);
const DataSrc* datasource = match.bestDataSrc();
const Name* zonename = match.closestName();
@@ -599,7 +611,7 @@
case QueryTask::GETANSWER:
case QueryTask::FOLLOWCNAME:
BOOST_FOREACH(RRsetPtr rrset, data) {
- m.addRRset(task->section, rrset, q.wantDnssec());
+ addToMessage(q, task->section, rrset);
if (q.tasks().empty()) {
need_auth = true;
}
@@ -615,9 +627,12 @@
// the authority section.
RRsetList auth;
if (!refQuery(*zonename, q.qclass(), datasource, zonename,
- auth)) {
- m.setRcode(Rcode::SERVFAIL());
- return;
+ auth) ||
+ !auth.findRRset(RRType::NS(),
+ datasource->getClass())) {
+ isc_throw(DataSourceError,
+ "NS RR not found in " << *zonename << "/" <<
+ datasource->getClass());
}
copyAuth(q, auth);
@@ -649,7 +664,7 @@
// queue to look up its target.
RRsetPtr rrset = data.findRRset(RRType::CNAME(), q.qclass());
if (rrset != NULL) {
- m.addRRset(task->section, rrset, q.wantDnssec());
+ addToMessage(q, task->section, rrset);
chaseCname(q, task, rrset);
}
continue;
@@ -665,12 +680,12 @@
}
BOOST_FOREACH (RRsetPtr rrset, auth) {
if (rrset->getType() == RRType::NS()) {
- m.addRRset(Section::AUTHORITY(), rrset, q.wantDnssec());
+ addToMessage(q, Section::AUTHORITY(), rrset);
} else if (rrset->getType() == task->qtype) {
- m.addRRset(Section::ANSWER(), rrset, q.wantDnssec());
+ addToMessage(q, Section::ANSWER(), rrset);
} else if (rrset->getType() == RRType::DS() &&
q.wantDnssec()) {
- m.addRRset(Section::AUTHORITY(), rrset, true);
+ addToMessage(q, Section::AUTHORITY(), rrset);
}
getAdditional(q, rrset);
}
@@ -706,8 +721,9 @@
result = addSOA(q, zonename, datasource);
if (result != SUCCESS) {
- m.setRcode(Rcode::SERVFAIL());
- return;
+ isc_throw(DataSourceError,
+ "SOA RR not found in" << *zonename <<
+ "/" << datasource->getClass());
}
}
@@ -737,13 +753,13 @@
// space, signatures in additional section are
// optional.)
BOOST_FOREACH(RRsetPtr rrset, additional) {
- m.addRRset(Section::ADDITIONAL(), rrset, false);
+ addToMessage(q, Section::ADDITIONAL(), rrset, true);
}
if (q.wantDnssec()) {
BOOST_FOREACH(RRsetPtr rrset, additional) {
if (rrset->getRRsig()) {
- m.addRRset(Section::ADDITIONAL(), rrset->getRRsig(), false);
+ addToMessage(q, Section::ADDITIONAL(), rrset->getRRsig(), true);
}
}
}
Modified: branches/trac172/src/lib/datasrc/sqlite3_datasrc.cc
==============================================================================
--- branches/trac172/src/lib/datasrc/sqlite3_datasrc.cc (original)
+++ branches/trac172/src/lib/datasrc/sqlite3_datasrc.cc Wed Jun 30 18:48:15 2010
@@ -330,7 +330,7 @@
Sqlite3DataSrc::findClosest(const Name& name, unsigned int* position) const {
const unsigned int nlabels = name.getLabelCount();
for (unsigned int i = 0; i < nlabels; ++i) {
- const Name matchname(name.split(i, nlabels - i));
+ const Name matchname(name.split(i));
const int rc = hasExactZone(matchname.toText().c_str());
if (rc >= 0) {
if (position != NULL) {
@@ -356,9 +356,7 @@
return;
}
- match.update(*this, match.qname().split(position,
- match.qname().getLabelCount() -
- position));
+ match.update(*this, match.qname().split(position));
}
DataSrc::Result
Modified: branches/trac172/src/lib/datasrc/tests/Makefile.am
==============================================================================
--- branches/trac172/src/lib/datasrc/tests/Makefile.am (original)
+++ branches/trac172/src/lib/datasrc/tests/Makefile.am Wed Jun 30 18:48:15 2010
@@ -22,8 +22,8 @@
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(SQLITE_LIBS)
run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.a
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
endif
Modified: branches/trac172/src/lib/datasrc/tests/datasrc_unittest.cc
==============================================================================
--- branches/trac172/src/lib/datasrc/tests/datasrc_unittest.cc (original)
+++ branches/trac172/src/lib/datasrc/tests/datasrc_unittest.cc Wed Jun 30 18:48:15 2010
@@ -540,6 +540,15 @@
EXPECT_TRUE(it->isLast());
}
+TEST_F(DataSrcTest, DnameExact) {
+ // The example.org test zone has a DNAME RR for dname2.foo.example.org.
+ // A query for that name with a different RR type than DNAME shouldn't
+ // confuse delegation processing.
+ createAndProcessQuery(Name("dname2.foo.example.org"), RRClass::IN(),
+ RRType::A());
+ headerCheck(msg, Rcode::NOERROR(), true, true, true, 0, 1, 0);
+}
+
TEST_F(DataSrcTest, Cname) {
readAndProcessQuery("q_cname");
@@ -761,8 +770,14 @@
}
TEST_F(DataSrcTest, CNAMELoop) {
- createAndProcessQuery(Name("loop1.example.com"), RRClass::IN(),
+ createAndProcessQuery(Name("one.loop.example"), RRClass::IN(),
RRType::A());
+ EXPECT_EQ(Rcode::NOERROR(), msg.getRcode());
+
+ // one.loop.example points to two.loop.example, which points back
+ // to one.loop.example, so there should be exactly two CNAME records
+ // in the answer.
+ EXPECT_EQ(2, msg.getRRCount(Section::ANSWER()));
}
// NSEC query for the name of a zone cut for non-secure delegation.
@@ -843,8 +858,8 @@
EXPECT_EQ(0, ds.dataSrcCount());
}
-#if 0 // currently fails
-TEST_F(DataSrcTest, synthesizedCnameTooLong) {
+// currently fails
+TEST_F(DataSrcTest, DISABLED_synthesizedCnameTooLong) {
// qname has the possible max length (255 octets). it matches a DNAME,
// and the synthesized CNAME would exceed the valid length.
createAndProcessQuery(
@@ -854,6 +869,23 @@
"0123456789abcdef0123456789abcdef0123456789a.dname.example.org."),
RRClass::IN(), RRType::A());
}
-#endif
-
-}
+
+TEST_F(DataSrcTest, noNSZone) {
+ EXPECT_THROW(createAndProcessQuery(Name("www.nons.example"),
+ RRClass::IN(), RRType::A()),
+ DataSourceError);
+}
+
+TEST_F(DataSrcTest, noNSButDnameZone) {
+ EXPECT_THROW(createAndProcessQuery(Name("www.nons-dname.example"),
+ RRClass::IN(), RRType::A()),
+ DataSourceError);
+}
+
+TEST_F(DataSrcTest, noSOAZone) {
+ EXPECT_THROW(createAndProcessQuery(Name("notexist.nosoa.example"),
+ RRClass::IN(), RRType::A()),
+ DataSourceError);
+}
+
+}
Modified: branches/trac172/src/lib/datasrc/tests/test_datasrc.cc
==============================================================================
--- branches/trac172/src/lib/datasrc/tests/test_datasrc.cc (original)
+++ branches/trac172/src/lib/datasrc/tests/test_datasrc.cc Wed Jun 30 18:48:15 2010
@@ -17,6 +17,8 @@
#include "config.h"
#include <cassert>
+
+#include <algorithm>
#include <dns/tests/unittest_util.h>
#include "test_datasrc.h"
@@ -45,69 +47,297 @@
namespace datasrc {
namespace {
-const Name example("example.com");
-const Name sql1("sql1.example.com");
-const Name www_sql1("www.sql1.example.com");
-const Name www("www.example.com");
-const Name foo("foo.example.com");
-const Name dns01("dns01.example.com");
-const Name dns02("dns02.example.com");
-const Name dns03("dns03.example.com");
-const Name cnameint("cname-int.example.com");
-const Name cnameext("cname-ext.example.com");
-const Name dname("dname.example.com");
-const Name wild("*.wild.example.com");
-const Name wild2("*.wild2.example.com");
-const Name wild3("*.wild3.example.com");
-const Name subzone("subzone.example.com");
-const Name loop1("loop1.example.com");
-const Name loop2("loop2.example.com");
-
-RRsetPtr example_ns;
-RRsetPtr example_soa;
-RRsetPtr example_nsec;
-RRsetPtr www_a;
-RRsetPtr www_nsec;
-RRsetPtr foo_cname;
-RRsetPtr foo_nsec;
-RRsetPtr cnameint_cname;
-RRsetPtr cnameint_nsec;
-RRsetPtr cnameext_cname;
-RRsetPtr cnameext_nsec;
-RRsetPtr dns01_a;
-RRsetPtr dns01_nsec;
-RRsetPtr dns02_a;
-RRsetPtr dns02_nsec;
-RRsetPtr dns03_a;
-RRsetPtr dns03_nsec;
-RRsetPtr wild_a;
-RRsetPtr wild_nsec;
-RRsetPtr wild2_cname;
-RRsetPtr wild2_nsec;
-RRsetPtr wild3_cname;
-RRsetPtr wild3_nsec;
-RRsetPtr dname_dname;
-RRsetPtr dname_nsec;
-RRsetPtr sql1_ns;
-RRsetPtr sql1_soa;
-RRsetPtr sql1_nsec;
-RRsetPtr sql1_ds;
-RRsetPtr sql1_ds_nsec;
-RRsetPtr www_sql1_a;
-RRsetPtr www_sql1_nsec;
-RRsetPtr subzone_ns;
-RRsetPtr subzone_nsec;
-RRsetPtr subzone_glue1;
-RRsetPtr subzone_glue2;
-RRsetPtr subzone_ds;
-RRsetPtr loop1_cname;
-RRsetPtr loop2_cname;
+
+// This is a mock data source for testing. It can contain multiple zones.
+// The content of each zone should be configured in the form of RRData{}.
+// Each RRData element is a tuple of char strings, representing
+// "name, RRtype, RDATA". For simplicity we use the same single TTL for
+// RRs (TEST_TTL) defined below.
+// Multiple RRs of the same pair of (name, RRtype) can be defined, but
+// they must not be interleaved with other types of pair. For example,
+// This is okay:
+// {"example.com", "AAAA", "2001:db8::1"},
+// {"example.com", "AAAA", "2001:db8::2"},
+// ...
+// but this is invalid:
+// {"example.com", "AAAA", "2001:db8::1"},
+// {"example.com", "A", "192.0.2.1"},
+// {"example.com", "AAAA", "2001:db8::2"},
+// ...
+// If an RRset is associated with an RRSIG, the RRSIG must immediately follow
+// the RRset to be signed. Currently, only one (or zero) RRSIG can be
+// specified per RRset.
+//
+// Names are sorted internally, and don't have to be sorted in the data.
+//
+// A zone is defined in the form of ZoneData{}, which contains:
+// zone name (character string)
+// RRclass (character string)
+// A pointer to in-zone RRs in the form of RRData{}
+// A pointer to glue RRs in the form of RRData{}
+// Glues can be omitted, in which case a convenient constant "empty_records"
+// can be specified.
+
+// For simplicity we use the same single TTL for all test RRs.
+const uint32_t TEST_TTL = 3600;
+
+struct RRData {
+ const char* const name;
+ const char* const rrtype;
+ const char* const rdata;
+};
+
+struct ZoneData {
+ const char* const zone_name;
+ const char* const rrclass;
+ const struct RRData* records;
+ const struct RRData* glue_records;
+};
+
+//
+// zone data for example.com
+//
+const struct RRData example_com_records[] = {
+ // example.com
+ {"example.com", "NS", "dns01.example.com"},
+ {"example.com", "NS", "dns02.example.com"},
+ {"example.com", "NS", "dns03.example.com"},
+ {"example.com", "RRSIG", "NS 5 2 3600 20100322084538 20100220084538 33495 example.com. ClcrfjkQZUY5L6ZlCkU3cJHzcrEGrofKSVeeoeZ+w6yeEowFNVXs2YBo3tom53DiCrdD9rs3feVSLGW5rjsz/O6lDuomgQG+EVSnWa7GTIPBXj1BmDXXp3XxeldYmhf4UzaN5BA+RUA5E8NChNKuNNof76j2S9tilfN/kvpy4fw="},
+ {"example.com", "SOA", "master.example.com. admin.example.com. 1234 3600 1800 2419200 7200"},
+ {"example.com", "RRSIG", "SOA 5 2 3600 20100322084538 20100220084538 33495 example.com. KUun66Qaw36osk2BJS6U1fAy3PPDkNo2QK4meGNbDBY8q8b+f2o+IXJ14YCvssGl1ORW0CcLnDRxssnk8V/Svmj5iFhO+8HC2hnVBdi2zewvdVtwRb+lWwKN7pkXXwuy6g1t9WCd/j5FCc/wgxqtZUTPb6XgZcnHrORDMOTqLs4="},
+ {"example.com", "NSEC", "cname-ext.example.com. NS SOA MX RRSIG NSEC DNSKEY"},
+ {"example.com", "RRSIG", "NSEC 5 2 7200 20100322084538 20100220084538 33495 example.com. KxuVaPPKNPJzr/q+cJPiNlkHVTQK0LVsgTbSqruXQc25lAd0wn5oKUtxL1bEAchHkfA8eLzcYCj2ZqqAv9OJubw53mfskTad7UHs4Uj2RTrIsNGMCiZGgOpvNb9JcWpQtoyXVT1uNse+Qsbeir0eyeYIufUynFU041jtNrlJMio="},
+
+ // dns01.example.com
+ {"dns01.example.com", "A", "192.0.2.1"},
+ {"dns01.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. NIawlZLk8WZAjNux7oQM2mslfW52OZFFkWt++7FHu2SU98XqEeKfCMnpgtWe5T8Nr9cS8df901iEOJoWQzGTEaHYUBtEhsSjBVn7mKp3fz6473a2xxy75SUKZ0rxjNXSZ8Q5rnFmkX0HTH2Sg51mtjH6aC2pfheQnA2t193BnSg="},
+ {"dns01.example.com", "NSEC", "dns02.example.com. A RRSIG NSEC"},
+ {"dns01.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. EkyeshmMNP9xiAz6mDFDIwksTdmkF9zsFzLuVKAgK6eUk7St6tp5PSvjA8nWol0vdvvz4LK85a4ffTFEiNRyvWeYP2vOhEkyDcrwuCd8Vc3jh/8Sm1Js+nX7hJStrZGFvp2TWPpt9nKH5p3MxXvTb/YVurnue0xSeFAE17O3+I0="},
+
+ // dns02.example.com
+ {"dns02.example.com", "A", "192.0.2.2"},
+ {"dns02.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. XJtVMbUIRE0mk6Hn/Nx6k36jaxaBDPK2/IYB6vCQjJETz6gW4T6q/H/eY9/Lsw5iYPFhoBRDxT4XFj575t98kELXnJe1WhuMbRPlOhyOjxkLECaUne/sbFPOtbGFx9ohuojI0RgxxZiCFaO8wJuv6nfPuzmlLajWS6z9NZeOMIk="},
+ {"dns02.example.com", "NSEC", "dns03.example.com. A RRSIG NSEC"},
+ {"dns02.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. imBNTMB3sPU4kblcaAH6V7lCVt5xgtAybi3DA/SbLEulLaV2NE6vcoEn/AieaM4mOJicQnUDj/H+1hSEhzxU2tRM8zfVlvztxQWn6eh7ZR4mKfNDSvRUGU9ykhpwMyC7wjOt1j5bcSA/OTnLRAilslnJyOM4bSaxVEFo8YPjncY="},
+
+ // dns03.example.com
+ {"dns03.example.com", "A", "192.0.2.3"},
+ {"dns03.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. Ubrcm1H+F6m8khle7P9zU8eO+Jtuj+1Vx1MM5KAkmZPJwQe9uTcoCpQa6DXOGG9kajDTnNN1Be1gkZuJDTZJG4SmJLXLbNY3RDnxpGmWta3qs/VgDq78/YM8ropt1/s7YKyrCfGE2ff+FUB0mLObiG01ZV2gu5HJzgE7SEWLEiI="},
+ {"dns03.example.com", "NSEC", "foo.example.com. A RRSIG NSEC"},
+ {"dns03.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. nn829Xw5CJFnPHwI9WHeT5epQv+odtCkHnjlPFGoPTLOyiks+041UmMqtq3uiSp4d2meMSe9UuDvoROT0L6NTtQQvVqiDhTn0irTFw1uw7fO8ZTG7eyu6Ypfz0+HvfbNvd4kMoD2OTgADRXPVsCTwK+PBOIIG9YTEQfl8pCqW5g="},
+
+ // www.example.com
+ {"www.example.com", "A", "192.0.2.1"},
+ {"www.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. qyFyyV/mE8x4pdhudr5iycwhDsva31MzwO1kBR+bDKvzJg8mN8KxlPZrOlNNUhd3YRXQVwieMyxOTWRPXoxrNEDkNwimXkfe3rrHY7ibV9eNS4OIBUjb44VjCNr9CmQSzfuQ2yxO2r+YIuPYHRCjieD4xh6t9ay4IaCN/tDAJ+Q="},
+ {"www.example.com", "NSEC", "example.com. A RRSIG NSEC"},
+ {"www.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. ZLZlSVBa2oe4U+7SZASnypP2VkI5gg1/1cVGqYUvfYNIUkcVMWDgn7DZCfpmo+2vdlV/4VhAc+sjDd+X+e57XGnW8+lqZHvG6NMMhmSGmeATD3D+8lEJJGo0dxoN4rHJQyp/eT2S4nChz+D/ze+YRagYxGF7pXm9zcrw3kKZGTs="},
+
+ // *.wild.example.com
+ {"*.wild.example.com", "A", "192.0.2.2"},
+ {"*.wild.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. FdO+UWONgtLKFxUzzygGunw67F9y8SzsP7yOLEYVJclRR8X3Ii62L0gtQHq2y0TcKsXttRsD6XY+tM5P/pgXlTNi7Bk4Fgb0PIDPjOsfT4DrS80kWn0YbinM/4/FA1j5ru5sTTboOY5UGhvDnoA9ogNuQQYb2/3wkoH0PrA2Q/0="},
+ {"*.wild.example.com", "NSEC", "*.wild2.example.com. A RRSIG NSEC"},
+ {"*.wild.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. OoGYslRj4xjZnBuzgOqsrvkDAHWycmQzbUxCRmgWnCbXiobJK7/ynONH3jm8G3vGlU0lwpHkhNs6cUK+6Nu8W49X3MT0Xksl/brroLcXYLi3vfxnYUNMMpXdeFl6WNNfoJRo90F/f/TWXAClRrDS29qiG3G1PEJZikIxZsZ0tyM="},
+
+ // *.wild2.example.com
+ {"*.wild2.example.com", "CNAME", "www.example.com"},
+ {"*.wild2.example.com", "RRSIG", "CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="},
+ {"*.wild2.example.com", "NSEC", "*.wild3.example.com. CNAME RRSIG NSEC"},
+ {"*.wild2.example.com", "RRSIG", "NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="},
+
+ // *.wild3.example.com -- a wildcard record with a lame CNAME
+ {"*.wild3.example.com", "CNAME", "spork.example.com"},
+ {"*.wild3.example.com", "RRSIG", "CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="},
+ {"*.wild3.example.com", "NSEC", "www.example.com. CNAME RRSIG NSEC"},
+ {"*.wild3.example.com", "RRSIG", "NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="},
+
+ // foo.example.com
+ {"foo.example.com", "CNAME", "cnametest.flame.org"},
+ {"foo.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. DSqkLnsh0gCeCPVW/Q8viy9GNP+KHmFGfWqyVG1S6koBtGN/VQQ16M4PHZ9Zssmf/JcDVJNIhAChHPE2WJiaPCNGTprsaUshf1Q2vMPVnkrJKgDY8SVRYMptmT8eaT0gGri4KhqRoFpMT5OYfesybwDgfhFSQQAh6ps3bIUsy4o="},
+ {"foo.example.com", "NSEC", "mail.example.com. CNAME RRSIG NSEC"},
+ {"foo.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. RTQwlSqui6StUYye1KCSOEr1d3irndWFqHBpwP7g7n+w8EDXJ8I7lYgwzHvlQt6BLAxe5fUDi7ct8M5hXvsm7FoWPZ5wXH+2/eJUCYxIw4vezKMkMwBP6M/YkJ2CMqY8DppYf60QaLDONQAr7AcK/naSyioeI5h6eaoVitUDMso="},
+
+ // cname-int.example.com
+ {"cname-int.example.com", "CNAME", "www.example.com."},
+ {"cname-int.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. U1wjt0XY9xjTwvUmWSUcfLGMhCjfX2ylWfHrycy50x2oxcK9z94E1ejen9wDTIEBSGYgi6wpZ8RK0+02N1DWTGpDqNXd7aFRfDrWQJ/q/XJHDx0vlcmhkWhrT82LBfKxkrptOzchuSo/c0mpK+mpiIMc1VOwY+yuQ2ALfcD6EHw="},
+ {"cname-int.example.com", "NSEC", "dname.example.com. CNAME RRSIG NSEC"},
+ {"cname-int.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. rbV+gaxfrsoha59NOLF4EFyWQ+GuFCVK/8D77x1atan3HNlXBlZ1smgudKTaJ3CtlobIDt0MEdPxY1yn2Tskw/5mlP1PWf8oaP3BwGSQdn4gLI8+sMpNOPFEdXpxqxngm2F6/7fqniL1QuSAQBEdO+5UiCAgnncPmAsSJg3u1zg="},
+
+ // cname-ext.example.com
+ {"cname-ext.example.com", "CNAME", "www.sql1.example.com"},
+ {"cname-ext.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. bGPIuZilyygvTThK4BrdECuaBcnZUgW/0d09iN2CrNjckchQl3dtbnMNirFsVs9hShDSldRNlQpiAVMpnPgXHhReNum7jmX6yqIH6s8GKIo91zr3VL/ramlezie5w4MilDHrxXLK2pb8IHmP+ZHivQ2EtdYQZgETWBWxr5FDfwk="},
+ {"cname-ext.example.com", "NSEC", "cname-int.example.com. CNAME RRSIG NSEC"},
+ {"cname-ext.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. inWsFwSDWG7TakjwbUTzTRpXz0WifelA5Kn3ABk6BVirIPmd+yQoNj2QZBDFAQwhnLPlNws2Oo4vgMsBMyx1Fv5eHgMUuCN3DUDaLlzlPtUb42CjOUa+jZBeTV/Hd7WZrirluASE1QFDprLdSSqoPPfAKvN3pORtW7y580dMOIM="},
+
+ // dname.example.com
+ {"dname.example.com", "DNAME", "sql1.example.com."},
+ {"dname.example.com", "RRSIG", "DNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. ae8U47oaiwWdurkSyzcsCAF6DxBqjukizwF7K7U6lQVMtfoUE14oiAqfj1fjH8YLDOO/Hd1twrd/u0vgjnI1Gg32YTi7cYOzwE912SV1u2B/y0awaQKWPBwOW0aI7vxelt1vMUF81xosiQD04gOIdDBTqbHKcDxum87iWbhk4Ug="},
+ {"dname.example.com", "NSEC", "dns01.example.com. DNAME RRSIG NSEC"},
+ {"dname.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. c21Fff2D8vBrLzohBnUeflkaRdUAnUxAFGp+UQ0miACDCMOFBlCS9v9g/2+orOnKfd3l4vyz55C310t8JXgXb119ofaZWj2zkdUe+X8Bax+sMS0Y5K/sUhSNvbJbozr9UYPdvjSVBiWgh3s9fsb+etKq9uFukAzGU/FuGYpO0r0="},
+
+ // subzone.example.com
+ {"subzone.example.com", "NS", "ns1.subzone.example.com"},
+ {"subzone.example.com", "NS", "ns2.subzone.example.com"},
+ {"subzone.example.com", "NSEC", "*.wild.example.com. NS DS RRSIG NSEC"},
+ {"subzone.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. Oe2kgIhsLtPJ4+lDZDxznV8/vEVoXKOBFN9lwWyebaKa19BaSXlQ+YVejmulmKDDjEucMvEfuItfn6w7bnU+DzOLk5D1lJCjwDlKz8u3xOAx16TiuQn4bgQAOiFtBQygmGGqO3BVpX+jxsmw7eH3emofy8uUqr/C4aopnwuf28g="},
+ {"subzone.example.com", "DS", "33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"},
+ {"subzone.example.com", "DS", "33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"},
+ {"subzone.example.com", "RRSIG", "DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="},
+
+ // subset of child zone: sql1
+ {"sql1.example.com", "NS", "dns01.example.com"},
+ {"sql1.example.com", "NS", "dns02.example.com"},
+ {"sql1.example.com", "NS", "dns03.example.com"},
+
+ {"sql1.example.com", "DS", "33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"},
+ {"sql1.example.com", "DS", "33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"},
+ {"sql1.example.com", "RRSIG", "DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="},
+ {"sql1.example.com", "NSEC", "subzone.example.com. NS DS RRSIG NSEC"},
+ {"sql1.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. k9FRdFyk/cPdkmmaoZbGZPpzIzfbFWQ3QCHd2qhJa0xAXaEOT/GBL6aFqx9SlunDu2wgES+To5fWPZGi4NzWpp6c5t27rnATN/oCEQ/UYIJKmWbqrXdst0Ps5boznk7suK2Y+km31KxaIf3fDd/T3kZCVsR0aWKRRRatPb7GfLw="},
+
+ {NULL, NULL, NULL}
+};
+const struct RRData example_com_glue_records[] = {
+ {"ns1.subzone.example.com", "A", "192.0.2.1"},
+ {"ns2.subzone.example.com", "A", "192.0.2.2"},
+ {NULL, NULL, NULL}
+};
+
+//
+// zone data for sql1.example.com
+//
+const struct RRData sql1_example_com_records[] = {
+ {"sql1.example.com", "NS", "dns01.example.com"},
+ {"sql1.example.com", "NS", "dns02.example.com"},
+ {"sql1.example.com", "NS", "dns03.example.com"},
+ {"sql1.example.com", "RRSIG", "NS 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. 0CL8noy0NSgoWwuKd+Dc6vyIIw2BrAEBx0IJzcSB6GlB25x/zjEd6AJG0be13HN6jOaTX8iWTuCVrEYuXg76V+M4EvTZHjEScj0az74TrDv4Vdo459paGKCX9B8NLJW1mW4fzZrrXQ8jmBEZeS91Q5rJrO+UKJEuUz3LYdTPvao="},
+ {"sql1.example.com", "SOA", "master.example.com. admin.example.com. 678 3600 1800 2419200 7200"},
+ {"sql1.example.com", "RRSIG", "SOA 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. oakulfyljL/RAKgCKXEZ3KsG8BJj5WG4JK4moWFB6c9OKem6jIk8hKP2XlUVXFuOYJlRdIM4KicmR2GAK+5jJp6z5ShssstYTXo3QosVm6oCKumuFeLFHzcjfqP1D+F9NsvHldJIBnS/4ebPkmR5OENyCZXQF5HmN2awIj4CLjE="},
+ {"sql1.example.com", "NSEC", "www.sql1.example.com. NS SOA RRSIG NSEC DNSKEY"},
+ {"sql1.example.com", "RRSIG", "NSEC 5 3 7200 20100322084536 20100220084536 12447 sql1.example.com. v71CgdTYccCiTqfRcn6HsvISQa8ruvUfCKtpwym0RW/G27xlZn8otj2IMtWwkLxti8Rqqu+PTViLaOIbeVfHBcqzAd7U59cAOYoq3ODZx6auiE3C23HAKqUavKcP7Esaajm1cbcWy6Kyie4CAZc8M7EeKxgkXMKJGqBQzF+/FOo="},
+
+ // www.sql1.example.com
+ {"www.sql1.example.com", "A", "192.0.2.2"},
+ {"www.sql1.example.com", "RRSIG", "A 5 4 3600 20100322084536 20100220084536 12447 sql1.example.com. DNdVKxB3oBsB14NPoV9WG14Y/g4zMcIXLYnFjj9vRZRZJpAvbTEipiXlayuhOxnqU827OipETQyeULZmLsqIQ1wK4Fgf+9b5aJ8D85/o4wBka00X4hZ3MwDPRb4mjuogwBTBg5NRpNSzUfbkPGiav08BFwgg+Efm9veSB05arS0="},
+ {"www.sql1.example.com", "NSEC", "sql1.example.com. A RRSIG NSEC"},
+ {"www.sql1.example.com", "RRSIG", "NSEC 5 4 7200 20100322084536 20100220084536 12447 sql1.example.com. cJMJhDx/ND7/9j3zhyXe+6eaSsU7ByYpXhJzbe+OhjFgH0VasQXq7o1QB3I293UZ+yhkjgXap+9QtPlraaNaYyTyOMQ42OoxSefJpYz9CME/FI2tsUfyrCnLFxYRNet7sMS0q+hLqxRayuEHDFDp72hHPGLJQ8a7jq4SrIonT50="},
+
+ {NULL, NULL, NULL}
+};
+
+//
+// zone data for loop.example
+//
+const struct RRData loop_example_records[] = {
+ {"loop.example", "SOA", "master.loop.example admin.loop.example. "
+ "1234 3600 1800 2419200 7200"},
+ {"loop.example", "NS", "ns.loop.example"},
+ {"one.loop.example", "CNAME", "two.loop.example"},
+ {"two.loop.example", "CNAME", "one.loop.example"},
+ {NULL, NULL, NULL}
+};
+
+//
+// zone data for nons.example
+//
+const struct RRData nons_example_records[] = {
+ {"nons.example", "SOA", "master.nons.example admin.nons.example. "
+ "1234 3600 1800 2419200 7200"},
+ {"www.nons.example", "A", "192.0.2.1"},
+ {"ns.nons.example", "A", "192.0.2.2"},
+ {NULL, NULL, NULL}
+};
+
+//
+// zone data for nons-dname.example
+//
+const struct RRData nonsdname_example_records[] = {
+ {"nons-dname.example", "SOA", "master.nons-dname.example "
+ "admin.nons-dname.example. 1234 3600 1800 2419200 7200"},
+ {"nons-dname.example", "DNAME", "example.org"},
+ {"www.nons-dname.example", "A", "192.0.2.1"},
+ {"ns.nons-dname.example", "A", "192.0.2.2"},
+ {NULL, NULL, NULL}
+};
+
+//
+// zone data for nosoa.example
+//
+const struct RRData nosoa_example_records[] = {
+ {"nosoa.example", "NS", "ns.nosoa.example"},
+ {"www.nosoa.example", "A", "192.0.2.1"},
+ {"ns.nosoa.example", "A", "192.0.2.2"},
+ {NULL, NULL, NULL}
+};
+
+//
+// empty data set, for convenience.
+//
+const struct RRData empty_records[] = {
+ {NULL, NULL, NULL}
+};
+
+//
+// test zones
+//
+const struct ZoneData zone_data[] = {
+ { "example.com", "IN", example_com_records, example_com_glue_records },
+ { "sql1.example.com", "IN", sql1_example_com_records, empty_records },
+ { "loop.example", "IN", loop_example_records, empty_records },
+ { "nons.example", "IN", nons_example_records, empty_records },
+ { "nons-dname.example", "IN", nonsdname_example_records, empty_records },
+ { "nosoa.example", "IN", nosoa_example_records, empty_records }
+};
+const size_t NUM_ZONES = sizeof(zone_data) / sizeof(zone_data[0]);
+
+struct Zone {
+ Zone(const char* const name, const char* const class_txt) :
+ zone_name(Name(name)), rrclass(class_txt)
+ {}
+ Name zone_name;
+ RRClass rrclass;
+ vector<Name> names;
+ vector<RRsetPtr> rrsets;
+};
+vector<Zone> zones;
}
DataSrc::Result
TestDataSrc::init(const isc::data::ElementPtr config UNUSED_PARAM)
{
return init();
+}
+
+void
+buildZone(Zone& zone, const RRData* records, const bool is_glue) {
+ RRsetPtr prev_rrset;
+ for (int i = 0; records[i].name != NULL; ++i) {
+ Name name(records[i].name);
+ RRType rrtype(records[i].rrtype);
+ RRsetPtr rrset;
+ bool new_name = false;
+
+ if (!prev_rrset || prev_rrset->getName() != name) {
+ if (!is_glue) {
+ zone.names.push_back(name);
+ }
+ new_name = true;
+ }
+
+ if (new_name || prev_rrset->getType() != rrtype) {
+ rrset = RRsetPtr(new RRset(name, zone.rrclass, rrtype,
+ RRTTL(TEST_TTL)));
+ if (rrtype != RRType::RRSIG()) {
+ zone.rrsets.push_back(rrset);
+ }
+ } else {
+ rrset = prev_rrset;
+ }
+ rrset->addRdata(createRdata(rrtype, zone.rrclass, records[i].rdata));
+ if (rrtype == RRType::RRSIG()) {
+ prev_rrset->addRRsig(rrset);
+ }
+ prev_rrset = rrset;
+ }
}
DataSrc::Result
@@ -116,353 +346,15 @@
return (SUCCESS);
}
- RRset* rp;
- RRsetPtr rrsig;
-
- // example.com
- example_ns = RRsetPtr(new RRset(example, RRClass::IN(),
- RRType::NS(), RRTTL(3600)));
- example_ns->addRdata(generic::NS(dns01));
- example_ns->addRdata(generic::NS(dns02));
- example_ns->addRdata(generic::NS(dns03));
-
- rp = new RRset(example, RRClass::IN(), RRType::RRSIG(), RRTTL(3600));
- rrsig = RRsetPtr(rp);
- rrsig->addRdata(generic::RRSIG("NS 5 2 3600 20100322084538 20100220084538 33495 example.com. ClcrfjkQZUY5L6ZlCkU3cJHzcrEGrofKSVeeoeZ+w6yeEowFNVXs2YBo3tom53DiCrdD9rs3feVSLGW5rjsz/O6lDuomgQG+EVSnWa7GTIPBXj1BmDXXp3XxeldYmhf4UzaN5BA+RUA5E8NChNKuNNof76j2S9tilfN/kvpy4fw="));
- example_ns->addRRsig(rrsig);
-
- example_soa = RRsetPtr(new RRset(example, RRClass::IN(),
- RRType::SOA(), RRTTL(3600)));
- example_soa->addRdata(generic::SOA("master.example.com. admin.example.com. 1234 3600 1800 2419200 7200"));
-
- rrsig = RRsetPtr(new RRset(example, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("SOA 5 2 3600 20100322084538 20100220084538 33495 example.com. KUun66Qaw36osk2BJS6U1fAy3PPDkNo2QK4meGNbDBY8q8b+f2o+IXJ14YCvssGl1ORW0CcLnDRxssnk8V/Svmj5iFhO+8HC2hnVBdi2zewvdVtwRb+lWwKN7pkXXwuy6g1t9WCd/j5FCc/wgxqtZUTPb6XgZcnHrORDMOTqLs4="));
- example_soa->addRRsig(rrsig);
-
- example_nsec = RRsetPtr(new RRset(example, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- example_nsec->addRdata(generic::NSEC("cname-ext.example.com. NS SOA MX RRSIG NSEC DNSKEY"));
- rrsig = RRsetPtr(new RRset(example, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NSEC 5 2 7200 20100322084538 20100220084538 33495 example.com. KxuVaPPKNPJzr/q+cJPiNlkHVTQK0LVsgTbSqruXQc25lAd0wn5oKUtxL1bEAchHkfA8eLzcYCj2ZqqAv9OJubw53mfskTad7UHs4Uj2RTrIsNGMCiZGgOpvNb9JcWpQtoyXVT1uNse+Qsbeir0eyeYIufUynFU041jtNrlJMio="));
- example_nsec->addRRsig(rrsig);
-
- // sql1.example.com
- sql1_ns = RRsetPtr(new RRset(sql1, RRClass::IN(),
- RRType::NS(), RRTTL(3600)));
- sql1_ns->addRdata(generic::NS(dns01));
- sql1_ns->addRdata(generic::NS(dns02));
- sql1_ns->addRdata(generic::NS(dns03));
-
- rrsig = RRsetPtr(new RRset(sql1, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NS 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. 0CL8noy0NSgoWwuKd+Dc6vyIIw2BrAEBx0IJzcSB6GlB25x/zjEd6AJG0be13HN6jOaTX8iWTuCVrEYuXg76V+M4EvTZHjEScj0az74TrDv4Vdo459paGKCX9B8NLJW1mW4fzZrrXQ8jmBEZeS91Q5rJrO+UKJEuUz3LYdTPvao="));
- sql1_ns->addRRsig(rrsig);
-
- sql1_soa = RRsetPtr(new RRset(sql1, RRClass::IN(),
- RRType::SOA(), RRTTL(3600)));
- sql1_soa->addRdata(generic::SOA("master.example.com. admin.example.com. 678 3600 1800 2419200 7200"));
-
- rrsig = RRsetPtr(new RRset(sql1, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("SOA 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. oakulfyljL/RAKgCKXEZ3KsG8BJj5WG4JK4moWFB6c9OKem6jIk8hKP2XlUVXFuOYJlRdIM4KicmR2GAK+5jJp6z5ShssstYTXo3QosVm6oCKumuFeLFHzcjfqP1D+F9NsvHldJIBnS/4ebPkmR5OENyCZXQF5HmN2awIj4CLjE="));
- sql1_soa->addRRsig(rrsig);
-
- sql1_nsec = RRsetPtr(new RRset(sql1, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- sql1_nsec->addRdata(generic::NSEC("www.sql1.example.com. NS SOA RRSIG NSEC DNSKEY"));
- rrsig = RRsetPtr(new RRset(sql1, RRClass::IN(), RRType::RRSIG(), RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084536 20100220084536 12447 sql1.example.com. v71CgdTYccCiTqfRcn6HsvISQa8ruvUfCKtpwym0RW/G27xlZn8otj2IMtWwkLxti8Rqqu+PTViLaOIbeVfHBcqzAd7U59cAOYoq3ODZx6auiE3C23HAKqUavKcP7Esaajm1cbcWy6Kyie4CAZc8M7EeKxgkXMKJGqBQzF+/FOo="));
- sql1_nsec->addRRsig(rrsig);
- sql1_ds = RRsetPtr(new RRset(sql1, RRClass::IN(),
- RRType::DS(), RRTTL(3600)));
- sql1_ds->addRdata(generic::DS("33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"));
- sql1_ds->addRdata(generic::DS("33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"));
-
- rrsig = RRsetPtr(new RRset(sql1, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="));
- sql1_ds->addRRsig(rrsig);
-
-
- sql1_ds_nsec = RRsetPtr(new RRset(sql1, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- sql1_ds_nsec->addRdata(generic::NSEC("subzone.example.com. NS DS RRSIG NSEC"));
- rrsig = RRsetPtr(new RRset(sql1, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. k9FRdFyk/cPdkmmaoZbGZPpzIzfbFWQ3QCHd2qhJa0xAXaEOT/GBL6aFqx9SlunDu2wgES+To5fWPZGi4NzWpp6c5t27rnATN/oCEQ/UYIJKmWbqrXdst0Ps5boznk7suK2Y+km31KxaIf3fDd/T3kZCVsR0aWKRRRatPb7GfLw="));
- sql1_ds_nsec->addRRsig(rrsig);
-
- // www.sql1.example.com
- www_sql1_a = RRsetPtr(new RRset(www_sql1,
- RRClass::IN(), RRType::A(),
- RRTTL(3600)));
- www_sql1_a->addRdata(in::A("192.0.2.2"));
-
- rrsig = RRsetPtr(new RRset(www_sql1, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("A 5 4 3600 20100322084536 20100220084536 12447 sql1.example.com. DNdVKxB3oBsB14NPoV9WG14Y/g4zMcIXLYnFjj9vRZRZJpAvbTEipiXlayuhOxnqU827OipETQyeULZmLsqIQ1wK4Fgf+9b5aJ8D85/o4wBka00X4hZ3MwDPRb4mjuogwBTBg5NRpNSzUfbkPGiav08BFwgg+Efm9veSB05arS0="));
- www_sql1_a->addRRsig(rrsig);
-
- www_sql1_nsec = RRsetPtr(new RRset(www_sql1,
- RRClass::IN(), RRType::NSEC(),
- RRTTL(3600)));
- www_sql1_nsec->addRdata(generic::NSEC("sql1.example.com. A RRSIG NSEC"));
- rrsig = RRsetPtr(new RRset(www_sql1, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NSEC 5 4 7200 20100322084536 20100220084536 12447 sql1.example.com. cJMJhDx/ND7/9j3zhyXe+6eaSsU7ByYpXhJzbe+OhjFgH0VasQXq7o1QB3I293UZ+yhkjgXap+9QtPlraaNaYyTyOMQ42OoxSefJpYz9CME/FI2tsUfyrCnLFxYRNet7sMS0q+hLqxRayuEHDFDp72hHPGLJQ8a7jq4SrIonT50="));
- www_sql1_nsec->addRRsig(rrsig);
-
- // dns01.example.com
- dns01_a = RRsetPtr(new RRset(dns01,
- RRClass::IN(), RRType::A(),
- RRTTL(3600)));
- dns01_a->addRdata(in::A("192.0.2.1"));
-
- rrsig = RRsetPtr(new RRset(dns01, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("A 5 3 3600 20100322084538 20100220084538 33495 example.com. NIawlZLk8WZAjNux7oQM2mslfW52OZFFkWt++7FHu2SU98XqEeKfCMnpgtWe5T8Nr9cS8df901iEOJoWQzGTEaHYUBtEhsSjBVn7mKp3fz6473a2xxy75SUKZ0rxjNXSZ8Q5rnFmkX0HTH2Sg51mtjH6aC2pfheQnA2t193BnSg="));
- dns01_a->addRRsig(rrsig);
-
- dns01_nsec = RRsetPtr(new RRset(dns01, RRClass::IN(), RRType::NSEC(), RRTTL(3600)));
- dns01_nsec->addRdata(generic::NSEC("dns02.example.com. A RRSIG NSEC"));
-
- rrsig = RRsetPtr(new RRset(dns01, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. EkyeshmMNP9xiAz6mDFDIwksTdmkF9zsFzLuVKAgK6eUk7St6tp5PSvjA8nWol0vdvvz4LK85a4ffTFEiNRyvWeYP2vOhEkyDcrwuCd8Vc3jh/8Sm1Js+nX7hJStrZGFvp2TWPpt9nKH5p3MxXvTb/YVurnue0xSeFAE17O3+I0="));
- dns01_nsec->addRRsig(rrsig);
-
- // dns02.example.com
- dns02_a = RRsetPtr(new RRset(dns02, RRClass::IN(), RRType::A(), RRTTL(3600)));
- dns02_a->addRdata(in::A("192.0.2.2"));
-
- rrsig = RRsetPtr(new RRset(dns02, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("A 5 3 3600 20100322084538 20100220084538 33495 example.com. XJtVMbUIRE0mk6Hn/Nx6k36jaxaBDPK2/IYB6vCQjJETz6gW4T6q/H/eY9/Lsw5iYPFhoBRDxT4XFj575t98kELXnJe1WhuMbRPlOhyOjxkLECaUne/sbFPOtbGFx9ohuojI0RgxxZiCFaO8wJuv6nfPuzmlLajWS6z9NZeOMIk="));
- dns02_a->addRRsig(rrsig);
-
- dns02_nsec = RRsetPtr(new RRset(dns02, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- dns02_nsec->addRdata(generic::NSEC("dns03.example.com. A RRSIG NSEC"));
- rrsig = RRsetPtr(new RRset(dns02, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
-
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. imBNTMB3sPU4kblcaAH6V7lCVt5xgtAybi3DA/SbLEulLaV2NE6vcoEn/AieaM4mOJicQnUDj/H+1hSEhzxU2tRM8zfVlvztxQWn6eh7ZR4mKfNDSvRUGU9ykhpwMyC7wjOt1j5bcSA/OTnLRAilslnJyOM4bSaxVEFo8YPjncY="));
- dns02_nsec->addRRsig(rrsig);
-
- // dns03.example.com
- dns03_a = RRsetPtr(new RRset(dns03,
- RRClass::IN(), RRType::A(),
- RRTTL(3600)));
- dns03_a->addRdata(in::A("192.0.2.3"));
-
- rrsig = RRsetPtr(new RRset(dns03, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("A 5 3 3600 20100322084538 20100220084538 33495 example.com. Ubrcm1H+F6m8khle7P9zU8eO+Jtuj+1Vx1MM5KAkmZPJwQe9uTcoCpQa6DXOGG9kajDTnNN1Be1gkZuJDTZJG4SmJLXLbNY3RDnxpGmWta3qs/VgDq78/YM8ropt1/s7YKyrCfGE2ff+FUB0mLObiG01ZV2gu5HJzgE7SEWLEiI="));
- dns03_a->addRRsig(rrsig);
-
- dns03_nsec = RRsetPtr(new RRset(dns03, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- dns03_nsec->addRdata(generic::NSEC("foo.example.com. A RRSIG NSEC"));
- rrsig = RRsetPtr(new RRset(dns03, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
-
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. nn829Xw5CJFnPHwI9WHeT5epQv+odtCkHnjlPFGoPTLOyiks+041UmMqtq3uiSp4d2meMSe9UuDvoROT0L6NTtQQvVqiDhTn0irTFw1uw7fO8ZTG7eyu6Ypfz0+HvfbNvd4kMoD2OTgADRXPVsCTwK+PBOIIG9YTEQfl8pCqW5g="));
- dns03_nsec->addRRsig(rrsig);
-
- // www.example.com
- www_a = RRsetPtr(new RRset(www, RRClass::IN(), RRType::A(),
- RRTTL(3600)));
- www_a->addRdata(in::A("192.0.2.1"));
-
- rrsig = RRsetPtr(new RRset(www, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("A 5 3 3600 20100322084538 20100220084538 33495 example.com. qyFyyV/mE8x4pdhudr5iycwhDsva31MzwO1kBR+bDKvzJg8mN8KxlPZrOlNNUhd3YRXQVwieMyxOTWRPXoxrNEDkNwimXkfe3rrHY7ibV9eNS4OIBUjb44VjCNr9CmQSzfuQ2yxO2r+YIuPYHRCjieD4xh6t9ay4IaCN/tDAJ+Q="));
- www_a->addRRsig(rrsig);
-
- www_nsec = RRsetPtr(new RRset(www, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- www_nsec->addRdata(generic::NSEC("example.com. A RRSIG NSEC"));
- rrsig = RRsetPtr(new RRset(www, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. ZLZlSVBa2oe4U+7SZASnypP2VkI5gg1/1cVGqYUvfYNIUkcVMWDgn7DZCfpmo+2vdlV/4VhAc+sjDd+X+e57XGnW8+lqZHvG6NMMhmSGmeATD3D+8lEJJGo0dxoN4rHJQyp/eT2S4nChz+D/ze+YRagYxGF7pXm9zcrw3kKZGTs="));
- www_nsec->addRRsig(rrsig);
-
- // *.wild.example.com
- wild_a = RRsetPtr(new RRset(wild, RRClass::IN(), RRType::A(),
- RRTTL(3600)));
- wild_a->addRdata(in::A("192.0.2.2"));
-
- rrsig = RRsetPtr(new RRset(wild, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("A 5 3 3600 20100322084538 20100220084538 33495 example.com. FdO+UWONgtLKFxUzzygGunw67F9y8SzsP7yOLEYVJclRR8X3Ii62L0gtQHq2y0TcKsXttRsD6XY+tM5P/pgXlTNi7Bk4Fgb0PIDPjOsfT4DrS80kWn0YbinM/4/FA1j5ru5sTTboOY5UGhvDnoA9ogNuQQYb2/3wkoH0PrA2Q/0="));
- wild_a->addRRsig(rrsig);
-
- wild_nsec = RRsetPtr(new RRset(wild, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- wild_nsec->addRdata(generic::NSEC("*.wild2.example.com. A RRSIG NSEC"));
-
- rrsig = RRsetPtr(new RRset(wild, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
-
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. OoGYslRj4xjZnBuzgOqsrvkDAHWycmQzbUxCRmgWnCbXiobJK7/ynONH3jm8G3vGlU0lwpHkhNs6cUK+6Nu8W49X3MT0Xksl/brroLcXYLi3vfxnYUNMMpXdeFl6WNNfoJRo90F/f/TWXAClRrDS29qiG3G1PEJZikIxZsZ0tyM="));
- wild_nsec->addRRsig(rrsig);
-
- // *.wild2.example.com
- wild2_cname = RRsetPtr(new RRset(wild2, RRClass::IN(), RRType::CNAME(),
- RRTTL(3600)));
- wild2_cname->addRdata(generic::CNAME("www.example.com"));
-
- rrsig = RRsetPtr(new RRset(wild2, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="));
- wild2_cname->addRRsig(rrsig);
-
- wild2_nsec = RRsetPtr(new RRset(wild2, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- wild2_nsec->addRdata(generic::NSEC("*.wild3.example.com. CNAME RRSIG NSEC"));
-
- rrsig = RRsetPtr(new RRset(wild2, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
-
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="));
- wild2_nsec->addRRsig(rrsig);
-
- // *.wild3.example.com -- a wildcard record with a lame CNAME
- wild3_cname = RRsetPtr(new RRset(wild3, RRClass::IN(), RRType::CNAME(),
- RRTTL(3600)));
- wild3_cname->addRdata(generic::CNAME("spork.example.com"));
-
- rrsig = RRsetPtr(new RRset(wild3, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="));
- wild3_cname->addRRsig(rrsig);
-
- wild3_nsec = RRsetPtr(new RRset(wild3, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- wild3_nsec->addRdata(generic::NSEC("www.example.com. CNAME RRSIG NSEC"));
-
- rrsig = RRsetPtr(new RRset(wild3, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
-
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="));
- wild3_nsec->addRRsig(rrsig);
-
- // foo.example.com
- foo_cname = RRsetPtr(new RRset(foo, RRClass::IN(), RRType::CNAME(),
- RRTTL(3600)));
- foo_cname->addRdata(generic::CNAME("cnametest.flame.org"));
-
- rrsig = RRsetPtr(new RRset(foo, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. DSqkLnsh0gCeCPVW/Q8viy9GNP+KHmFGfWqyVG1S6koBtGN/VQQ16M4PHZ9Zssmf/JcDVJNIhAChHPE2WJiaPCNGTprsaUshf1Q2vMPVnkrJKgDY8SVRYMptmT8eaT0gGri4KhqRoFpMT5OYfesybwDgfhFSQQAh6ps3bIUsy4o="));
- foo_cname->addRRsig(rrsig);
-
- foo_nsec = RRsetPtr(new RRset(foo, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- foo_nsec->addRdata(generic::NSEC("mail.example.com. CNAME RRSIG NSEC"));
- rrsig = RRsetPtr(new RRset(foo, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. RTQwlSqui6StUYye1KCSOEr1d3irndWFqHBpwP7g7n+w8EDXJ8I7lYgwzHvlQt6BLAxe5fUDi7ct8M5hXvsm7FoWPZ5wXH+2/eJUCYxIw4vezKMkMwBP6M/YkJ2CMqY8DppYf60QaLDONQAr7AcK/naSyioeI5h6eaoVitUDMso="));
- foo_nsec->addRRsig(rrsig);
-
- // cname-int.example.com
- cnameint_cname = RRsetPtr(new RRset(cnameint, RRClass::IN(),
- RRType::CNAME(), RRTTL(3600)));
- cnameint_cname->addRdata(generic::CNAME("www.example.com."));
-
- rrsig = RRsetPtr(new RRset(cnameint, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. U1wjt0XY9xjTwvUmWSUcfLGMhCjfX2ylWfHrycy50x2oxcK9z94E1ejen9wDTIEBSGYgi6wpZ8RK0+02N1DWTGpDqNXd7aFRfDrWQJ/q/XJHDx0vlcmhkWhrT82LBfKxkrptOzchuSo/c0mpK+mpiIMc1VOwY+yuQ2ALfcD6EHw="));
- cnameint_cname->addRRsig(rrsig);
-
- cnameint_nsec = RRsetPtr(new RRset(cnameint, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- cnameint_nsec->addRdata(generic::NSEC("dname.example.com. CNAME RRSIG NSEC"));
- rrsig = RRsetPtr(new RRset(cnameint, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. rbV+gaxfrsoha59NOLF4EFyWQ+GuFCVK/8D77x1atan3HNlXBlZ1smgudKTaJ3CtlobIDt0MEdPxY1yn2Tskw/5mlP1PWf8oaP3BwGSQdn4gLI8+sMpNOPFEdXpxqxngm2F6/7fqniL1QuSAQBEdO+5UiCAgnncPmAsSJg3u1zg="));
- cnameint_nsec->addRRsig(rrsig);
-
- // cname-ext.example.com
- cnameext_cname = RRsetPtr(new RRset(cnameext, RRClass::IN(),
- RRType::CNAME(), RRTTL(3600)));
- cnameext_cname->addRdata(generic::CNAME("www.sql1.example.com"));
-
- rrsig = RRsetPtr(new RRset(cnameext, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. bGPIuZilyygvTThK4BrdECuaBcnZUgW/0d09iN2CrNjckchQl3dtbnMNirFsVs9hShDSldRNlQpiAVMpnPgXHhReNum7jmX6yqIH6s8GKIo91zr3VL/ramlezie5w4MilDHrxXLK2pb8IHmP+ZHivQ2EtdYQZgETWBWxr5FDfwk="));
- cnameext_cname->addRRsig(rrsig);
-
- cnameext_nsec = RRsetPtr(new RRset(cnameext, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- cnameext_nsec->addRdata(generic::NSEC("cname-int.example.com. CNAME RRSIG NSEC"));
- rrsig = RRsetPtr(new RRset(cnameext, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. inWsFwSDWG7TakjwbUTzTRpXz0WifelA5Kn3ABk6BVirIPmd+yQoNj2QZBDFAQwhnLPlNws2Oo4vgMsBMyx1Fv5eHgMUuCN3DUDaLlzlPtUb42CjOUa+jZBeTV/Hd7WZrirluASE1QFDprLdSSqoPPfAKvN3pORtW7y580dMOIM="));
- cnameext_nsec->addRRsig(rrsig);
-
- // dname.example.com
- dname_dname = RRsetPtr(new RRset(dname, RRClass::IN(), RRType::DNAME(),
- RRTTL(3600)));
- dname_dname->addRdata(generic::DNAME("sql1.example.com."));
-
- rrsig = RRsetPtr(new RRset(dname, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("DNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. ae8U47oaiwWdurkSyzcsCAF6DxBqjukizwF7K7U6lQVMtfoUE14oiAqfj1fjH8YLDOO/Hd1twrd/u0vgjnI1Gg32YTi7cYOzwE912SV1u2B/y0awaQKWPBwOW0aI7vxelt1vMUF81xosiQD04gOIdDBTqbHKcDxum87iWbhk4Ug="));
- dname_dname->addRRsig(rrsig);
-
- dname_nsec = RRsetPtr(new RRset(dname, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- dname_nsec->addRdata(generic::NSEC("dns01.example.com. DNAME RRSIG NSEC"));
- rrsig = RRsetPtr(new RRset(dname, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. c21Fff2D8vBrLzohBnUeflkaRdUAnUxAFGp+UQ0miACDCMOFBlCS9v9g/2+orOnKfd3l4vyz55C310t8JXgXb119ofaZWj2zkdUe+X8Bax+sMS0Y5K/sUhSNvbJbozr9UYPdvjSVBiWgh3s9fsb+etKq9uFukAzGU/FuGYpO0r0="));
- dname_nsec->addRRsig(rrsig);
-
- // subzone.example.com
- subzone_ns = RRsetPtr(new RRset(subzone, RRClass::IN(), RRType::NS(),
- RRTTL(3600)));
- subzone_ns->addRdata(generic::NS(Name("ns1.subzone.example.com")));
- subzone_ns->addRdata(generic::NS(Name("ns2.subzone.example.com")));
-
- subzone_ds = RRsetPtr(new RRset(subzone, RRClass::IN(), RRType::DS(),
- RRTTL(3600)));
-
- subzone_glue1 = RRsetPtr(new RRset(Name("ns1.subzone.example.com"),
- RRClass::IN(), RRType::A(),
- RRTTL(3600)));
- subzone_glue1->addRdata(in::A("192.0.2.1"));
- subzone_glue2 = RRsetPtr(new RRset(Name("ns2.subzone.example.com"),
- RRClass::IN(), RRType::A(),
- RRTTL(3600)));
- subzone_glue2->addRdata(in::A("192.0.2.2"));
-
- subzone_ds = RRsetPtr(new RRset(subzone, RRClass::IN(), RRType::DS(),
- RRTTL(3600)));
-
- subzone_ds->addRdata(generic::DS("33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"));
- subzone_ds->addRdata(generic::DS("33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"));
-
- rrsig = RRsetPtr(new RRset(subzone, RRClass::IN(), RRType::RRSIG(),
- RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="));
- subzone_ds->addRRsig(rrsig);
-
- subzone_nsec = RRsetPtr(new RRset(subzone, RRClass::IN(),
- RRType::NSEC(), RRTTL(3600)));
- subzone_nsec->addRdata(generic::NSEC("*.wild.example.com. NS DS RRSIG NSEC"));
- rrsig = RRsetPtr(new RRset(subzone, RRClass::IN(), RRType::RRSIG(), RRTTL(3600)));
- rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. Oe2kgIhsLtPJ4+lDZDxznV8/vEVoXKOBFN9lwWyebaKa19BaSXlQ+YVejmulmKDDjEucMvEfuItfn6w7bnU+DzOLk5D1lJCjwDlKz8u3xOAx16TiuQn4bgQAOiFtBQygmGGqO3BVpX+jxsmw7eH3emofy8uUqr/C4aopnwuf28g="));
- subzone_nsec->addRRsig(rrsig);
-
- loop1_cname = RRsetPtr(new RRset(loop1, RRClass::IN(), RRType::CNAME(),
- RRTTL(3600)));
- loop1_cname->addRdata(generic::CNAME(loop2));
- loop2_cname = RRsetPtr(new RRset(loop2, RRClass::IN(), RRType::CNAME(),
- RRTTL(3600)));
- loop2_cname->addRdata(generic::CNAME(loop1));
+ if (zones.empty()) {
+ for (int i = 0; i < NUM_ZONES; ++i) {
+ Zone zone(zone_data[i].zone_name, zone_data[i].rrclass);
+ buildZone(zone, zone_data[i].records, false);
+ buildZone(zone, zone_data[i].glue_records, true);
+ sort(zone.names.begin(), zone.names.end());
+ zones.push_back(zone);
+ }
+ }
initialized = true;
return (SUCCESS);
@@ -470,276 +362,160 @@
void
TestDataSrc::findClosestEnclosure(NameMatch& match,
- const RRClass& qclass) const {
+ const RRClass& qclass) const
+{
const Name& qname = match.qname();
- NameComparisonResult::NameRelation cmp;
if (qclass != getClass() && qclass != RRClass::ANY()) {
return;
}
- cmp = qname.compare(sql1).getRelation();
- if (cmp == NameComparisonResult::EQUAL ||
- cmp == NameComparisonResult::SUBDOMAIN) {
- match.update(*this, sql1);
- return;
- }
-
- cmp = qname.compare(example).getRelation();
- if (cmp == NameComparisonResult::EQUAL ||
- cmp == NameComparisonResult::SUBDOMAIN) {
- match.update(*this, example);
- return;
- }
-
-}
+ vector<Zone>::const_iterator it;
+ vector<Zone>::const_iterator best_it = zones.end();
+ unsigned int best_common_labels = 0;
+ for (it = zones.begin(); it != zones.end(); ++it) {
+ const NameComparisonResult cmp = qname.compare(it->zone_name);
+ const NameComparisonResult::NameRelation reln = cmp.getRelation();
+
+ if ((reln == NameComparisonResult::EQUAL ||
+ reln == NameComparisonResult::SUBDOMAIN) &&
+ cmp.getCommonLabels() > best_common_labels) {
+ best_it = it;
+ best_common_labels = cmp.getCommonLabels();
+ }
+ }
+
+ if (best_it != zones.end()) {
+ match.update(*this, best_it->zone_name);
+ }
+}
+
+struct ZoneNameMatch : public unary_function<Name, bool> {
+ ZoneNameMatch(const Name& name) : name_(name) {}
+ bool operator()(const Zone& zone) const {
+ return (zone.zone_name == name_);
+ }
+ const Name& name_;
+};
+
+// XXX: the main data source module can override the returned RRset.
+// That's bad and should be fixed (Trac #254), but for now we work around it.
+RRsetPtr
+copyRRset(RRsetPtr const source) {
+ RRsetPtr rrset = RRsetPtr(new RRset(source->getName(), source->getClass(),
+ source->getType(), source->getTTL()));
+ RdataIteratorPtr it = source->getRdataIterator();
+ for (it->first(); !it->isLast(); it->next()) {
+ rrset->addRdata(it->getCurrent());
+ }
+ if (source->getRRsig()) {
+ rrset->addRRsig(copyRRset(source->getRRsig()));
+ }
+
+ return (rrset);
+}
+
+class TestDataSrc::RRsetMatch {
+public:
+ struct MatchResult {
+ MatchResult(const bool name_found, const bool has_delegation) :
+ name_found_(name_found), has_delegation_(has_delegation)
+ {}
+ bool name_found_;
+ bool has_delegation_;
+ };
+ RRsetMatch(const Name& name, const RRType& rrtype, const Mode mode,
+ RRsetList& target, uint32_t& flags) :
+ name_(name), rrtype_(rrtype), mode_(mode), target_(target),
+ flags_(flags), name_found_(false), has_delegation_(false)
+ {}
+ void operator()(const RRsetPtr& rrset) {
+ if (rrset->getName() != name_) {
+ return;
+ }
+ name_found_ = true;
+
+ if (rrset->getType() == RRType::NS() ||
+ rrset->getType() == RRType::DNAME()) {
+ has_delegation_ = true;
+ }
+
+ if (mode_ == DELEGATION) {
+ if (rrset->getType() == RRType::NS() ||
+ rrset->getType() == RRType::DNAME() ||
+ rrset->getType() == RRType::DS()) {
+ target_.addRRset(copyRRset(rrset));
+ }
+ } else if (mode_ == ADDRESS) {
+ if (rrset->getType() == RRType::A() ||
+ rrset->getType() == RRType::AAAA()) {
+ target_.addRRset(copyRRset(rrset));
+ }
+ } else {
+ if (rrtype_ == RRType::NSEC() &&
+ rrset->getType() == RRType::CNAME()) {
+ // XXX: ignore CNAME if the qtype is NSEC.
+ // tricky, but necessary.
+ return;
+ }
+ if (rrtype_ == RRType::ANY() || rrtype_ == rrset->getType() ||
+ rrset->getType() == RRType::CNAME() ||
+ rrset->getType() == RRType::DNAME()) {
+ target_.addRRset(copyRRset(rrset));
+ if (rrset->getType() == RRType::CNAME()) {
+ flags_ |= CNAME_FOUND;
+ }
+ if (rrset->getType() == RRType::DNAME()) {
+ flags_ |= REFERRAL;
+ }
+ }
+ }
+
+ }
+ MatchResult getResult() { return (MatchResult(name_found_,
+ has_delegation_)); }
+ const Name& name_;
+ const RRType& rrtype_;
+ const Mode mode_;
+ RRsetList& target_;
+ uint32_t& flags_;
+ bool name_found_;
+ bool has_delegation_;
+};
void
TestDataSrc::findRecords(const Name& name, const RRType& rdtype,
- RRsetList& target, const Name* zonename, const Mode mode,
- uint32_t& flags) const
-{
- const bool any = (rdtype == RRType::ANY());
+ RRsetList& target, const Name* zonename,
+ const Mode mode, uint32_t& flags) const
+{
flags = 0;
assert(zonename != NULL);
- if (*zonename == sql1) {
- if (name == sql1 && mode == DELEGATION) {
- target.addRRset(sql1_ns);
- flags |= REFERRAL;
- } else if (name == sql1) {
- flags |= REFERRAL;
- if (any) {
- target.addRRset(sql1_ns);
- target.addRRset(sql1_nsec);
- } else if (rdtype == RRType::NS()) {
- target.addRRset(sql1_ns);
- } else if (rdtype == RRType::SOA()) {
- target.addRRset(sql1_soa);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(sql1_nsec);
- } else {
- flags |= TYPE_NOT_FOUND;
- }
- } else if (name == www_sql1) {
- if (any) {
- target.addRRset(www_sql1_a);
- target.addRRset(www_sql1_nsec);
- } else if (rdtype == RRType::A()) {
- target.addRRset(www_sql1_a);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(www_sql1_nsec);
- } else {
- flags |= TYPE_NOT_FOUND;
- }
+
+ vector<Zone>::const_iterator zone = find_if(zones.begin(), zones.end(),
+ ZoneNameMatch(*zonename));
+ if (zone == zones.end()) {
+ return;
+ }
+
+ const RRsetMatch::MatchResult match_result =
+ for_each(zone->rrsets.begin(), zone->rrsets.end(),
+ RRsetMatch(name, rdtype, mode, target, flags)).getResult();
+ if (match_result.has_delegation_) {
+ flags |= REFERRAL;
+ }
+ if (target.size() == 0) {
+ if (match_result.name_found_) {
+ flags |= TYPE_NOT_FOUND;
} else {
flags |= NAME_NOT_FOUND;
}
- } else {
- if (name == example && mode == DELEGATION) {
- target.addRRset(example_ns);
- flags |= REFERRAL;
- } else if (name == example) {
- flags |= REFERRAL;
- if (any) {
- target.addRRset(example_ns);
- target.addRRset(example_soa);
- target.addRRset(example_nsec);
- } else if (rdtype == RRType::NS()) {
- target.addRRset(example_ns);
- } else if (rdtype == RRType::SOA()) {
- target.addRRset(example_soa);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(example_nsec);
- } else {
- flags |= TYPE_NOT_FOUND;
- }
- } else if (name == sql1 && mode == DELEGATION) {
- target.addRRset(sql1_ns);
- target.addRRset(sql1_ds);
- target.addRRset(sql1_ds_nsec);
- flags |= REFERRAL;
- } else if (name == sql1) {
- flags |= REFERRAL;
- if (any) {
- target.addRRset(sql1_ns);
- target.addRRset(sql1_ds);
- target.addRRset(sql1_ds_nsec);
- } else if (rdtype == RRType::DS()) {
- target.addRRset(sql1_ds);
- } else if (rdtype == RRType::NS()) {
- target.addRRset(sql1_ns);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(sql1_ds_nsec);
- } else {
- flags |= TYPE_NOT_FOUND;
- }
- } else if (name == subzone && mode == DELEGATION) {
- target.addRRset(subzone_ns);
- target.addRRset(subzone_ds);
- flags |= REFERRAL;
- } else if (name == subzone) {
- flags |= REFERRAL;
- if (any) {
- target.addRRset(subzone_ns);
- target.addRRset(subzone_nsec);
- } else if (rdtype == RRType::NS()) {
- target.addRRset(subzone_ns);
- } else if (rdtype == RRType::DS()) {
- target.addRRset(subzone_ds);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(subzone_nsec);
- } else {
- flags |= TYPE_NOT_FOUND;
- }
- } else if (name == dns01 && mode == ADDRESS) {
- target.addRRset(dns01_a);
- } else if (name == dns01) {
- if (any) {
- target.addRRset(dns01_a);
- target.addRRset(dns01_nsec);
- } else if (rdtype == RRType::A()) {
- target.addRRset(dns01_a);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(dns01_nsec);
- } else {
- flags |= TYPE_NOT_FOUND;
- }
- } else if (name == dns02 && mode == ADDRESS) {
- target.addRRset(dns02_a);
- } else if (name == dns02) {
- if (any) {
- target.addRRset(dns02_a);
- target.addRRset(dns02_nsec);
- } else if (rdtype == RRType::A()) {
- target.addRRset(dns02_a);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(dns02_nsec);
- } else {
- flags |= TYPE_NOT_FOUND;
- }
- } else if (name == dns03 && mode == ADDRESS) {
- target.addRRset(dns03_a);
- } else if (name == dns03) {
- if (any) {
- target.addRRset(dns03_a);
- target.addRRset(dns03_nsec);
- } else if (rdtype == RRType::A()) {
- target.addRRset(dns03_a);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(dns03_nsec);
- } else {
- flags |= TYPE_NOT_FOUND;
- }
- } else if (name == wild) {
- if (any) {
- target.addRRset(wild_a);
- target.addRRset(wild_nsec);
- } else if (rdtype == RRType::A()) {
- target.addRRset(wild_a);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(wild_nsec);
- } else {
- flags |= TYPE_NOT_FOUND;
- }
- } else if (name == wild2) {
- if (any) {
- target.addRRset(wild2_cname);
- target.addRRset(wild2_nsec);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(wild2_nsec);
- } else {
- target.addRRset(wild2_cname);
- if (rdtype != RRType::CNAME()) {
- flags |= CNAME_FOUND;
- }
- }
- } else if (name == wild3) {
- if (any) {
- target.addRRset(wild3_cname);
- target.addRRset(wild3_nsec);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(wild3_nsec);
- } else {
- target.addRRset(wild3_cname);
- if (rdtype != RRType::CNAME()) {
- flags |= CNAME_FOUND;
- }
- }
- } else if (name == www) {
- if (any) {
- target.addRRset(www_a);
- target.addRRset(www_nsec);
- } else if (rdtype == RRType::A()) {
- target.addRRset(www_a);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(www_nsec);
- } else {
- flags |= TYPE_NOT_FOUND;
- }
- } else if (name == foo) {
- if (rdtype == RRType::NSEC()) {
- target.addRRset(foo_nsec);
- } else {
- target.addRRset(foo_cname);
- if (rdtype != RRType::CNAME()) {
- flags |= CNAME_FOUND;
- }
- }
- } else if (name == cnameint) {
- if (rdtype == RRType::NSEC()) {
- target.addRRset(cnameint_nsec);
- } else {
- target.addRRset(cnameint_cname);
- if (rdtype != RRType::CNAME()) {
- flags |= CNAME_FOUND;
- }
- }
- } else if (name == cnameext) {
- if (rdtype == RRType::NSEC()) {
- target.addRRset(cnameext_nsec);
- } else {
- target.addRRset(cnameext_cname);
- if (rdtype != RRType::CNAME()) {
- flags |= CNAME_FOUND;
- }
- }
- } else if (name == dname) {
- flags |= REFERRAL;
- if (any) {
- target.addRRset(dname_dname);
- target.addRRset(dname_nsec);
- } else if (rdtype == RRType::DNAME()) {
- target.addRRset(dname_dname);
- } else if (rdtype == RRType::NSEC()) {
- target.addRRset(dns01_nsec);
- } else {
- flags |= TYPE_NOT_FOUND;
- }
- } else if (name == Name("ns1.subzone.example.com") && mode == ADDRESS) {
- target.addRRset(subzone_glue1);
- } else if (name == Name("ns2.subzone.example.com") && mode == ADDRESS) {
- target.addRRset(subzone_glue2);
- } else if (name == loop1) {
- target.addRRset(loop1_cname);
- if (rdtype != RRType::CNAME()) {
- flags |= CNAME_FOUND;
- }
- } else if (name == loop2) {
- target.addRRset(loop1_cname);
- if (rdtype != RRType::CNAME()) {
- flags |= CNAME_FOUND;
- }
- } else {
- flags |= NAME_NOT_FOUND;
- }
- }
- return;
+ }
}
DataSrc::Result
TestDataSrc::findRRset(const Name& qname,
- const RRClass& qclass UNUSED_PARAM,
+ const RRClass& qclass,
const RRType& qtype,
RRsetList& target,
uint32_t& flags,
@@ -755,7 +531,7 @@
DataSrc::Result
TestDataSrc::findExactRRset(const Name& qname,
- const RRClass& qclass UNUSED_PARAM,
+ const RRClass& qclass,
const RRType& qtype,
RRsetList& target,
uint32_t& flags,
@@ -770,7 +546,7 @@
flags &= ~REFERRAL;
// CNAMEs don't count in this case
- if (flags & CNAME_FOUND) {
+ if ((flags & CNAME_FOUND) != 0) {
flags &= ~CNAME_FOUND;
flags |= TYPE_NOT_FOUND;
}
@@ -780,7 +556,7 @@
DataSrc::Result
TestDataSrc::findAddrs(const Name& qname,
- const RRClass& qclass UNUSED_PARAM,
+ const RRClass& qclass,
RRsetList& target,
uint32_t& flags,
const Name* zonename) const
@@ -795,7 +571,7 @@
DataSrc::Result
TestDataSrc::findReferral(const Name& qname,
- const RRClass& qclass UNUSED_PARAM,
+ const RRClass& qclass,
RRsetList& target,
uint32_t& flags,
const Name* zonename) const
@@ -815,42 +591,30 @@
{
assert(zonename != NULL);
- if (*zonename == example) {
- if (qname >= example && qname < cnameext) {
- target = example;
- } else if (qname < cnameint) {
- target = cnameext;
- } else if (qname < dname) {
- target = cnameint;
- } else if (qname < dns01) {
- target = dname;
- } else if (qname < dns02) {
- target = dns01;
- } else if (qname < dns03) {
- target = dns02;
- } else if (qname < foo) {
- target = dns03;
- } else if (qname < sql1) {
- target = foo;
- } else if (qname < subzone) {
- target = sql1;
- } else if (qname < wild) {
- target = subzone;
- } else if (qname < wild2) {
- target = wild;
- } else if (qname < wild3) {
- target = wild2;
- } else if (qname < www) {
- target = wild3;
- } else {
- target = www;
- }
+ vector<Zone>::const_iterator zone = find_if(zones.begin(), zones.end(),
+ ZoneNameMatch(*zonename));
+ if (zone == zones.end()) {
+ return (ERROR);
+ }
+
+ if (zone->names.empty()) {
+ return (ERROR);
+ }
+
+ // if found, next_name >= qname.
+ vector<Name>::const_iterator next_name =
+ lower_bound(zone->names.begin(), zone->names.end(), qname);
+ if (next_name == zone->names.end()) {
+ // if no such name was found, the previous name is the last name.
+ target = zone->names.back();
+ } else if (*next_name == qname) {
+ target = *next_name;
+ } else if (next_name == zone->names.begin()) {
+ // if qname < first_name, the "previous name" is the last name.
+ target = zone->names.back();
} else {
- if (qname >= sql1 || qname < www_sql1) {
- target = sql1;
- } else {
- target = www_sql1;
- }
+ // otherwise, qname and next_name share the same previous name.
+ target = *(next_name - 1);
}
return (SUCCESS);
}
Modified: branches/trac172/src/lib/datasrc/tests/test_datasrc.h
==============================================================================
--- branches/trac172/src/lib/datasrc/tests/test_datasrc.h (original)
+++ branches/trac172/src/lib/datasrc/tests/test_datasrc.h Wed Jun 30 18:48:15 2010
@@ -96,6 +96,7 @@
ADDRESS,
DELEGATION
};
+ class RRsetMatch;
void findRecords(const isc::dns::Name& name, const isc::dns::RRType& rdtype,
isc::dns::RRsetList& target,
Modified: branches/trac172/src/lib/datasrc/tests/testdata/example.org
==============================================================================
--- branches/trac172/src/lib/datasrc/tests/testdata/example.org (original)
+++ branches/trac172/src/lib/datasrc/tests/testdata/example.org Wed Jun 30 18:48:15 2010
@@ -11,3 +11,4 @@
sub.example.org. NS ns.sub.example.org.
ns.sub.example.org. A 192.0.2.101
dname.example.org. DNAME dname.example.info.
+dname2.foo.example.org. DNAME dname2.example.info.
Modified: branches/trac172/src/lib/datasrc/tests/testdata/example.org.sqlite3
==============================================================================
Binary files - no diff available.
Modified: branches/trac172/src/lib/dns/Makefile.am
==============================================================================
--- branches/trac172/src/lib/dns/Makefile.am (original)
+++ branches/trac172/src/lib/dns/Makefile.am Wed Jun 30 18:48:15 2010
@@ -1,4 +1,4 @@
-SUBDIRS = . tests
+SUBDIRS = . tests python
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CXXFLAGS = $(B10_CXXFLAGS)
@@ -55,51 +55,30 @@
BUILT_SOURCES = rrclass.h rrtype.h rrparamregistry.cc
#TODO: check this###BUILT_SOURCES = rdataclass.h rdataclass.cc
-lib_LTLIBRARIES = libdns.la
+lib_LTLIBRARIES = libdns++.la
-libdns_la_SOURCES = base32.h base32.cc
-libdns_la_SOURCES += base64.h base64.cc
-libdns_la_SOURCES += buffer.h
-libdns_la_SOURCES += dnssectime.h dnssectime.cc
-libdns_la_SOURCES += exceptions.h exceptions.cc
-libdns_la_SOURCES += hex.h hex.cc
-libdns_la_SOURCES += message.h message.cc
-libdns_la_SOURCES += messagerenderer.h messagerenderer.cc
-libdns_la_SOURCES += name.h name.cc
-libdns_la_SOURCES += rdata.h rdata.cc
-libdns_la_SOURCES += rrclass.cc
-libdns_la_SOURCES += rrparamregistry.h
-libdns_la_SOURCES += rrset.h rrset.cc
-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 += sha1.h sha1.cc
-libdns_la_SOURCES += tsig.h tsig.cc
+libdns___la_SOURCES = base32.h base32.cc
+libdns___la_SOURCES += base64.h base64.cc
+libdns___la_SOURCES += buffer.h
+libdns___la_SOURCES += dnssectime.h dnssectime.cc
+libdns___la_SOURCES += exceptions.h exceptions.cc
+libdns___la_SOURCES += hex.h hex.cc
+libdns___la_SOURCES += message.h message.cc
+libdns___la_SOURCES += messagerenderer.h messagerenderer.cc
+libdns___la_SOURCES += name.h name.cc
+libdns___la_SOURCES += rdata.h rdata.cc
+libdns___la_SOURCES += rrclass.cc
+libdns___la_SOURCES += rrparamregistry.h
+libdns___la_SOURCES += rrset.h rrset.cc
+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 += sha1.h sha1.cc
+libdns___la_SOURCES += tsig.h tsig.cc
-if HAVE_BOOST_PYTHON
-# This is a loadable module for python scripts, so we use the prefix "pyexec"
-# to make sure the object files will be installed in the appropriate place
-# for this purpose.
-pyexec_LTLIBRARIES = bind10_dns.la
-bind10_dns_la_SOURCES = python_dns.cc
-bind10_dns_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-bind10_dns_la_CXXFLAGS = $(AM_CXXFLAGS) $(B10_CXXFLAGS)
-if GCC_WERROR_OK
-# XXX: Boost.Python triggers strict aliasing violation, so if we use -Werror
-# we need to suppress the warnings.
-bind10_dns_la_CXXFLAGS += -fno-strict-aliasing
-endif
-bind10_dns_la_LDFLAGS = $(BOOST_LDFLAGS) $(PYTHON_LDFLAGS)
-# Python prefers .so, while some OSes (specifically MacOS) use a different
-# suffix for dynamic objects. -module is necessary to work this around.
-bind10_dns_la_LDFLAGS += -module
-bind10_dns_la_LIBADD = $(top_builddir)/src/lib/dns/libdns.la
-bind10_dns_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-bind10_dns_la_LIBADD += $(BOOST_PYTHON_LIB) $(PYTHON_LIB)
-endif
-
-nodist_libdns_la_SOURCES = rdataclass.cc rrclass.h rrtype.h rrparamregistry.cc
+nodist_libdns___la_SOURCES = rdataclass.cc rrclass.h rrtype.h
+nodist_libdns___la_SOURCES += rrparamregistry.cc
rrclass.h: rrclass-placeholder.h
rrtype.h: rrtype-placeholder.h
@@ -107,8 +86,8 @@
rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: Makefile
./gen-rdatacode.py
-libdns_includedir = $(includedir)/dns
-libdns_include_HEADERS = \
+libdns++_includedir = $(includedir)/dns
+libdns++_include_HEADERS = \
buffer.h \
dnssectime.h \
exceptions.h \
Modified: branches/trac172/src/lib/dns/message.cc
==============================================================================
--- branches/trac172/src/lib/dns/message.cc (original)
+++ branches/trac172/src/lib/dns/message.cc Wed Jun 30 18:48:15 2010
@@ -21,6 +21,7 @@
#include <sstream>
#include <vector>
+#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
@@ -370,7 +371,6 @@
"addRRset performed in non-render mode");
}
- // Note: should check duplicate (TBD)
impl_->rrsets_[sectionCodeToId(section)].push_back(rrset);
impl_->counts_[section.getCode()] += rrset->getRdataCount();
@@ -379,6 +379,20 @@
impl_->rrsets_[sectionCodeToId(section)].push_back(sp);
impl_->counts_[section.getCode()] += sp->getRdataCount();
}
+}
+
+bool
+Message::hasRRset(const Section& section, RRsetPtr rrset) {
+ BOOST_FOREACH(RRsetPtr r, impl_->rrsets_[sectionCodeToId(section)]) {
+ if (r->getType() == rrset->getType() &&
+ r->getName() == rrset->getName())
+ {
+ return (true);
+
+ }
+ }
+
+ return (false);
}
void
@@ -923,7 +937,7 @@
template <typename T>
const T*
SectionIterator<T>::operator->() const {
- return (impl_->it_.operator->());
+ return (&(operator*()));
}
template <typename T>
Modified: branches/trac172/src/lib/dns/message.h
==============================================================================
--- branches/trac172/src/lib/dns/message.h (original)
+++ branches/trac172/src/lib/dns/message.h Wed Jun 30 18:48:15 2010
@@ -739,7 +739,15 @@
/// \c rrset. This interface design needs to be revisited later.
///
/// Only allowed in the \c RENDER mode.
+ ///
+ /// Note that addRRset() does not currently check for duplicate
+ /// data before inserting RRsets. The caller is responsible for
+ /// checking for these (see hasRRset() below).
void addRRset(const Section& section, RRsetPtr rrset, bool sign = false);
+
+ /// \brief Determine whether the given section already has an RRset
+ /// matching the name and type of this one
+ bool hasRRset(const Section& section, RRsetPtr rrset);
// The following methods are not currently implemented.
//void removeQuestion(QuestionPtr question);
Modified: branches/trac172/src/lib/dns/name.cc
==============================================================================
--- branches/trac172/src/lib/dns/name.cc (original)
+++ branches/trac172/src/lib/dns/name.cc Wed Jun 30 18:48:15 2010
@@ -267,7 +267,7 @@
if (state == ft_ordinary) {
assert(count != 0);
ndata.at(offsets.back()) = count;
-
+
offsets.push_back(ndata.size());
// add a trailing \0
ndata.push_back('\0');
Modified: branches/trac172/src/lib/dns/rrsetlist.cc
==============================================================================
--- branches/trac172/src/lib/dns/rrsetlist.cc (original)
+++ branches/trac172/src/lib/dns/rrsetlist.cc Wed Jun 30 18:48:15 2010
@@ -29,8 +29,7 @@
namespace dns {
void
-RRsetList::addRRset(RRsetPtr rrsetptr)
-{
+RRsetList::addRRset(RRsetPtr rrsetptr) {
ConstRRsetPtr rrset_found = findRRset(rrsetptr->getType(),
rrsetptr->getClass());
if (rrset_found != NULL) {
@@ -42,8 +41,7 @@
}
RRsetPtr
-RRsetList::findRRset(const RRType& rrtype, const RRClass& rrclass)
-{
+RRsetList::findRRset(const RRType& rrtype, const RRClass& rrclass) {
BOOST_FOREACH(RRsetPtr rrsetptr, rrsets_) {
if ((rrsetptr->getClass() == rrclass) &&
(rrsetptr->getType() == rrtype)) {
Modified: branches/trac172/src/lib/dns/rrsetlist.h
==============================================================================
--- branches/trac172/src/lib/dns/rrsetlist.h (original)
+++ branches/trac172/src/lib/dns/rrsetlist.h Wed Jun 30 18:48:15 2010
@@ -60,7 +60,7 @@
}
P operator->() const
{
- return (it_.operator->());
+ return (&(operator*()));
}
bool operator==(const RRsetListIterator& other)
{
Modified: branches/trac172/src/lib/dns/tests/Makefile.am
==============================================================================
--- branches/trac172/src/lib/dns/tests/Makefile.am (original)
+++ branches/trac172/src/lib/dns/tests/Makefile.am Wed Jun 30 18:48:15 2010
@@ -40,7 +40,7 @@
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/dns/.libs/libdns.a
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
endif
Modified: branches/trac172/src/lib/python/isc/Makefile.am
==============================================================================
--- branches/trac172/src/lib/python/isc/Makefile.am (original)
+++ branches/trac172/src/lib/python/isc/Makefile.am Wed Jun 30 18:48:15 2010
@@ -1,4 +1,4 @@
-SUBDIRS = datasrc cc config # Util
+SUBDIRS = datasrc cc config log # Util
python_PYTHON = __init__.py
Modified: branches/trac172/src/lib/python/isc/__init__.py
==============================================================================
--- branches/trac172/src/lib/python/isc/__init__.py (original)
+++ branches/trac172/src/lib/python/isc/__init__.py Wed Jun 30 18:48:15 2010
@@ -1,3 +1,5 @@
import isc.datasrc
import isc.cc
import isc.config
+#import isc.dns
+import isc.log
Modified: branches/trac172/src/lib/python/isc/config/cfgmgr.py
==============================================================================
--- branches/trac172/src/lib/python/isc/config/cfgmgr.py (original)
+++ branches/trac172/src/lib/python/isc/config/cfgmgr.py Wed Jun 30 18:48:15 2010
@@ -347,7 +347,7 @@
# passes both specification and commands at once
spec_update = ccsession.create_command(ccsession.COMMAND_MODULE_SPECIFICATION_UPDATE,
[ spec.get_module_name(), spec.get_full_spec() ])
- self.cc.group_sendmsg(spec_update, "Cmd-Ctrld")
+ self.cc.group_sendmsg(spec_update, "Cmdctl")
return ccsession.create_answer(0)
def handle_msg(self, msg):
Modified: branches/trac172/src/lib/python/isc/config/tests/cfgmgr_test.py
==============================================================================
--- branches/trac172/src/lib/python/isc/config/tests/cfgmgr_test.py (original)
+++ branches/trac172/src/lib/python/isc/config/tests/cfgmgr_test.py Wed Jun 30 18:48:15 2010
@@ -271,9 +271,9 @@
# the name here is actually wrong (and hardcoded), but needed in the current version
# TODO: fix that
#self.assertEqual({'specification_update': [ self.name, self.spec ] },
- # self.fake_session.get_message("Cmd-Ctrld", None))
+ # self.fake_session.get_message("Cmdctl", None))
#self.assertEqual({'commands_update': [ self.name, self.commands ] },
- # self.fake_session.get_message("Cmd-Ctrld", None))
+ # self.fake_session.get_message("Cmdctl", None))
self._handle_msg_helper({ "command":
["shutdown"]
Modified: branches/trac172/src/lib/python/isc/datasrc/master.py
==============================================================================
--- branches/trac172/src/lib/python/isc/datasrc/master.py (original)
+++ branches/trac172/src/lib/python/isc/datasrc/master.py Wed Jun 30 18:48:15 2010
@@ -16,7 +16,8 @@
# $Id$
import sys, re, string
-
+import time
+import os
#########################################################################
# define exceptions
#########################################################################
@@ -102,7 +103,7 @@
# isttl: check whether a string is a valid TTL specifier.
# returns: boolean
#########################################################################
-ttl_regex = re.compile('[0-9]+[wdhms]?', re.I)
+ttl_regex = re.compile('([0-9]+[wdhms]?)+', re.I)
def isttl(s):
global ttl_regex
if ttl_regex.match(s):
@@ -121,19 +122,26 @@
# MasterFileError
#########################################################################
def parse_ttl(s):
- m = re.match('([0-9]+)(.*)', s)
- if not m:
+ sum = 0
+ if not isttl(s):
raise MasterFileError('Invalid TTL: ' + s)
- ttl, suffix = int(m.group(1)), m.group(2)
- if suffix.lower() == 'w':
- ttl *= 604800
- elif suffix.lower() == 'd':
- ttl *= 86400
- elif suffix.lower() == 'h':
- ttl *= 3600
- elif suffix.lower() == 'm':
- ttl *= 60
- return str(ttl)
+ for ttl_expr in re.findall('\d+[wdhms]?', s, re.I):
+ if ttl_expr.isdigit():
+ ttl = int(ttl_expr)
+ sum += ttl
+ continue
+ ttl = int(ttl_expr[:-1])
+ suffix = ttl_expr[-1].lower()
+ if suffix == 'w':
+ ttl *= 604800
+ elif suffix == 'd':
+ ttl *= 86400
+ elif suffix == 'h':
+ ttl *= 3600
+ elif suffix == 'm':
+ ttl *= 60
+ sum += ttl
+ return str(sum)
#########################################################################
# records: generator function to return complete RRs from the zone file,
@@ -147,7 +155,9 @@
record = []
complete = True
paren = 0
+ size = 0
for line in input:
+ size += len(line)
list = cleanup(line).split()
for word in list:
if paren == 0:
@@ -169,10 +179,12 @@
if paren == 1 or not record:
continue
-
+
ret = ' '.join(record)
record = []
- yield ret
+ oldsize = size
+ size = 0
+ yield ret, oldsize
#########################################################################
# define the MasterFile class for reading zone master files
@@ -181,24 +193,62 @@
__rrclass = 'IN'
__maxttl = 0x7fffffff
__ttl = ''
+ __lastttl = ''
__zonefile = ''
__name = ''
-
- def __init__(self, filename, initial_origin = ''):
- if initial_origin == '.':
- initial_origin = ''
+ __file_level = 0
+ __file_type = ""
+ __init_time = time.time()
+ __records_num = 0
+
+ def __init__(self, filename, initial_origin = '', verbose = False):
self.__initial_origin = initial_origin
self.__origin = initial_origin
+ self.__datafile = filename
+
try:
self.__zonefile = open(filename, 'r')
except:
raise MasterFileError("Could not open " + filename)
+ self.__filesize = os.fstat(self.__zonefile.fileno()).st_size
+
+ self.__cur = 0
+ self.__numback = 0
+ self.__verbose = verbose
+ try:
+ self.__zonefile = open(filename, 'r')
+ except:
+ raise MasterFileError("Could not open " + filename)
+
+ def __status(self):
+ interval = time.time() - MasterFile.__init_time
+ if self.__filesize == 0:
+ percent = 100
+ else:
+ percent = (self.__cur * 100)/self.__filesize
+
+ sys.stdout.write("\r" + (80 * " "))
+ sys.stdout.write("\r%d RR(s) loaded in %d second(s) (%.2f%% of %s%s)"\
+ % (MasterFile.__records_num, interval, percent, MasterFile.__file_type, self.__datafile))
def __del__(self):
if self.__zonefile:
self.__zonefile.close()
-
- #########################################################################
+ ########################################################################
+ # check if the zonename is relative
+ # no then return
+ # yes , sets the relative domain name to the stated name
+ #######################################################################
+ def __statedname(self, name, record):
+ if name[-1] != '.':
+ if not self.__origin:
+ raise MasterFileError("Cannot parse RR, No $ORIGIN: " + record)
+ elif self.__origin == '.':
+ name += '.'
+ else:
+ name += '.' + self.__origin
+ return name
+ #####################################################################
# handle $ORIGIN, $TTL and $GENERATE directives
# (currently only $ORIGIN and $TTL are implemented)
# input:
@@ -216,20 +266,22 @@
raise MasterFileError('Invalid $ORIGIN')
if more:
raise MasterFileError('Invalid $ORIGIN')
- if second == '.':
- self.__origin = ''
- elif second[-1] == '.':
+ if second[-1] == '.':
self.__origin = second
+ elif not self.__origin:
+ raise MasterFileError("$ORIGIN is not absolute in record:%s" % s)
+ elif self.__origin != '.':
+ self.__origin = second + '.' + self.__origin
else:
- self.__origin = second + '.' + self.__origin
+ self.__origin = second + '.'
return True
elif re.match('\$ttl', first, re.I):
if not second or not isttl(second):
raise MasterFileError('Invalid TTL: "' + second + '"')
if more:
raise MasterFileError('Invalid $TTL statement')
- self.__ttl = parse_ttl(second)
- if int(self.__ttl) > self.__maxttl:
+ MasterFile.__ttl = parse_ttl(second)
+ if int(MasterFile.__ttl) > self.__maxttl:
raise MasterFileError('TTL too high: ' + second)
return True
elif re.match('\$generate', first, re.I):
@@ -246,14 +298,28 @@
# throws:
# MasterFileError
#########################################################################
- __filename = re.compile('[\"\']*([^\'\"]+)[\"\']*')
+ __include_syntax1 = re.compile('\s+(\S+)(?:\s+(\S+))?$', re.I)
+ __include_syntax2 = re.compile('\s+"([^"]+)"(?:\s+(\S+))?$', re.I)
+ __include_syntax3 = re.compile("\s+'([^']+)'(?:\s+(\S+))?$", re.I)
def __include(self, s):
- first, rest = pop(s)
- if re.match('\$include', first, re.I):
- m = self.__filename.match(rest)
- if m:
- file = m.group(1)
- return file
+ if not s.lower().startswith('$include'):
+ return "", ""
+ s = s[len('$include'):]
+ m = self.__include_syntax1.match(s)
+ if not m:
+ m = self.__include_syntax2.match(s)
+ if not m:
+ m = self.__include_syntax3.match(s)
+ if not m:
+ raise MasterFileError('Invalid $include format')
+ file = m.group(1)
+ if m.group(2):
+ if not isname(m.group(2)):
+ raise MasterFileError('Invalid $include format (invalid origin)')
+ origin = self.__statedname(m.group(2), s)
+ else:
+ origin = self.__origin
+ return file, origin
#########################################################################
# try parsing an RR on the assumption that the type is specified in
@@ -272,6 +338,14 @@
if istype(list[3]):
if isclass(list[2]) and isttl(list[1]) and isname(list[0]):
name, ttl, rrclass, rrtype = list[0:4]
+ ttl = parse_ttl(ttl)
+ MasterFile.__lastttl = ttl or MasterFile.__lastttl
+ rdata = ' '.join(list[4:])
+ ret = name, ttl, rrclass, rrtype, rdata
+ elif isclass(list[1]) and isttl(list[2]) and isname(list[0]):
+ name, rrclass, ttl, rrtype = list[0:4]
+ ttl = parse_ttl(ttl)
+ MasterFile.__lastttl = ttl or MasterFile.__lastttl
rdata = ' '.join(list[4:])
ret = name, ttl, rrclass, rrtype, rdata
return ret
@@ -284,6 +358,9 @@
# returns:
# empty list if parse failed, else name, ttl, class, type, rdata
#########################################################################
+ def __getttl(self):
+ return MasterFile.__ttl or MasterFile.__lastttl
+
def __three(self, record, curname):
ret = ''
list = record.split()
@@ -292,19 +369,25 @@
if istype(list[2]) and not istype(list[1]):
if isclass(list[1]) and not isttl(list[0]) and isname(list[0]):
rrclass = list[1]
- ttl = self.__ttl
+ ttl = self.__getttl()
name = list[0]
- elif not isclass(list[1]) and isttl(list[1]) and isname(list[0]):
+ elif not isclass(list[1]) and isttl(list[1]) and not isclass(list[0]) and isname(list[0]):
rrclass = self.__rrclass
ttl = parse_ttl(list[1])
+ MasterFile.__lastttl = ttl or MasterFile.__lastttl
name = list[0]
elif curname and isclass(list[1]) and isttl(list[0]):
- rrclass = self.__rrclass
+ rrclass = list[1]
ttl = parse_ttl(list[0])
+ MasterFile.__lastttl = ttl or MasterFile.__lastttl
+ name = curname
+ elif curname and isttl(list[1]) and isclass(list[0]):
+ rrclass = list[0]
+ ttl = parse_ttl(list[1])
+ MasterFile.__lastttl = ttl or MasterFile.__lastttl
name = curname
else:
return ret
-
rrtype = list[2]
rdata = ' '.join(list[3:])
ret = name, ttl, rrclass, rrtype, rdata
@@ -325,29 +408,37 @@
list = record.split()
if len(list) <= 2:
return ret
-
if istype(list[1]):
rrclass = self.__rrclass
rrtype = list[1]
if list[0].lower() == 'rrsig':
name = curname
- ttl = self.__ttl
+ ttl = self.__getttl()
rrtype = list[0]
rdata = ' '.join(list[1:])
elif isttl(list[0]):
ttl = parse_ttl(list[0])
name = curname
rdata = ' '.join(list[2:])
+ elif isclass(list[0]):
+ ttl = self.__getttl()
+ name = curname
+ rdata = ' '.join(list[2:])
elif isname(list[0]):
name = list[0]
- ttl = self.__ttl
+ ttl = self.__getttl()
rdata = ' '.join(list[2:])
else:
raise MasterFileError("Cannot parse RR: " + record)
ret = name, ttl, rrclass, rrtype, rdata
-
return ret
+
+ ########################################################################
+ #close verbose
+ ######################################################################
+ def closeverbose(self):
+ self.__status()
#########################################################################
# zonedata: generator function to parse a zone master file and return
@@ -355,16 +446,43 @@
#########################################################################
def zonedata(self):
name = ''
-
- for record in records(self.__zonefile):
+ last_status = 0.0
+ flag = 1
+
+ for record, size in records(self.__zonefile):
+ if self.__verbose:
+ now = time.time()
+ if flag == 1:
+ self.__status()
+ flag = 0
+ if now - last_status >= 1.0:
+ self.__status()
+ last_status = now
+
+ self.__cur += size
if self.__directive(record):
continue
- incl = self.__include(record)
+ incl, suborigin = self.__include(record)
if incl:
- sub = MasterFile(incl, self.__origin)
- for name, ttl, rrclass, rrtype, rdata in sub.zonedata():
- yield (name, ttl, rrclass, rrtype, rdata)
+ if self.__filesize == 0:
+ percent = 100
+ else:
+ percent = (self.__cur * 100)/self.__filesize
+ if self.__verbose:
+ sys.stdout.write("\r" + (80 * " "))
+ sys.stdout.write("\rIncluding \"%s\" from \"%s\"\n" % (incl, self.__datafile))
+ MasterFile.__file_level += 1
+ MasterFile.__file_type = "included "
+ sub = MasterFile(incl, suborigin, self.__verbose)
+
+ for rrname, ttl, rrclass, rrtype, rdata in sub.zonedata():
+ yield (rrname, ttl, rrclass, rrtype, rdata)
+ if self.__verbose:
+ sub.closeverbose()
+ MasterFile.__file_level -= 1
+ if MasterFile.__file_level == 0:
+ MasterFile.__file_type = ""
del sub
continue
@@ -373,7 +491,7 @@
if rl[0] == '@':
rl[0] = self.__origin
if not self.__origin:
- rl[0] = '.'
+ raise MasterFileError("Cannot parse RR, No $ORIGIN: " + record)
record = ' '.join(rl)
result = self.__four(record, name)
@@ -387,36 +505,43 @@
if not result:
first, rdata = pop(record)
if istype(first):
- result = name, self.__ttl, self.__rrclass, first, rdata
+ result = name, self.__getttl(), self.__rrclass, first, rdata
if not result:
raise MasterFileError("Cannot parse RR: " + record)
name, ttl, rrclass, rrtype, rdata = result
- if name[-1] != '.':
- name += '.' + self.__origin
+ name = self.__statedname(name, record)
if rrclass.lower() != 'in':
raise MasterFileError("CH and HS zones not supported")
-
- if not ttl:
- raise MasterFileError("No TTL specified; zone rejected")
# add origin to rdata containing names, if necessary
if rrtype.lower() in ('cname', 'dname', 'ns', 'ptr'):
if not isname(rdata):
raise MasterFileError("Invalid " + rrtype + ": " + rdata)
- if rdata[-1] != '.':
- rdata += '.' + self.__origin
+ rdata = self.__statedname(rdata, record)
+
if rrtype.lower() == 'soa':
soa = rdata.split()
if len(soa) < 2 or not isname(soa[0]) or not isname(soa[1]):
raise MasterFileError("Invalid " + rrtype + ": " + rdata)
- if soa[0][-1] != '.':
- soa[0] += '.' + self.__origin
- if soa[1][-1] != '.':
- soa[1] += '.' + self.__origin
+ soa[0] = self.__statedname(soa[0], record)
+ soa[1] = self.__statedname(soa[1], record)
+ if not MasterFile.__ttl and not ttl:
+ MasterFile.__ttl = MasterFile.__ttl or parse_ttl(soa[-1])
+ ttl = MasterFile.__ttl
+
+ for index in range(3, len(soa)):
+ if isttl(soa[index]):
+ soa[index] = parse_ttl(soa[index])
+ else :
+ raise MasterFileError("No TTL specified; in soa record!")
rdata = ' '.join(soa)
+
+ if not ttl:
+ raise MasterFileError("No TTL specified; zone rejected")
+
if rrtype.lower() == 'mx':
mx = rdata.split()
if len(mx) != 2 or not isname(mx[1]):
@@ -424,7 +549,7 @@
if mx[1][-1] != '.':
mx[1] += '.' + self.__origin
rdata = ' '.join(mx)
-
+ MasterFile.__records_num += 1
yield (name, ttl, rrclass, rrtype, rdata)
#########################################################################
@@ -436,16 +561,22 @@
return self.__name
old_origin = self.__origin
self.__origin = self.__initial_origin
+ cur_value = self.__cur
old_location = self.__zonefile.tell()
+ old_verbose = self.__verbose
+ self.__verbose = False
self.__zonefile.seek(0)
+
for name, ttl, rrclass, rrtype, rdata in self.zonedata():
if rrtype.lower() == 'soa':
break
self.__zonefile.seek(old_location)
self.__origin = old_origin
+ self.__cur = cur_value
if rrtype.lower() != 'soa':
raise MasterFileError("No SOA found")
self.__name = name
+ self.__verbose = old_verbose
return name
#########################################################################
@@ -454,7 +585,8 @@
def reset(self):
self.__zonefile.seek(0)
self.__origin = self.__initial_origin
- self.__ttl = ''
+ MasterFile.__ttl = ''
+ MasterFile.__lastttl = ''
#########################################################################
# main: used for testing; parse a zone file and print out each record
Modified: branches/trac172/src/lib/xfr/Makefile.am
==============================================================================
--- branches/trac172/src/lib/xfr/Makefile.am (original)
+++ branches/trac172/src/lib/xfr/Makefile.am Wed Jun 30 18:48:15 2010
@@ -10,20 +10,16 @@
libxfr_la_SOURCES = xfrout_client.h xfrout_client.cc
libxfr_la_SOURCES += fd_share.h fd_share.cc
-if HAVE_BOOST_PYTHON
-pyexec_LTLIBRARIES = bind10_xfr.la
-bind10_xfr_la_SOURCES = python_xfr.cc fd_share.cc fd_share.h
-bind10_xfr_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-bind10_xfr_la_CXXFLAGS = $(AM_CXXFLAGS)
-if GCC_WERROR_OK
-# XXX: Boost.Python triggers strict aliasing violation, so if we use -Werror
-# we need to suppress the warnings.
-bind10_xfr_la_CXXFLAGS += -fno-strict-aliasing
-endif
-bind10_xfr_la_LDFLAGS = $(BOOST_LDFLAGS) $(PYTHON_LDFLAGS)
+pyexec_LTLIBRARIES = libxfr_python.la
+libxfr_python_la_SOURCES = fdshare_python.cc fd_share.cc fd_share.h
+libxfr_python_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
+libxfr_python_la_CXXFLAGS = $(AM_CXXFLAGS)
+
+#bind10_xfr_la_LDFLAGS = $(BOOST_LDFLAGS) $(PYTHON_LDFLAGS)
+
# Python prefers .so, while some OSes (specifically MacOS) use a different
# suffix for dynamic objects. -module is necessary to work this around.
-bind10_xfr_la_LDFLAGS += -module
-bind10_xfr_la_LIBADD = $(BOOST_PYTHON_LIB) $(PYTHON_LIB)
-endif
+#bind10_xfr_la_LDFLAGS += -module
+#bind10_xfr_la_LIBADD = $(BOOST_PYTHON_LIB) $(PYTHON_LIB)
+#endif
Modified: branches/trac172/tools/import_boost.sh
==============================================================================
--- branches/trac172/tools/import_boost.sh (original)
+++ branches/trac172/tools/import_boost.sh Wed Jun 30 18:48:15 2010
@@ -30,6 +30,7 @@
boost/iterator
boost/mpl
boost/preprocessor
+boost/python
boost/range
boost/smart_ptr
boost/type_traits
More information about the bind10-changes
mailing list